bknd-env-config

Use when configuring environment variables for Bknd projects. Covers .env files, secrets management, env injection in config, platform-specific variables, and production security.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "bknd-env-config" with this command: npx skills add cameronapak/bknd-skills/cameronapak-bknd-skills-bknd-env-config

Environment Variables Configuration

Configure environment variables for Bknd applications across development and production.

Prerequisites

  • Bknd project initialized (bknd.config.ts exists)
  • Understanding of your deployment target (local, Cloudflare, Vercel, etc.)

When to Use UI Mode

  • Viewing current config via admin panel
  • N/A for environment variables - all done via code/files

When to Use Code Mode

  • Creating .env files
  • Configuring secrets in bknd.config.ts
  • Setting up platform-specific env vars
  • All environment configuration tasks

Code Approach

Step 1: Create .env File

Create .env in project root:

# Database
DB_URL=file:data.db
DB_TOKEN=

# Auth
JWT_SECRET=your-secret-here-min-32-chars

# Server
PORT=3000

# Development
LOCAL=true

Step 2: Inject Env in Config

Access env vars via the env parameter in bknd.config.ts:

import type { CliBkndConfig } from "bknd";

export default {
  app: (env) => ({
    connection: {
      url: env.DB_URL ?? "file:data.db",
      authToken: env.DB_TOKEN,
    },
    auth: {
      jwt: {
        secret: env.JWT_SECRET ?? "dev-secret-change-in-prod",
      },
    },
  }),
} satisfies CliBkndConfig;

The env parameter receives all environment variables loaded from .env files and system environment.

Step 3: Use .dev.vars for Dev Overrides (Optional)

Bknd loads env files in order (later takes precedence):

  1. .env - Base configuration
  2. .dev.vars - Development-specific overrides (Cloudflare style)

Create .dev.vars for local dev overrides:

# .dev.vars - Dev-only, overrides .env
DB_URL=:memory:
JWT_SECRET=dev-only-secret

Common Environment Variables

Database

VariableDescriptionExample
DB_URLDatabase connection URLfile:data.db, libsql://db.turso.io
DB_TOKENLibSQL/Turso auth tokeneyJhbGciOiJFZERTQSIs...

Authentication

VariableDescriptionExample
JWT_SECRETJWT signing secret (min 32 chars)your-very-long-secret-key-here
GOOGLE_CLIENT_IDGoogle OAuth client ID123456.apps.googleusercontent.com
GOOGLE_CLIENT_SECRETGoogle OAuth secretGOCSPX-xxx
GITHUB_CLIENT_IDGitHub OAuth client IDIv1.abc123
GITHUB_CLIENT_SECRETGitHub OAuth secretsecret_xxx

Media/Storage

VariableDescriptionExample
S3_ACCESS_KEYS3/R2 access keyAKIAIOSFODNN7EXAMPLE
S3_SECRET_KEYS3/R2 secret keywJalrXUtnFEMI/K7MDENG/...
S3_ENDPOINTS3-compatible endpointhttps://bucket.s3.region.amazonaws.com
CLOUDINARY_CLOUD_NAMECloudinary cloud namemy-cloud
CLOUDINARY_API_KEYCloudinary API key123456789012345
CLOUDINARY_API_SECRETCloudinary API secretabcdefghijk...

Server

VariableDescriptionDefault
PORTServer port3000
LOCALDisable telemetry-
NODE_ENV / ENVIRONMENTEnvironment modedevelopment

Complete Configuration Example

import type { CliBkndConfig } from "bknd";
import { em, entity, text } from "bknd";

const schema = em({
  posts: entity("posts", { title: text().required() }),
});

export default {
  app: (env) => ({
    // Database
    connection: {
      url: env.DB_URL ?? "file:data.db",
      authToken: env.DB_TOKEN,
    },

    // Production flag
    isProduction: env.NODE_ENV === "production",

    // Pass all secrets to app
    secrets: env,
  }),

  config: {
    data: schema.toJSON(),

    // Auth with env-based secrets
    auth: {
      enabled: true,
      jwt: {
        secret: env.JWT_SECRET,
        issuer: "my-app",
      },
      strategies: {
        password: { enabled: true },
        google: env.GOOGLE_CLIENT_ID ? {
          config: {
            name: "google",
            type: "oidc",
            client: {
              client_id: env.GOOGLE_CLIENT_ID,
              client_secret: env.GOOGLE_CLIENT_SECRET,
            },
          },
        } : undefined,
      },
    },

    // Media with env-based adapter config
    media: {
      enabled: true,
      adapter: {
        type: "s3",
        config: {
          access_key: env.S3_ACCESS_KEY,
          secret_access_key: env.S3_SECRET_KEY,
          url: env.S3_ENDPOINT,
        },
      },
    },
  },
} satisfies CliBkndConfig;

Platform-Specific Configuration

Cloudflare Workers/Pages

Use wrangler.toml for non-secret vars and dashboard for secrets:

# wrangler.toml
[vars]
ENVIRONMENT = "production"

Set secrets via CLI:

npx wrangler secret put JWT_SECRET
npx wrangler secret put DB_TOKEN

Access in config:

import type { CloudflareBkndConfig } from "bknd/adapter/cloudflare";

export default {
  app: (env) => ({
    connection: env.DB,  // D1 binding
    isProduction: env.ENVIRONMENT === "production",
    secrets: env,
  }),
} satisfies CloudflareBkndConfig;

Vercel

Use Vercel dashboard or CLI for env vars:

vercel env add JWT_SECRET production
vercel env add DB_URL production

Or .env.local for local development (auto-loaded by Next.js):

# .env.local
DB_URL=file:data.db
JWT_SECRET=dev-secret

Docker

Pass via docker-compose or -e flag:

# docker-compose.yml
services:
  app:
    environment:
      - DB_URL=file:/data/app.db
      - JWT_SECRET=${JWT_SECRET}
    env_file:
      - .env.production

Generate .env Template

Use CLI to generate env template from your config:

# Output required secrets as template
npx bknd secrets --template --format env

# Save to file
npx bknd secrets --template --format env --out .env.example

This creates a template without actual values, safe for version control.

SyncSecrets Option

Auto-generate .env.example on config changes:

export default {
  syncSecrets: {
    enabled: true,
    outFile: ".env.example",
    format: "env",  // or "json"
  },
  app: (env) => ({ ... }),
} satisfies CliBkndConfig;

Environment-Based Feature Flags

Conditionally enable features based on environment:

export default {
  app: (env) => ({
    connection: { url: env.DB_URL ?? "file:data.db" },
  }),
  config: {
    auth: {
      enabled: true,
      // Only enable OAuth in production (requires secrets)
      strategies: {
        password: { enabled: true },
        google: env.GOOGLE_CLIENT_ID ? {
          config: {
            name: "google",
            type: "oidc",
            client: {
              client_id: env.GOOGLE_CLIENT_ID,
              client_secret: env.GOOGLE_CLIENT_SECRET,
            },
          },
        } : undefined,
      },
    },
    // Only enable S3 media in production
    media: env.S3_ACCESS_KEY ? {
      enabled: true,
      adapter: {
        type: "s3",
        config: {
          access_key: env.S3_ACCESS_KEY,
          secret_access_key: env.S3_SECRET_KEY,
          url: env.S3_ENDPOINT,
        },
      },
    } : {
      enabled: false,
    },
  },
} satisfies CliBkndConfig;

Database Connection Priority

Bknd resolves database connection in order:

  1. --db-url CLI argument
  2. Config file connection.url
  3. --memory flag (uses :memory:)
  4. DB_URL environment variable
  5. Fallback: file:data.db

Verification

Check env loading:

# Server logs show connection source
npx bknd run
# Look for: "Using connection from ..."

Test env injection:

// Temporarily log env in config
app: (env) => {
  console.log("Loaded env:", Object.keys(env));
  return { ... };
},

Verify secrets command:

npx bknd secrets --template

Common Pitfalls

.env Not Loading

Problem: Env vars undefined in config

Fix: Check file location and format:

# .env must be in project root (same level as bknd.config.ts)
ls -la .env

# No quotes around values
DB_URL=file:data.db     # Correct
DB_URL="file:data.db"   # May cause issues

JWT_SECRET Too Short

Problem: Auth fails or warning about weak secret

Fix: Use minimum 32 characters:

# Generate secure secret
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
# or
openssl rand -hex 32

Secrets in Version Control

Problem: Committed .env with real secrets

Fix:

# Add to .gitignore
echo ".env" >> .gitignore
echo ".env.local" >> .gitignore
echo ".dev.vars" >> .gitignore

# Remove from git history if committed
git rm --cached .env

Platform Env Not Available

Problem: env.VAR is undefined in deployed app

Fix: Platform-specific setup:

  • Vercel: Add via dashboard or vercel env add
  • Cloudflare: Add via wrangler secret put or dashboard
  • Docker: Check environment: or env_file: in compose

Wrong Fallback in Production

Problem: Using dev defaults in production

Fix: Fail fast instead of fallback:

app: (env) => {
  if (!env.JWT_SECRET && env.NODE_ENV === "production") {
    throw new Error("JWT_SECRET required in production");
  }
  return {
    auth: {
      jwt: { secret: env.JWT_SECRET ?? "dev-only" },
    },
  };
},

DOs and DON'Ts

DO:

  • Use .env.example as template (no real values)
  • Generate JWT_SECRET with crypto-safe randomness
  • Use platform-specific secret management in production
  • Validate required secrets on app start
  • Use syncSecrets to keep .env.example updated

DON'T:

  • Commit .env with real secrets
  • Use weak or short JWT secrets
  • Hardcode secrets in config files
  • Use same secrets across environments
  • Log env vars containing secrets

Related Skills

  • bknd-local-setup - Initial project setup
  • bknd-setup-auth - Configure authentication
  • bknd-oauth-setup - OAuth provider configuration
  • bknd-storage-config - Storage adapter configuration
  • bknd-production-config - Production configuration
  • bknd-deploy-hosting - Deployment options

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Security

bknd-row-level-security

No summary provided by upstream source.

Repository SourceNeeds Review
General

btca-bknd-repo-learn

No summary provided by upstream source.

Repository SourceNeeds Review
General

bknd-registration

No summary provided by upstream source.

Repository SourceNeeds Review
General

bknd-bulk-operations

No summary provided by upstream source.

Repository SourceNeeds Review