npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@gopinath_natarajan/env-validator

v2.0.1

Published

Schema-based environment variable validator with full TypeScript type inference — validates required vars are present, typed, and within constraints before your Node.js app starts.

Readme

env-validator

Schema-based environment variable validator for Node.js with full TypeScript type inference.

Validates that all required env vars are present, correctly typed, and within constraints before your app starts — with zero runtime dependencies.

✖  Environment Validation Failed
────────────────────────────────────────────────────────────────
  Errors (3):
  › DATABASE_URL  —  is required but was not set
      hint: PostgreSQL connection string
  › JWT_SECRET  —  must be at least 32 characters long, got 8
  › PORT  —  Port must be an integer between 1 and 65535, got 99999
────────────────────────────────────────────────────────────────

Why

  • Eliminate runtime crashes from missing or misconfigured env vars
  • Full TypeScript inferenceenv.PORT is number, not string | undefined
  • Works as a CLI pre-deployment check in CI/CD pipelines
  • First-class AWS Lambda and Express integrations
  • Plugin system for loading secrets (AWS Secrets Manager, etc.)
  • The schema is your single source of truth for what your app needs

Install

npm install @gopinath_natarajan/env-validator
# Optional: for .env file loading
npm install dotenv

Quick Start

Programmatic — add at the very top of your server entry point

import { createEnv } from 'env-validator';

const env = createEnv({
  NODE_ENV:     { type: 'string',  enum: ['development', 'staging', 'production'] as const },
  PORT:         { type: 'port',    default: 3000 },
  DATABASE_URL: { type: 'url',     description: 'PostgreSQL connection string' },
  JWT_SECRET:   { type: 'string',  minLength: 32 },
  DEBUG:        { type: 'boolean', required: false },
}, {
  dotenv:  true,     // load .env file (requires dotenv package)
  mode:    'strict', // throw if validation fails
});

// All values are correctly typed — no casting needed
app.listen(env.PORT);            // number
console.log(env.NODE_ENV);       // 'development' | 'staging' | 'production'
console.log(env.DEBUG);          // boolean | undefined

CLI — pre-deployment check

# Validate against a schema file
npx env-validator validate --schema=env.schema.js

# Generate .env.example from schema
npx env-validator generate --schema=env.schema.js --output=.env.example

# CI/CD (vars already set in environment)
npx env-validator validate --schema=env.schema.js --no-dotenv

Add to package.json:

{
  "scripts": {
    "prestart": "env-validator validate --schema=env.schema.js --no-dotenv"
  }
}

TypeScript Inference

createEnv uses TypeScript 5 const type parameters — no as const needed on the schema. The return type is fully inferred from your schema:

const env = createEnv({
  PORT:         { type: 'port',    default: 3000              },  // → number
  DB_URL:       { type: 'url'                                 },  // → string
  DEBUG:        { type: 'boolean', required: false            },  // → boolean | undefined
  NODE_ENV:     { type: 'string',  enum: ['dev', 'prod'] as const }, // → 'dev' | 'prod'
  FLAGS:        { type: 'json',    required: false            },  // → unknown | undefined
}, { env: process.env });

| Schema field | Output type | |---|---| | required: true (default) | T | | required: false (no default) | T \| undefined | | default: value | T (always present) | | enum: [...] as const | Literal union of enum values | | type: 'port' | number | | type: 'boolean' | boolean | | type: 'json' | unknown |


Schema Reference

{
  VAR_NAME: {
    type?:        'string' | 'number' | 'boolean' | 'url' | 'email' | 'json' | 'port',
    required?:    boolean,              // default: true
    default?:     unknown,              // makes field always-present
    description?: string,              // shown in error hints
    enum?:        readonly unknown[],  // restrict to specific values (use as const)
    min?:         number,              // number/port: minimum value
    max?:         number,              // number/port: maximum value
    minLength?:   number,              // string/url/email: min char count
    maxLength?:   number,              // string/url/email: max char count
    pattern?:     RegExp | string,     // string/url/email: regex pattern
    validate?:    (v) => boolean | string | void, // custom: return string = error message
    example?:     string,              // shown in generated .env.example
  }
}

Type Coercion

| Type | Raw string input | Output | |---|---|---| | string | "hello" | "hello" | | number | "3.14" | 3.14 (number) | | boolean | "true" / "1" / "yes" / "on" | true | | boolean | "false" / "0" / "no" / "off" | false | | port | "8080" | 8080 (integer, 1–65535) | | url | "https://..." | validated string | | email | "[email protected]" | validated string | | json | '{"a":1}' | { a: 1 } (parsed object) |


API

createEnv(schema, options)InferEnv<S>

Validates and returns coerced env values. Throws on failure by default.

import { createEnv } from 'env-validator';
const env = createEnv(schema, options);

createEnvAsync(schema, options)Promise<InferEnv<S>>

Async version — supports plugins that load secrets asynchronously.

import { createEnvAsync } from 'env-validator';
import { awsSecretsPlugin } from 'env-validator/plugins/aws-secrets';

const env = await createEnvAsync(schema, {
  plugins: [awsSecretsPlugin({ secretId: 'my-app/production' })],
});

checkEnv(schema, options)ValidationResult<InferEnv<S>>

Low-level, no side effects. Returns raw result for custom handling.

const { valid, errors, parsed } = checkEnv(schema, { env: process.env });
if (!valid) {
  errors.forEach(e => console.error(`${e.variable}: ${e.message}`));
}

Options

| Option | Type | Default | Description | |---|---|---|---| | dotenv | boolean \| string \| string[] | false | Load .env file(s). true = .env, string = path, array = multiple files (later overrides earlier) | | override | boolean | false | Let dotenv override already-set vars | | mode | 'strict' \| 'warn' \| 'silent' | 'strict' | Failure behavior | | abortEarly | boolean | false | Stop after first error | | strict | boolean | false | Warn on undeclared env vars | | quiet | boolean | false | Suppress all output | | env | object | process.env | Override env source (tests) |

mode values:

  • 'strict' — throw an Error (with .errors + .parsed attached)
  • 'warn' — print warnings, return partial values, don't throw
  • 'silent' — no output, return partial values, don't throw

Multi-env Support

Load multiple .env files — later files override earlier ones:

const env = createEnv(schema, {
  dotenv: ['.env', '.env.local', `.env.${process.env.NODE_ENV}`],
});
// .env.local overrides .env; .env.production overrides both

Express Integration

import express from 'express';
import { attachEnv, envMiddleware } from 'env-validator/integrations/express';

const app = express();

// Validate at startup, attach to app.locals.env
const env = attachEnv(app, {
  PORT:     { type: 'port', default: 3000 },
  DB_URL:   { type: 'url' },
  NODE_ENV: { type: 'string', enum: ['development', 'production'] as const },
}, { dotenv: true, mode: 'strict' });

// Optional: make env available on req.env in routes
app.use(envMiddleware());

app.get('/health', (req, res) => {
  res.json({ status: 'ok', env: env.NODE_ENV });
});

app.listen(env.PORT);

AWS Lambda Integration

Validates env vars once on cold start, then reuses the cached result on warm invocations:

import { withEnvValidation } from 'env-validator/integrations/lambda';

export const handler = withEnvValidation(
  {
    TABLE_NAME:     { type: 'string' },
    AWS_REGION:     { type: 'string', default: 'us-east-1' },
    ENABLE_TRACING: { type: 'boolean', default: false },
  },
  async (event, context, env) => {
    // env.TABLE_NAME → string (validated + typed)
    // env.ENABLE_TRACING → boolean
    return { statusCode: 200, body: JSON.stringify({ table: env.TABLE_NAME }) };
  },
  { mode: 'strict' },
);

Lambda + AWS Secrets Manager (async)

import { withEnvValidationAsync } from 'env-validator/integrations/lambda';
import { awsSecretsPlugin } from 'env-validator/plugins/aws-secrets';

export const handler = withEnvValidationAsync(
  schema,
  async (event, context, env) => { /* handler */ },
  {
    plugins: [awsSecretsPlugin({ secretId: 'my-app/prod', region: 'us-east-1' })],
  },
);

Plugin System

Plugins load additional key/value pairs into the environment before validation.

import { createEnvAsync, type EnvPlugin } from 'env-validator';

// Custom plugin example
const vaultPlugin = (): EnvPlugin => ({
  name: 'vault',
  async load() {
    const secrets = await fetchFromVault();
    return { DB_PASSWORD: secrets.dbPassword };
  },
});

const env = await createEnvAsync(schema, { plugins: [vaultPlugin()] });

AWS Secrets Manager Plugin

import { awsSecretsPlugin } from 'env-validator/plugins/aws-secrets';

const env = await createEnvAsync(schema, {
  plugins: [
    awsSecretsPlugin({
      secretId:   'my-app/production',
      region:     'us-east-1',
      keyMapping: { 'db-password': 'DB_PASSWORD' }, // optional: rename keys
    }),
  ],
});

Requires: npm install @aws-sdk/client-secrets-manager


CLI Reference

Usage: env-validator <command> [options]

Commands:
  validate   Validate environment variables against a schema  [default]
  generate   Generate a .env.example file from a schema

Validate options:
  --schema=<path>     Path to schema file (.js)   [required]
  --env=<path>        .env file(s) to load         [default: .env]
  --strict            Warn on undeclared env vars
  --no-dotenv         Skip .env loading (use in CI where vars are already set)
  --abort-early       Stop after first error
  --quiet             No output — use exit code only
  --mode=<mode>       strict | warn | silent

Generate options:
  --schema=<path>     Path to schema file (.js)   [required]
  --output=<path>     Output file path             [default: .env.example]

Exit codes:
  0   Valid / generated successfully
  1   Validation errors found
  2   Bad arguments or schema load failure

CI/CD Integration

GitHub Actions:

- name: Validate environment
  run: npx env-validator validate --schema=env.schema.js --no-dotenv
  env:
    NODE_ENV:     production
    DATABASE_URL: ${{ secrets.DATABASE_URL }}
    JWT_SECRET:   ${{ secrets.JWT_SECRET }}
    PORT:         "3000"

Docker / entrypoint:

# entrypoint.sh
node_modules/.bin/env-validator validate --schema=env.schema.js --no-dotenv || exit 1
node dist/server.js

Real-World Schema Example

// env.schema.js
module.exports = {
  NODE_ENV:     { type: 'string', enum: ['development', 'staging', 'production'] },
  PORT:         { type: 'port',   default: 3000 },
  DATABASE_URL: { type: 'url',    description: 'PostgreSQL connection string' },
  DB_POOL_SIZE: { type: 'number', required: false, default: 10, min: 1, max: 100 },
  JWT_SECRET:   { type: 'string', minLength: 32, description: 'Min 32 chars' },
  JWT_EXPIRES_IN: { type: 'string', required: false, default: '7d', pattern: /^\d+[smhd]$/ },
  REDIS_URL:    { type: 'url',    required: false },
  ADMIN_EMAIL:  { type: 'email',  required: false },
  FEATURE_FLAGS:{ type: 'json',   required: false, default: {} },
  ENABLE_METRICS: { type: 'boolean', default: false },
};

Tips

Use env option in tests to avoid touching process.env:

const { valid } = checkEnv(schema, { env: { PORT: '3000', DB_URL: 'https://...' } });

Disable colors: Set NO_COLOR=1 (follows no-color.org).

JSON type returns parsed object — use the returned env object, not process.env:

const env = createEnv({ FLAGS: { type: 'json', default: {} } });
env.FLAGS  // object — already parsed

License

MIT