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

@shreyas-patil/env-guard

v1.1.0

Published

Runtime .env validation — typed, zero-deps, with coercion, async custom validators, and .env.example generation

Readme

env-guard 🛡️

Runtime .env validation for Node.js. Zero dependencies.

"name": "@shreyas-patil/env-guard",

Stop your app from starting with bad config — get a clear, actionable error instead of a cryptic crash.

  env-guard: 2 environment variable errors found

  ✖  DATABASE_URL
     → is required but was not provided

  ✖  JWT_SECRET
     → must be at least 32 characters (got 9)
     received: toosho****
 
  Check your .env file and fix the above issues.

Why env-guard?

| Feature | dotenv | zod | envalid | env-guard | |---|---|---|---|---| | Loads .env | ✅ | ❌ | ✅ | ✅ | | Type coercion | ❌ | ✅ | ✅ | ✅ | | Custom validators | ❌ | ✅ | ✅ | ✅ | | Async validators | ❌ | ❌ | ❌ | ✅ | | Secret masking | ❌ | ❌ | ❌ | ✅ | | .env.example CLI | ❌ | ❌ | ❌ | ✅ | | Pattern hints in example | ❌ | ❌ | ❌ | ✅ | | Zero dependencies | ✅ | ❌ | ❌ | ✅ | | Browser/Edge safe | ✅ | ✅ | ❌ | ✅ |

env-guard = lightweight + zero deps + typed errors + secret masking + CLI


Quick start

// src/env.js — import this everywhere instead of process.env
const { guard } = require('env-guard');

module.exports = guard({
  PORT:         { type: 'port',    default: 3000 },
  DATABASE_URL: { type: 'url',     description: 'PostgreSQL connection URL' },
  JWT_SECRET:   { type: 'string',  minLength: 32 },
  DEBUG:        { type: 'boolean', default: false },
  NODE_ENV: {
    type: 'string',
    enum: ['development', 'test', 'production'],
    default: 'development',
  },
}, { exitOnError: true });
// app.js
const env = require('./src/env');
console.log(env.PORT);   // number  → 3000
console.log(env.DEBUG);  // boolean → false

API

guard(schema, options) — synchronous, throws on error

const { guard } = require('env-guard');

const env = guard(schema, {
  envPath?: string | false,  // Path to .env. false = skip file loading. Default: ./.env
  failFast?: boolean,         // Stop after first error. Default: false
  exitOnError?: boolean,      // Print errors and process.exit(1). Default: false
  overrides?: object,         // Injected after process.env. Great for tests.
});

safeGuard(schema, options) — no throw, returns result object

const { safeGuard } = require('env-guard');

const result = safeGuard(schema);

if (!result.success) {
  console.error(result.errors); // [{ key, message, received? }]
} else {
  console.log(result.data.PORT);
}

guardAsync(schema, options) — async custom validators

const { guardAsync } = require('env-guard');

const env = await guardAsync({
  STRIPE_KEY: {
    type: 'string',
    custom: async (v) => {
      const ok = await verifyStripeKey(v);
      return ok || 'STRIPE_KEY is invalid or revoked';
    },
  },
});

generateExample(schema, outputPath) — write .env.example

const { generateExample } = require('env-guard');
const schema = require('./src/env.schema');

generateExample(schema, '.env.example');

Schema reference

Every field requires type. Everything else is optional.

Common properties

| Property | Type | Description | |---|---|---| | type | string | Required. See types below. | | description | string | Written as a comment in .env.example. | | required | boolean | Defaults to true. | | default | any | Used when variable is missing. | | example | string | Shown in generated .env.example. | | custom | function | Custom validator (see below). |

Types

{ type: 'string',  minLength, maxLength, pattern, enum }
{ type: 'number',  min, max }
{ type: 'boolean' }  // accepts true/false/1/0/yes/no/on/off (case-insensitive)
{ type: 'url',     protocols: ['http:', 'https:'] }
{ type: 'email' }
{ type: 'port',    min, max }  // integer 1–65535
{ type: 'json' }               // parsed with JSON.parse

Custom validators

Return true / undefined to pass. Return false or a string to fail:

API_KEY: {
  type: 'string',
  custom: (v) => v.startsWith('sk_') || 'Must start with sk_',
},

// Async — verify against a live server
STRIPE_KEY: {
  type: 'string',
  custom: async (v) => {
    const valid = await verifyWithStripe(v);
    return valid || 'Key is invalid or revoked';
  },
},

The custom function always receives the coerced value — a number for type: 'number', a boolean for type: 'boolean', etc.


Secret masking

Keys containing secret, token, key, password, auth, or credential automatically have their value masked in error output:

  ✖  JWT_SECRET
     → must be at least 32 characters (got 9)
     received: toosho****        ← never leaks the full secret

Generating .env.example

CLI

npx env-guard env.schema.js
npx env-guard env.schema.js --output=.env.example.ci

Schema file must export a plain object:

// env.schema.js
module.exports = {
  PORT:         { type: 'port',   default: 3000 },
  DATABASE_URL: { type: 'url',    description: 'PostgreSQL URL' },
  JWT_SECRET:   { type: 'string', minLength: 32, pattern: /^[a-zA-Z0-9_-]{32,}$/ },
};

Generated output:

# ─── Auto-generated by env-guard ─────────────────────────────────────────────
# Do not commit real secrets. Fill in values before running the application.

# HTTP server port
# Type: port | optional
# Default: 3000
PORT=3000

# PostgreSQL URL
# Type: url | required
DATABASE_URL=

# Type: string | required
# Pattern: /^[a-zA-Z0-9_-]{32,}$/     ← pattern hint auto-included
# Length: min 32 chars
JWT_SECRET=

Programmatic

const { generateExample } = require('env-guard');
generateExample(require('./env.schema'), '.env.example');

Testing

Use overrides to inject env vars without touching process.env:

const { safeGuard } = require('env-guard');
const schema = require('./src/env.schema');

test('valid config passes', () => {
  const result = safeGuard(schema, {
    envPath: false,
    overrides: {
      DATABASE_URL: 'postgres://localhost/test',
      JWT_SECRET:   'a-sufficiently-long-secret-for-testing',
    },
  });
  expect(result.success).toBe(true);
});

test('missing DATABASE_URL is caught', () => {
  const result = safeGuard(schema, { envPath: false });
  const keys = result.errors.map(e => e.key);
  expect(keys).toContain('DATABASE_URL');
});

Browser / Edge runtime

guard() detects non-server environments (typeof window !== 'undefined') and skips validation entirely, returning process.env as-is. This prevents crashes in Next.js Client Components or Edge functions where fs is unavailable.


Publishing checklist

# 1. Set your name in package.json
# 2. Bump version: 1.0.0
npm login
npm publish --access public

License

MIT#