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

@harshkhandelwalcs/env-doctor

v0.1.0

Published

Validate that your environment variables actually work — not just that they exist

Readme

env-doctor

Validate that your environment variables actually work — not just that they exist.

Most tools check that DATABASE_URL is present. env-doctor checks that it can connect to the database.

  env-doctor  v0.1.0
  ────────────────────────────────────────────────────

  DATABASE_URL     ✓  passed (23ms)   PostgreSQL 16.2
  REDIS_URL        ✗  ECONNREFUSED — Connection refused
                      → Redis is not running. Start it: redis-server
  OPENAI_API_KEY   ✗  HTTP 401 Unauthorized — API key rejected
                      → Check your API key is correct and has not expired
  JWT_SECRET       ✓  passed          HMAC-SHA256 compatible, 64 chars
  NODE_ENV         ✓  passed          "production"
  PORT             ✗  Invalid port: "abc"
                      → Must be an integer between 1 and 65535

  ────────────────────────────────────────────────────

  ✗ 3 of 6 failed   3 passed   (487ms)

Why?

| Tool | What it checks | |------|---------------| | dotenv | Loads .env into process.env | | dotenv-safe | Checks required keys are present | | zod / envalid | Validates types and formats | | env-doctor | Validates that the services actually respond |

"Works on my machine" is usually a broken environment. env-doctor catches that before your app crashes in production.


Install

npm install -D @harshkhandelwalcs/env-doctor

No required peer deps. Only install what you need:

npm install pg           # for check.postgres.connect()
npm install ioredis      # for check.redis.ping()
npm install nodemailer   # for check.smtp.connect()
npm install mongodb      # for check.mongo.connect()
npm install mysql2       # for check.mysql.connect()

Quick Start

1. Generate a config:

npx env-doctor init > env.doctor.js

2. Edit env.doctor.js:

// env.doctor.js
import { check } from '@harshkhandelwalcs/env-doctor'

export default {
  DATABASE_URL:  check.postgres.connect(),
  REDIS_URL:     check.redis.ping(),
  JWT_SECRET:    check.crypto.hmacable({ minLength: 32 }),
  API_URL:       check.http.reachable(),
  NODE_ENV:      check.format.oneOf('development', 'production', 'test'),
}

3. Run it:

npx env-doctor

4. Add to your package.json so it runs before every dev session:

{
  "scripts": {
    "predev": "env-doctor",
    "dev": "node server.js"
  }
}

All Checks

check.postgres.connect(options?)

Connects to a PostgreSQL database and runs SELECT version().

DATABASE_URL: check.postgres.connect({ timeout: 5000 })
// DATABASE_URL=postgres://user:pass@localhost:5432/mydb

check.redis.ping(options?)

Sends PING to Redis and expects PONG.

REDIS_URL: check.redis.ping({ timeout: 3000 })
// REDIS_URL=redis://localhost:6379
// REDIS_URL=redis://:password@localhost:6379

check.mongo.connect(options?)

Connects to MongoDB and runs buildInfo.

MONGODB_URI: check.mongo.connect()
// MONGODB_URI=mongodb://localhost:27017/mydb

check.mysql.connect(options?)

Connects to MySQL/MariaDB and runs SELECT VERSION().

MYSQL_URL: check.mysql.connect()
// MYSQL_URL=mysql://user:pass@localhost:3306/mydb

check.smtp.connect(options?)

Authenticates with an SMTP server using nodemailer.verify().

SMTP_URL: check.smtp.connect()
// SMTP_URL=smtp://user:[email protected]:587
// SMTP_URL=smtps://user:[email protected]:465

check.http.reachable(options?)

Makes a GET request and passes for any HTTP < 500 response (server is up).

API_URL: check.http.reachable({ timeout: 5000 })

check.http.status(code, options?)

Expects an exact HTTP status code.

HEALTH_URL: check.http.status(200)

check.http.bearerAuth(url, options?)

Validates an API key by calling a URL with it as a Bearer token. Fails if the server returns 401 or 403.

OPENAI_API_KEY:  check.http.bearerAuth('https://api.openai.com/v1/models'),
GITHUB_TOKEN:    check.http.bearerAuth('https://api.github.com/user'),
STRIPE_API_KEY:  check.http.bearerAuth('https://api.stripe.com/v1/customers?limit=1'),

check.crypto.hmacable(options?)

Validates a secret is long and usable as an HMAC-SHA256 key.

JWT_SECRET: check.crypto.hmacable({ minLength: 32 })

check.crypto.minLength(n)

SESSION_SECRET: check.crypto.minLength(64)

check.crypto.base64()

ENCRYPTION_KEY: check.crypto.base64()

check.crypto.jwt()

Validates structural JWT format (3 base64url parts).

REFRESH_TOKEN: check.crypto.jwt()

check.format.oneOf(...values)

NODE_ENV: check.format.oneOf('development', 'production', 'test')
LOG_LEVEL: check.format.oneOf('debug', 'info', 'warn', 'error')

check.format.url()

SITE_URL: check.format.url()

check.format.email()

ADMIN_EMAIL: check.format.email()

check.format.port(options?)

PORT: check.format.port({ min: 1024, max: 65535 })

check.format.uuid()

TENANT_ID: check.format.uuid()

check.format.regex(pattern, hint?)

AWS_REGION: check.format.regex(/^[a-z]{2}-[a-z]+-\d$/, 'e.g. us-east-1')

Chaining Checks

Pass an array to run checks in sequence — stops at first failure:

ENCRYPTION_KEY: [
  check.crypto.notEmpty(),
  check.crypto.minLength(32),
  check.crypto.base64(),
],

CLI Options

npx env-doctor [options]

Options:
  -c, --config <path>   Path to config file (default: env.doctor.js)
  -e, --env <file>      .env file to load (default: .env)
  --timeout <ms>        Timeout per check (default: 10000)
  --json                Output results as JSON
  --no-exit             Do not exit with code 1 on failure
  -V, --version         Show version
  -h, --help            Show help

Commands:
  run (default)         Run all checks
  init                  Print a starter env.doctor.js to stdout

Programmatic API

import { run, check } from '@harshkhandelwalcs/env-doctor'

const summary = await run({
  DATABASE_URL: check.postgres.connect(),
  JWT_SECRET:   check.crypto.hmacable({ minLength: 32 }),
}, {
  envFile: '.env.test',   // which .env file to load
  timeout: 5000,          // ms per check
  exitOnFail: false,      // don't call process.exit
})

console.log(summary.passed.length)  // 1
console.log(summary.failed.length)  // 0
console.log(summary.duration)       // total ms

for (const result of summary.failed) {
  console.log(result.key, result.result.error, result.result.hint)
}

CI / CD Integration

GitHub Actions:

- name: Check environment
  run: npx env-doctor --json
  env:
    DATABASE_URL: ${{ secrets.DATABASE_URL }}
    JWT_SECRET:   ${{ secrets.JWT_SECRET }}

Exit codes:

  • 0 — all checks passed
  • 1 — one or more checks failed

Is It Worth It?

Backend developers (Node.js, Express, Fastify, NestJS)

High value. Every check is relevant:

  • DB connections catch wrong credentials, wrong host, DB not created
  • Redis checks catch missing password, wrong port
  • SMTP checks catch firewall blocking port 587
  • Secret checks catch JWT secrets that are too short

Frontend developers (React, Vue, Vite, Next.js)

Medium value — mainly useful checks:

  • check.http.reachable() for your API base URL
  • check.http.bearerAuth() for third-party API keys (OpenAI, Stripe, etc.)
  • check.format.url() for VITE_API_URL, NEXT_PUBLIC_* vars
  • check.format.oneOf() for NODE_ENV

Full-stack (Next.js, Nuxt, Remix, SvelteKit)

Highest value. You have both — API routes with DB access AND frontend env vars. Add env-doctor to your predev script and never debug a broken env again.


License

MIT