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.PORTis 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