DEV Community

Cover image for I Audited 5 Popular awesome-nodejs Packages for Their Environment Variable Documentation. Here's the Scorecard.
ckmtools
ckmtools

Posted on

I Audited 5 Popular awesome-nodejs Packages for Their Environment Variable Documentation. Here's the Scorecard.

awesome-nodejs is the canonical curated list of quality Node.js packages. Quality implies documentation. I wanted to see how these packages handle .env documentation specifically — the section most developers rely on when setting up a new service in a fresh environment.

Methodology

I picked 5 packages from across the awesome-nodejs categories: a web framework, an ORM, an auth library, a logger, and a test runner. For each, I inspected the README, searched for process.env usage across the codebase using the GitHub search API, checked for a .env.example file, and looked at any dedicated docs pages.

Scoring criteria (0–3 each, 9 max):

  • Completeness: are all env vars the package reads actually documented?
  • Clarity: does the documentation explain what each variable does, what values are valid, and what the default is?
  • Freshness: does the documentation match what's in the current code?

express — expressjs/express

GitHub: expressjs/express

Express reads exactly one env var in its core: NODE_ENV. It uses this in lib/application.js to set the application environment mode and, when set to 'production', enables view caching automatically. The behavior is not trivial — it silently changes runtime behavior. The README contains zero mentions of NODE_ENV. There is no .env.example file. The only documentation lives in the external expressjs.com website, which is a separate repository.

The gap between "this env var changes how your app behaves in production" and "it is not mentioned in the main README" is notable for a project this widely used.

Env vars found: NODE_ENV
Completeness: 1/3 — the var exists and is used, but the README is silent on it
Clarity: 0/3 — no explanation of valid values or default behavior in the repo itself
Freshness: N/A — nothing to go stale
Score: 1/9


prisma — prisma/prisma

GitHub: prisma/prisma

Prisma is the standout in this audit. The README documents DATABASE_URL with actual code examples showing both the direct string form and the type-safe env('DATABASE_URL') helper from prisma/config. It explicitly states that Prisma does not automatically load .env files, and names specific alternatives (dotenv, @dotenvx/dotenvx, node --env-file, Bun's built-in loading). There are 248 process.env references across the codebase, which reflects its complexity, but the primary configuration path is clearly documented.

The README walks through the full setup sequence — prisma.config.ts, typed env access, and loading mechanism — in about 150 lines. That is more than most projects offer for env vars at all.

Env vars found: DATABASE_URL (primary, documented), plus internal vars in packages
Completeness: 3/3 — the critical configuration variable is covered explicitly
Clarity: 3/3 — explains the variable's purpose, shows multiple usage patterns, documents the .env loading caveat
Freshness: 3/3 — code examples in the README match the current prisma/config API
Score: 9/9


passport — jaredhanson/passport

GitHub: jaredhanson/passport

Passport reads zero environment variables in its core codebase. The GitHub search API returns 0 results for process.env in the repo. This is by design — passport's architecture puts all configuration into the application layer. Strategies (like passport-google-oauth20) are separate packages and handle their own env vars (GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, etc.).

The README does not document env vars because there are none to document in the core library. The absence here is defensible, but it creates a documentation gap for new users who need to configure OAuth secrets. That gap belongs to individual strategy packages, not to passport itself.

Env vars found: None in core library
Completeness: 3/3 — nothing to document, and the zero-config-env design is consistent
Clarity: 1/3 — the README doesn't mention that env vars live in strategy packages, which creates confusion for newcomers
Freshness: 3/3 — nothing to go stale
Score: 7/9


pino — pinojs/pino

GitHub: pinojs/pino

Pino reads NODE_OPTIONS in its transport worker (lib/transport.js) to sanitize options before passing them to worker threads. This is internal behavior. The public-facing docs do not mention any env var that users should set. The README contains no env var documentation. The docs/api.md contains no process.env references.

The docs/transports.md file does include process.env.AXIOM_DATASET and process.env.AXIOM_TOKEN — but these are in an example snippet showing how to configure a third-party Axiom transport, not pino's own env vars. They are undocumented as pino configuration.

If you want to set pino's log level via environment, you do it through your application code (level: process.env.LOG_LEVEL || 'info'). Pino does not read it for you. This is a valid design choice, but it is not explained anywhere in the main docs.

Env vars found: NODE_OPTIONS (internal, transport worker), third-party transport vars in examples
Completeness: 1/3 — internal env var usage is not documented for users
Clarity: 0/3 — no guidance on whether or how users should use env vars with pino
Freshness: 2/3 — internal usage is consistent with code, but third-party examples reference undocumented vars
Score: 3/9


jest — jestjs/jest

GitHub: jestjs/jest

Jest has a dedicated docs/EnvironmentVariables.md page that documents exactly two variables it sets: NODE_ENV (set to 'test' if not already set) and JEST_WORKER_ID (a unique index for each worker process, useful for parallelizing database access in tests). Both entries explain the variable's purpose and behavior.

The main README mentions NODE_ENV in a practical context — explaining how to make Babel config jest-aware by detecting process.env.NODE_ENV === 'test'. The repo's own jest.config.mjs uses process.env.GLOBALS_CLEANUP internally, which is not in the public docs, but that is a development-only variable.

Env vars found: NODE_ENV, JEST_WORKER_ID (documented); GLOBALS_CLEANUP (internal, undocumented)
Completeness: 2/3 — public env vars are documented; one internal var is not
Clarity: 3/3 — the EnvironmentVariables.md page is clear, brief, and directly useful
Freshness: 3/3 — documentation matches current behavior
Score: 8/9


Scorecard

Package Completeness Clarity Freshness Total
express 1/3 0/3 N/A 1/9
prisma 3/3 3/3 3/3 9/9
passport 3/3 1/3 3/3 7/9
pino 1/3 0/3 2/3 3/9
jest 2/3 3/3 3/3 8/9

Patterns

The two packages with the highest scores (prisma and jest) have a few things in common. Both document env vars in the context of actual user workflows, not as an afterthought. Prisma documents DATABASE_URL because it is in the critical path for getting started. Jest documents NODE_ENV and JEST_WORKER_ID because users encounter them when debugging flaky tests or configuring parallel test suites.

The lower-scoring packages (express, pino) have env vars that affect behavior but are not mentioned in their main docs. Express's NODE_ENV silently enables view caching in production — a behavior change that has caused real bugs when developers test locally and deploy to production without knowing the setting. Pino's transport worker reads NODE_OPTIONS for security reasons (sanitizing --inspect flags), which is internal but undocumented.

Passport scores mid-range because its zero-env design is intentional, but the docs don't explain where to look for strategy-specific env vars.


One More Thing

I built envscan to automate this kind of audit. It scans your source files to find env vars you're reading in code but haven't added to your .env.example or documentation. The audit above took me a few hours of manual GitHub API calls. envscan does it in seconds. Early access at ckmtools.dev/envscan/.


Which package surprised you? Drop it in the comments.

Top comments (0)