DEV Community

Chintan Shah
Chintan Shah

Posted on

Make your app crash at startup, not in production

2am. Slack notification. Production app is down.

The error? Cannot read property 'split' of undefined

Turns out ALLOWED_ORIGINS wasn't set in production. The app started fine. Health checks passed. Then the first CORS request came in and crashed the server.

Or that time STRIPE_SECRET_KEY had a trailing space from copy-paste. App started. First payment request? Failed. Took 30 minutes to figure out.

Or when someone set ENABLE_CACHING=false as a string, but the code checked if (config.ENABLE_CACHING) - string "false" is truthy, so caching stayed on.

This stuff happens constantly.

The real problem isn't missing env vars

It's that your app doesn't know they're wrong until it tries to use them.

const port = process.env.PORT || 3000
const apiKey = process.env.API_KEY
const enableCache = process.env.ENABLE_CACHING
const origins = process.env.ALLOWED_ORIGINS?.split(',')

// App starts fine
// apiKey is undefined
// enableCache is the string "false" (truthy!)
// origins will crash when undefined
// Everything looks good... until it's not
Enter fullscreen mode Exit fullscreen mode

Your app starts. Health checks pass. Then 5 minutes later, it tries to call the API and crashes because apiKey is undefined.

Or your boolean flag is the string "false" but your code checks if (enableCache) - string "false" is truthy, so the logic is backwards.

Or someone has a trailing space in STRIPE_KEY=" sk_live_123 " and all payment requests fail with cryptic auth errors.

Fail fast, not later

What if your app refused to start unless everything was valid?

import { env } from 'envconfig-kit'

const config = env({
  PORT: { type: 'number', default: 3000 },
  API_KEY: { type: 'string' },
  DATABASE_URL: { type: 'url' },
})
Enter fullscreen mode Exit fullscreen mode

Now if API_KEY is missing or DATABASE_URL isn't a valid URL, your app won't start at all.

❌ Environment validation failed:

  API_KEY: Missing required environment variable
  ➜ Fix: Add to .env file
    Example: API_KEY=your-value-here

  STRIPE_SECRET_KEY: Value contains leading/trailing whitespace
  ➜ Fix: Remove extra spaces
    Current: " sk_live_123 "
    Expected: "sk_live_123"
Enter fullscreen mode Exit fullscreen mode

Crash at startup, not during runtime. Get useful error messages, not undefined is not a function.

What you get

Type safety

config.PORT       // number
config.API_KEY    // string
config.DEBUG      // boolean
config.REDIS_URL  // string | undefined (if optional)
Enter fullscreen mode Exit fullscreen mode

TypeScript knows the exact types. No more process.env.PORT as number.

Built-in .env loading

No need for dotenv. Automatically loads from .env, .env.local, .env.production, etc.

const config = env({ 
  PORT: { type: 'number' } 
})
// Just works. No extra setup.
Enter fullscreen mode Exit fullscreen mode

Transform values

Parse arrays, trim whitespace, normalize URLs:

const config = env({
  ALLOWED_ORIGINS: {
    type: 'string',
    transform: (value) => value.split(',').map(s => s.trim())
  },
  API_URL: {
    type: 'url',
    transform: (value) => value.replace(/\/$/, '') // remove trailing slash
  }
})

config.ALLOWED_ORIGINS // ['http://localhost:3000', 'https://app.com']
Enter fullscreen mode Exit fullscreen mode

Validation types that matter

  • string, number, boolean - the basics
  • url - validates protocol, catches localhost and http:/missing-slash
  • email - actual email validation
  • port - number between 0-65535

Real example

Here's what a typical API config looks like:

import { env } from 'envconfig-kit'

export const config = env({
  // Server
  PORT: { type: 'port', default: 3000 },
  HOST: { type: 'string', default: '0.0.0.0' },
  NODE_ENV: { type: 'string', default: 'development' },

  // Database
  DATABASE_URL: { type: 'url' },

  // Redis (optional)
  REDIS_URL: { type: 'url', optional: true },

  // API Keys
  API_KEY: { type: 'string' },
  JWT_SECRET: { type: 'string' },

  // External services
  STRIPE_KEY: { type: 'string' },
  SENDGRID_KEY: { type: 'string' },

  // CORS
  ALLOWED_ORIGINS: {
    type: 'string',
    default: 'http://localhost:3000',
    transform: (value) => value.split(',')
  },

  // Feature flags
  ENABLE_ANALYTICS: { type: 'boolean', default: false },
})

// Now everything is typed and validated
// App won't start if anything is wrong
Enter fullscreen mode Exit fullscreen mode

CLI tools

Generate .env.example for your team:

npx envconfig-kit generate
Enter fullscreen mode Exit fullscreen mode

Validate before deployment:

npx envconfig-kit check
Enter fullscreen mode Exit fullscreen mode

Health check:

npx envconfig-kit doctor
Enter fullscreen mode Exit fullscreen mode

Install

npm install envconfig-kit
Enter fullscreen mode Exit fullscreen mode

Zero dependencies. 3KB minified. Works with CommonJS and ESM.


Stop debugging undefined errors at 2am. Make your app fail fast with clear error messages.

GitHub | npm

Have environment variable horror stories? Drop them in the comments.

Top comments (0)