a secure dotenv–from the creator of dotenv.
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!
with npm 🌍
npm i -g @dotenvx/dotenvx
dotenvx encrypt
with curl 🌐
curl -sfS https://dotenvx.sh | sh
dotenvx encrypt
with brew 🍺
brew tap dotenvx/brew
brew trust dotenvx/brew
brew install dotenvx
dotenvx encrypt
with docker 🐳
docker run -it --rm -v $(pwd):/app dotenv/dotenvx encrypt
with github releases 🐙
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 encrypt
or windows 🪟
winget install dotenvx
dotenvx encrypt
$ echo "HELLO=Dotenvx" > .env
$ echo "console.log('Hello ' + process.env.HELLO)" > index.js
$ node index.js
Hello undefined # without dotenvx
$ dotenvx run -- node index.js
Hello Dotenvx # with dotenvx
> :-D
More examples
TypeScript 📘
// package.json
{
"type": "module",
"dependencies": {
"chalk": "^5.3.0"
}
}
// index.ts
import chalk from 'chalk'
console.log(chalk.blue(`Hello ${process.env.HELLO}`))
$ npm install
$ echo "HELLO=Dotenvx" > .env
$ dotenvx run -- npx tsx index.ts
Hello Dotenvx
Next.js ▲
Install Dotenvx and @dotenvx/next-env.
$ npm install @dotenvx/dotenvx
$ npm install @dotenvx/next-env
Override @next/env in your package.json.
{
"overrides": {
"@next/env": "npm:@dotenvx/next-env"
}
}
Encrypt your .env file.
$ npx dotenvx encrypt
◈ encrypted (.env)
Your encrypted secrets are automatically injected and readable in Next.js.
import { NextResponse } from 'next/server'
export async function GET() {
return NextResponse.json({
HELLO: process.env.HELLO
})
}
Set DOTENV_PRIVATE_KEY in production before deploying.
Cloudflare Workers ⛅️
$ dotenvx encrypt -f .env.txt
// src/index.js
import envSrc from '../.env.txt'
import dotenvx from '@dotenvx/dotenvx'
const config = dotenvx.config({ envs: [{ type: 'env', value: envSrc, privateKeyName: 'DOTENV_PRIVATE_KEY' }] })
const envx = config.parsed
export default {
async fetch(request, env, ctx) {
return new Response(`Hello ${envx.HELLO}`)
}
}
"scripts": {
"deploy": "wrangler deploy",
"dev": "wrangler dev --var $(dotenvx keypair -f .env.txt --format=colon)",
"start": "wrangler dev --var $(dotenvx keypair -f .env.txt --format=colon)",
}
Deno 🦕
$ echo "HELLO=Dotenvx" > .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 Dotenvx
[!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 cipherInstead, use
dotenvxas designed, by installing the cli as a binary - via curl, brew, etc.
Bun 🥟
$ 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 🐍
$ echo "HELLO=Dotenvx" > .env
$ echo 'import os;print("Hello " + os.getenv("HELLO", ""))' > index.py
$ dotenvx run -- python3 index.py
Hello Dotenvx
PHP 🐘
$ echo "HELLO=Dotenvx" > .env
$ echo '<?php echo "Hello {$_SERVER["HELLO"]}\n";' > index.php
$ dotenvx run -- php index.php
Hello Dotenvx
Ruby 💎
$ echo "HELLO=Dotenvx" > .env
$ echo 'puts "Hello #{ENV["HELLO"]}"' > index.rb
$ dotenvx run -- ruby index.rb
Hello Dotenvx
Go 🐹
$ echo "HELLO=Dotenvx" > .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 Dotenvx
Rust 🦀
$ echo "HELLO=Dotenvx" > .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 Dotenvx
Java ☕️
$ echo "HELLO=Dotenvx" > .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 Dotenvx
Clojure 🌿
$ echo "HELLO=Dotenvx" > .env
$ echo '(println "Hello" (System/getenv "HELLO"))' > index.clj
$ dotenvx run -- clojure -M index.clj
Hello Dotenvx
Kotlin 📐
$ echo "HELLO=Dotenvx" > .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 Dotenvx
.NET 🔵
$ dotnet new console -n HelloWorld -o HelloWorld
$ cd HelloWorld
$ echo "HELLO=Dotenvx" | Out-File -FilePath .env -Encoding utf8
$ echo 'Console.WriteLine($"Hello {Environment.GetEnvironmentVariable("HELLO")}");' > Program.cs
$ dotenvx run -- dotnet run
Hello Dotenvx
Bash 🖥️
$ echo "HELLO=Dotenvx" > .env
$ dotenvx run --quiet -- sh -c 'echo Hello $HELLO'
Hello Dotenvx
Fish 🐠
$ echo "HELLO=Dotenvx" > .env
$ dotenvx run --quiet -- sh -c 'echo Hello $HELLO'
Hello Dotenvx
Cron ⏰
# run every day at 8am
0 8 * * * dotenvx run -- /path/to/myscript.sh
Frameworks ▲
$ dotenvx run -- next dev
$ dotenvx run -- npm start
$ dotenvx run -- bin/rails s
$ dotenvx run -- php artisan serve
see framework guides
Docker 🐳
$ docker run -it --rm -v $(pwd):/app dotenv/dotenvx run -- node index.js
Or in any image:
FROM node:latest
RUN echo "HELLO=Dotenvx" > .env && echo "console.log('Hello ' + process.env.HELLO)" > index.js
RUN curl -fsS https://dotenvx.sh/install.sh | sh
CMD ["/usr/local/bin/dotenvx", "run", "--", "echo", "Hello $HELLO"]
see docker guide
CI/CDs 🐙
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 }}
Platforms
# heroku
heroku buildpacks:add https://github.com/dotenvx/heroku-buildpack-dotenvx
# docker
RUN curl -fsS https://dotenvx.sh | sh
# vercel
npm install @dotenvx/dotenvx --save
see platform guides
Process Managers
// pm2
"scripts": {
"start": "dotenvx run -- pm2-runtime start ecosystem.config.js --env production"
},
npx
# alternatively use npx
$ npx @dotenvx/dotenvx run -- node index.js
$ npx @dotenvx/dotenvx run -- next dev
$ npx @dotenvx/dotenvx run -- npm start
npm
$ npm install @dotenvx/dotenvx --save
{
"scripts": {
"start": "./node_modules/.bin/dotenvx run -- node index.js"
},
"dependencies": {
"@dotenvx/dotenvx": "^0.5.0"
}
}
$ npm run start
> start
> ./node_modules/.bin/dotenvx run -- node index.js
[dotenvx@1.X.X] injecting env (1) from .env.production
Hello Dotenvx
asdf
# use dotenvx with asdf
$ asdf plugin add dotenvx
$ asdf install dotenvx latest
thank you @jgburet of Paris 🇫🇷
Git
# 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.
# .env
USERNAME="username"
DATABASE_URL="postgres://${USERNAME}@localhost/my_database"
// index.js
console.log('DATABASE_URL', process.env.DATABASE_URL)
$ 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.
# .env
DATABASE_URL="postgres://$(whoami)@localhost/my_database"
// index.js
console.log('DATABASE_URL', process.env.DATABASE_URL)
$ dotenvx run --debug -- node index.js
[dotenvx@0.14.1] injecting env (1) from .env
DATABASE_URL postgres://yourusername@localhost/my_database
Create a
.env.productionfile and use-fto load it. It's straightforward, yet flexible.
$ 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
multiple .env files
$ echo "HELLO=local" > .env.local
$ echo "HELLO=Dotenvx" > .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, above local wins – from the first file.
--overload flag
$ echo "HELLO=local" > .env.local
$ echo "HELLO=Dotenvx" > .env
$ dotenvx run -f .env.local -f .env --overload -- node index.js
[dotenvx@1.X.X] injecting env (1) from .env.local,.env
Hello Dotenvx
Note that with --overload subsequent files DO override pre-existing variables defined in previous files.
--verbose flag
$ 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
--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 [d
$ claude mcp add dotenvx \
-- python -m otcore.mcp_server <graph>