Advanced environment variable loader with multi-file support, hot reload, and cross-platform file watching.
- Multi-file Support: Load multiple
.envfiles in a specific order with override control. - Auto Type Generation: Automatically generates
env.d.tsfor your environment variables. - Zero Dependencies: Lightweight and fast, no external runtime dependencies.
- Hot Reload: Automatically reloads environment variables when files change (opt-in).
- Secret Masking: Automatically masks sensitive values in verbose logs for better security.
- Enterprise Ready: Supports
/etc/internal-secrets.envand/etc/shared-secrets.envout of the box for secure deployments. - Smart Runtime: Generates a type-safe
env.tsfor easy runtime access. - Standard Compliant: Supports
#comments, inline comments, andexportprefixes.
npm install @explita/env-loader
# or
yarn add @explita/env-loader
# or
pnpm add @explita/env-loaderLoad the default .env files (current directory .env, /etc/internal-secrets.env, and /etc/shared-secrets.env):
import { loadEnv } from "@explita/env-loader";
loadEnv();You can automatically load environment variables by importing the auto-config module. This is ideal for an environment or scripts where you want zero-config loading based on your NODE_ENV.
// ES Modules
import "@explita/env-loader/auto";
// CommonJS
require("@explita/env-loader/auto");
// If you want to enable watch mode.
import "@explita/env-loader/auto/watch";Import this once at the start of your application or entry point.
The auto-loader searches for files in this priority order:
/etc/internal-secrets.env/etc/shared-secrets.env.env.${NODE_ENV}.local.env.${NODE_ENV}.env.local.env
import { loadEnv } from "@explita/env-loader";
loadEnv({
paths: [".env", ".env.local", "secrets.env"],
verbose: true,
overrideExisting: true,
generateTypes: true, // Generates env.d.ts in the root
});For Node.js applications, you can generate a centralized env.ts file that exports all your environment variables. This provides a clean way to access variables across your project without worrying about where they were loaded from.
import { loadEnv } from "@explita/env-loader";
loadEnv({
generateEnvFile: true, // Generates src/lib/env.ts or lib/env.ts or your specified path
generateTypes: true, // Generates env.d.ts in the root or your specified path
});
// If you are using import "@explita/env-loader/auto"; or import "@explita/env-loader/auto/watch";
// It will generate the env.d.ts and env.ts file automaticallyUsage in your project:
import { DATABASE_URL, API_TOKEN } from "@/lib/env";
console.log(DATABASE_URL);Enable automatic reloading of environment variables when your .env files change. This is perfect for long-running processes or dev servers.
Type declarations and env.ts files are generated only when environment keys change. Value changes do not regenerate types.
import { loadEnv } from "@explita/env-loader";
loadEnv({
watch: true,
});
//import "@explita/env-loader/auto/watch";
// Enables hot reload and auto generation of env.d.ts and env.ts files.Note
Do not use watch mode in CLI contexts (for example, inside a Prisma config file). Watch mode keeps the Node.js process alive and will prevent CLI commands from exiting.
Note
To keep the core library lightweight, chokidar is an optional dependency. If it's not installed, the watcher falls back to Node's built-in fs.watch (less reliable across platforms, but zero dependencies).
Tip
Automatic Server Restart: When watch and generateEnvFile are enabled, changes to your environment keys will trigger a file regeneration. Since dev servers (Vite, Next.js, tsx, nodemon) watch for changes in your src or lib directories, they will automatically restart the server for you. This creates a seamless development workflow where adding a new variable to .env immediately makes it available and typed in your code without a manual restart.
The library provides several helper functions to simplify common tasks:
Common loading patterns wrapped in a clean API:
EnvLoader.loadWithPrecedence(paths, options): Later files always override earlier ones.EnvLoader.loadSystemAndApp(appEnvPath?): Loads system secrets and then your app's.env.EnvLoader.loadForEnvironment(env): Loads system secrets,.env.{env}, and.envin order.
getEnv(key, defaultValue?): A type-safe way to get an environment variable. In development, it warns if a key is missing.hasKeys(...keys): Returnstrueif all specified keys are defined inprocess.env.getKeys(filePaths?): Reads one or more.envfiles and returns aMapof filenames to their contained variable names.
The loader automatically checks two system-level secret files before any project-level .env files:
| File | Purpose |
|---|---|
/etc/internal-secrets.env |
Project-specific internal secrets (e.g., database credentials, API keys). |
/etc/shared-secrets.env |
Shared secrets across multiple projects (e.g., cloud provider keys, organizational credentials). |
This allows you to maintain a single source of truth for sensitive credentials without duplicating them across projects.
- No Duplication: Stop copying
.envfiles from project to project. Update a secret once, and every project that uses@explita/env-loadergets the update instantly. - Security: Keep your most sensitive secrets outside of your project directory, reducing the risk of accidental git commits.
- Cross-platform Compatibility:
- Linux/macOS:
/etc/internal-secrets.envand/etc/shared-secrets.env - Windows:
\etc\internal-secrets.envand\etc\shared-secrets.env(resolves to the root of the current drive, e.g.,C:\etc\...orD:\etc\...)
- Linux/macOS:
Setting NODE_ENV in your external env files can cause issues regardless of the value:
| Value | Problem |
|---|---|
NODE_ENV=development |
Breaks production builds (Next.js, etc. expect production during build). |
NODE_ENV=production |
Breaks development β no source maps, no HMR, and the loader skips type/file generation. |
The loader also uses NODE_ENV to resolve which .env files to load (.env.production, .env.development, etc.). If it's set early in an external file, it overrides the intended environment before the project-level files are even considered.
Avoid setting NODE_ENV in your external env files. Let your runtime environment (shell, Docker, CI) control it instead.
| Option | Type | Default | Description |
|---|---|---|---|
paths |
string | string[] |
[system-secrets, '.env'] |
Path or array of paths to .env files. Defaults to /etc/internal-secrets.env, /etc/shared-secrets.env, and environment-appropriate .env files. |
verbose |
boolean | 'debug' |
false |
Enable detailed logging. 'debug' shows variable sources. |
overrideExisting |
boolean |
false |
If true, later files will override variables set by earlier files or the environment. |
requireAll |
boolean |
false |
If true, the loader will fail if any specified file is missing. |
requireAny |
boolean |
true |
If true, at least one file must exist for the loader to succeed. |
generateTypes |
boolean | string |
false |
If true, generates env.d.ts. If a string, specifies the output path. |
generateEnvFile |
boolean | string |
false |
If true, generates env.ts in lib. If a string, specifies the output path. |
watch |
boolean |
false |
Watch .env files for changes and auto-reload. Uses chokidar if available, falls back to fs.watch. |
ignore |
string[] |
[] |
List of environment variable keys to skip β they won't be set on process.env. |
Sensitive variables containing keywords like key, secret, token, or password are automatically masked in the verbose output to prevent accidental exposure in logs.
Env Loader is built to simplify and secure environment variable management across your projects. If it has improved your development workflow or deployment security, please consider supporting the project to ensure its continued growth and maintenance!
- Give us a β: It helps others discover the project.
- Join the Discussion: Report bugs or suggest new features.
- Spread the Word: Share your experience with Env Loader on social media.
A huge thank you to everyone helping us build better dev tools!
MIT Β© Explita