dotenvx
dotenvx CLI
dotenvx is a secure dotenv — from the creator of dotenv. It provides encrypted environment variables, cross-platform run injection, and multi-environment support.
Key capabilities:
dotenvx run— inject env vars into any command, any languagedotenvx encrypt— encrypt.envfiles with public-key cryptography (secp256k1)dotenvx set/get— manage individual env varsdotenvx decrypt— decrypt.envfiles back to plaintext- Multi-environment support via
-fflag andDOTENV_PRIVATE_KEY_*convention
Installation
# npm (local to project)
npm install @dotenvx/dotenvx --save
# global installs
curl -sfS https://dotenvx.sh | sh # curl
brew install dotenvx/brew/dotenvx # brew
winget install dotenvx # windows
docker run -it --rm -v $(pwd):/app dotenv/dotenvx help # docker
For Node.js, also usable as a library:
require('@dotenvx/dotenvx').config()
// or: import '@dotenvx/dotenvx/config'
Core Commands
dotenvx run
Inject environment variables from .env files into any process. This is the primary command.
dotenvx run -- <command>
Flags:
| Flag | Description |
|---|---|
-f <file> |
Specify env file(s). Repeatable. Default: .env |
--env KEY=value |
Set inline env var |
--overload |
Later files/values override earlier ones (default: first wins) |
--strict |
Exit code 1 on any error (missing file, decrypt failure) |
--ignore=ERROR_CODE |
Ignore specific errors (e.g., MISSING_ENV_FILE) |
--convention=nextjs|flow |
Load files using Next.js or dotenv-flow convention |
-fk <path> |
Specify path to .env.keys file (useful for monorepos) |
--quiet |
Suppress all output except errors |
--verbose |
Verbose logging |
--debug |
Debug-level logging |
--log-level=<level> |
Set log level: error, warn, info, verbose, debug, silly |
Examples:
# Basic usage
dotenvx run -- node index.js
# Specific env file
dotenvx run -f .env.production -- node index.js
# Multiple env files (first file's values win by default)
dotenvx run -f .env.local -f .env -- node index.js
# Override: last file wins
dotenvx run -f .env.local -f .env --overload -- node index.js
# Inline env var (overrides file values)
dotenvx run --env HELLO=String -f .env -- node index.js
# Any language works
dotenvx run -- python3 app.py
dotenvx run -- ruby index.rb
dotenvx run -- go run main.go
dotenvx run -- cargo run
dotenvx run -- php artisan serve
dotenvx run -- next dev
# Shell expansion (use subshell to prevent premature expansion)
dotenvx run --env="HELLO=World" -- sh -c 'echo Hello $HELLO'
# Strict mode for CI
dotenvx run -f .env.ci --strict -- node build.js
Precedence rules:
- By default, env vars already set in the shell take precedence over
.envfile values - With multiple
-ffiles, the first file's value wins (historic dotenv behavior) --overloadreverses this: later files override earlier ones--envflag values take precedence over file values
Variable expansion and interpolation:
dotenvx supports ${VAR} expansion, default values, alternate values, and command substitution inside .env files:
# Variable expansion
USERNAME="admin"
DATABASE_URL="postgres://${USERNAME}@localhost/mydb"
# Default values (use fallback if unset/empty)
DB_HOST=${DB_HOST:-localhost}
DB_PORT=${DB_PORT:-5432}
# Alternate values (use alternate if variable IS set)
DEBUG_MODE=${NODE_ENV:+false}
# Command substitution
WHOAMI="$(whoami)"
Multiline values are supported — wrap in double quotes:
CERT="-----BEGIN CERTIFICATE-----
MIIB...
-----END CERTIFICATE-----"
Important: What dotenvx Does NOT Have
Do NOT hallucinate these — they do not exist:
- ❌
dotenvx keys— usedotenvx keypairinstead - ❌
dotenvx status— no such command - ❌
dotenvx rotate— to rotate, usedotenvx setto update values, or decrypt → delete .env.keys → re-encrypt - ❌
--env-nameflag — does not exist - ❌
.env.vaultfiles — dotenvx encrypts in place, not to a separate vault file - ❌
DOTENVX_PRIVATE_KEY— the correct env var isDOTENV_PRIVATE_KEY(no X in the middle) - ❌
pip install dotenvx— there is no Python package; dotenvx is a CLI tool that wraps any language - ❌
dotenvx.load_dotenv()— no Python API; usedotenvx run -- python app.pyat the CLI level
dotenvx encrypt
Encrypt .env file(s) in place. Generates a DOTENV_PUBLIC_KEY (added to the .env file) and a DOTENV_PRIVATE_KEY (saved to .env.keys).
dotenvx encrypt # encrypts .env
dotenvx encrypt -f .env.production # encrypts specific file
dotenvx encrypt --stdout # output to stdout instead of in-place
After encryption:
.envcontains encrypted values +DOTENV_PUBLIC_KEY.env.keyscontainsDOTENV_PRIVATE_KEY(keep this secret, never commit it)- The encrypted
.envis safe to commit to version control
dotenvx decrypt
Decrypt an encrypted .env file back to plaintext.
dotenvx decrypt # decrypts .env
dotenvx decrypt -f .env.production # decrypts specific file
dotenvx decrypt --stdout # output to stdout
Requires the private key to be available (via .env.keys file or DOTENV_PRIVATE_KEY* env var).
dotenvx set
Set an individual environment variable in a .env file. Creates the file if it doesn't exist. If the file is encrypted, re-encrypts automatically.
dotenvx set KEY value # set in .env
dotenvx set KEY value -f .env.production # set in specific file
dotenvx set KEY "multi word value" # quoted values
dotenvx set KEY value -fk .env.keys -f apps/app1/.env # monorepo
dotenvx get
Retrieve a single environment variable's value.
dotenvx get HELLO # from .env
dotenvx get HELLO -f .env.production # from specific file
dotenvx get HELLO --env HELLO=Override # from --env string
dotenvx get HELLO --overload # with overload semantics
dotenvx get HELLO --strict # exit 1 if key missing
dotenvx get HELLO --convention=nextjs # with convention
dotenvx get HELLO -fk .env.keys -f app/.env # monorepo
Get all as JSON:
dotenvx get # all vars from .env as JSON
dotenvx get -f .env.production # all vars from specific file
dotenvx get --all # include DOTENV_PUBLIC_KEY
dotenvx get --format shell # output as KEY=value lines
dotenvx keypair
Output the public/private keypair for an encrypted .env file.
dotenvx keypair # all keypairs as JSON
dotenvx keypair DOTENV_PRIVATE_KEY # just the private key
dotenvx keypair -f .env.production # for specific file
dotenvx keypair DOTENV_PRIVATE_KEY_PRODUCTION -f .env.production
Encryption Workflow
Initial Setup
# 1. Create your .env
echo "DATABASE_URL=postgres://localhost/mydb" > .env
echo "API_KEY=sk-secret123" >> .env
# 2. Encrypt it
dotenvx encrypt
# ✔ encrypted (.env)
# Creates .env.keys with your private key
# 3. Commit .env (encrypted, safe), do NOT commit .env.keys
echo ".env.keys" >> .gitignore
git add .env .gitignore
git commit -m "add encrypted env"
Multi-Environment Encryption
Each environment gets its own keypair. The naming convention is automatic:
# Encrypt each environment
dotenvx encrypt -f .env.production
dotenvx encrypt -f .env.staging
dotenvx encrypt -f .env.ci
# Each creates a corresponding private key in .env.keys:
# DOTENV_PRIVATE_KEY_PRODUCTION="..."
# DOTENV_PRIVATE_KEY_STAGING="..."
# DOTENV_PRIVATE_KEY_CI="..."
Runtime Decryption
Set the appropriate DOTENV_PRIVATE_KEY_* env var, and dotenvx run decrypts automatically:
# The private key suffix matches the file suffix
DOTENV_PRIVATE_KEY="key" dotenvx run -- node app.js # decrypts .env
DOTENV_PRIVATE_KEY_PRODUCTION="key" dotenvx run -- node app.js # decrypts .env.production
DOTENV_PRIVATE_KEY_CI="key" dotenvx run -- node app.js # decrypts .env.ci
# Combine multiple
DOTENV_PRIVATE_KEY="k1" DOTENV_PRIVATE_KEY_PRODUCTION="k2" dotenvx run -- node app.js
# Comma-separated keys for monorepos (same environment, different apps)
DOTENV_PRIVATE_KEY_CI="key1,key2" dotenvx run -f app1/.env.ci -f app2/.env.ci -- node app.js
CI/CD Integration
# GitHub Actions example
name: deploy
on: [push]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: curl -fsS https://dotenvx.sh/install.sh | sh
- run: dotenvx run -- node build.js
env:
DOTENV_PRIVATE_KEY_PRODUCTION: ${{ secrets.DOTENV_PRIVATE_KEY_PRODUCTION }}
Conventions
--convention=nextjs
Loads files in Next.js priority order:
.env.$(NODE_ENV).local.env.local.env.$(NODE_ENV).env
dotenvx run --convention=nextjs -- next dev
--convention=flow
Loads files in dotenv-flow priority order. Uses DOTENV_ENV or NODE_ENV:
DOTENV_ENV=development dotenvx run --convention=flow -- node app.js
Monorepo Support
Use -fk to specify a shared .env.keys path:
# Set values for different apps
dotenvx set HELLO app1 -fk .env.keys -f apps/app1/.env
dotenvx set HELLO app2 -fk .env.keys -f apps/app2/.env
# Run with shared keys
dotenvx run -fk .env.keys -f apps/app1/.env -- node apps/app1/index.js
# Get values
dotenvx get HELLO -fk .env.keys -f apps/app1/.env
Docker
FROM node:latest
RUN curl -fsS https://dotenvx.sh/install.sh | sh
COPY . .
CMD ["dotenvx", "run", "--", "node", "index.js"]
Or run directly:
docker run -it --rm -v $(pwd):/app dotenv/dotenvx run -- node index.js
Common Patterns
Add a new secret to an encrypted file:
dotenvx set NEW_SECRET "value" -f .env.production
# Automatically re-encrypts
Rotate a value:
dotenvx set API_KEY "new-key-value" -f .env.production
View decrypted values without running a command:
dotenvx get -f .env.production # needs private key available
dotenvx get API_KEY -f .env.production # single value
Convert existing plaintext .env to encrypted:
dotenvx encrypt -f .env.production
# Done. Commit the encrypted .env.production, store .env.keys privately.
Suppress dotenvx output in scripts:
dotenvx run --quiet -- ./my-script.sh
Fail CI on missing/broken env:
dotenvx run -f .env.ci --strict -- npm test
Gitignore Recommendations
# Never commit private keys
.env.keys
# Encrypted .env files ARE safe to commit
# !.env
# !.env.production
# !.env.staging
Troubleshooting
MISSING_ENV_FILE— the specified.envfile doesn't exist. Create it or use--ignore=MISSING_ENV_FILE.MISSING_KEY— the requested key isn't in the.envfile.- Decryption fails — ensure the correct
DOTENV_PRIVATE_KEY_*is set. The suffix must match the file suffix (e.g.,_PRODUCTIONfor.env.production). - Deno + encrypt — don't use
deno run npm:@dotenvx/dotenvx encrypt. Deno has incomplete cipher support. Install dotenvx as a binary instead. - Shell expanding
$VARSprematurely — use a subshell:dotenvx run -- sh -c 'echo $MY_VAR'
Extension Commands (dotenvx ext)
Utility commands for managing dotenvx workflows:
dotenvx ext genexample # generate .env.example from .env
dotenvx ext genexample -f .env.production # from specific file
dotenvx ext gitignore # append .env.keys to .gitignore
dotenvx ext ls # list all .env files in project
dotenvx ext ls -f .env.production # check specific file
dotenvx ext settings # view current dotenvx settings