a better dotenv–from the creator of dotenv
.
- run anywhere (cross-platform)
- multi-environment
- encrypted envs
Quickstart

Install and use it in code just like dotenv
.
npm install @dotenvx/dotenvx --save
// index.js
require('@dotenvx/dotenvx').config()
// or import '@dotenvx/dotenvx/config' // for esm
console.log(`Hello ${process.env.HELLO}`)
or install globally - unlocks dotenv for any language, framework, or platform!
sh
curl -L -o dotenvx.tar.gz "https://github.com/dotenvx/dotenvx/releases/latest/download/dotenvx-$(uname -s)-$(uname -m).tar.gz"
tar -xzf dotenvx.tar.gz
./dotenvx help
sh
winget install dotenvx
dotenvx help
Run Anywhere
$ echo "HELLO=World" > .env
$ echo "console.log('Hello ' + process.env.HELLO)" > index.js
$ node index.js
Hello undefined # without dotenvx
$ dotenvx run -- node index.js
Hello World # with dotenvx
> :-D
More examples
- <summary>TypeScript 📘</summary>
json // package.json { "type": "module", "dependencies": { "chalk": "^5.3.0" } }
js // index.ts import chalk from 'chalk' console.log(chalk.blue(`Hello ${process.env.HELLO}`))
sh $ npm install $ echo "HELLO=World" > .env $ dotenvx run -- npx tsx index.ts Hello World
- <summary>Deno 🦕</summary>
sh $ echo "HELLO=World" > .env $ echo "console.log('Hello ' + Deno.env.get('HELLO'))" > index.ts $ deno run --allow-env index.ts Hello undefined $ dotenvx run -- deno run --allow-env index.ts Hello World
> [!WARNING] > Some of you are attempting to use the npm module directly withdeno run
. Don't, because deno currently has incomplete support for these encryption ciphers. > >> $ deno run -A npm:@dotenvx/dotenvx encrypt > Unknown cipher >
> > Instead, usedotenvx
as designed, by installing the cli as a binary - via curl, brew, etc. - <summary>Bun 🥟</summary>
sh $ echo "HELLO=Test" > .env.test $ echo "console.log('Hello ' + process.env.HELLO)" > index.js $ bun index.js Hello undefined $ dotenvx run -f .env.test -- bun index.js Hello Test
- <summary>Python 🐍</summary>
sh $ echo "HELLO=World" > .env $ echo 'import os;print("Hello " + os.getenv("HELLO", ""))' > index.py $ dotenvx run -- python3 index.py Hello World
see extended python guide - <summary>PHP 🐘</summary>
sh $ echo "HELLO=World" > .env $ echo '<?php echo "Hello {$_SERVER["HELLO"]}\n";' > index.php $ dotenvx run -- php index.php Hello World
see extended php guide - <summary>Ruby 💎</summary>
sh $ echo "HELLO=World" > .env $ echo 'puts "Hello #{ENV["HELLO"]}"' > index.rb $ dotenvx run -- ruby index.rb Hello World
see extended ruby guide - <summary>Go 🐹</summary>
sh $ echo "HELLO=World" > .env $ echo 'package main; import ("fmt"; "os"); func main() { fmt.Printf("Hello %s\n", os.Getenv("HELLO")) }' > main.go $ dotenvx run -- go run main.go Hello World
see extended go guide - <summary>Rust 🦀</summary>
sh $ echo "HELLO=World" > .env $ echo 'fn main() {let hello = std::env::var("HELLO").unwrap_or("".to_string());println!("Hello {hello}");}' > src/main.rs $ dotenvx run -- cargo run Hello World
see extended rust guide - <summary>Java ☕️</summary>
sh $ echo "HELLO=World" > .env $ echo 'public class Index { public static void main(String[] args) { System.out.println("Hello " + System.getenv("HELLO")); } }' > index.java $ dotenvx run -- java index.java Hello World
- <summary>Clojure 🌿</summary>
sh $ echo "HELLO=World" > .env $ echo '(println "Hello" (System/getenv "HELLO"))' > index.clj $ dotenvx run -- clojure -M index.clj Hello World
- <summary>Kotlin 📐</summary>
sh $ echo "HELLO=World" > .env $ echo 'fun main() { val hello = System.getenv("HELLO") ?: ""; println("Hello $hello") }' > index.kt $ kotlinc index.kt -include-runtime -d index.jar $ dotenvx run -- java -jar index.jar Hello World
- <summary>.NET 🔵</summary>
sh $ dotnet new console -n HelloWorld -o HelloWorld $ cd HelloWorld $ echo "HELLO=World" | Out-File -FilePath .env -Encoding utf8 $ echo 'Console.WriteLine($"Hello {Environment.GetEnvironmentVariable("HELLO")}");' > Program.cs $ dotenvx run -- dotnet run Hello World
- <summary>Bash 🖥️</summary>
sh $ echo "HELLO=World" > .env $ dotenvx run --quiet -- sh -c 'echo Hello $HELLO' Hello World
- <summary>Fish 🐠</summary>
sh $ echo "HELLO=World" > .env $ dotenvx run --quiet -- sh -c 'echo Hello $HELLO' Hello World
- <summary>Cron ⏰</summary>
sh # run every day at 8am 0 8 * * * dotenvx run -- /path/to/myscript.sh
- <summary>Frameworks ▲</summary>
sh $ dotenvx run -- next dev $ dotenvx run -- npm start $ dotenvx run -- bin/rails s $ dotenvx run -- php artisan serve
see framework guides - <summary>Docker 🐳</summary>
sh $ docker run -it --rm -v $(pwd):/app dotenv/dotenvx run -- node index.js
Or in any image:sh FROM node:latest RUN echo "HELLO=World" > .env && echo "console.log('Hello ' + process.env.HELLO)" > index.js RUN curl -fsS https://dotenvx.sh/install.sh | sh CMD ["dotenvx", "run", "--", "echo", "Hello $HELLO"]
see docker guide - <summary>CI/CDs 🐙</summary>
yaml name: build on: [push] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: node-version: 16 - run: curl -fsS https://dotenvx.sh/install.sh | sh - run: dotenvx run -- node build.js env: DOTENV_KEY: ${{ secrets.DOTENV_KEY }}
see github actions guide - <summary>Platforms</summary>
sh # heroku heroku buildpacks:add https://github.com/dotenvx/heroku-buildpack-dotenvx # docker RUN curl -fsS https://dotenvx.sh/install.sh | sh # vercel npm install @dotenvx/dotenvx --save
see platform guides - <summary>Process Managers</summary>
js // pm2 "scripts": { "start": "dotenvx run -- pm2-runtime start ecosystem.config.js --env production" },
see process manager guides - <summary>npx</summary>
sh # alternatively use npx $ npx @dotenvx/dotenvx run -- node index.js $ npx @dotenvx/dotenvx run -- next dev $ npx @dotenvx/dotenvx run -- npm start
- <summary>npm</summary>
sh $ npm install @dotenvx/dotenvx --save
json { "scripts": { "start": "./node_modules/.bin/dotenvx run -- node index.js" }, "dependencies": { "@dotenvx/dotenvx": "^0.5.0" } }
sh $ npm run start > start > ./node_modules/.bin/dotenvx run -- node index.js [dotenvx@1.X.X] injecting env (1) from .env.production Hello World
- <summary>asdf</summary>
sh # use dotenvx with asdf $ asdf plugin add dotenvx $ asdf install dotenvx latest
thank you @jgburet of Paris 🇫🇷 - <summary>Git</summary>
sh # use as a git submodule $ git dotenvx run -- node index.js $ git dotenvx run -- next dev $ git dotenvx run -- npm start
- <summary>Variable Expansion</summary>
Reference and expand variables already on your machine for use in your .env file.ini # .env USERNAME="username" DATABASE_URL="postgres://${USERNAME}@localhost/my_database"
js // index.js console.log('DATABASE_URL', process.env.DATABASE_URL)
sh $ dotenvx run --debug -- node index.js [dotenvx@0.14.1] injecting env (2) from .env DATABASE_URL postgres://username@localhost/my_database
- <summary>Command Substitution</summary>
Add the output of a command to one of your variables in your .env file.ini # .env DATABASE_URL="postgres://$(whoami)@localhost/my_database"
js // index.js console.log('DATABASE_URL', process.env.DATABASE_URL)
sh $ dotenvx run --debug -- node index.js [dotenvx@0.14.1] injecting env (1) from .env DATABASE_URL postgres://yourusername@localhost/my_database
Multiple Environments
Create a
.env.production
file and use-f
to load it. It's straightforward, yet flexible. ```sh $ echo "HELLO=production" > .env.production $ echo "console.log('Hello ' + process.env.HELLO)" > index.js
$ dotenvx run -f .env.production -- node index.js [dotenvx@1.X.X] injecting env (1) from .env.production Hello production
^^ ```
More examples
- <summary>multiple
.env
files</summary>
sh $ echo "HELLO=local" > .env.local $ echo "HELLO=World" > .env $ dotenvx run -f .env.local -f .env -- node index.js [dotenvx@1.X.X] injecting env (1) from .env.local,.env Hello local
Note subsequent files do NOT override pre-existing variables defined in previous files or env. This follows historic principle. For example, abovelocal
wins – from the first file. - <summary>
--overload
flag</summary>
$ echo "HELLO=local" > .env.local $ echo "HELLO=World" > .env $ dotenvx run -f .env.local -f .env --overload -- node index.js [dotenvx@1.X.X] injecting env (1) from .env.local,.env Hello World
Note that with
--overload
subsequent files DO override pre-existing variables defined in previous files. - <summary>
--verbose
flag</summary>
$ echo "HELLO=production" > .env.production $ dotenvx run -f .env.production --verbose -- node index.js [dotenvx][verbose] injecting env from /path/to/.env.production [dotenvx][verbose] HELLO set [dotenvx@1.X.X] injecting env (1) from .env.production Hello production
- <summary>
--debug
flag</summary>
sh $ echo "HELLO=production" > .env.production $ dotenvx run -f .env.production --debug -- node index.js [dotenvx][debug] configuring options [dotenvx][debug] {"envFile":[".env.production"]} [dotenvx][verbose] injecting env from /path/to/.env.production [dotenvx][debug] reading env from /path/to/.env.production [dotenvx][debug] parsing env from /path/to/.env.production [dotenvx][debug] {"HELLO":"production"} [dotenvx][debug] writing env from /path/to/.env.production [dotenvx][verbose] HELLO set [dotenvx][debug] HELLO set to production [dotenvx@1.X.X] injecting env (1) from .env.production Hello production
- <summary>
--quiet
flag</summary>
Use--quiet
to suppress all output (except errors).sh $ echo "HELLO=production" > .env.production $ dotenvx run -f .env.production --quiet -- node index.js Hello production
- <summary>
--log-level
flag</summary>
Set--log-level
to whatever you wish. For example, to suppress warnings (risky), set log level toerror
:sh $ echo "HELLO=production" > .env.production $ dotenvx run -f .env.production --log-level=error -- node index.js Hello production
Available log levels areerror, warn, info, verbose, debug, silly
- <summary>
--convention
flag</summary>
Load envs using Next.js' convention or dotenv-flow convention. Set--convention
tonextjs
orflow
:sh $ echo "HELLO=development local" > .env.development.local $ echo "HELLO=local" > .env.local $ echo "HELLO=development" > .env.development $ echo "HELLO=env" > .env $ dotenvx run --convention=nextjs -- node index.js Hello development local $ dotenvx run --convention=flow -- node index.js Hello development local
(more conventions available upon request)
Encryption
Add encryption to your
.env
files with a single command. Usedotenvx encrypt
.
$ dotenvx encrypt
✔ encrypted (.env)
A
DOTENV_PUBLIC_KEY
(encryption key) and aDOTENV_PRIVATE_KEY
(decryption key) are generated using the same public-key cryptography as Bitcoin.
More examples
- <summary>
.env
</summary>
sh $ echo "HELLO=World" > .env $ dotenvx encrypt $ echo "console.log('Hello ' + process.env.HELLO)" > index.js $ dotenvx run -- node index.js [dotenvx@1.X.X] injecting env (2) from .env Hello World
- <summary>
.env.production
</summary>
sh $ echo "HELLO=Production" > .env.production $ dotenvx encrypt -f .env.production $ echo "console.log('Hello ' + process.env.HELLO)" > index.js $ DOTENV_PRIVATE_KEY_PRODUCTION="<.env.production private key>" dotenvx run -- node index.js [dotenvx@1.X.X] injecting env (2) from .env.production Hello Production
Note theDOTENV_PRIVATE_KEY_PRODUCTION
ends with_PRODUCTION
. This instructsdotenvx run
to load the.env.production
file. - <summary>
.env.ci
</summary>
sh $ echo "HELLO=Ci" > .env.ci $ dotenvx encrypt -f .env.ci $ echo "console.log('Hello ' + process.env.HELLO)" > index.js $ DOTENV_PRIVATE_KEY_CI="<.env.ci private key>" dotenvx run -- node index.js [dotenvx@1.X.X] injecting env (2) from .env.ci Hello Ci
Note theDOTENV_PRIVATE_KEY_CI
ends with_CI
. This instructsdotenvx run
to load the.env.ci
file. See the pattern? - <summary>combine multiple encrypted .env files</summary>
sh $ dotenvx set HELLO World -f .env $ dotenvx set HELLO Production -f .env.production $ echo "console.log('Hello ' + process.env.HELLO)" > index.js $ DOTENV_PRIVATE_KEY="<.env private key>" DOTENV_PRIVATE_KEY_PRODUCTION="<.env.production private key>" dotenvx run -- node index.js [dotenvx@1.X.X] injecting env (3) from .env, .env.production Hello World
Note theDOTENV_PRIVATE_KEY
instructsdotenvx run
to load the.env
file and theDOTENV_PRIVATE_KEY_PRODUCTION
instructs it to load the.env.production
file. See the pattern? - <summary>combine multiple encrypted .env files for monorepo</summary>
sh $ mkdir app1 $ mkdir app2 $ dotenvx set HELLO app1 -f app1/.env.ci $ dotenvx set HELLO app2 -f app2/.env.ci $ echo "console.log('Hello ' + process.env.HELLO)" > index.js $ DOTENV_PRIVATE_KEY_CI="<app1/privat ci key>,<app2/private ci key>" dotenvx run -f app1/.env.ci -f app2/.env.ci -- node index.js [dotenvx@1.X.X] injecting env (2) from app1/.env.ci,app2/.env.ci Hello app1 $ DOTENV_PRIVATE_KEY_CI="<app1/privat ci key>,<app2/private ci key>" dotenvx run -f app1/.env.ci -f app2/.env.ci --overload -- node index.js [dotenvx@1.X.X] injecting env (2) from app1/.env.ci,app2/.env.ci Hello app2
Note theDOTENV_PRIVATE_KEY_CI
(and anyDOTENV_PRIVATE_KEY*
) can take multiple private keys by simply comma separating them. - <summary>
--stdout
</summary>
sh $ echo "HELLO=World" > .env $ dotenvx encrypt --stdout $ dotenvx encrypt --stdout > .env.encrypted
- <summary>other curves</summary>
>secp256k1
is a well-known and battle tested curve, in use with Bitcoin and other cryptocurrencies, but we are open to adding support for more curves. > > If your organization's compliance department requires NIST approved curves or other curves likecurve25519
, please reach out at security@dotenvx.com.
Advanced
Become a
dotenvx
power user.
CLI 📟
Advanced CLI commands.
- <summary>
run
- Variable Expansion</summary>
Reference and expand variables already on your machine for use in your .env file.ini # .env USERNAME="username" DATABASE_URL="postgres://${USERNAME}@localhost/my_database"
js // index.js console.log('DATABASE_URL', process.env.DATABASE_URL)
sh $ dotenvx run --debug -- node index.js [dotenvx@1.X.X] injecting env (2) from .env DATABASE_URL postgres://username@localhost/my_database
- <summary>
run
- Command Substitution</summary>
Add the output of a command to one of your variables in your .env file.ini # .env DATABASE_URL="postgres://$(whoami)@localhost/my_database"
js // index.js console.log('DATABASE_URL', process.env.DATABASE_URL)
sh $ dotenvx run --debug -- node index.js [dotenvx@1.X.X] injecting env (1) from .env DATABASE_URL postgres://yourusername@localhost/my_database
- <summary>
run
- Shell Expansion</summary>
Prevent your shell from expanding inline$VARIABLES
before dotenvx has a chance to inject it. Use a subshell.sh $ dotenvx run --env="HELLO=World" -- sh -c 'echo Hello $HELLO' Hello World
- <summary>
run
- Multiline</summary>
Dotenvx supports multiline values. This is particularly useful in conjunction with Docker - which does not support multiline values.ini # .env MULTILINE_PEM="-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnNl1tL3QjKp3DZWM0T3u LgGJQwu9WqyzHKZ6WIA5T+7zPjO1L8l3S8k8YzBrfH4mqWOD1GBI8Yjq2L1ac3Y/ bTdfHN8CmQr2iDJC0C6zY8YV93oZB3x0zC/LPbRYpF8f6OqX1lZj5vo2zJZy4fI/ kKcI5jHYc8VJq+KCuRZrvn+3V+KuL9tF9v8ZgjF2PZbU+LsCy5Yqg1M8f5Jp5f6V u4QuUoobAgMBAAE= -----END PUBLIC KEY-----"
js // index.js console.log('MULTILINE_PEM', process.env.MULTILINE_PEM)
sh $ dotenvx run -- node index.js MULTILINE_PEM -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnNl1tL3QjKp3DZWM0T3u LgGJQwu9WqyzHKZ6WIA5T+7zPjO1L8l3S8k8YzBrfH4mqWOD1GBI8Yjq2L1ac3Y/ bTdfHN8CmQr2iDJC0C6zY8YV93oZB3x0zC/LPbRYpF8f6OqX1lZj5vo2zJZy4fI/ kKcI5jHYc8VJq+KCuRZrvn+3V+KuL9tF9v8ZgjF2PZbU+LsCy5Yqg1M8f5Jp5f6V u4QuUoobAgMBAAE= -----END PUBLIC KEY-----
- <summary>
run
- Contextual Help</summary>
Unlike other dotenv libraries, dotenvx attempts to unblock you with contextual help. For example, when missing a custom .env file:sh $ dotenvx run -f .env.missing -- echo $HELLO [MISSING_ENV_FILE] missing .env.missing file (/Users/scottmotte/Code/dotenvx/playground/apr-16/.env.missing) [MISSING_ENV_FILE] https://github.com/dotenvx/dotenvx/issues/484 and re-run [dotenvx run -- echo]
or when missing a KEY:sh $ echo "HELLO=World" > .env $ dotenvx get GOODBYE [MISSING_KEY] missing GOODBYE key
- <summary>
run
- multiple-f
flags</summary>
Compose multiple.env
files for environment variables loading, as you need.sh $ echo "HELLO=local" > .env.local $ echo "HELLO=World" > .env $ echo "console.log('Hello ' + process.env.HELLO)" > index.js $ dotenvx run -f .env.local -f .env -- node index.js [dotenvx@1.X.X] injecting env (1) from .env.local, .env Hello local
Note subsequent files do NOT override pre-existing variables defined in previous files or env. This follows historic principle. For example, abovelocal
wins – from the first file. - <summary>
run --env HELLO=String
</summary>
Set environment variables as a simpleKEY=value
string pair.sh $ echo "HELLO=World" > .env $ echo "console.log('Hello ' + process.env.HELLO)" > index.js $ dotenvx run --env HELLO=String -f .env -- node index.js [dotenvx@1.X.X] injecting env (1) from .env, and --env flag Hello String
- <summary>
run --overload
</summary>
Override existing env variables. These can be variables already on your machine or variables loaded as files consecutively. The last variable seen will 'win'.sh $ echo "HELLO=local" > .env.local $ echo "HELLO=World" > .env $ echo "console.log('Hello ' + process.env.HELLO)" > index.js $ dotenvx run -f .env.local -f .env --overload -- node index.js [dotenvx@1.X.X] injecting env (1) from .env.local, .env Hello World
Note that with--overload
subsequent files DO override pre-existing variables defined in previous files. - <summary>
DOTENV_PRIVATE_KEY=key run
</summary>
Decrypt your encrypted.env
by settingDOTENV_PRIVATE_KEY
beforedotenvx run
.sh $ touch .env $ dotenvx set HELLO encrypted $ echo "console.log('Hello ' + process.env.HELLO)" > index.js # check your .env.keys files for your privateKey $ DOTENV_PRIVATE_KEY="122...0b8" dotenvx run -- node index.js [dotenvx@1.X.X] injecting env (2) from .env Hello encrypted
- <summary>
DOTENV_PRIVATE_KEY_PRODUCTION=key run
</summary>
Decrypt your encrypted.env.production
by settingDOTENV_PRIVATE_KEY_PRODUCTION
beforedotenvx run
. Alternatively, this can be already set on your server or cloud provider.sh $ touch .env.production $ dotenvx set HELLO "production encrypted" -f .env.production $ echo "console.log('Hello ' + process.env.HELLO)" > index.js # check .env.keys for your privateKey $ DOTENV_PRIVATE_KEY_PRODUCTION="122...0b8" dotenvx run -- node index.js [dotenvx@1.X.X] injecting env (2) from .env.production Hello production encrypted
Note theDOTENV_PRIVATE_KEY_PRODUCTION
ends with_PRODUCTION
. This instructs dotenvx run to load the.env.production
file. - <summary>
DOTENV_PRIVATE_KEY_CI=key dotenvx run
</summary>
Decrypt your encrypted.env.ci
by settingDOTENV_PRIVATE_KEY_CI
beforedotenvx run
. Alternatively, this can be already set on your server or cloud provider.sh $ touch .env.ci $ dotenvx set HELLO "ci encrypted" -f .env.ci $ echo "console.log('Hello ' + process.env.HELLO)" > index.js # check .env.keys for your privateKey $ DOTENV_PRIVATE_KEY_CI="122...0b8" dotenvx run -- node index.js [dotenvx@1.X.X] injecting env (2) from .env.ci Hello ci encrypted
Note theDOTENV_PRIVATE_KEY_CI
ends with_CI
. This instructs dotenvx run to load the.env.ci
file. See the pattern? - <summary>
DOTENV_PRIVATE_KEY=key DOTENV_PRIVATE_KEY_PRODUCTION=key run
- Combine Multiple</summary>
Decrypt your encrypted.env
and.env.production
files by settingDOTENV_PRIVATE_KEY
andDOTENV_PRIVATE_KEY_PRODUCTION
beforedotenvx run
.sh $ touch .env $ touch .env.production $ dotenvx set HELLO encrypted $ dotenvx set HELLO "production encrypted" -f .env.production $ echo "console.log('Hello ' + process.env.HELLO)" > index.js # check .env.keys for your privateKeys $ DOTENV_PRIVATE_KEY="122...0b8" DOTENV_PRIVATE_KEY_PRODUCTION="122...0b8" dotenvx run -- node index.js [dotenvx@1.X.X] injecting env (3) from .env, .env.production Hello encrypted $ DOTENV_PRIVATE_KEY_PRODUCTION="122...0b8" DOTENV_PRIVATE_KEY="122...0b8" dotenvx run -- node index.js [dotenvx@1.X.X] injecting env (3) from .env.production, .env Hello production encrypted
Compose any encrypted files you want this way. As long as aDOTENV_PRIVATE_KEY_${environment}
is set, the values from.env.${environment}
will be decrypted at runtime. - <summary>
run --verbose
</summary>
Set log level toverbose
. (log levels)sh $ echo "HELLO=production" > .env.production $ echo "console.log('Hello ' + process.env.HELLO)" > index.js $ dotenvx run -f .env.production --verbose -- node index.js loading env from .env.production (/path/to/.env.production) HELLO set [dotenvx@1.X.X] injecting env (1) from .env.production Hello production
- <summary>
run --debug
</summary>
Set log level todebug
. (log levels)sh $ echo "HELLO=production" > .env.production $ echo "console.log('Hello ' + process.env.HELLO)" > index.js $ dotenvx run -f .env.production --debug -- node index.js process command [node index.js] options: {"env":[],"envFile":[".env.production"]} loading env from .env.production (/path/to/.env.production) {"HELLO":"production"} HELLO set HELLO set to production [dotenvx@1.X.X] injecting env (1) from .env.production executing process command [node index.js] expanding process command to [/opt/homebrew/bin/node index.js] Hello production
- <summary>
run --quiet
</summary>
Use--quiet
to suppress all output (except errors). (log levels)sh $ echo "HELLO=production" > .env.production $ echo "console.log('Hello ' + process.env.HELLO)" > index.js $ dotenvx run -f .env.production --quiet -- node index.js Hello production
- <summary>
run --log-level
</summary>
Set--log-level
to whatever you wish. For example, to suppress warnings (risky), set log level toerror
:sh $ echo "HELLO=production" > .env.production $ echo "console.log('Hello ' + process.env.HELLO)" > index.js $ dotenvx run -f .env.production --log-level=error -- node index.js Hello production
Available log levels areerror, warn, info, verbose, debug, silly
(source) - <summary>
run --strict
</summary>
Exit with code1
if any errors are encountered - like a missing .env file or decryption failure.sh $ echo "console.log('Hello ' + process.env.HELLO)" > index.js $ dotenvx run -f .env.missing --strict -- node index.js [MISSING_ENV_FILE] missing .env.missing file (/path/to/.env.missing) [MISSING_ENV_FILE] ? add one with [echo "HELLO=World" > .env.missing]
This can be useful inci
scripts where you want to fail the ci if your.env
file could not be decrypted at runtime. - <summary>
run --ignore
</summary>
Ignore errors likeMISSING_ENV_FILE
.sh $ echo "console.log('Hello ' + process.env.HELLO)" > index.js $ dotenvx run -f .env.missing --ignore=MISSING_ENV_FILE -- node index.js ...
- <summary>
run --convention=nextjs
</summary>
Load envs using Next.js' convention. Set--convention
tonextjs
:sh $ echo "HELLO=development local" > .env.development.local $ echo "HELLO=local" > .env.local $ echo "HELLO=development" > .env.development $ echo "HELLO=env" > .env $ echo "console.log('Hello ' + process.env.HELLO)" > index.js $ dotenvx run --convention=nextjs -- node index.js [dotenvx@1.X.X] injecting env (1) from .env.development.local, .env.local, .env.development, .env Hello development local
(more conventions available upon request) - <summary>
run --convention=flow
</summary>
Load envs using dotenv-flow's convention. Set--convention
toflow
:sh $ echo "HELLO=development local" > .env.development.local $ echo "HELLO=development" > .env.development $ echo "HELLO=local" > .env.local $ echo "HELLO=env" > .env $ echo "console.log('Hello ' + process.env.HELLO)" > index.js $ NODE_ENV=development dotenvx run --convention=flow -- node index.js [dotenvx@1.X.X] injecting env (1) from .env.development.local, .env.development, .env.local, .env Hello development local
Further, we recommend usingDOTENV_ENV
overNODE_ENV
– asdotenvx
works everywhere, not just node.sh $ DOTENV_ENV=development dotenvx run --convention=flow -- node index.js [dotenvx@1.X.X] injecting env (1) from .env.development.local, .env.development, .env.local, .env Hello development local
- <summary>
run -fk
</summary>
Specify path to.env.keys
. This is useful with monorepos.sh $ mkdir -p apps/app1 $ touch apps/app1/.env $ dotenvx set HELLO world -fk .env.keys -f apps/app1/.env $ dotenvx run -fk .env.keys -f apps/app1/.env -- yourcommand
- <summary>
get KEY
</summary>
Return a single environment variable's value.sh $ echo "HELLO=World" > .env $ dotenvx get HELLO World
- <summary>
get KEY -f
</summary>
Return a single environment variable's value from a specific.env
file.sh $ echo "HELLO=World" > .env $ echo "HELLO=production" > .env.production $ dotenvx get HELLO -f .env.production production
- <summary>
get KEY -fk
</summary>
Specify path to.env.keys
. This is useful with monorepos.sh $ mkdir -p apps/app1 $ touch apps/app1/.env $ dotenvx set HELLO world -fk .env.keys -f apps/app1/.env $ dotenvx get HELLO -fk .env.keys -f apps/app1/.env world
- <summary>
get KEY --env
</summary>
Return a single environment variable's value from a--env
string.sh $ dotenvx get HELLO --env HELLO=String -f .env.production String
- <summary>
get KEY --overload
</summary>
Return a single environment variable's value where each found value is overloaded.sh $ echo "HELLO=World" > .env $ echo "HELLO=production" > .env.production $ dotenvx get HELLO -f .env.production --env HELLO=String -f .env --overload World
- <summary>
get KEY --strict
</summary>
Exit with code1
if any errors are encountered - like a missing key, missing .env file, or decryption failure.sh $ dotenvx get DOES_NOT_EXIST --strict [MISSING_KEY] missing DOES_NOT_EXIST key
- <summary>
get KEY --convention=nextjs
</summary>
Return a single environment variable's value using Next.js' convention. Set--convention
tonextjs
:sh $ echo "HELLO=development local" > .env.development.local $ echo "HELLO=local" > .env.local $ echo "HELLO=development" > .env.development $ echo "HELLO=env" > .env $ echo "console.log('Hello ' + process.env.HELLO)" > index.js $ dotenvx get HELLO --convention=nextjs development local
- <summary>
get KEY --convention=flow
</summary>
Return a single environment variable's value using dotenv-flow's convention. Set--convention
toflow
:sh $ echo "HELLO=development local" > .env.development.local $ echo "HELLO=development" > .env.development $ echo "HELLO=local" > .env.local $ echo "HELLO=env" > .env $ echo "console.log('Hello ' + process.env.HELLO)" > index.js $ NODE_ENV=development dotenvx get HELLO --convention=flow development local
Further, we recommend usingDOTENV_ENV
overNODE_ENV
– asdotenvx
works everywhere, not just node.sh $ DOTENV_ENV=development dotenvx get HELLO --convention=flow development local
- <summary>
get
(json)</summary>
Return a json response of all key/value pairs in a.env
file.sh $ echo "HELLO=World" > .env $ dotenvx get {"HELLO":"World"}
- <summary>
get --format shell
</summary>
Return a shell formatted response of all key/value pairs in a.env
file.sh $ echo "HELLO=World" > .env $ echo "KEY=value" >> .env $ dotenvx get --format shell HELLO=World KEY=value
This can be useful when combined withenv
on the command line.$ echo "console.log('Hello ' + process.env.KEY + ' ' + process.env.HELLO)" > index.js $ env $(dotenvx get --format=shell) node index.js Hello value World
or withexport
.$ echo "console.log('Hello ' + process.env.KEY + ' ' + process.env.HELLO)" > index.js $ export $(dotenvx get --format=shell) $ node index.js Hello value World
- <summary>
get --format eval
</summary>
Return aneval
-ready shell formatted response of all key/value pairs in a.env
file.sh $ echo "HELLO=World" > .env $ echo "KEY=value" >> .env $ dotenvx get --format eval HELLO="World" KEY="value"
Note that this exports newlines and quoted strings. This can be useful for more complex .env values (spaces, escaped characters, quotes, etc) combined witheval
on the command line.sh $ echo "console.log('Hello ' + process.env.KEY + ' ' + process.env.HELLO)" > index.js $ eval $(dotenvx get --format=eval) node index.js Hello value World
Be careful witheval
as it allows for arbitrary execution of commands. Preferdotenvx run --
but in some caseseval
is a sharp knife that is useful to have. - <summary>
get --all
</summary>
Return preset machine envs as well.sh $ echo "HELLO=World" > .env $ dotenvx get --all {"PWD":"/some/file/path","USER":"username","LIBRARY_PATH":"/usr/local/lib", ..., "HELLO":"World"}
- <summary>
get --all --pretty-print
</summary>
Make the output more readable - pretty print it.sh $ echo "HELLO=World" > .env $ dotenvx get --all --pretty-print { "PWD": "/some/filepath", "USER": "username", "LIBRARY_PATH": "/usr/local/lib", ..., "HELLO": "World" }
- <summary>
set KEY value
</summary>
Set an encrypted key/value (on by default).sh $ touch .env $ dotenvx set HELLO World set HELLO with encryption (.env)
- <summary>
set KEY value -f
</summary>
Set an (encrypted) key/value for another.env
file.sh $ touch .env.production $ dotenvx set HELLO production -f .env.production set HELLO with encryption (.env.production)
- <summary>
set KEY value -fk
</summary>
Specify path to.env.keys
. This is useful with monorepos.sh $ mkdir -p apps/app1 $ touch apps/app1/.env $ dotenvx set HELLO world -fk .env.keys -f apps/app1/.env set HELLO with encryption (.env)
Put it to use.sh $ dotenvx get -fk .env.keys -f apps/app1/.env
Use it with a relative path.sh $ cd apps/app1 $ dotenvx get -fk ../../.env.keys -f .env
- <summary>
set KEY "value with spaces"
</summary>
Set a value containing spaces.sh $ touch .env.ci $ dotenvx set HELLO "my ci" -f .env.ci set HELLO with encryption (.env.ci)
- <summary>
set KEY -- "- + * ÷"
</summary>
If your value starts with a dash (-
), then place two dashes instructing the cli that there are no more flag arguments.sh $ touch .env.ci $ dotenvx set HELLO -f .env.ci -- "- + * ÷" set HELLO with encryption (.env.ci)
- <summary>
set KEY value --plain
</summary>
Set a plaintext key/value.sh $ touch .env $ dotenvx set HELLO World --plain set HELLO (.env)
- <summary>
encrypt
</summary>
Encrypt the contents of a.env
file to an encrypted.env
file.sh $ echo "HELLO=World" > .env $ dotenvx encrypt ✔ encrypted (.env) ✔ key added to .env.keys (DOTENV_PRIVATE_KEY) ⮕ next run [dotenvx ext gitignore --pattern .env.keys] to gitignore .env.keys ⮕ next run [DOTENV_PRIVATE_KEY='122...0b8' dotenvx run -- yourcommand] to test decryption locally
- <summary>
encrypt -f
</summary>
Encrypt the contents of a specified.env
file to an encrypted.env
file.sh $ echo "HELLO=World" > .env $ echo "HELLO=Production" > .env.production $ dotenvx encrypt -f .env.production ✔ encrypted (.env.production) ✔ key added to .env.keys (DOTENV_PRIVATE_KEY_PRODUCTION) ⮕ next run [dotenvx ext gitignore --pattern .env.keys] to gitignore .env.keys ⮕ next run [DOTENV_PRIVATE_KEY='bff...bc4' dotenvx run -- yourcommand] to test decryption locally
- <summary>
encrypt -fk
</summary>
Specify path to.env.keys
. This is useful with monorepos.sh $ mkdir -p apps/app1 $ echo "HELLO=World" > apps/app1/.env $ dotenvx encrypt -fk .env.keys -f apps/app1/.env ✔ encrypted (apps/app1/.env)
Put it to use.sh $ dotenvx run -fk .env.keys -f apps/app1/.env
Use with a relative path.sh $ cd apps/app1 $ dotenvx run -fk ../../.env.keys -f .env
- <summary>
encrypt -k
</summary>
Specify the key(s) to encrypt by passing--key
.sh $ echo "HELLO=World\nHELLO2=Universe" > .env $ dotenvx encrypt -k HELLO2 ✔ encrypted (.env)
Even specify a glob pattern.sh $ echo "HELLO=World\nHOLA=Mundo" > .env $ dotenvx encrypt -k "HE*" ✔ encrypted (.env)
- <summary>
encrypt -ek
</summary>
Specify the key(s) to NOT encrypt by passing--exclude-key
.sh $ echo "HELLO=World\nHELLO2=Universe" > .env $ dotenvx encrypt -ek HELLO ✔ encrypted (.env)
Even specify a glob pattern.sh $ echo "HELLO=World\nHOLA=Mundo" > .env $ dotenvx encrypt -ek "HO*" ✔ encrypted (.env)
- <summary>
encrypt --stdout
</summary>
Encrypt the contents of a.env
file and send to stdout.sh $ echo "HELLO=World" > .env $ dotenvx encrypt --stdout #/-------------------[DOTENV_PUBLIC_KEY]--------------------/ #/ public-key encryption for .env files / #/ [how it works](https://dotenvx.com/encryption) / #/----------------------------------------------------------/ DOTENV_PUBLIC_KEY="034af93e93708b994c10f236c96ef88e47291066946cce2e8d98c9e02c741ced45" # .env HELLO="encrypted:BDqDBibm4wsYqMpCjTQ6BsDHmMadg9K3dAt+Z9HPMfLEIRVz50hmLXPXRuDBXaJi/LwWYEVUNiq0HISrslzQPaoyS8Lotg3gFWJTsNCdOWnqpjF2xNUX2RQiP05kAbEXM6MWVjDr"
or send to a file:sh $ echo "HELLO=World" > .env $ dotenvx encrypt --stdout > somefile.txt
- <summary>
decrypt
</summary>
Decrypt the contents of an encrypted.env
file to an unencrypted.env
file.sh $ echo "HELLO=World" > .env $ dotenvx encrypt ✔ encrypted (.env) $ dotenvx decrypt ✔ decrypted (.env)
- <summary>
decrypt -f
</summary>
Decrypt the contents of a specified encrypted.env
file to an unencrypted.env
file.sh $ echo "HELLO=World" > .env $ echo "HELLO=Production" > .env.production $ dotenvx encrypt -f .env.production ✔ encrypted (.env.production) $ dotenvx decrypt -f .env.production ✔ decrypted (.env.production)
- <summary>
decrypt -fk
</summary>
Specify path to.env.keys
. This is useful with monorepos.sh $ mkdir -p apps/app1 $ echo "HELLO=World" > apps/app1/.env $ dotenvx encrypt -fk .env.keys -f apps/app1/.env ✔ encrypted (apps/app1/.env) $ dotenvx decrypt -fk .env.keys -f apps/app1/.env ✔ decrypted (apps/app1/.env)
- <summary>
decrypt -k
</summary>
Decrypt the contents of a specified key inside an encrypted.env
file.sh $ echo "HELLO=World\nHOLA=Mundo" > .env $ dotenvx encrypt ✔ encrypted (.env) $ dotenvx decrypt -k HELLO ✔ decrypted (.env)
Even specify a glob pattern.sh $ echo "HELLO=World\nHOLA=Mundo" > .env $ dotenvx encrypt ✔ encrypted (.env) $ dotenvx decrypt -k "HE*" ✔ encrypted (.env)
- <summary>
decrypt -ek
</summary>
Decrypt the contents inside an encrypted.env
file except for an excluded key.sh $ echo "HELLO=World\nHOLA=Mundo" > .env $ dotenvx encrypt ✔ encrypted (.env) $ dotenvx decrypt -ek HOLA ✔ decrypted (.env)
Even specify a glob pattern.sh $ echo "HELLO=World\nHOLA=Mundo" > .env $ dotenvx encrypt ✔ encrypted (.env) $ dotenvx decrypt -ek "HO*" ✔ encrypted (.env)
- <summary>
decrypt --stdout
</summary>
Decrypt the contents of an encrypted.env
file and send to stdout.sh $ dotenvx decrypt --stdout #/-------------------[DOTENV_PUBLIC_KEY]--------------------/ #/ public-key encryption for .env files / #/ [how it works](https://dotenvx.com/encryption) / #/----------------------------------------------------------/ DOTENV_PUBLIC_KEY="034af93e93708b994c10f236c96ef88e47291066946cce2e8d98c9e02c741ced45" # .env HELLO="World"
or send to a file:sh $ dotenvx decrypt --stdout > somefile.txt
- <summary>
keypair
</summary>
Print public/private keys for.env
file.sh $ echo "HELLO=World" > .env $ dotenvx encrypt $ dotenvx keypair {"DOTENV_PUBLIC_KEY":"<publicKey>","DOTENV_PRIVATE_KEY":"<privateKey>"}
- <summary>
keypair -f
</summary>
Print public/private keys for.env.production
file.sh $ echo "HELLO=Production" > .env.production $ dotenvx encrypt -f .env.production $ dotenvx keypair -f .env.production {"DOTENV_PUBLIC_KEY_PRODUCTION":"<publicKey>","DOTENV_PRIVATE_KEY_PRODUCTION":"<privateKey>"}
- <summary>
keypair -fk
</summary>
Specify path to.env.keys
. This is useful for printing public/private keys for monorepos.sh $ mkdir -p apps/app1 $ echo "HELLO=World" > apps/app1/.env $ dotenvx encrypt -fk .env.keys -f apps/app1/.env $ dotenvx keypair -fk .env.keys -f apps/app1/.env {"DOTENV_PUBLIC_KEY":"<publicKey>","DOTENV_PRIVATE_KEY":"<privateKey>"}
- <summary>
keypair DOTENV_PRIVATE_KEY
</summary>
Print specific keypair for.env
file.sh $ echo "HELLO=World" > .env $ dotenvx encrypt $ dotenvx keypair DOTENV_PRIVATE_KEY <privateKey>
- <summary>
keypair --format shell
</summary>
Print a shell formatted response of public/private keys.sh $ echo "HELLO=World" > .env $ dotenx encrypt $ dotenvx keypair --format shell DOTENV_PUBLIC_KEY=<publicKey> DOTENV_PRIVATE_KEY=<privateKey>
- <summary>
ls
</summary>
Print all.env
files in a tree structure.sh $ touch .env $ touch .env.production $ mkdir -p apps/backend $ touch apps/backend/.env $ dotenvx ls ├─ .env.production ├─ .env └─ apps └─ backend └─ .env
- <summary>
ls directory
</summary>
Print all.env
files inside a specified path to a directory.sh $ touch .env $ touch .env.production $ mkdir -p apps/backend $ touch apps/backend/.env $ dotenvx ls apps/backend └─ .env
- <summary>
ls -f
</summary>
Glob.env
filenames matching a wildcard.sh $ touch .env $ touch .env.production $ mkdir -p apps/backend $ touch apps/backend/.env $ touch apps/backend/.env.prod $ dotenvx ls -f **/.env.prod* ├─ .env.production └─ apps └─ backend └─ .env.prod
- <summary>
ls -ef
</summary>
Glob.env
filenames excluding a wildcard.sh $ touch .env $ touch .env.production $ mkdir -p apps/backend $ touch apps/backend/.env $ touch apps/backend/.env.prod $ dotenvx ls -ef '**/.env.prod*' ├─ .env └─ apps └─ backend └─ .env
- <summary>
rotate
</summary>
Rotate public/private keys for.env
file and re-encrypt all encrypted values.sh $ echo "HELLO=World" > .env $ dotenvx encrypt ✔ encrypted (.env) $ dotenvx rotate ✔ rotated (.env)
- <summary>
rotate -f
</summary>
Rotate public/private keys for a specified encrypted.env
file and re-encrypt all encrypted values.sh $ echo "HELLO=World" > .env $ echo "HELLO=Production" > .env.production $ dotenvx encrypt -f .env.production ✔ encrypted (.env.production) $ dotenvx rotate -f .env.production ✔ rotated (.env.production)
- <summary>
rotate -fk
</summary>
Specify path to.env.keys
. This is useful with monorepos.sh $ mkdir -p apps/app1 $ echo "HELLO=World" > apps/app1/.env $ dotenvx encrypt -fk .env.keys -f apps/app1/.env ✔ encrypted (apps/app1/.env) $ dotenvx rotate -fk .env.keys -f apps/app1/.env ✔ rotated (apps/app1/.env)
- <summary>
rotate -k
</summary>
Rotate the contents of a specified key inside an encrypted.env
file.sh $ echo "HELLO=World\nHOLA=Mundo" > .env $ dotenvx encrypt ✔ encrypted (.env) $ dotenvx rotate -k HELLO ✔ rotated (.env)
Even specify a glob pattern.sh $ echo "HELLO=World\nHOLA=Mundo" > .env $ dotenvx encrypt ✔ encrypted (.env) $ dotenvx rotate -k "HE*" ✔ rotated (.env)
- <summary>
rotate -ek
</summary>
Rotate the encrypted contents inside an encrypted.env
file except for an excluded key.sh $ echo "HELLO=World\nHOLA=Mundo" > .env $ dotenvx encrypt ✔ encrypted (.env) $ dotenvx rotate -ek HOLA ✔ rotated (.env)
Even specify a glob pattern.sh $ echo "HELLO=World\nHOLA=Mundo" > .env $ dotenvx encrypt ✔ encrypted (.env) $ dotenvx rotate -ek "HO*" ✔ rotated (.env)
- <summary>
rotate --stdout
</summary>
Rotate the contents of an encrypted.env
file and send to stdout.sh $ dotenvx rotate --stdout #/-------------------[DOTENV_PUBLIC_KEY]--------------------/ #/ public-key encryption for .env files / #/ [how it works](https://dotenvx.com/encryption) / #/----------------------------------------------------------/ DOTENV_PUBLIC_KEY="034af93e93708b994c10f236c96ef88e47291066946cce2e8d98c9e02c741ced45" # .env HELLO="encrypted:12345"
or send to a file:sh $ dotenvx rotate --stdout > somefile.txt
- <summary>
help
</summary>
Output help fordotenvx
.sh $ dotenvx help Usage: dotenvx run -- yourcommand a better dotenv–from the creator of `dotenv` Options: -l, --log-level <level> set log level (default: "info") -q, --quiet sets log level to error -v, --verbose sets log level to verbose -d, --debug sets log level to debug -V, --version output the version number -h, --help display help for command Commands: run inject env at runtime [dotenvx run -- yourcommand] get [KEY] return a single environment variable set <KEY> <value> set a single environment variable encrypt convert .env file(s) to encrypted .env file(s) decrypt convert encrypted .env file(s) to plain .env file(s) keypair [KEY] print public/private keys for .env file(s) ls [directory] print all .env files in a tree structure Advanced: pro 🏆 pro ext 🔌 extensions
You can get more detailed help per command withdotenvx help COMMAND
.sh $ dotenvx help run Usage: @dotenvx/dotenvx run [options] inject env at runtime [dotenvx run -- yourcommand] Options: -e, --env <strings...> environment variable(s) set as string (example: "HELLO=World") (default: []) -f, --env-file <paths...> path(s) to your env file(s) (default: []) -fv, --env-vault-file <paths...> path(s) to your .env.vault file(s) (default: []) -o, --overload override existing env variables --convention <name> load a .env convention (available conventions: ['nextjs']) -h, --help display help for command Examples: $ dotenvx run -- npm run dev $ dotenvx run -- flask --app index run $ dotenvx run -- php artisan serve $ dotenvx run -- bin/rails s Try it: $ echo "HELLO=World" > .env $ echo "console.log('Hello ' + process.env.HELLO)" > index.js $ dotenvx run -- node index.js [dotenvx@1.X.X] injecting env (1) from .env Hello World
- <summary>
--version
</summary>
Check current version ofdotenvx
.sh $ dotenvx --version X.X.X
Extensions 🔌
CLI extensions.
- <summary>
ext genexample
</summary>
In one command, generate a.env.example
file from your current.env
file contents.sh $ echo "HELLO=World" > .env $ dotenvx ext genexample ✔ updated .env.example (1)
ini # .env.example HELLO=""
- <summary>
ext genexample -f
</summary>
Pass multiple.env
files to generate your.env.example
file from the combination of their contents.sh $ echo "HELLO=World" > .env $ echo "DB_HOST=example.com" > .env.production $ dotenvx ext genexample -f .env -f .env.production ✔ updated .env.example (2)
ini # .env.example HELLO="" DB_HOST=""
- <summary>
ext genexample directory
</summary>
Generate a.env.example
file inside the specified directory. Useful for monorepos.sh $ echo "HELLO=World" > .env $ mkdir -p apps/backend $ echo "HELLO=Backend" > apps/backend/.env $ dotenvx ext genexample apps/backend ✔ updated .env.example (1)
ini # apps/backend/.env.example HELLO=""
- <summary>
ext gitignore
</summary>
Gitignore your.env
files.sh $ dotenvx ext gitignore ✔ ignored .env* (.gitignore)
- <summary>
ext gitignore --pattern
</summary>
Gitignore specific pattern(s) of.env
files.sh $ dotenvx ext gitignore --pattern .env.keys ✔ ignored .env.keys (.gitignore)
- <summary>
ext precommit
</summary>
Prevent.env
files from being committed to code.sh $ dotenvx ext precommit [dotenvx][precommit] .env files (1) protected (encrypted or gitignored)
- <summary>
ext precommit --install
</summary>
Install a shell script to.git/hooks/pre-commit
to prevent accidentally committing any.env
files to source control.sh $ dotenvx ext precommit --install [dotenvx][precommit] dotenvx ext precommit installed [.git/hooks/pre-commit]
- <summary>
ext precommit directory
</summary>
Prevent.env
files from being committed to code inside a specified path to a directory.sh $ echo "HELLO=World" > .env $ mkdir -p apps/backend $ echo "HELLO=Backend" > apps/backend/.env $ dotenvx ext precommit apps/backend [dotenvx][precommit] apps/backend/.env not protected (encrypted or gitignored)
- <summary>
ext prebuild
</summary>
Prevent.env
files from being built into your docker containers. Add it to yourDockerfile
.sh # Dockerfile RUN curl -fsS https://dotenvx.sh | sh ... RUN dotenvx ext prebuild CMD ["dotenvx", "run", "--", "node", "index.js"]
- <summary>
ext prebuild directory
</summary>
Prevent.env
files from being built into your docker containers inside a specified path to a directory. Add it to yourDockerfile
.sh # Dockerfile RUN curl -fsS https://dotenvx.sh | sh ... RUN dotenvx ext prebuild apps/backend CMD ["dotenvx", "run", "--", "node", "apps/backend/index.js"]
- <summary>
ext scan
</summary>
Scan for leaked secrets.sh $ dotenvx ext scan 100 commits scanned. no leaks found
Uses gitleaks under the hood.
Library 📦
Use dotenvx directly in code.
- <summary>
config()
</summary>
Use directly in node.js code.ini # .env HELLO="World"
js // index.js require('@dotenvx/dotenvx').config() console.log(`Hello ${process.env.HELLO}`)
sh $ node index.js [dotenvx@1.X.X] injecting env (1) from .env Hello World
It defaults to looking for a.env
file. - <summary>
config(path: ['.env.local', '.env'])
- multiple files</summary>
Specify path(s) to multiple .env files.ini # .env.local HELLO="Me"
ini # .env HELLO="World"
js // index.js require('@dotenvx/dotenvx').config({path: ['.env.local', '.env']}) // esm // import dotenvx from "@dotenvx/dotenvx"; // dotenvx.config({path: ['.env.local', '.env']}); console.log(`Hello ${process.env.HELLO}`)
sh $ node index.js [dotenvx@1.X.X] injecting env (1) from .env.local, .env Hello Me
- <summary>
config(overload: true)
- overload</summary>
Useoverload
to overwrite the prior set value.ini # .env.local HELLO="Me"
ini # .env HELLO="World"
js // index.js require('@dotenvx/dotenvx').config({path: ['.env.local', '.env'], overload: true}) // esm // import dotenvx from "@dotenvx/dotenvx"; // dotenvx.config({path: ['.env.local', '.env'], overload: true}); console.log(`Hello ${process.env.HELLO}`)
sh $ node index.js [dotenvx@1.X.X] injecting env (1) from .env.local, .env Hello World
- <summary>
config(strict: true)
- strict</summary>
Usestrict
to throw if an error is encountered - like a missing .env file.ini # .env HELLO="World"
js // index.js require('@dotenvx/dotenvx').config({path: ['.env.missing', '.env'], strict: true}) // esm // import dotenvx from "@dotenvx/dotenvx"; // dotenvx.config({path: ['.env.missing', '.env'], strict: true}); console.log(`Hello ${process.env.HELLO}`)
sh $ node index.js Error: [MISSING_ENV_FILE] missing .env.missing file (/path/to/.env.missing)
- <summary>
config(ignore:)
- ignore</summary>
Useignore
to suppress specific errors likeMISSING_ENV_FILE
.ini # .env HELLO="World"
js // index.js require('@dotenvx/dotenvx').config({path: ['.env.missing', '.env'], ignore: ['MISSING_ENV_FILE']}) // esm // import dotenvx from "@dotenvx/dotenvx"; // dotenvx.config({path: ['.env.missing', '.env'], ignore: ['MISSING_ENV_FILE']}); console.log(`Hello ${process.env.HELLO}`)
sh $ node index.js [dotenvx@1.X.X] injecting env (1) from .env Hello World
- <summary>
config(envKeysFile:)
- envKeysFile</summary>
UseenvKeysFile
to customize the path to your.env.keys
file. This is useful with monorepos.ini # .env HELLO="World"
js // index.js require('@dotenvx/dotenvx').config({path: ['.env'], envKeysFile: '../../.env.keys'})
- <summary>
parse(src)
</summary>
Parse a.env
string directly in node.js code.js // index.js const dotenvx = require('@dotenvx/dotenvx') const src = 'HELLO=World' const parsed = dotenvx.parse(src) console.log(`Hello ${parsed.HELLO}`)
sh $ node index.js Hello World
- <summary>
parse(src, {processEnv:})
</summary>
Sometimes, you want to runparse
without it accessingprocess.env
. (You can pass a fake processEnv this way as well - sometimes useful.)js // index.js const dotenvx = require('@dotenvx/dotenvx') const src = 'USER=Me' const parsed = dotenvx.parse(src, { processEnv: {} }) console.log(`Hello ${parsed.USER}`)
sh $ node index.js Hello Me
- <summary>
parse(src, {privateKey:})
</summary>
Decrypt an encrypted.env
string withprivateKey
.js // index.js const dotenvx = require('@dotenvx/dotenvx') const src = 'HELLO="encrypted:BE9Y7LKANx77X1pv1HnEoil93fPa5c9rpL/1ps48uaRT9zM8VR6mHx9yM+HktKdsPGIZELuZ7rr2mn1gScsmWitppAgE/1lVprNYBCqiYeaTcKXjDUXU5LfsEsflnAsDhT/kWG1l"' const parsed = dotenvx.parse(src, { privateKey: 'a4547dcd9d3429615a3649bb79e87edb62ee6a74b007075e9141ae44f5fb412c' }) console.log(`Hello ${parsed.HELLO}`)
sh $ node index.js Hello World
- <summary>
set(KEY, value)
</summary>
Programmatically set an environment variable.js // index.js const dotenvx = require('@dotenvx/dotenvx') dotenvx.set('HELLO', 'World', { path: '.env' })
- <summary>
get(KEY)
- Decryption at Access</summary>
Programmatically get an environment variable at access/runtime.js // index.js const dotenvx = require('@dotenvx/dotenvx') const decryptedValue = dotenvx.get('HELLO') console.log(decryptedValue)
This is known as Decryption at Access and is written about in the whitepaper.
Pro 🏆
Dotenvx Pro is a commercial extension for dotenvx.
Secrets Manager for Env Files.
- <summary>
pro keypair
</summary>
Print fully managed public/private keys for.env
file.sh $ echo "HELLO=World" > .env $ dotenvx encrypt $ dotenvx pro push $ dotenvx pro keypair {"DOTENV_PUBLIC_KEY":"<publicKey>","DOTENV_PRIVATE_KEY":"<privateKey>"}
- <summary>
pro keypair -f
</summary>
Print fully managed public/private keys for.env.production
file.sh $ echo "HELLO=Production" > .env.production $ dotenvx encrypt -f .env.production $ dotenvx pro push $ dotenvx pro keypair -f .env.production {"DOTENV_PUBLIC_KEY_PRODUCTION":"<publicKey>","DOTENV_PRIVATE_KEY_PRODUCTION":"<privateKey>"}
- <summary>
pro keypair DOTENV_PRIVATE_KEY
</summary>
Print specific fully managed keypair for.env
file.sh $ echo "HELLO=World" > .env $ dotenvx encrypt $ dotenvx pro push $ dotenvx pro keypair DOTENV_PRIVATE_KEY <privateKey>
- <summary>
pro settings org
</summary>
Print organization.sh $ dotenvx pro settings org motdotla
- <summary>
pro settings orgpublickey
</summary>
Print organization public key–used for encrypting project private keys.sh $ dotenvx pro settings orgpublickey 02761eccd2a442ebbfa14ac2e72762d885a1e96b8949428deea62db305947d6408
- <summary>
pro settings orgprivatekey
</summary>
Print masked organization private key–used for decrypting project private keys.sh $ dotenvx pro settings orgprivatekey 322c004*********************************************************
- <summary>
pro settings orgprivatekey --unmask
</summary>
Print unmasked organization private key–used for decrypting project private keys.sh $ dotenvx pro settings orgprivatekey --unmask 322c004271ac6ad1b548df3f316ff4e8f08e17e0b15f459db64f3f3b48b0efb7
- <summary>
pro settings orgteam
</summary>
Print team status in tabular format.sh $ dotenvx pro settings orgteam ╔═══════════╤════════╗ ║ username │ synced ║ ╟───────────┼────────╢ ║ motdotla │ ✔ ║ ╟───────────┼────────╢ ║ motdotenv │ ✔ ║ ╚═══════════╧════════╝
- <summary>
pro settings storetree
</summary>
Print encrypted store tree–backing your dotenvx pro installation.sh $ dotenvx pro settings storetree ├─ .env └─ pro.dotenvx.com ├─ user-1-organization-1.json ├─ user-1-private-key.json └─ user-1.json
Whitepaper
Dotenvx: Reducing Secrets Risk with Cryptographic Separation
Abstract. An ideal secrets solution would not only centralize secrets but also contain the fallout of a breach. While secrets managers offer centralized storage and distribution, their design creates a large blast radius, risking exposure of thousands or even millions of secrets. We propose a solution that reduces the blast radius by splitting secrets management into two distinct components: an encrypted secrets file and a separate decryption key.
...
Guides
Go deeper with
dotenvx
– detailed framework and platform guides.