Zod-based environment variable validation for Node.js. Type-safe, runtime-validated, developer-friendly.
| Package | Description |
|---|---|
@stacklance/envguard-core | Zod-based env validation library |
@stacklance/envguard-cli | CLI tool for validating and managing env files |
@stacklance/envguard-audit | Static analysis: audit process.env usage against schema |
@stacklance/envguard-nestjs | NestJS dynamic module integration |
npm install @stacklance/envguard-core zodimport{guard}from'@stacklance/envguard-core';import{z}from'zod';constenv=guard({PORT: z.coerce.number().default(3000),NODE_ENV: z.enum(['development','staging','production']),DB_URL: z.string().url(),DB_SSL: z.coerce.boolean().default(false),DB_CERT: z.string().optional(),});// Fully typed!// env.PORT → number// env.NODE_ENV → 'development' | 'staging' | 'production'// env.DB_URL → string// env.DB_SSL → boolean// env.DB_CERT → string | undefinednpm install -g @stacklance/envguard-cli
# Validate env against a schema
env-guard check --path .env --schema ./env.schema.ts
# Diff .env vs .env.example
env-guard diff
# Print env with secrets masked
env-guard mask
# Fix missing keys from .env.example
env-guard fixnpm install @stacklance/envguard-auditimport{audit}from'@stacklance/envguard-audit';constresult=awaitaudit({dir: './src',schema: './env.schema.ts',});console.log(result.undeclared);// { key, file, line }[] — used but not in schemaconsole.log(result.unused);// string[] — in schema but never usedconsole.log(result.unsafe);// { expression, file, line }[] — dynamic accessCLI:
# Audit process.env usage against schema
env-guard audit --dir ./src --schema ./env.schema.ts
# Auto-fix: add undeclared keys to schema
env-guard audit --dir ./src --schema ./env.schema.ts --fix
# JSON output for tooling
env-guard audit --dir ./src --schema ./env.schema.ts --json
# Monorepo: scan multiple directories
env-guard audit --dir ./apps/api ./apps/web --schema ./env.schema.tsnpm install @stacklance/envguard-nestjs @stacklance/envguard-core zodimport{Module}from'@nestjs/common';import{EnvGuardModule}from'@stacklance/envguard-nestjs';import{z}from'zod';
@Module({imports: [EnvGuardModule.forRoot({schema: {PORT: z.coerce.number().default(3000),DB_URL: z.string().url(),},}),],})exportclassAppModule{}import{Injectable}from'@nestjs/common';import{EnvGuardService}from'@stacklance/envguard-nestjs';
@Injectable()exportclassAppService{constructor(privatereadonlyenvGuard: EnvGuardService){}getPort(): number{returnthis.envGuard.get('PORT');}}- Zod schema validation with full TypeScript inference
- Type coercion —
"true"→boolean,"3000"→numberviaz.coerce - Cross-field validation via
.superRefine()(e.g., ifDB_SSL=truethenDB_CERTrequired) .envfile loading via dotenv with configurable path- Masked logging — auto-redact keys containing
SECRET,KEY,TOKEN,PASSWORD,PASS - Freeze —
Object.freezethe result so env can't be mutated - Watch mode —
fs.watchon.env, re-validate on change, emit events .env.examplesync — warn on missing or extra keys- Pretty errors — colored output with key name + Zod error message
- CI-friendly — GitHub Actions
::error::annotations whenCI=true - Static audit — scan codebase for undeclared, unused, and dynamic
process.envaccesses - Auto-fix —
--fixappends undeclared keys to your schema asz.string().optional() - NestJS integration —
forRoot()/forRootAsync()with typedEnvGuardService
| Feature | envguard | dotenv-safe | envalid | t3-env |
|---|---|---|---|---|
| Zod schemas | ✅ | ❌ | ❌ | ✅ |
| Full TypeScript inference | ✅ | ❌ | ✅ | ✅ |
| Type coercion | ✅ | ❌ | ✅ | ✅ |
| Cross-field validation | ✅ | ❌ | ❌ | ❌ |
.env.example sync | ✅ | ✅ | ❌ | ❌ |
| Watch mode | ✅ | ❌ | ❌ | ❌ |
| Masked logging | ✅ | ❌ | ❌ | ❌ |
| Freeze result | ✅ | ❌ | ❌ | ❌ |
| CLI tool | ✅ | ❌ | ❌ | ❌ |
| Static audit / linting | ✅ | ❌ | ❌ | ❌ |
| Auto-fix undeclared keys | ✅ | ❌ | ❌ | ❌ |
| NestJS module | ✅ | ❌ | ❌ | ❌ |
| Pretty error output | ✅ | ❌ | ✅ | ✅ |
| CI annotations | ✅ | ❌ | ❌ | ❌ |
| Zero peer deps (except zod) | ✅ | ✅ | ✅ | ❌ |
# Install dependencies
pnpm install
# Build all packages
pnpm build
# Run tests
pnpm test# Run tests with coverage
pnpm test:coverage
# Lint
pnpm lint
# Create a changeset
pnpm changesetMIT