Type-safe environment variable validation for TypeScript/Node.js. Validates process.env against a developer-defined schema at startup — catching misconfigured environments at boot time, not at runtime.
- Throws a descriptive
EnvValidationErroron missing, wrong-type, or invalid variables - Infers TypeScript types from the schema — no manual casting
- Redacts
sensitivefields automatically intoJSON()/JSON.stringify() - Adapters for Express, Fastify, Vite, Next.js, and NestJS
- CLI for scaffolding, diffing, and syncing
.env.example
| Package | Description |
|---|---|
envzen-core |
Validation engine, types, masker, printer |
envzen-cli |
envzen check / sync / init CLI |
envzen-express |
Express / Fastify middleware |
envzen-vite |
Vite plugin |
envzen-next |
Next.js withEnvGuard() wrapper |
envzen-nestjs |
NestJS EnvGuardModule.forRoot() |
# Core only
npm install envzen-core
# With a framework adapter
npm install envzen-core envzen-express
npm install envzen-core envzen-vite
npm install envzen-core envzen-next
npm install envzen-core envzen-nestjs
# CLI (global or dev dependency)
npm install -g envzen-cli// env.ts
import { createEnv } from 'envzen-core'
export const env = createEnv({
NODE_ENV: {
type: 'enum',
values: ['development', 'production', 'test'],
default: 'development',
},
PORT: {
type: 'port',
default: 3000,
},
DATABASE_URL: {
type: 'url',
required: true,
sensitive: true,
},
API_KEY: {
type: 'string',
required: true,
sensitive: true,
},
})Call dotenv.config() before createEnv() if you load from a .env file — EnvZen does not load .env files itself.
// index.ts
import 'dotenv/config'
import { env } from './env.js'
console.log(env.PORT) // number
console.log(env.NODE_ENV) // 'development' | 'production' | 'test'
console.log(JSON.stringify(env)) // DATABASE_URL and API_KEY → "[REDACTED]"| Property | Type | Description |
|---|---|---|
type |
FieldType |
Variable type (see below) |
required |
boolean |
Must be present; ignores default |
default |
string | number | boolean |
Fallback when variable is absent |
description |
string |
Used in .env.example output |
sensitive |
boolean |
Redacts value in toJSON() |
values |
string[] |
Required when type: 'enum' |
validate |
ZodType |
Custom Zod refinement chained after base type |
| Value | Coercion / Validation |
|---|---|
string |
Raw string |
number |
z.coerce.number() |
boolean |
Accepts "true", "false", "1", "0" |
port |
Integer 1–65535 |
url |
z.string().url() |
email |
z.string().email() |
enum |
Must match one of values |
import express from 'express'
import { envGuardMiddleware } from 'envzen-express'
import { schema } from './env.js'
const app = express()
app.use(envGuardMiddleware(schema))// vite.config.ts
import { envGuardPlugin } from 'envzen-vite'
import { schema } from './env.js'
export default {
plugins: [envGuardPlugin(schema)],
}// next.config.ts
import { withEnvGuard } from 'envzen-next'
import { schema } from './env.js'
export default withEnvGuard({ /* your next config */ }, schema)import { EnvGuardModule } from 'envzen-nestjs'
import { schema } from './env.js'
@Module({
imports: [EnvGuardModule.forRoot(schema)],
})
export class AppModule {}# Scaffold an env.ts config file
envzen init
# Generate .env.example from your schema
envzen sync --schema ./env.ts
# Diff your .env against the schema
envzen check --schema ./env.ts --env ./.env
# CI mode (no interactive prompts, plain-text output)
envzen init --ci
envzen check --cienvzen init --ci also generates a .github/workflows/envzen.yml GitHub Actions workflow.
import { createEnv, EnvValidationError } from 'envzen-core'
try {
const env = createEnv(schema)
} catch (err) {
if (err instanceof EnvValidationError) {
console.error(err.message) // formatted list of failures
console.error(err.failures) // ValidationFailure[]
}
}pnpm install
pnpm build
pnpm test
pnpm lintMIT
