Skip to content

Repository files navigation

EnvDoctor

Offline static analysis for environment variables. Scan your project, find missing definitions, unused variables, and naming issues — before they hit production.

$ envdoctor scan .

EnvDoctor Scan Report
════════════════════
Project: .
Scanned: 2026-07-23 07:11:04 UTC
Duration: 0.32s

Summary
───────
Total variables:      47
Defined in .env:      12
Used in code:         84
Errors:               0
Warnings:             5

Features

  • Multi-language — JavaScript, TypeScript, Python, Rust, Go, Ruby via tree-sitter AST parsing
  • Smart .env parsing.env, .env.example, .env.local, .env.production, and more
  • 4 analysis rules out of the box:
    • R001 Missing Definition — variables used in code but not in any .env file
    • R002 Unused Variable — variables defined in .env but never referenced in code
    • R003 Naming Convention — enforce UPPER_SNAKE_CASE (configurable regex)
    • R004 Undocumented Variable — variables in .env but missing from .env.example
  • Multiple output formats — terminal text, JSON, HTML report
  • Configurableenvdoctor.toml for rules, exclusions, include/exclude globs
  • Offline — no network, no telemetry, no accounts

Install

cargo install envdoctor

Or build from source:

git clone https://github.com/mangodxd/envdoctor
cd envdoctor
cargo build --release

Usage

# Scan current directory
envdoctor scan

# Check with exit code (CI-friendly)
envdoctor check

# Explain a specific variable
envdoctor explain DATABASE_URL

# Export HTML report
envdoctor export --format html -o report.html

# Export JSON
envdoctor export --format json -o report.json

# Generate config file
envdoctor init

# Validate config
envdoctor doctor

Commands

Command Description
scan Scan workspace and print results
check Validate and exit with code 0 (clean) or 1 (issues found)
explain <VAR> Show all usages, definitions, and issues for a variable
export Export to HTML or JSON
init Generate a default envdoctor.toml
doctor Validate configuration and diagnose environment
completions Generate shell completions (bash, zsh, fish, PowerShell)

Configuration

Create an envdoctor.toml in your project root:

[analysis]
naming_pattern = "^[A-Z][A-Z0-9_]*$"
naming_min_length = 2
strict_mode = false

[analysis.severity]
missing_definition = "warning"
unused_variable = "info"
naming_convention = "warning"
undocumented_var = "info"

[scan]
max_file_size = 1048576  # 1MB
include = ["src/**", "lib/**", "app/**"]
exclude = ["node_modules/**", "target/**", "dist/**", ".git/**"]

How It Works

Scanner → Adapter → IR → Analysis → Report
  │          │       │       │          │
  │          │       │       │          └─ Text / JSON / HTML
  │          │       │       └─ R001-R004 rules
  │          │       └─ Common intermediate representation
  │          └─ Language-specific parsers (tree-sitter)
  └─ File discovery with glob filtering
  1. Scanner discovers files, filters by extension and globs
  2. Adapters parse each language with tree-sitter AST (not regex)
  3. IR Builder normalizes everything into a common graph
  4. Analysis Engine runs rules against the IR
  5. Renderer outputs results as text, JSON, or HTML

Tested On

  • Payload CMS — 8,666 files, 119 variables, 844 usages
  • Node.js / Express / Next.js projects
  • Python / Django / FastAPI projects
  • Rust / Go / Ruby projects

Rules

R001 — Missing Definition

Variable is used in code but not defined in any .env file.

⚠ DATABASE_URL (warning): Variable 'DATABASE_URL' is used in code but not defined in .env
  at src/config.ts:12:21

R002 — Unused Variable

Variable is defined in .env but never referenced in code.

ℹ OLD_API_KEY (info): Variable 'OLD_API_KEY' is defined in .env but not used in code
  at .env:5

R003 — Naming Convention

Variable name doesn't match the configured pattern (default: UPPER_SNAKE_CASE).

⚠ api_key (warning): Variable 'api_key' does not match naming convention

R004 — Undocumented Variable

Variable is in .env but missing from .env.example.

ℹ SECRET_KEY (info): Variable 'SECRET_KEY' is in .env but not documented in .env.example

Supported Languages

Language Access Patterns
JavaScript process.env.X, import.meta.env.X, require('dotenv').config()
TypeScript Same as JavaScript
Python os.environ['X'], os.getenv('X'), os.environ.get('X'), from dotenv import load_dotenv
Rust std::env::var("X"), std::env::var_os("X"), env!("X"), dotenv::dotenv()
Go os.Getenv("X"), os.Lookupenv("X"), os.Setenv("X"), os.Unsetenv("X")
Ruby ENV['X'], ENV.fetch('X'), Dotenv.load

License

MIT

About

Offline static analysis for environment variables — find missing definitions, unused vars, and naming issues before they hit production

Topics

Resources

Stars

Watchers

Forks

Releases

Contributors

Languages