🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@whenlabs/envalid

Package Overview
Dependencies
Maintainers
1
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@whenlabs/envalid

Type safety for .env files

Source
npmnpm
Version
0.3.1
Version published
Weekly downloads
94
95.83%
Maintainers
1
Weekly downloads
 
Created
Source

Envalid

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.

Part of the WhenLabs toolkit — install all 6 tools with one command:

npx @whenlabs/when install

Why envalid?

envaliddotenvManual .env checking
Type-safe schemaYAML schema with types, ranges, patternsNo validationEyeball it
Detects undocumented varsScans codebase for process.env usage missing from schemaNo detectiongrep and hope
Validates against schemaCatches wrong types, missing vars, format mismatchesLoads vars, no validationCompare files by hand
Multi-environment syncValidates .env, .env.staging, .env.production togetherOne file at a timeDiff files manually
CI-ready--ci flag, exit codes, JSON/Markdown outputNot designed for CICustom scripting

Install

Recommended: Install the full WhenLabs toolkit with npx @whenlabs/when install to get envalid plus 5 other tools in one step.

npm install -g envalid

Or use directly with npx:

npx envalid init

Requirements: Node.js >= 20

Quick Start

# 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

Schema Format

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]

Supported Types

TypeValidatesExample
stringNon-empty string, optional regex pattern, minLength, maxLengthsk_test_abc123
integerParseable integer, optional range3000
floatParseable float, optional range0.95
booleantrue, false, 1, 0true
urlValid URL, optional protocol constraintpostgres://localhost/db
emailValid email formatadmin@example.com
enumOne of specified valuesdevelopment
csvComma-separated valueshttp://a.com,http://b.com
jsonValid JSON string{"key": "value"}
pathFile/directory path./data/uploads
semverValid semver string1.2.3

Variable Options

OptionTypeDescription
typestringOne of the supported types above (required)
requiredbooleanWhether the variable must be present (default: true)
defaultanyDefault value
descriptionstringHuman-readable description
sensitivebooleanMask value in output
environmentsstring[]Only required in these environments
patternstringRegex pattern (for string type)
range[min, max]Numeric range (for integer/float types)
valuesstring[]Allowed values (for enum type)
protocolstring[]Allowed URL protocols (for url type)
minLengthnumberMinimum string length
maxLengthnumberMaximum string length

Groups

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]

Commands

envalid init

Scan 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 validate

Validate 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 diff

Compare 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 sync

Validate 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-example

Generate 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 onboard

Interactive 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 detect

Scan 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

# Auto-generate a schema from detected env vars in code
envalid detect --generate

# Generate schema to a custom path
envalid detect --generate -o custom.schema

The --generate flag scans your codebase for process.env (and equivalents), infers types, and writes a .env.schema — useful for projects that don't have a schema yet.

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 secrets

Scan 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.••••••••"

Smart Type Inference

envalid init now infers richer types from .env values:

  • Empty or missing values are marked required: false (optional)
  • PORT, *_PORT variables get type: port with range [1, 65535]
  • "true" / "false" values are inferred as type: boolean
  • URL-shaped values are inferred as type: url

envalid hook

Manage 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).

envalid codegen

Generate a fully-typed env.ts from the schema. Literal unions for enums, coerced numbers/booleans, readonly arrays for CSV, defaults folded in. Drop in next to process.env and stop writing ! casts.

envalid codegen -o src/env.ts            # Node / default (process.env)
envalid codegen --runtime import-meta    # Vite (import.meta.env)

envalid export

Emit the schema as a JSON Schema (Draft 2020-12) or an OpenAPI component. Plugin-contributed types participate through their toJsonSchema hook.

envalid export --format json-schema --pretty
envalid export --format openapi --openapi-version 3.0 -o env.openapi.json

envalid watch

Re-run validation on every schema / .env change. Debounced. Useful in dev or while authoring a schema.

envalid watch
envalid watch --environment production --format json

envalid fix

Interactively patch validation errors — prompts you for a replacement value, validates it against the schema before writing, masks prompts for sensitive: true vars. --auto fills defaults non-interactively.

envalid fix                 # interactive
envalid fix --auto          # fill from schema defaults
envalid fix -o .env.fixed   # write to a different file

envalid migrate

Apply a declarative migration to the schema, .env files, and source code in a single shot. Renames, removes, and retypes; idempotent via a content-hash ledger at .envalid/migrations.json; --dry-run prints a diff, --backup keeps originals under .envalid/backups/<id>/.

# migrations/2026-04-19-rename-db-host.yaml
version: 1
id: 2026-04-19-rename-db-host
migrations:
  - rename: { from: DB_HOST, to: DATABASE_HOST }
  - retype: { variable: PORT, to: integer, default: 3000 }
  - remove: { variable: LEGACY_TOKEN }
envalid migrate -f migrations/2026-04-19-rename-db-host.yaml \
  --env .env,.env.staging \
  --code src/app.ts,src/config.ts
envalid migrate -f migration.yaml --dry-run

Async validators, plugins & secret providers

Plugins

Register custom types from any npm package. Validators can be sync or async.

// envalid.config.js
import awsPlugin from "@company/envalid-aws";
export default { plugins: [awsPlugin()] };
import { definePlugin } from "@whenlabs/envalid";

export default () => definePlugin({
  name: "@company/envalid-aws",
  validators: [
    {
      name: "aws-region",
      typeHint: "string",
      validate: (value) =>
        /^[a-z]{2}-[a-z]+-\d+$/.test(value)
          ? { valid: true }
          : { valid: false, message: "bad region" },
      toJsonSchema: () => ({
        type: "string",
        pattern: "^[a-z]{2}-[a-z]+-\\d+$",
      }),
    },
  ],
});

Live (async) validation

Async validators are skipped by default. Pass --check-live (or set checkLive: true in envalid.config.js) to run them in CI. Concurrency is capped with --concurrency N (default 8).

envalid validate --check-live --concurrency 16

Secret provider references

Reference values in .env files as @scheme:payload — envalid resolves them before validation when --check-live is enabled. Built-in providers: vault, aws-sm, doppler, 1password. Custom providers are contributed via plugins.

# .env
DATABASE_URL=@vault:secret/data/app#DATABASE_URL
STRIPE_KEY=@aws-sm:my-secret#STRIPE_KEY
FEATURE_FLAGS=@doppler:myapp/prod/FEATURE_FLAGS
API_TOKEN=@1password:op://vault/item/token

Offline runs (--no-resolve-secrets or the default without --check-live) surface an info issue per reference and leave the raw token in place.

Schema composition

Compose schemas across monorepos. extends contributes defaults; imports overlays last-wins.

# apps/web/.env.schema
version: 1
extends: ../../.env.schema
imports:
  - ./payments.schema.yaml
variables:
  SESSION_SECRET:
    type: string
    required: true

Cycles are detected; groups merge variable-lists and required_in arrays.

Framework adapters

Subpath imports for first-class integration. Each adapter validates once at process start and exposes a frozen typed env object.

// Express
import { envalidMiddleware, getEnv } from "@whenlabs/envalid/express";
app.use(envalidMiddleware());
console.log(getEnv().DATABASE_URL);

// Fastify
import { envalidFastifyPlugin } from "@whenlabs/envalid/fastify";
await fastify.register(envalidFastifyPlugin());

// Next.js
import { createServerEnv, createClientEnv } from "@whenlabs/envalid/nextjs";
export const serverEnv = createServerEnv();
export const clientEnv = createClientEnv(); // only NEXT_PUBLIC_* vars

// NestJS
import { envalidProvider, ENVALID_TOKEN } from "@whenlabs/envalid/nestjs";
@Module({ providers: [envalidProvider()] })
export class AppModule {}

// Vite
import { envalidVitePlugin } from "@whenlabs/envalid/vite";
export default defineConfig({ plugins: [envalidVitePlugin()] });

CI Integration

GitHub Action

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

Action Inputs

InputDefaultDescription
schema.env.schemaPath to schema file
env-file.envPath to .env file to validate
environmentTarget environment (e.g. production)
formatterminalOutput format: terminal, json, markdown
fail-on-warningfalseTreat warnings as errors
node-version20Node.js version to use

Generic CI

npx envalid validate --ci --environment production

The --ci flag makes warnings into errors and returns exit code 1 on any issue.

Output Formats

Use --format to control output:

  • terminal (default) -- colored, human-readable with icons
  • json -- machine-readable for CI pipelines
  • markdown -- tables for PR comments

Configuration

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.

Programmatic API

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.

Project Structure

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

Tech Stack

  • TypeScript (ESM, targeting ES2022)
  • Commander.js -- CLI framework
  • Zod v4 -- schema-of-schema validation
  • yaml + dotenv -- file parsing
  • Chalk -- colored terminal output
  • Inquirer -- interactive prompts
  • Ora -- spinners
  • cosmiconfig -- config file discovery
  • tsup -- build tooling
  • Vitest -- test framework

Development

# 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

License

MIT

Keywords

env

FAQs

Package last updated on 20 Apr 2026

Did you know?

Socket

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.

Install

Related posts