dotenv-flow

Loads NODE_ENV-specific .env files with local overrides, extending dotenv with a predictable file cascade.

Library
npm
v4.1.0
902stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
39/100Needs Attention
Development Activity0
Maintenance20
Community48
Maturity60
Momentum28

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
72/100Good
Architecture75
Code Quality88
Innovation58
Learning Curve65

dotenv-flow extends the widely used dotenv library by adding support for NODE_ENV-specific .env* files (like .env.development, .env.test, and .env.production) plus their .env*.local overrides. Instead of a single flat .env file, apps can keep a default fallback file, per-environment files tracked in version control, and untracked local override files for secrets, all merged in a fixed ascending-priority order.

It is used as a drop-in replacement for dotenv, either required directly, preloaded via node -r dotenv-flow/config, or configured through CLI switches and DOTENV_FLOW_* environment variables. Options like pattern let teams customize the file naming convention, purge_dotenv resolves conflicts with a dependency that already called the original dotenv, and an .env.defaults file eases migration from projects that already commit their .env.

What You Get

  • Ordered .env, .env.local, .env.${NODE_ENV}, .env.${NODE_ENV}.local file cascade with a fixed, documented override priority
  • listFiles(), parse(), load(), and unload() functions for programmatic control over which files are read and applied
  • Configurable pattern option for teams with non-default .env* directory or naming conventions
  • CLI-switch and environment-variable driven dotenv-flow/config entry point for zero-code preloading via node -r
  • Bundled TypeScript type definitions (lib/dotenv-flow.d.ts) covering the full config/parse/load/unload API

Common Use Cases

  • Running the same app across development/test/production with environment-specific .env.* files
  • Overriding secrets locally per environment via untracked .env.*.local files
  • Migrating from plain dotenv while keeping an existing tracked .env file, via the .env.defaults fallback
  • Preloading configuration for scripts, CLI tools, and test runners without modifying application code

Under The Hood

Architecture dotenv-flow is a small, single-purpose module built around three composable stages: lib/cli-options.js and lib/env-options.js each translate CLI switches or DOTENV_FLOW_* environment variables into a shared options object consumed by config() in lib/dotenv-flow.js, the only file containing real logic. composeFilename() expands a pattern string with [local]/[node_env] placeholders into concrete filenames, listFiles() checks each candidate’s existence via fs.existsSync in a fixed ascending-priority order (.env.defaults -> .env -> .env.local -> .env.${NODE_ENV} -> .env.${NODE_ENV}.local), and actual file parsing and merging is delegated entirely to the upstream dotenv package rather than reimplemented. This clean separation between filename resolution, file-content parsing, and process.env assignment keeps the core config() function small and easy to reason about, and the purge_dotenv option is layered on top as a self-contained escape hatch for the common case where a dependency has already called dotenv.config() earlier in the boot sequence.

Tech Stack The library ships as plain CommonJS JavaScript (lib/*.js) alongside a hand-written TypeScript declaration file (lib/dotenv-flow.d.ts) rather than being authored in TypeScript and compiled; typescript is used only to typecheck example usage in CI, not to build the shipped code. Its sole runtime dependency is dotenv, used purely for its parsing routine. Development tooling is Mocha, Chai, and Sinon for tests plus conventional-changelog-cli for release notes. GitHub Actions runs the test suite across several Node.js versions on Ubuntu, Windows, and macOS before every publish, with releases cut through a dedicated “Publish to NPM” workflow gated on that matrix passing.

Code Quality Testing is thorough and layered: unit specs cover the CLI-options, env-options, and public API modules in isolation, integration specs exercise real .env* file combinations against fixtures for scenarios like symlinked local overrides, node-env-specific locals, and .env.defaults migration, and a dedicated type-check script runs tsc against sample usage to keep the bundled .d.ts file honest against real call sites. Source files carry consistent JSDoc annotations documenting every option, and error handling funnels through a single internal helper that respects silent/debug flags rather than swallowing errors silently. This is a disciplined, well-tested example of a small utility package.

API Design The public surface (config, parse, load, unload, listFiles) mirrors and extends dotenv’s own naming, so switching from plain dotenv requires little more than a package swap in the common case, and the dotenv-flow/config entry point gives a zero-code preload path via node -r. The tradeoff is a moderately dense options surface — node_env, default_node_env, pattern, files, purge_dotenv — each with subtly different precedence rules that require reading the documentation closely (for example, .env.local is silently skipped under NODE_ENV=test), which raises the learning curve for anything beyond the default file convention despite extensive README coverage.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search