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

envforge-ts

v1.1.1

Published

Type-safe environment variable and config validation for TypeScript using Zod.

Readme

🔥 envforge-ts

Type-safe environment variable and config validation for TypeScript and Node.js
Built on Zod. Zero runtime dependencies besides Zod. Fully typed. Production-ready.

npm version npm downloads License

npm install envforge-ts zod

📖 Documentation · 🚀 Features · 💡 Examples · 🔌 Framework Integrations · 🪝 Git Hooks


🚀 Features

  • Type-safe parsing – Full TypeScript inference on parsed outputs
  • Elegant DSL – Intuitive schema builders for env/config validation
  • Safe by default – Rich diagnostics with grouped errors
  • Secret protection – Automatic redaction of sensitive values in logs
  • Colorized output – Beautiful, readable error formatting with chalk
  • Flexible parsingsafeParse, parseOrThrow, and formatted error output
  • Zero config – Works with process.env out of the box
  • Extensible – Built-in source adapters; easy to add custom ones
  • Strict mode – Optional strict validation; permissive by default for env vars
  • Production-ready – Dual ESM/CJS, declaration files, tree-shaking
  • Fully tested – Unit, integration, and type inference tests
  • Build-time validation – Vite, Webpack, and Next.js plugins validate env before your app bundles
  • NestJS module – Drop-in EnvForgeModule for startup validation in NestJS apps
  • Git hooks – Block .env file commits and validate env on push — framework-agnostic

📖 Quick Start

1. Define your schema

import { defineEnv, enumValue, number, secret, string } from 'envforge-ts';

const schema = defineEnv({
  NODE_ENV: enumValue(['development', 'test', 'production']),
  PORT: number({ min: 1, max: 65535 }).default(3000),
  DATABASE_URL: string().min(1),
  API_KEY: secret(string().min(10)),
});

2. Parse and use

// Throw on validation error
const env = parseEnv(schema);
console.log(env.PORT); // number | 3000

// Or handle errors gracefully
const result = safeParse(schema, process.env);
if (!result.success) {
  console.error(formatErrors(result.error));
  process.exit(1);
}

const config = result.data;

3. See beautifully formatted errors

❌ Validation failed for env with 2 issue(s).
Error code: VALIDATION_FAILED
Scope: env
  📍 API_KEY
    ⚠️  [too_small] String must contain at least 10 character(s)
       input: [REDACTED]
  📍 PORT
    ⚠️  [invalid_type] Expected number, received string
       input: abc

Features:

  • ✨ Auto-colored output in TTY environments (disable with color: false)
  • 🚫 Secrets automatically redacted
  • 📍 Grouped by field with visual hierarchy
  • 🎨 Emoji indicators for clarity

💡 Examples

Parse environment variables

import { defineEnv, number, parseEnv, string } from 'envforge-ts';

const env = defineEnv({
  DATABASE_HOST: string().default('localhost'),
  DATABASE_PORT: number({ min: 1, max: 65535 }).default(5432),
  DEBUG: boolean().optional(),
});

const config = parseEnv(env);
// → { DATABASE_HOST: 'localhost', DATABASE_PORT: 5432 }

Validate config objects

import { defineConfig, parseConfig } from 'envforge-ts';
import { z } from 'zod';

const schema = defineConfig(
  {
    serviceName: string().min(1),
    retries: z.number().int().min(0).max(5),
    timeout: number().default(5000),
  },
  { unknownKeys: 'strict' }
);

const config = parseConfig(schema, {
  serviceName: 'my-api',
  retries: 3,
  timeout: 10000,
});

Secret protection

import { defineEnv, secret, string, safeParse, formatErrors } from 'envforge-ts';

const schema = defineEnv({
  API_KEY: secret(string().min(32)),
  DATABASE_PASSWORD: secret(string().min(8)),
  SENTRY_DSN: secret(string().url()),
});

const result = safeParse(schema, process.env);
if (!result.success) {
  // Secret values are automatically redacted in error output
  console.error(formatErrors(result.error));
  // API_KEY input will show as [REDACTED], not the actual value
}

Custom sources

import { defineEnv, parseEnv, processEnvSource, fromRecord } from 'envforge-ts';

// Use specific object instead of process.env
const customEnv = fromRecord({
  NODE_ENV: 'production',
  PORT: '8080',
});

const schema = defineEnv({
  NODE_ENV: enumValue(['development', 'production']),
  PORT: number(),
});

const config = parseEnv(schema, customEnv);

📚 API Reference

Core Functions

defineEnv(schema, options?)

Define an environment variable schema with passthrough mode by default.

const schema = defineEnv(
  {
    NODE_ENV: enumValue(['development', 'production']),
    PORT: number({ min: 1, max: 65535 }),
  },
  { unknownKeys: 'passthrough' } // optional; this is default
);

defineConfig(schema, options?)

Define a config schema with strict mode by default.

const schema = defineConfig(
  {
    appName: string().min(1),
    retries: number().default(1),
  },
  { unknownKeys: 'strict' } // optional; this is default
);

parseEnv(definition, source?, options?)

Parse environment variables and throw on error.

const env = parseEnv(schema);
const env = parseEnv(schema, processEnvSource(process.env));

parseConfig(definition, config, options?)

Parse config object and throw on error.

const config = parseConfig(schema, configObject);

safeParse(definition, input, options?)

Parse with error handling.

const result = safeParse(schema, process.env);
if (result.success) {
  const data = result.data;
} else {
  const diagnostics = result.error;
}

formatErrors(diagnostics, options?)

Format validation errors into human-readable, colored output.

const message = formatErrors(diagnostics, { 
  includeInput: true,   // Show input values (default: true)
  color: true           // Use colors in output (default: true in TTY)
});
console.error(message);

Output includes:

  • 🎨 Color-coded messages (red for errors, yellow for codes, cyan for scope)
  • 📍 Visual path indicators
  • ⚠️ Issue markers with error codes
  • 🚫 Automatically redacted secrets

Schema Builders

| Builder | Type | Options | Example | |---------|------|---------|---------| | string() | string | trim, minLength, maxLength | string({ minLength: 1 }) | | number() | number | int, min, max | number({ min: 0, max: 100 }) | | boolean() | boolean | — | boolean() | | enumValue() | T (union) | — | enumValue(['dev', 'prod']) | | url() | URL | — | url() | | json() | T | optional schema | json(z.object({ x: z.number() })) | | array() | T[] | delimiter | array(string(), { delimiter: ',' }) | | secret() | marks path | — | secret(string().min(10)) |

Source Adapters

processEnvSource(env?)

Create a source from process.env or custom env object.

const source = processEnvSource(); // uses process.env
const source = processEnvSource({ NODE_ENV: 'test' });

fromRecord(record)

Create a source from a plain object.

const source = fromRecord({ PORT: '3000', DEBUG: 'true' });

🎯 Why envforge-ts?

vs. Dotenv + manual validation

// ❌ Before: Manual, error-prone, no types
const port = parseInt(process.env.PORT, 10);
if (!port || port < 1 || port > 65535) {
  throw new Error('Invalid PORT');
}

// ✅ After: Declarative, type-safe, automatic
const { port } = parseEnv(defineEnv({
  PORT: number({ min: 1, max: 65535 }).default(3000),
}));

vs. Zod directly

// ✅ envforge-ts is Zod-powered
// You get all of Zod's power + env-specific shortcuts
const schema = defineEnv({
  API_KEY: secret(string().min(32)), // auto-redacted secrets
  PORT: number({ min: 1, max: 65535 }), // coerces "3000" → 3000
  FEATURES: array(string()),            // coerces "a,b,c" → ['a', 'b', 'c']
  DEBUG: boolean(),                      // coerces "true" → true
});

// Plus automatic grouping, formatting, and diagnostics

🛠️ Installation

npm

npm install envforge-ts zod

Yarn

yarn add envforge-ts zod

pnpm

pnpm add envforge-ts zod

Bun

bun add envforge-ts zod

Modes & Behavior

unknownKeys

Controls how unknown keys are handled:

// passthrough (default for env)
const env = defineEnv({ PORT: number() });
parseEnv(env, { PORT: '3000', UNKNOWN: 'value' }); // ✅ passes

// strict (default for config)
const config = defineConfig({ name: string() });
parseConfig(config, { name: 'app', unknown: 'value' }); // ❌ error

Secret redaction

Automatically redact sensitive values in diagnostics:

const schema = defineEnv({
  API_KEY: secret(string().min(10)),
});

const result = safeParse(schema, { API_KEY: 'short' });
if (!result.success) {
  formatErrors(result.error);
  // Input shows [REDACTED], not the actual value
}

� Framework Integrations

envforge-ts ships dedicated integrations for build-time and startup validation. Each integration is a separate export so you only pay for what you use.

Validation Modes

| Mode | How it works | When it runs | |------|-------------|--------------| | Runtime | Call parseEnv / parseConfig in your app | When your app starts | | Build time | Add the Vite or Webpack plugin | Before bundling | | Startup (NestJS) | Import EnvForgeModule | During NestFactory.create | | Git hooks | Run npx envforge install-hooks | On git commit / git push |

You can combine any of these — e.g. build-time plugin and git hooks for layered enforcement.


Vite (+ SvelteKit, Astro, Remix/Vite, Nuxt)

# No extra install — uses envforge-ts/vite sub-path
// vite.config.ts
import { defineConfig } from 'vite';
import { envForgeVitePlugin } from 'envforge-ts/vite';
import { envSchema } from './src/env';  // your defineEnv(...) export

export default defineConfig({
  plugins: [
    envForgeVitePlugin({
      schema: envSchema,
      // source: '.env',    // read from a .env file instead of process.env
      enforce: 'error',     // 'error' (default) | 'warn'
    }),
  ],
});

The plugin runs at buildStart and configureServer, so it catches problems both during vite build and vite dev.


Next.js (Webpack)

// next.config.ts
import type { NextConfig } from 'next';
import { EnvForgeWebpackPlugin } from 'envforge-ts/webpack';
import { envSchema } from './src/env';

const nextConfig: NextConfig = {
  webpack(config) {
    config.plugins.push(
      new EnvForgeWebpackPlugin({
        schema: envSchema,
        // source: '.env.local',   // optional: read from a specific .env file
        enforce: 'error',
      }),
    );
    return config;
  },
};

export default nextConfig;

Works with Next.js, Angular, and any other Webpack-based setup.


NestJS

// app.module.ts
import { Module } from '@nestjs/common';
import { EnvForgeModule } from 'envforge-ts/nest';
import { envSchema } from './env';

@Module({
  imports: [
    EnvForgeModule.forRoot({
      schema: envSchema,
      enforce: 'error',  // fail bootstrap if env is invalid
    }),
  ],
})
export class AppModule {}

EnvForgeModule is a global module. It runs validation in onModuleInit, so your app never fully bootstraps with bad env.


Integration Options

All integrations accept the same BaseIntegrationOptions:

type BaseIntegrationOptions<TSchema> = {
  /** A Definition returned by defineEnv() or defineConfig() */
  schema: Definition<TSchema>;

  /**
   * Where to read env values at build time.
   * 'process' (default) — uses process.env (works when dotenv is pre-loaded)
   * './path/to/.env'    — reads and parses a specific .env file directly
   */
  source?: 'process' | string;

  /**
   * What to do on validation failure.
   * 'error' (default) — halt the build / throw
   * 'warn'            — print and continue
   */
  enforce?: 'error' | 'warn';
};

🪝 Git Hooks

Git hooks are the most framework-agnostic enforcement layer. They work in any project regardless of bundler or framework.

Install hooks

npx envforge install-hooks

This writes two hooks to .git/hooks/:

| Hook | What it does | |------|-------------| | pre-commit | Scans staged files for .env patterns and blocks the commit if a secrets file is about to be pushed | | pre-push | Runs npm run envforge:validate (if defined) or npx envforge validate to catch env issues before they reach your remote |

.env leak protection (pre-commit)

The pre-commit hook automatically detects and blocks commits that include files like:

  • .env
  • .env.local, .env.production, .env.staging, etc.

Safe files (.env.example, .env.sample, .env.template) are allowed through.

⚠️  [envforge-ts] Potential secret leak detected!
   Staged file that looks like an env file: .env.local

   If this file contains secrets, remove it from staging:
     git restore --staged .env.local

   Add it to .gitignore to prevent future accidents:
     echo '.env.local' >> .gitignore

[envforge-ts] Commit blocked. Remove the env file(s) above before committing.
   To bypass (not recommended): git commit --no-verify

Schema validation on push (pre-push)

Add a validate script to your package.json so the pre-push hook knows what to run:

{
  "scripts": {
    "envforge:validate": "envforge validate --schema ./src/env.ts"
  }
}

Or run the CLI directly:

npx envforge validate --schema ./src/env.ts
npx envforge validate --schema ./src/env.ts --env .env.production  # validate against a specific .env file
npx envforge validate --schema ./src/env.ts --warn                 # warn instead of error

Force-reinstall or install a single hook

npx envforge install-hooks --force           # overwrite existing hooks
npx envforge install-hooks --hook pre-commit # only install pre-commit
npx envforge install-hooks --hook pre-push   # only install pre-push

Programmatic hook installation

import { installHooks } from 'envforge-ts/hooks';

const result = installHooks({ force: true });
console.log(result.installed); // ['pre-commit', 'pre-push']

🗺️ Supported Frameworks & Environments

| Framework / Tool | Integration | Import path | |-----------------|-------------|-------------| | Vite | Build-time plugin | envforge-ts/vite | | SvelteKit | Build-time plugin (via Vite) | envforge-ts/vite | | Astro | Build-time plugin (via Vite) | envforge-ts/vite | | Remix (Vite mode) | Build-time plugin (via Vite) | envforge-ts/vite | | Nuxt | Build-time plugin (via Vite) | envforge-ts/vite | | Next.js | Build-time Webpack plugin | envforge-ts/webpack | | Angular | Build-time Webpack plugin | envforge-ts/webpack | | NestJS | Bootstrap module | envforge-ts/nest | | Express / Fastify / Hapi | Runtime (parseEnv) | envforge-ts | | Any Node.js app | Runtime (parseEnv) + git hooks | envforge-ts | | Any git repo | Git hooks (CI/CD-friendly) | npx envforge install-hooks |


🚀 Roadmap

  • [x] Build-time Vite plugin
  • [x] Build-time Webpack / Next.js plugin
  • [x] NestJS module
  • [x] Git hooks (pre-commit env leak detection, pre-push validation)
  • [x] CLI for hook installation and schema validation
  • [ ] CLI: generate .env.example from a schema
  • [ ] Config file format support (YAML, TOML, JSON5)
  • [ ] Async validators and remote config sources
  • [ ] Enhanced diagnostics with suggestions

📄 License

MIT © 2026


Forge your configs with confidence 🔥

npm · GitHub