envalid vs envscan

envalid validates env vars against a TypeScript schema you write. envscan reads your source code to know which vars you need — then generates and validates automatically.

Jump to waitlist ↓

Side-by-side comparison

Feature envalid envscan
TypeScript-first API
Validates at app startup
Auto-discovers vars from source
Generates .env.example automatically
File + line location of each var
Type inference from var naming (_PORT, _SECRET, _URL)
No schema file to maintain
Works as CI gate (exit code 1)
GitHub Action with PR comments (CI tier)
Custom validators / transforms
Coercion (string to number, bool) (validates existence only)
Zero config — no schema needed

The workflow

envalid (TypeScript)

// Install: npm install envalid
import { cleanEnv, str, port, bool } from 'envalid'

// You maintain this schema manually
const env = cleanEnv(process.env, {
  DATABASE_URL: str(),
  PORT: port({ default: 3000 }),
  JWT_SECRET: str(),
  REDIS_URL: str({ default: undefined }),
  DEBUG: bool({ default: false }),
})
// Throws on missing required vars at startup

You write the schema. Add a new process.env reference anywhere in your codebase — if you forget to add it to cleanEnv, envalid won't validate it.

envscan

# Scan source code for env vars
$ envscan scan
Found 8 environment variables:
  DATABASE_URL    type: url     src/db.ts:12
  PORT            type: number  src/server.ts:5
  JWT_SECRET      type: secret  src/auth.ts:8

# Generate .env.example from what it finds
$ envscan generate
# Wrote .env.example (8 vars)

# Validate before deploy
$ envscan validate
Validation: 7/8 vars set. Missing: JWT_SECRET
Exit code: 1

No schema to write. envscan reads your .ts and .js files — what's in your code is what gets validated.

The schema drift problem

envalid's schema-first approach gives you TypeScript types and smart coercion (string-to-number, string-to-bool). Those are genuine advantages for runtime type safety. The trade-off: the schema is another file to maintain. Add process.env.NEW_STRIPE_KEY to your payment module on Monday; forget to add it to cleanEnv; envalid has no way to know. Your new env var ships undocumented.

envscan inverts this: the schema comes from your source code. Run envscan scan and it tells you every env var referenced in every file, with exact file and line locations. Run envscan generate and it writes .env.example for you.

When to use envalid

  • You want TypeScript types for env vars (env.PORT is a number, not a string)
  • You need coercion (string-to-number, comma-delimited arrays, booleans)
  • You want custom validators with meaningful error messages
  • You have a well-maintained schema and want runtime type safety

When to use envscan

  • You want .env.example generated, not written manually
  • You want CI to fail when anyone adds env vars without documenting them
  • You want file and line context for every var in your project
  • You want zero config — no schema file to set up

Get Early Access

envscan is in development. Join the waitlist to get notified at launch.

From the team behind textlens — 96/week npm downloads.

Get Early Access

$0 — no credit card required