
Company News
Free Business Plan Upgrades for Open Source Maintainers
Open source maintainers are under more pressure than ever. We're raising our open source program from the Team plan to the Business plan, free.
@whenlabs/envalid
Advanced tools
Type safety for .env files. Define a schema, validate every environment against it. Catch missing vars, wrong types, format mismatches, and drift between environments before they cause runtime failures.
Part of the WhenLabs toolchain.
| envalid | dotenv | Manual .env checking | |
|---|---|---|---|
| Type-safe schema | YAML schema with types, ranges, patterns | No validation | Eyeball it |
| Detects undocumented vars | Scans codebase for process.env usage missing from schema | No detection | grep and hope |
| Validates against schema | Catches wrong types, missing vars, format mismatches | Loads vars, no validation | Compare files by hand |
| Multi-environment sync | Validates .env, .env.staging, .env.production together | One file at a time | Diff files manually |
| CI-ready | --ci flag, exit codes, JSON/Markdown output | Not designed for CI | Custom scripting |
npm install -g envalid
Or use directly with npx:
npx envalid init
Requirements: Node.js >= 20
# 1. Generate a schema from your existing .env
envalid init
# 2. Validate your .env against the schema
envalid validate
# 3. Generate an up-to-date .env.example
envalid generate-example
Create a .env.schema file in your project root (YAML):
version: 1
variables:
NODE_ENV:
type: enum
values: [development, staging, production, test]
required: true
default: development
description: "Application environment"
PORT:
type: integer
required: true
default: 3000
range: [1024, 65535]
description: "HTTP server port"
DATABASE_URL:
type: url
required: true
protocol: [postgres, postgresql]
description: "PostgreSQL connection string"
sensitive: true
STRIPE_SECRET_KEY:
type: string
required: true
pattern: "^sk_(test|live)_[a-zA-Z0-9]+"
sensitive: true
environments: [staging, production]
ENABLE_FEATURE_X:
type: boolean
required: false
default: false
CORS_ORIGINS:
type: csv
required: false
description: "Comma-separated list of allowed CORS origins"
groups:
payments:
variables: [STRIPE_SECRET_KEY]
required_in: [staging, production]
| Type | Validates | Example |
|---|---|---|
string | Non-empty string, optional regex pattern, minLength, maxLength | sk_test_abc123 |
integer | Parseable integer, optional range | 3000 |
float | Parseable float, optional range | 0.95 |
boolean | true, false, 1, 0 | true |
url | Valid URL, optional protocol constraint | postgres://localhost/db |
email | Valid email format | admin@example.com |
enum | One of specified values | development |
csv | Comma-separated values | http://a.com,http://b.com |
json | Valid JSON string | {"key": "value"} |
path | File/directory path | ./data/uploads |
semver | Valid semver string | 1.2.3 |
| Option | Type | Description |
|---|---|---|
type | string | One of the supported types above (required) |
required | boolean | Whether the variable must be present (default: true) |
default | any | Default value |
description | string | Human-readable description |
sensitive | boolean | Mask value in output |
environments | string[] | Only required in these environments |
pattern | string | Regex pattern (for string type) |
range | [min, max] | Numeric range (for integer/float types) |
values | string[] | Allowed values (for enum type) |
protocol | string[] | Allowed URL protocols (for url type) |
minLength | number | Minimum string length |
maxLength | number | Maximum string length |
Groups let you bundle related variables and enforce that all variables in a group are present for specific environments:
groups:
payments:
variables: [STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET]
description: "Payment processing"
required_in: [staging, production]
envalid initScan an existing .env file and generate a starter .env.schema with inferred types. Envalid auto-detects booleans, integers, floats, URLs, emails, semver strings, JSON, CSV values, and flags sensitive-looking keys (containing secret, key, token, password, etc.).
envalid init # reads .env, writes .env.schema
envalid init -e .env.production # read from a specific file
envalid init --force # overwrite existing schema
envalid validateValidate a .env file against the schema.
envalid validate # basic validation
envalid validate --environment production # check production requirements
envalid validate --ci # strict mode (warnings become errors)
envalid validate --format json # machine-readable output
envalid validate -s custom.schema -e .env.staging # custom paths
Exit codes: 0 = valid, 1 = validation failed, 2 = tool error
envalid diffCompare two .env files side by side. When a schema is provided, sensitive values are automatically masked.
envalid diff .env .env.production
envalid diff .env .env.staging -s .env.schema # masks sensitive values
envalid diff .env .env.production --format json
envalid syncValidate multiple environments against the schema at once. Environment names are inferred from file names (e.g. .env.production -> production).
envalid sync --environments .env,.env.staging,.env.production
envalid sync --environments .env,.env.production --ci
envalid generate-exampleGenerate an .env.example file from the schema with descriptions, defaults, and type-appropriate placeholders.
envalid generate-example # writes .env.example
envalid generate-example -o .env.template # custom output path
envalid onboardInteractive guided setup for new developers. Walks through each required variable, explains what it is, validates input in real-time, and writes a .env file. Enum types get a selection list; sensitive values use masked input.
envalid onboard
envalid onboard -s custom.schema -o .env.local
envalid detectScan your codebase for environment variable usage and compare with the schema. Finds variables referenced in code but missing from the schema, and schema variables not used in code.
envalid detect # scan current directory
envalid detect -d src # scan specific directory
envalid detect --exclude vendor,tmp # exclude directories
Supports: process.env.X (Node.js), import.meta.env.X (Vite), os.environ / os.getenv (Python), ENV[] (Ruby), os.Getenv (Go), env::var (Rust), getenv / $_ENV (PHP).
file:line references -- envalid detect now shows exactly where each undocumented variable is used:
REDIS_URL (missing from schema)
src/cache.ts:14
src/workers/queue.ts:7
envalid secretsScan your codebase for hardcoded API keys, tokens, and passwords. Reports file:line locations but redacts actual values to keep output safe for logs.
envalid secrets # scan current directory
envalid secrets -d src # scan specific directory
src/config.ts:23 STRIPE_KEY = "sk_live_••••••••"
src/email.ts:5 SENDGRID_TOKEN = "SG.••••••••"
envalid init now infers richer types from .env values:
required: false (optional)PORT, *_PORT variables get type: port with range [1, 65535]"true" / "false" values are inferred as type: booleantype: urlenvalid hookManage git pre-commit hooks for automatic validation. The hook runs envalid validate --ci before each commit and blocks the commit on failure.
envalid hook install # install pre-commit hook
envalid hook uninstall # remove pre-commit hook
envalid hook status # check if hook is installed
Works with custom core.hooksPath configurations (e.g. Husky).
name: Environment Validation
on: [pull_request]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: WhenLabs-org/envalid@v1
with:
schema: .env.schema
environment: production
fail-on-warning: true
| Input | Default | Description |
|---|---|---|
schema | .env.schema | Path to schema file |
env-file | .env | Path to .env file to validate |
environment | Target environment (e.g. production) | |
format | terminal | Output format: terminal, json, markdown |
fail-on-warning | false | Treat warnings as errors |
node-version | 20 | Node.js version to use |
npx envalid validate --ci --environment production
The --ci flag makes warnings into errors and returns exit code 1 on any issue.
Use --format to control output:
Configure defaults via .envalidrc, .envalidrc.json, envalid.config.js, or package.json#envalid:
{
"schema": ".env.schema",
"env": ".env",
"format": "terminal",
"ci": false,
"exclude": ["vendor", "tmp"]
}
CLI flags always override config file values.
import { parseSchemaFile, readEnvFile, validate } from "envalid";
const schema = parseSchemaFile(".env.schema");
const envFile = readEnvFile(".env");
const result = validate(schema, envFile, { environment: "production" });
console.log(result.valid); // true/false
console.log(result.issues); // ValidationIssue[]
console.log(result.stats); // { total, valid, errors, warnings, missing }
All CLI functionality is available as importable functions:
import {
// Schema
parseSchemaFile, parseSchemaString, validateValue,
// Validation
validate, diffEnvFiles, syncCheck,
// Env files
readEnvFile, parseEnvString, detectEnvUsage,
// Generation
generateExample, inferType, generateSchema,
// Reporting
createReporter,
// Git hooks
installHook, uninstallHook, isHookInstalled, getGitRoot,
// Config
loadConfig, mergeOptions,
// Utilities
maskValue,
} from "envalid";
Full TypeScript types are exported for EnvSchema, VariableSchema, ValidationResult, ValidationIssue, DiffResult, Reporter, EnvFile, DetectionResult, and more.
envalid/
├── src/
│ ├── cli.ts # Commander.js entry point
│ ├── index.ts # Public API exports
│ ├── config.ts # cosmiconfig-based config loading
│ ├── errors.ts # Custom error classes
│ ├── commands/
│ │ ├── validate.ts # Core validation logic
│ │ ├── init.ts # Schema generation from .env
│ │ ├── diff.ts # Cross-environment comparison
│ │ ├── sync.ts # Multi-environment sync check
│ │ ├── generate.ts # .env.example generation
│ │ ├── onboard.ts # Interactive developer setup
│ │ └── hook.ts # Git hook management
│ ├── schema/
│ │ ├── types.ts # TypeScript type definitions
│ │ ├── parser.ts # YAML schema parser (Zod-validated)
│ │ └── validators.ts # Per-type validation functions
│ ├── env/
│ │ ├── reader.ts # .env file reader (dotenv)
│ │ ├── writer.ts # .env file writer (with quoting)
│ │ └── detector.ts # Codebase env var usage scanner
│ ├── reporters/
│ │ ├── index.ts # Reporter factory
│ │ ├── terminal.ts # Colored terminal output
│ │ ├── json.ts # JSON output for CI
│ │ └── markdown.ts # Markdown tables for PRs
│ └── utils/
│ ├── git.ts # Git hook install/uninstall
│ └── crypto.ts # Sensitive value masking
├── tests/ # Vitest test suite
├── action.yml # GitHub Action definition
├── tsconfig.json
├── tsup.config.ts # Build config (ESM, Node 20)
└── vitest.config.ts
# Install dependencies
npm install
# Build
npm run build
# Watch mode (rebuild on changes)
npm run dev
# Run tests
npm test
# Run tests once
npm run test:run
# Type check
npm run lint
MIT
FAQs
Type safety for .env files
The npm package @whenlabs/envalid receives a total of 89 weekly downloads. As such, @whenlabs/envalid popularity was classified as not popular.
We found that @whenlabs/envalid demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Company News
Open source maintainers are under more pressure than ever. We're raising our open source program from the Team plan to the Business plan, free.

Security News
The supply chain control that delays freshly published gems now covers lockfile generation and gem vendoring in Ruby projects.

Security News
During a UK cyber test, a Mythos 5 agent used sockpuppets, social engineering, and prompt injection to try to get a maintainer to merge malware.