envalid
Type-safe environment variable validation and cleanup for Node.js and Bun with zero runtime dependencies.
Repository Health
Technical Analysis
Envalid validates and sanitizes environment variables for Node.js, Bun, and other JS runtimes, ensuring a program only starts when all of its required environment dependencies are present and well-formed. Built entirely in TypeScript with strong type inference and zero runtime dependencies, it wraps process.env in a frozen, strictly-typed object so validated env vars can’t drift or be mutated once the app is running.
Beyond basic presence checks, envalid ships built-in validators for strings, booleans, numbers, emails, hosts, ports, URLs, and JSON, plus devDefault/testDefault fallbacks that adapt required vars per NODE_ENV, custom validators via makeValidator, and a pluggable reporter/middleware system for teams who want to customize error handling or extend the cleaned env object.
What You Get
- Built-in validators for str, bool, num, email, host, port, url, and json env var types
- An immutable, proxy-wrapped env object that throws on unvalidated property access or mutation attempts
- Environment-aware defaults via default, devDefault, and testDefault, so required vars can differ by NODE_ENV
- isDev/isProd/isTest convenience accessors computed automatically from NODE_ENV
- Custom validator and reporter APIs (makeValidator, customCleanEnv) for extending validation and error handling
Common Use Cases
- Validating required API keys and secrets before a Node.js server boots, failing fast with a readable error list
- Enforcing different required env vars for production vs. local development using devDefault
- Type-safe access to environment configuration in TypeScript projects, with types inferred directly from validator specs
- Providing executable documentation of an app’s environment requirements for new contributors
Under The Hood
Architecture
Envalid is a small functional pipeline rather than a class hierarchy: core.ts’s getSanitizedEnv() iterates each validator spec, reads the raw value via readRawEnvValue(), applies default/devDefault/testDefault fallback logic keyed off NODE_ENV, and delegates actual parsing to each spec’s _parse function (defined in validators.ts and created by the factories in makers.ts); envalid.ts’s cleanEnv() then hands the sanitized object to middleware.ts, which layers on accessorMiddleware (computes isDev/isProd/isTest) and strictProxyMiddleware (a Proxy that throws ReferenceError on unvalidated reads or any write) before Object.freeze() locks it down; customCleanEnv() exposes the same pipeline with a swappable middleware step for advanced use. The separation between spec validation (core), validator definitions (validators/makers), and post-processing (middleware) keeps each layer independently testable, and swapping the core validation algorithm would only require changes to core.ts without touching the public cleanEnv surface.
Tech Stack
The library is pure TypeScript compiled with tsc (no bundler), has zero runtime dependencies, and is tested with Vitest (including a coverage command) across a Node.js 20/22/24 CI matrix using Bun for dependency installation. Biome handles both linting and formatting, @arethetypeswrong/cli checks that the published package’s type exports are correct, and Husky enforces lint+tsc on pre-commit and the full test suite on pre-push.
Code Quality
The project has an extensive Vitest test suite spanning basics, validators, middleware, error subclassing, requiredWhen conditional logic, and dedicated type-level tests (using expect-type) that assert the inferred TypeScript types are correct, not just the runtime behavior. Errors are explicit and typed via custom EnvError/EnvMissingError subclasses rather than swallowed, naming conventions are consistent and minimal, and CI enforces type-checking, linting, and the test suite on every push across multiple Node versions, with a separate CodeQL workflow for security scanning.
What Makes It Unique
Rather than reusing a general-purpose schema validator, envalid’s API is purpose-built around the specific shape of environment-variable configuration: devDefault/testDefault let a var be strictly required in production while auto-filling sensible values in development and test based on NODE_ENV, and requiredWhen allows one var to become conditionally required based on the rest of the already-cleaned environment. The strict proxy wrapper is a distinctive enforcement mechanism, turning a typo’d or unvalidated env var access into an immediate, descriptive runtime error instead of a silent undefined.
Used by 3 apps in this directory
Ghostfolio
Invoicing Finance
Track your stocks, ETFs, and crypto with a privacy-first, self-hostable wealth management platform built for data-driven investors.
Kutt
Analytics · Marketing
Self-hosted URL shortener with custom domains, per-link analytics, and zero build step required.
Novu
Developer Tools
Open-source communication infrastructure that connects your products and AI agents to every channel your users live on — Inbox, Email, SMS, Push, Chat, and more.