[![dotenvx](https://dotenvx.com/better-banner.png)](https://dotenvx.com) *a better dotenv*โ€“from the creator of [`dotenv`](https://github.com/motdotla/dotenv). * run anywhere (cross-platform) * multi-environment * encrypted envs   ### Quickstart [![npm version](https://img.shields.io/npm/v/@dotenvx/dotenvx.svg)](https://www.npmjs.com/package/@dotenvx/dotenvx) [![downloads](https://img.shields.io/npm/dw/@dotenvx/dotenvx)](https://www.npmjs.com/package/@dotenvx/dotenvx) [![test suite](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/motdotenv/bb76445765a9731e7d824a6efdf53524/raw/dotenvxTestCount.json)](https://github.com/dotenvx/dotenvx/tree/main/tests) Install and use it in code just like `dotenv`. ```sh npm install @dotenvx/dotenvx --save ``` ```js // index.js require('@dotenvx/dotenvx').config() console.log(`Hello ${process.env.HELLO}`) ```   or install globally - *unlocks dotenv for any language, framework, or platform!*
with curl ๐ŸŒ
```sh curl -sfS https://dotenvx.sh | sh dotenvx help ``` [![curl installs](https://img.shields.io/endpoint?url=https://dotenvx.sh/stats/curl&label=curl%20installs)](https://github.com/dotenvx/dotenvx.sh/blob/main/install.sh)  
with brew ๐Ÿบ
```sh brew install dotenvx/brew/dotenvx dotenvx help ``` [![brew installs](https://img.shields.io/github/downloads/dotenvx/dotenvx/total?label=brew%20installs)](https://github.com/dotenvx/homebrew-brew/blob/main/Formula/dotenvx.rb)  
with docker ๐Ÿณ
```sh docker run -it --rm -v $(pwd):/app dotenv/dotenvx help ``` [![docker pulls](https://img.shields.io/docker/pulls/dotenv/dotenvx)](https://hub.docker.com/r/dotenv/dotenvx)  
with github releases ๐Ÿ™
```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 ``` [![github releases](https://img.shields.io/github/downloads/dotenvx/dotenvx/total)](https://github.com/dotenvx/dotenvx/releases)  
or with windows ๐ŸŸฆ๐ŸŸฉ๐ŸŸฅ๐ŸŸจ
```sh winget install dotenvx dotenvx help ```
  ## Run Anywhere ```sh $ 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 ``` see [extended quickstart guide](https://dotenvx.com/docs/quickstart) More examples *
TypeScript ๐Ÿ“˜
```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 ```
*
Deno ๐Ÿฆ•
```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 with `deno run`. Don't, because deno currently has incomplete support for these encryption ciphers. > > ``` > $ deno run -A npm:@dotenvx/dotenvx encrypt > Unknown cipher > ``` > > Instead, use `dotenvx` as designed, by installing the cli as a binary - via curl, brew, etc.
*
Bun ๐ŸฅŸ
```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 ```
*
Python ๐Ÿ
```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](https://dotenvx.com/docs/quickstart)
*
PHP ๐Ÿ˜
```sh $ echo "HELLO=World" > .env $ echo ' index.php $ dotenvx run -- php index.php Hello World ``` see [extended php guide](https://dotenvx.com/docs/quickstart)
*
Ruby ๐Ÿ’Ž
```sh $ echo "HELLO=World" > .env $ echo 'puts "Hello #{ENV["HELLO"]}"' > index.rb $ dotenvx run -- ruby index.rb Hello World ``` see [extended ruby guide](https://dotenvx.com/docs/quickstart)
*
Go ๐Ÿน
```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](https://dotenvx.com/docs/quickstart)
*
Rust ๐Ÿฆ€
```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](https://dotenvx.com/docs/quickstart)
*
Java โ˜•๏ธ
```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 ```
*
Clojure ๐ŸŒฟ
```sh $ echo "HELLO=World" > .env $ echo '(println "Hello" (System/getenv "HELLO"))' > index.clj $ dotenvx run -- clojure -M index.clj Hello World ```
*
Kotlin ๐Ÿ“
```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 ```
*
.NET ๐Ÿ”ต
```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 ```
*
Bash ๐Ÿ–ฅ๏ธ
```sh $ echo "HELLO=World" > .env $ dotenvx run --quiet -- sh -c 'echo Hello $HELLO' Hello World ```
*
Fish ๐Ÿ 
```sh $ echo "HELLO=World" > .env $ dotenvx run --quiet -- sh -c 'echo Hello $HELLO' Hello World ```
*
Cron โฐ
```sh # run every day at 8am 0 8 * * * dotenvx run -- /path/to/myscript.sh ```
*
Frameworks โ–ฒ
```sh $ dotenvx run -- next dev $ dotenvx run -- npm start $ dotenvx run -- bin/rails s $ dotenvx run -- php artisan serve ``` see [framework guides](https://dotenvx.com/docs#frameworks)
*
Docker ๐Ÿณ
```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](https://dotenvx.com/docs/platforms/docker)
*
CI/CDs ๐Ÿ™
```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](https://dotenvx.com/docs/cis/github-actions)
*
Platforms
```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](https://dotenvx.com/docs#platforms)
*
Process Managers
```js // pm2 "scripts": { "start": "dotenvx run -- pm2-runtime start ecosystem.config.js --env production" }, ``` see [process manager guides](https://dotenvx.com/docs#process-managers)
*
npx
```sh # alternatively use npx $ npx @dotenvx/dotenvx run -- node index.js $ npx @dotenvx/dotenvx run -- next dev $ npx @dotenvx/dotenvx run -- npm start ```
*
npm
```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][info] loading env (1) from .env Hello World ```
*
asdf
```sh # use dotenvx with asdf $ asdf plugin add dotenvx $ asdf install dotenvx latest ``` thank you [@jgburet](https://github.com/jgburet/asdf-dotenvx) of Paris ๐Ÿ‡ซ๐Ÿ‡ท
*
Git
```sh # use as a git submodule $ git dotenvx run -- node index.js $ git dotenvx run -- next dev $ git dotenvx run -- npm start ```
*
Variable Expansion
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 ```
*
Command Substitution
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][info] loading env (1) from .env.production Hello production > ^^ ``` More examples *
multiple `.env` files
```sh $ echo "HELLO=local" > .env.local $ echo "HELLO=World" > .env $ dotenvx run -f .env.local -f .env -- node index.js [dotenvx][info] loading env (1) from .env.local,.env Hello local ```
*
`--overload` flag
```sh $ echo "HELLO=local" > .env.local $ echo "HELLO=World" > .env $ dotenvx run -f .env.local -f .env --overload -- node index.js [dotenvx][info] loading env (1) from .env.local,.env Hello World ``` *
`--verbose` flag
```sh $ 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][info] loading env (1) from .env.production Hello production ``` *
`--debug` flag
```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][info] loading env (1) from .env.production Hello production ```
*
`--quiet` flag
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 ```
*
`--log-level` flag
Set `--log-level` to whatever you wish. For example, to supress warnings (risky), set log level to `error`: ```sh $ echo "HELLO=production" > .env.production $ dotenvx run -f .env.production --log-level=error -- node index.js Hello production ``` Available log levels are `error, warn, info, verbose, debug, silly`
*
`--convention` flag
Load envs using [Next.js' convention](https://nextjs.org/docs/pages/building-your-application/configuring/environment-variables#environment-variable-load-order). Set `--convention` to `nextjs`: ```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 ``` (more conventions available upon request)
  ## Encryption > Add encryption to your `.env` files with a single command. Use `dotenvx encrypt`. ```sh $ dotenvx encrypt โœ” encrypted (.env) ``` ![encrypted .env](https://github.com/dotenvx/dotenvx/assets/3848/2a8c3dc5-cd8e-4a08-8a59-c24d0535c81a) > A `DOTENV_PUBLIC_KEY` (encryption key) and a `DOTENV_PRIVATE_KEY` (decryption key) are generated using the same public-key cryptography as [Bitcoin](https://en.bitcoin.it/wiki/Secp256k1). More examples *
`.env`
```sh $ echo "HELLO=World" > .env $ dotenvx encrypt $ echo "console.log('Hello ' + process.env.HELLO)" > index.js $ dotenvx run -- node index.js [dotenvx] injecting env (2) from .env Hello World ```
*
`.env.production`
```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] injecting env (2) from .env.production Hello Production ``` Note the `DOTENV_PRIVATE_KEY_PRODUCTION` ends with `_PRODUCTION`. This instructs `dotenvx run` to load the `.env.production` file.
*
`.env.ci`
```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] injecting env (2) from .env.ci Hello Ci ``` Note the `DOTENV_PRIVATE_KEY_CI` ends with `_CI`. This instructs `dotenvx run` to load the `.env.ci` file. See the pattern?
*
combine multiple encrypted .env files
```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] injecting env (3) from .env, .env.production Hello World ``` Note the `DOTENV_PRIVATE_KEY` instructs `dotenvx run` to load the `.env` file and the `DOTENV_PRIVATE_KEY_PRODUCTION` instructs it to load the `.env.production` file. See the pattern?
*
combine multiple encrypted .env files for monorepo
```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="," dotenvx run -f app1/.env.ci -f app2/.env.ci -- node index.js [dotenvx] injecting env (2) from app1/.env.ci,app2/.env.ci Hello app1 $ DOTENV_PRIVATE_KEY_CI="," dotenvx run -f app1/.env.ci -f app2/.env.ci --overload -- node index.js [dotenvx] injecting env (2) from app1/.env.ci,app2/.env.ci Hello app2 ``` Note the `DOTENV_PRIVATE_KEY_CI` (and any `DOTENV_PRIVATE_KEY*`) can take multiple private keys by simply comma separating them.
*
`--stdout`
```sh $ echo "HELLO=World" > .env $ dotenvx encrypt --stdout $ dotenvx encrypt --stdout > .env.encrypted ```
*
other curves
> `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](https://csrc.nist.gov/projects/elliptic-curve-cryptography) or other curves like `curve25519`, please reach out at [security@dotenvx.com](mailto:security@dotenvx.com).
  ## Advanced > Become a `dotenvx` power user. > *
`run` - Variable Expansion
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] injecting env (2) from .env DATABASE_URL postgres://username@localhost/my_database ```
*
`run` - Command Substitution
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] injecting env (1) from .env DATABASE_URL postgres://yourusername@localhost/my_database ```
*
`run` - Shell Expansion
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 ```
*
`run` - multiple `-f` flags
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] injecting env (1) from .env.local, .env Hello local ```
*
`run --env HELLO=String`
Set environment variables as a simple `KEY=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] injecting env (1) from .env, and --env flag Hello String ```
*
`run --overload`
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] injecting env (1) from .env.local, .env Hello World ```
*
`DOTENV_PRIVATE_KEY=key run`
Decrypt your encrypted `.env` by setting `DOTENV_PRIVATE_KEY` before `dotenvx 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] injecting env (2) from .env Hello encrypted ```
*
`DOTENV_PRIVATE_KEY_PRODUCTION=key run`
Decrypt your encrypted `.env.production` by setting `DOTENV_PRIVATE_KEY_PRODUCTION` before `dotenvx 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] injecting env (2) from .env.production Hello production encrypted ``` Note the `DOTENV_PRIVATE_KEY_PRODUCTION` ends with `_PRODUCTION`. This instructs dotenvx run to load the `.env.production` file.
*
`DOTENV_PRIVATE_KEY_CI=key dotenvx run`
Decrypt your encrypted `.env.ci` by setting `DOTENV_PRIVATE_KEY_CI` before `dotenvx 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] injecting env (2) from .env.ci Hello ci encrypted ``` Note the `DOTENV_PRIVATE_KEY_CI` ends with `_CI`. This instructs dotenvx run to load the `.env.ci` file. See the pattern?
*
`DOTENV_PRIVATE_KEY=key DOTENV_PRIVATE_KEY_PRODUCTION=key run` - Combine Multiple
Decrypt your encrypted `.env` and `.env.production` files by setting `DOTENV_PRIVATE_KEY` and `DOTENV_PRIVATE_KEY_PRODUCTION` before `dotenvx 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] 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] injecting env (3) from .env.production, .env Hello production encrypted ``` Compose any encrypted files you want this way. As long as a `DOTENV_PRIVATE_KEY_${environment}` is set, the values from `.env.${environment}` will be decrypted at runtime.
*
`run --verbose`
Set log level to `verbose`. ([log levels](https://docs.npmjs.com/cli/v8/using-npm/logging#setting-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] injecting env (1) from .env.production Hello production ```
*
`run --debug`
Set log level to `debug`. ([log levels](https://docs.npmjs.com/cli/v8/using-npm/logging#setting-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] injecting env (1) from .env.production executing process command [node index.js] expanding process command to [/opt/homebrew/bin/node index.js] Hello production ```
*
`run --quiet`
Use `--quiet` to suppress all output (except errors). ([log levels](https://docs.npmjs.com/cli/v8/using-npm/logging#setting-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 ```
*
`run --log-level`
Set `--log-level` to whatever you wish. For example, to supress warnings (risky), set log level to `error`: ```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 are `error, warn, info, verbose, debug, silly` ([source](https://docs.npmjs.com/cli/v8/using-npm/logging#setting-log-levels))
*
`run --convention=nextjs`
Load envs using [Next.js' convention](https://nextjs.org/docs/pages/building-your-application/configuring/environment-variables#environment-variable-load-order). Set `--convention` to `nextjs`: ```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] injecting env (1) from .env.development.local, .env.local, .env.development, .env Hello development local ``` (more conventions available upon request)
*
`get KEY`
Return a single environment variable's value. ```sh $ echo "HELLO=World" > .env $ dotenvx get HELLO World ```
*
`get KEY -f`
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 ```
*
`get KEY --env`
Return a single environment variable's value from a `--env` string. ```sh $ dotenvx get HELLO --env HELLO=String -f .env.production String ```
*
`get KEY --overload`
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 ```
*
`get KEY --convention=nextjs`
Return a single environment variable's value using [Next.js' convention](https://nextjs.org/docs/pages/building-your-application/configuring/environment-variables#environment-variable-load-order). Set `--convention` to `nextjs`: ```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 ```
*
`get` (json)
Return a json response of all key/value pairs in a `.env` file. ```sh $ echo "HELLO=World" > .env $ dotenvx get {"HELLO":"World"} ```
*
`get --format shell`
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 with `env` 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 with `export`. ``` $ echo "console.log('Hello ' + process.env.KEY + ' ' + process.env.HELLO)" > index.js $ export $(dotenvx get --format=shell) $ node index.js Hello value World ```
*
`get --format eval`
Return an `eval`-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 with `eval` 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 with `eval` as it allows for arbitrary execution of commands. Prefer `dotenvx run --` but in some cases `eval` is a sharp knife that is useful to have.
*
`get --all`
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"} ```
*
`get --all --pretty-print`
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" } ```
*
`set KEY value`
Set an encrypted key/value (on by default). ```sh $ touch .env $ dotenvx set HELLO World set HELLO with encryption (.env) ```
*
`set KEY value -f`
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) ```
*
`set KEY "value with spaces"`
Set a value containing spaces. ```sh $ touch .env.ci $ dotenvx set HELLO "my ci" -f .env.ci set HELLO with encryption (.env.ci) ```
*
`set KEY -- "- + * รท"`
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) ```
*
`set KEY value --plain`
Set a plaintext key/value. ```sh $ touch .env $ dotenvx set HELLO World --plain set HELLO (.env) ```
*
`encrypt`
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 ```
*
`encrypt -f`
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 ```
*
`encrypt -k`
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) ```
*
`encrypt -ek`
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) ```
*
`encrypt --stdout`
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 ```
*
`decrypt`
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) ```
*
`decrypt -f`
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) ```
*
`decrypt -k`
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) ```
*
`decrypt -ek`
Decrypt the contents inside an encrypted `.env` file except for an exluded 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) ```
*
`decrypt --stdout`
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 ```
*
`keypair`
Print public/private keys for `.env` file. ```sh $ echo "HELLO=World" > .env $ dotenvx encrypt $ dotenvx keypair {"DOTENV_PUBLIC_KEY":"","DOTENV_PRIVATE_KEY":""} ```
*
`keypair -f .env.production`
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":"","DOTENV_PRIVATE_KEY_PRODUCTION":""} ```
*
`keypair DOTENV_PRIVATE_KEY`
Print specific keypair for `.env` file. ```sh $ echo "HELLO=World" > .env $ dotenvx encrypt $ dotenvx keypair DOTENV_PRIVATE_KEY ```
*
`keypair --format shell`
Print a shell formatted reponse of public/private keys. ```sh $ echo "HELLO=World" > .env $ dotenx encrypt $ dotenvx keypair --format shell DOTENV_PUBLIC_KEY= DOTENV_PRIVATE_KEY= ```
*
`ls`
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 ```
*
`ls directory`
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 ```
*
`ls -f`
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 ```
*
`ls -ef`
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 ```
*
`help`
Output help for `dotenvx`. ```sh $ dotenvx help Usage: dotenvx run -- yourcommand a better dotenvโ€“from the creator of `dotenv` Options: -l, --log-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 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 with `dotenvx help COMMAND`. ```sh $ dotenvx help run Usage: @dotenvx/dotenvx run [options] inject env at runtime [dotenvx run -- yourcommand] Options: -e, --env environment variable(s) set as string (example: "HELLO=World") (default: []) -f, --env-file path(s) to your env file(s) (default: []) -fv, --env-vault-file path(s) to your .env.vault file(s) (default: []) -o, --overload override existing env variables --convention 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] injecting env (1) from .env Hello World ```
*
`--version`
Check current version of `dotenvx`. ```sh $ dotenvx --version X.X.X ```
### Extensions ๐Ÿ”Œ *
`ext genexample`
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="" ```
*
`ext genexample -f`
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="" ```
*
`ext genexample directory`
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="" ```
*
`ext gitignore`
Gitignore your `.env` files. ```sh $ dotenvx ext gitignore creating .gitignore appending .env* to .gitignore done ```
*
`ext precommit`
Prevent `.env` files from being committed to code. ```sh $ dotenvx ext precommit [dotenvx][precommit] success ```
*
`ext precommit --install`
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 precommit installed [.git/hooks/pre-commit] ```
*
`ext prebuild`
Prevent `.env` files from being built into your docker containers. Add it to your `Dockerfile`. ```sh RUN curl -fsS https://dotenvx.sh | sh ... RUN dotenvx ext prebuild CMD ["dotenvx", "run", "--", "node", "index.js"] ```
*
`ext scan`
Use [gitleaks](https://gitleaks.io) under the hood to scan for possible secrets in your code. ```sh $ dotenvx ext scan โ—‹ โ”‚โ•ฒ โ”‚ โ—‹ โ—‹ โ–‘ โ–‘ gitleaks 100 commits scanned. no leaks found ```
  ## Guides > Go deeper into using `dotenvx` with detailed framework and platform guides. > * Digital Ocean Digital Ocean * Docker Docker * Fly.io Fly.io * GitHub Actions GitHub * Heroku Heroku * Netlify Netlify * NPM NPM Logo * Nx Nx Logo * Render Render * Railway Railway * Turborepo Turborepo Logo * Vercel Vercel * [more](https://dotenvx.com/docs/guides) * Node.js Node.js Logo * Python Python Logo * PHP PHP Logo * Ruby Ruby Logo * Rust Rust Logo   ## FAQ #### Why am I getting the error `node: .env: not found`? You are using Node 20 or greater and it adds a differing implementation of `--env-file` flag support. Rather than warn on a missing `.env` file (like dotenv has historically done), it raises an error: `node: .env: not found`. This fix is easy. Replace `--env-file` with `-f`. ```bash # from this: ./node_modules/.bin/dotenvx run --env-file .env -- yourcommand # to this: ./node_modules/.bin/dotenvx run -f .env -- yourcommand ``` [more context](https://github.com/dotenvx/dotenvx/issues/131) #### What happened to the `.env.vault` file? I've decided we should sunset it as a technological solution to this. The `.env.vault` file got us far, but it had limitations such as: * *Pull Requests* - it was difficult to tell which key had been changed * *Security* - there was no mechanism to give a teammate the ability to encrypt without also giving them the ability to decrypt. Sometimes you just want to let a contractor encrypt a new value, but you don't want them to know the rest of the secrets. * *Conceptual* - it takes more mental energy to understand the `.env.vault` format. Encrypted values inside a `.env` file is easier to quickly grasp. * *Combining Multiple Files* - there was simply no mechanism to do this well with the `.env.vault` file format. That said, the `.env.vault` tooling will still stick around for at least 1 year under `dotenvx vault` parent command. I'm still using it in projects as are many thousands of other people. #### How do I migrate my `.env.vault` file(s) to encrypted `.env` files? Run `$ dotenvx ext vault migrate` and follow the instructions.