dotenv-flow
Loads NODE_ENV-specific .env files with local overrides, extending dotenv with a predictable file cascade.
Repository Health
Technical Analysis
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}.localfile cascade with a fixed, documented override priority listFiles(),parse(),load(), andunload()functions for programmatic control over which files are read and applied- Configurable
patternoption for teams with non-default.env*directory or naming conventions - CLI-switch and environment-variable driven
dotenv-flow/configentry point for zero-code preloading vianode -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.*.localfiles - Migrating from plain dotenv while keeping an existing tracked
.envfile, via the.env.defaultsfallback - 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.
Used by 4 apps in this directory
Dub
Marketing · Analytics
The open-source link attribution platform for short links, conversion tracking, and affiliate programs — powering 100M+ clicks monthly.
Sanity
CMS
Open-source headless CMS with a fully customizable React Studio, real-time collaborative editing, structured content modeling, and GROQ query language
Teable
Databases · No Code Platforms
A no-code PostgreSQL database with spreadsheet UX, real-time collaboration, and native AI agents — built for teams that outgrow Airtable.
Tolgee
Developer Tools
In-context localization platform that lets developers and translators edit app strings directly in the running application, with AI-powered machine translation and framework SDKs for React, Angular, Vue, and Svelte.