Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/dotenvx/dotenvx

a better dotenv–from the creator of `dotenv`
https://github.com/dotenvx/dotenvx

dotenv env

Last synced: 3 months ago
JSON representation

a better dotenv–from the creator of `dotenv`

Awesome Lists containing this project

README

        

[![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) [![test count](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/motdotenv/bb76445765a9731e7d824a6efdf53524/raw/dotenvxTestCount.json)](https://github.com/dotenvx/dotenvx/tree/main/tests) [![npm installs](https://img.shields.io/npm/dt/@dotenvx/dotenvx)](https://www.npmjs.com/package/@dotenvx/dotenvx)

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 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)
*homebrew installs sourced from github releases - formula

 

with curl 🌐

```sh
curl -sfS https://dotenvx.sh | sh
dotenvx help
```

[![mac](https://img.shields.io/endpoint?url=https://dotenvx.sh/stats/curl/darwin&label=mac)](https://github.com/dotenvx/dotenvx.sh/blob/main/install.sh)
[![linux](https://img.shields.io/endpoint?url=https://dotenvx.sh/stats/curl/linux&label=linux)](https://github.com/dotenvx/dotenvx.sh/blob/main/install.sh)
[![windows](https://img.shields.io/endpoint?url=https://dotenvx.sh/stats/curl/windows&label=windows)](https://github.com/dotenvx/dotenvx.sh/blob/main/install.sh)
*curl installs sourced from npm binary packages - example

 

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)

 

or 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)
*includes homebrew installs

 

## 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
```


* 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
```


* .NET 🔵

```sh
$ dotnet new console -n HelloWorld -o HelloWorld
$ cd HelloWorld
$ echo "HELLO=World" > .env
$ 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
```


* 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
[[email protected]] 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
[[email protected]] 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 [[email protected]](mailto:[email protected]).

 

## 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.production
$ 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://github.com/winstonjs/winston?tab=readme-ov-file#logging))

```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://github.com/winstonjs/winston?tab=readme-ov-file#logging))

```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://github.com/winstonjs/winston?tab=readme-ov-file#logging))

```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://github.com/winstonjs/winston?tab=readme-ov-file#logging))


* `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 --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)
ℹ add .env.keys to .gitignore: [echo ".env.keys" >> .gitignore]
ℹ 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)
ℹ add .env.keys to .gitignore: [echo ".env.keys" >> .gitignore]
ℹ run [DOTENV_PRIVATE_KEY_PRODUCTION='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)
```


* `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 --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
```

* `help`

Output help for `dotenvx`.

```sh
$ dotenvx help
Usage: @dotenvx/dotenvx [options] [command]

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 [options] inject env at runtime [dotenvx run -- yourcommand]
get [options] [key] return a single environment variable
set [options] set a single environment variable
encrypt [options] convert .env file(s) to encrypted .env file(s)
decrypt [options] convert encrypted .env file(s) to plain .env file(s)
pro 🏆 pro
ext [command] [args...] 🔌 extensions
help [command] display help for command
```

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 ls`

Print all `.env` files in a tree structure.

```sh
$ touch .env
$ touch .env.production
$ mkdir -p apps/backend
$ touch apps/backend/.env

$ dotenvx ext ls
├─ .env.production
├─ .env
└─ apps
└─ backend
└─ .env
```


* `ext 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 ext ls apps/backend
└─ .env
```


* `ext 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 ext ls -f **/.env.prod*
├─ .env.production
└─ apps
└─ backend
└─ .env.prod
```


* `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 vault migrate` and follow the instructions.

 

## Contributing

You can fork this repo and create [pull requests](https://github.com/dotenvx/dotenvx/pulls) or if you have questions or feedback:

* [github.com/dotenvx/dotenvx](https://github.com/dotenvx/dotenvx/issues) - bugs and discussions
* [@dotenvx 𝕏](https://x.com/dotenvx) (DMs are open)