ZenoZENO

Local setup & env vars

Managing environment variables and local development configuration

Zeno apps read their configuration from environment variables, which you set per environment in .env files.

Environment files

.env                 # Default values (committed)
.env.local           # Local overrides (not committed)
.env.development     # Development-specific
.env.production      # Production-specific
.env.test            # Test-specific

Loading order

Environment variables are loaded in this order (later overrides earlier):

  1. .env
  2. .env.local
  3. .env.[NODE_ENV]
  4. .env.[NODE_ENV].local

Next.js variables

For Next.js apps, prefix public variables with NEXT_PUBLIC_:

# Server-only (secure)
DATABASE_URL=postgres://...
API_SECRET=secret123

# Browser-accessible
NEXT_PUBLIC_API_URL=https://api.example.com
NEXT_PUBLIC_APP_NAME=My App

TypeScript support

Create a typed env file for autocomplete:

env.ts
export const env = {
  DATABASE_URL: process.env.DATABASE_URL!,
  API_SECRET: process.env.API_SECRET!,
  NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL!,
}

Vitest environment

Tests use .env.test and NODE_ENV=test. The shared config from @zeno-lib/test loads the env files for you, through Vite's loadEnv in test mode:

vitest.config.ts
export { defaultConfig as default } from "@zeno-lib/test/configs"

Turborepo

Pass environment variables to Turborepo tasks:

turbo.json
{
  "globalEnv": ["NODE_ENV"],
  "tasks": {
    "build": {
      "inputs": ["$TURBO_DEFAULT$", ".env*"]
    },
    "e2e": {
      "passThroughEnv": ["PLAYWRIGHT_*"]
    }
  }
}

Security

  • Never commit secrets. Use .env.local for sensitive values.
  • Use .gitignore. Make sure it ignores .env*.local.
  • Validate at startup. Check that the required variables exist.
  • Rotate credentials. Replace secrets on a regular schedule.

A startup check can look like this:

function validateEnv() {
  const required = ["DATABASE_URL", "API_SECRET"]
  for (const key of required) {
    if (!process.env[key]) {
      throw new Error(`Missing required env var: ${key}`)
    }
  }
}