Zod-powered environment variable validation and generation for TypeScript/Node.js projects. Written in Rust for speed. Ensures consistency between your code, Zod schemas, and .env.example documentation.
- Direct Usage Detection - Catches
process.envandBun.envusage outside validated schema files - Schema Coverage - Verifies
env.tsZod schemas match.env.exampledocumentation - Orphan Detection - Finds env vars defined but unused, or used but undocumented
- Naming Conventions - Enforces
UPPER_SNAKE_CASEand meaningful prefixes - Duplicate Detection - Identifies vars sharing identical values (potential copy-paste errors)
- Multiple Output Formats - Pretty, JSON, YAML, Standard
- Configurable - JSON config with schema validation for IDE autocompletion
- NEW: .env Generator - Interactive generation of
.envfiles from.env.examplewith metadata annotations
# npm
npm install -D @modlogtv/zenv
# Bun
bun add -d @modlogtv/zenv
# pnpm
pnpm add -D @modlogtv/zenv
# Yarn
yarn add -D @modlogtv/zenvThen add to your package.json scripts:
{
"scripts": {
"env:validate": "zenv",
"env:generate": "zenv generate"
}
}Or run directly:
npx @modlogtv/zenv
npx @modlogtv/zenv generate --dry-run
# Bun
bunx @modlogtv/zenvDownload from Releases.
# Clone the repository
git clone https://github.com/ModLogTV/zenv.git
cd zenv
# Build release binary
cargo build --release
# Binary is at ./target/release/zenv# Run all validation tests
zenv
# Run specific tests
zenv validate --test process-env --test env-coverage
# Output as JSON (for CI/CD)
zenv -o json
# Generate .env files interactively
zenv generate
# See all options
zenv --helpzenv [OPTIONS] [COMMAND]
Commands:
validate Run validation tests (default)
generate Generate .env files from .env.example with metadata
Options:
-c, --config <FILE> Config file path [default: test-env.config.json]
-o, --output <FORMAT> Output format: pretty, json, yaml, standard [default: pretty]
-q, --quiet Minimal output
-V, --verbose Verbose output
--no-color Disable colored output
-h, --help Print help
-v, --version Print version
Validate Options:
[DIR] Target directory (defaults to current directory)
-t, --test <NAME> Run specific test (can be repeated)
-a, --all Run all tests [default]
--skip <NAME> Skip specific test (can be repeated)
--process-env Only run process-env test
--env-coverage Only run env-coverage test
--orphaned-vars Only run orphaned-vars test
--naming-conventions Only run naming-conventions test
--duplicate-values Only run duplicate-values test
Generate Options:
[DIR] Target directory (defaults to current directory)
--dry-run Preview without writing files
--force Overwrite existing .env files
--non-interactive Skip prompts, use defaults/generate only (for CI)
| Test | Description |
|---|---|
process-env |
Detects direct process.env / Bun.env usage outside env.ts files |
env-coverage |
Verifies env.ts Zod schemas match .env.example documentation |
orphaned-vars |
Finds orphaned (unused) and undocumented env vars |
naming-conventions |
Enforces UPPER_SNAKE_CASE naming and meaningful prefixes |
duplicate-values |
Detects multiple vars with identical values |
The generate command creates .env files interactively from .env.example files with metadata annotations.
Add annotations as comments above variables in your .env.example:
# @required @prompt "Database connection URL"
DATABASE_URL=
# @optional @generate 32
SESSION_SECRET=
# @required @generate 64
JWT_SECRET=
# No metadata - uses default value, required by default
DEBUG=falseAvailable annotations:
| Annotation | Description |
|---|---|
@required |
Variable must have a value (default behavior) |
@optional |
Variable can be skipped during generation |
@prompt "description" |
Prompt user for input with description |
@generate <length> |
Auto-generate base64 secret of specified byte length |
Annotations can be combined: @required @prompt "description" or @optional @generate 32
See examples/generator/ for a comprehensive example with all annotation types.
# Interactive generation in current directory
zenv generate
# Generate in a specific directory
zenv generate ./apps/api
# Preview without writing
zenv generate --dry-run
# Force overwrite existing .env files
zenv generate --force
# Non-interactive mode (CI/CD) - only processes @generate vars
zenv generate --non-interactiveThe generator will:
- Find all
.env.examplefiles in the project - Parse metadata annotations from each file
- Group variables by directory
- Prompt for values marked with
@prompt - Auto-generate values marked with
@generate - Preview all values before writing
- Write
.envfiles after confirmation
Colored, human-readable terminal output with icons.
Plain text without colors (for logs).
Structured JSON for programmatic consumption.
{
"version": "2.0.0",
"timestamp": "2026-01-10T12:00:00+00:00",
"summary": {
"errors": 0,
"warnings": 2,
"status": "pass"
},
"tests": [...],
"errors": [],
"warnings": [...]
}Structured YAML output.
Create a test-env.config.json file to customize behavior:
{
"$schema": "./test-env.config.schema.json",
"description": "My project env validation config",
"processEnvCheck": {
"enabled": true,
"excludeDirs": ["apps/legacy"],
"excludeFiles": ["scripts/*.ts"]
},
"envCoverageCheck": {
"enabled": true,
"excludeVars": ["PORT"]
},
"orphanedEnvVarsCheck": {
"enabled": true,
"excludeVars": ["VERCEL_URL", "TURBO_INVOCATION_ID"]
},
"undocumentedEnvVarsCheck": {
"enabled": true,
"excludeVars": ["NODE_ENV"]
},
"namingConventionCheck": {
"enabled": true,
"allowGenericNames": ["PORT", "HOST"]
},
"duplicateValueCheck": {
"enabled": true,
"excludeVars": ["DATABASE_URL", "READ_DATABASE_URL"]
},
"generator": {
"excludeDirs": [],
"excludeFiles": [],
"defaultSecretLength": 32
}
}The tool works with any TypeScript/Node.js project structure. It recursively searches for .env.example files and env.ts Zod schemas.
your-project/
├── .env # Actual environment values (gitignored)
├── .env.example # Root-level documented env vars
├── apps/
│ ├── api/
│ │ ├── .env.example # App-specific env vars
│ │ └── src/
│ │ └── env.ts # Zod schema for this app
│ └── web/
│ ├── .env.example
│ └── src/
│ └── env.ts
└── packages/
└── shared/
└── src/
└── env.ts
your-project/
├── .env
├── .env.example
└── src/
└── env.ts
The tool looks for Zod schema definitions like:
// apps/api/src/env.ts
import { z } from "zod";
const envSchema = z.object({
NODE_ENV: z.enum(["development", "production"]).default("development"),
PORT: z.string().default("3000"),
DATABASE_URL: z.string().url(),
API_KEY: z.string().min(1),
});
export const env = envSchema.parse(process.env);- name: Validate environment variables
run: |
zenv -o json > env-report.json
if [ $? -ne 0 ]; then
echo "Environment validation failed"
cat env-report.json
exit 1
fi
- name: Generate .env for CI
run: |
zenv generate --non-interactive --force#!/bin/bash
# .git/hooks/pre-commit
zenv -q
if [ $? -ne 0 ]; then
echo "Environment validation failed. Run 'zenv' for details."
exit 1
fi| Code | Meaning |
|---|---|
0 |
All tests passed (warnings are OK) |
1 |
One or more tests failed with errors |
See the examples/ directory for complete working examples:
examples/validator/- Demonstrates all validation tests with intentional violationsexamples/generator/- Demonstrates all metadata annotations for.envgeneration
# Run validator example (will show errors and warnings)
zenv validate examples/validator
# Run generator example (dry run, non-interactive)
zenv generate --dry-run --non-interactive examples/generator# Run all tests with pretty output
zenv
# Run only process-env and naming checks
zenv validate --process-env --naming-conventions
# Skip duplicate check
zenv validate --skip duplicate-values
# Use custom config
zenv -c ./custom-config.json
# CI mode: JSON output, fail on errors
zenv -o json && echo "OK" || echo "FAIL"
# Generate .env files interactively
zenv generate
# Generate for a specific directory
zenv generate ./apps/api
# Preview generation without writing files
zenv generate --dry-run# Build debug
cargo build
# Build release
cargo build --release
# Run tests
cargo test
# Run with verbose output
cargo run -- -V validateThe package is distributed via npm with platform-specific binaries:
# Build for your current platform
./scripts/build-npm.sh local
# Test locally
cd npm/zenv
npm link
zenv --help
# Publish (after building for all platforms)
# See .github/workflows/release.yml for automated publishingTo trigger a release, push a version tag:
git tag v2.0.1
git push origin v2.0.1The GitHub Actions workflow will:
- Build binaries for all platforms (macOS, Linux, Windows)
- Publish platform-specific packages (
@modlogtv/zenv-linux-x64, etc.) - Publish the main
zenvpackage - Create a GitHub release with downloadable binaries
MIT License - see LICENSE for details.