EnvDoctor Documentation

Type-check your environment before your users do. Every feature explained with examples.

Overview

EnvDoctor is a local-first developer utility that verifies whether your application's configuration is complete, valid, safe, and consistent before it reaches runtime.

🔍

Discover

Finds env vars your code actually reads, not just what's in .env files.

Validate

Checks types, ranges, formats, requiredness, and allowed values.

🔄

Compare

Detects drift between .env, .env.example, source code, and contracts.

💡

Explain

Every finding includes file location, cause, and a suggested fix.

Quick Start

Three commands to go from zero to confidence:

# Step 1: Generate a contract from your codebase
npx envdoctor init

# Step 2: Validate your current environment
npx envdoctor check

# Step 3: Open the web dashboard
npx envdoctor web
The init command scans your source code, discovers which env vars you use, and writes an envdoctor.yml contract. Review it, commit it, and your team shares the same source of truth.

Installation

Run without installing

npx envdoctor check

Install globally

npm install -g envdoctor

Install as a dev dependency

npm install -D envdoctor

Then add scripts to your package.json:

{
  "scripts": {
    "env:check": "envdoctor check",
    "env:init": "envdoctor init",
    "env:web": "envdoctor web"
  }
}

envdoctor init

Scans your codebase and generates an envdoctor.yml environment contract.

Usage

npx envdoctor init [root]

What it does

StepDescription
1. Project detectionFinds your package.json, detects framework (Next.js, Express, etc.)
2. Source scanningReads all .ts, .tsx, .js, .jsx files for process.env.X and import.meta.env.X
3. Type inferenceInfers types from .env.example values (integer, boolean, URL, etc.)
4. Secret detectionFlags variables with names like *_SECRET, *_KEY, *_TOKEN
5. Contract generationWrites envdoctor.yml with all discovered variables

Example output

Discovered 5 environment variables from source code.

5 high-confidence variables:
  + PORT (required)
  + DATABASE_URL (required)
  + API_KEY (required, secret)
  + ENABLE_CACHE (required)
  + NODE_ENV (required)

Contract written to ./envdoctor.yml
The contract is a starting point. Edit envdoctor.yml to add constraints like min/max values, enum options, or URL scheme restrictions.

envdoctor check

Validates the current environment against the contract and produces a diagnostic report.

Usage

npx envdoctor check [root] [options]

Options

FlagDescription
--ciCI mode: compact output, stable exit codes
--format jsonMachine-readable JSON output
--format compactSingle-line summary format
--no-colorDisable colored output

What it checks

RuleWhat it catchesDefault
ENV001Required variable is missingBlocker
ENV002Variable declared but never used in codeWarning
ENV003Value does not match declared typeBlocker
ENV004Value outside permitted rangeBlocker
ENV005Used in code but not in contractWarning
ENV006.env.example is incompleteWarning
ENV007Possible misspelling detectedWarning
ENV008Required variable has empty valueBlocker
ENV009Public variable contains secretBlocker
CFG001Inconsistent values across filesWarning

Exit codes

CodeMeaning
0All checks passed
1Blockers found (or warnings if configured)

envdoctor explain

Shows a detailed explanation of a specific diagnostic rule.

Usage

npx envdoctor explain ENV003

Example output

  ✖  ENV003  BLOCKER

  PORT: expected integer, got "no********er"

  Variable
    PORT

  Location
    src/server.ts:5

  How to fix
    ensure PORT is a valid integer

envdoctor web

Launches a local web dashboard showing the latest check results.

Usage

npx envdoctor web [root] [-p port]

Options

FlagDescriptionDefault
-p, --portPort to serve on3777

Dashboard features

📊

Stat Cards

Total, blockers, warnings, info at a glance.

🚨

Status Banner

Green/yellow/red banner with summary.

🔍

Expandable Cards

Click any diagnostic to see the fix.

Animated

Staggered fade-in animations on load.

envdoctor docs

Opens this documentation in your browser.

npx envdoctor docs

Environment Contract

The contract (envdoctor.yml) is the single source of truth for your application's configuration requirements.

Full example

version: 1
service: web
variables:
  DATABASE_URL:
    type: url
    required: true
    secret: true
    schemes: [postgres, postgresql]

  PORT:
    type: integer
    required: false
    default: 3000
    min: 1
    max: 65535

  NODE_ENV:
    type: enum
    required: true
    values: [development, test, staging, production]

  ENABLE_CACHE:
    type: boolean
    required: false
    default: false

  API_KEY:
    type: string
    required: true
    secret: true
    minLength: 20

Supported types

TypeValidatesExample
stringAny texthello
integerWhole numbers3000
numberDecimals allowed3.14
booleantrue/false/yes/no/1/0true
urlValid URL formathttps://example.com
jsonValid JSON{"key":"val"}
enumOne of allowed valuesdevelopment
port1-655353000

Variable options

OptionTypeDescription
typestringData type (see above)
requiredbooleanWhether the variable must be set
secretbooleanMark as sensitive (redacted in output)
publicbooleanMark as client-facing (warns if secret-like)
defaultanyDefault value if not set
valuesstring[]Allowed values (for enum type)
schemesstring[]Allowed URL schemes (for url type)
minnumberMinimum value
maxnumberMaximum value
patternstringRegex pattern to match
minLengthnumberMinimum string length

Rules and Diagnostics

Every diagnostic has a stable ID, severity, message, and fix suggestion.

RuleCategoryDescription
ENV001RequirednessRequired variable is missing from the environment
ENV002UnusedDeclared in contract but never referenced in source code
ENV003TypeValue cannot be parsed as the declared type
ENV004RangeValue outside min/max, not in enum, or fails pattern
ENV005UndeclaredUsed in code but missing from the contract
ENV006ExampleVariable missing from .env.example
ENV007SpellingPossible misspelling relative to another declaration
ENV008EmptyRequired variable exists but has empty value
ENV009ExposurePublic variable appears to contain a credential
CFG001ConsistencySame variable has different values in .env vs .env.example

Severity and Policy

Every rule has a default severity. You can override severity per-rule in the contract.

Severity levels

LevelEffect
blockerFails the check (exit code 1)
warningReported but does not fail by default
infoInformational only

Custom policy

policy:
  fail_on: blocker
  overrides:
    SEC001: warning
    ENV002: ignore
Setting fail_on: warning means any warning will cause exit code 1 in CI. Use this for strict enforcement.

Secret Redaction

EnvDoctor never prints secret values in full. All output masks sensitive data.

Privacy guarantees

🔒

Local-first

Nothing leaves your machine during a normal scan.

🧰

No telemetry

Telemetry is opt-in only. Off by default.

🗄

No raw cache

Cached data uses fingerprints, not values.

🛡

CI safe

Secrets are masked in CI logs automatically.

CI Integration

Add EnvDoctor to your CI pipeline with one line.

GitHub Actions

- name: Check environment contract
  run: npx envdoctor check --ci
  env:
    DATABASE_URL: ${{ secrets.DATABASE_URL }}
    API_KEY: ${{ secrets.API_KEY }}
    NODE_ENV: production

GitLab CI

env-check:
  script:
    - npx envdoctor check --ci

Monorepo Support

For monorepos, create a separate contract per service.

packages/
  web/
    envdoctor.yml
    src/
  api/
    envdoctor.yml
    src/

Run checks per service:

npx envdoctor check packages/web
npx envdoctor check packages/api

Troubleshooting

"No variables found"

EnvDoctor looks for process.env.X and import.meta.env.X. If you use a custom config loader, you may need to add the contract manually.

"CLI not found"

Run npm run build before using the web command from a local install.

False positives

Use the policy.overrides section in your contract to suppress or downgrade specific rules.

policy:
  overrides:
    ENV002: ignore
    ENV007: warning