# Setup environment files
$ echo "HELLO=development local" > .env.development.local
$ echo "HELLO=local" > .env.local
$ echo "HELLO=development" > .env.development
$ echo "HELLO=env" > .env
```

```js
// index.js
require('@dotenvx/dotenvx').config({ convention: 'nextjs' })

console.log(`Hello ${process.env.HELLO}`)
```

```sh
$ NODE_ENV=development node index.js
[dotenvx@1.28.0] injecting env (1) from .env.development.local, .env.local, .env.development, .env
Hello development local
```

This is equivalent to using `--convention=nextjs` with the CLI:

```sh
$ dotenvx run --convention=nextjs -- node index.js
```

</details>
<details><summary>`config(opsOff:)` - opsOff</summary><br>

Turn off [Dotenvx Ops](https://dotenvx.com/ops) features.

```js
// index.js
require('@dotenvx/dotenvx').config({opsOff: true})
```

</details>
<details><summary>`parse(src)`</summary><br>

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

</details>
<details><summary>`parse(src, {processEnv:})`</summary><br>

Sometimes, you want to run `parse` without it accessing `process.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
```

</details>
<details><summary>`parse(src, {privateKey:})`</summary><br>

Decrypt an encrypted `.env` string with `privateKey`.

```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
```
</details>
<details><summary>`set(KEY, value)`</summary><br>

Programmatically set an environment variable.

```js
// index.js
const dotenvx = require('@dotenvx/dotenvx')
dotenvx.set('HELLO', 'World', { path: '.env' })
```

</details>
<details><summary>`get(KEY)` - <i>Decryption at Access</i></summary><br>

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](https://dotenvx.com/dotenvx.pdf).

</details>

&nbsp;

## Ops 🏰

[![dotenvx-ops](https://dotenvx.com/dotenvx-ops-banner.png?v=2)](https://dotenvx.com/ops)

> [Dotenvx Ops](https://dotenvx.com/ops) is optional commercial tooling for [dotenvx](https://github.com/dotenvx/dotenvx).

*Use dotenvx across your team, infrastructure, agents, and more.*

### Usage

1. Install dotenvx-ops

```sh
$ curl -sfS https://dotenvx.sh/ops | sh
```

2. Log in

```sh
$ dotenvx-ops login
✔ logged in [username]
```

3. Run dotenvx

```sh
$ dotenvx run -- yourcommand
[dotenvx@1.0.0] 📡 radar active
[dotenvx@1.0.0] injecting env (1) from .env
```

That's it! Your environment variables are auto-observed and backed up by [Dotenvx Ops](https://dotenvx.com/ops) radar feature.

### UI

![dotenvx-ops](https://dotenvx.com/ops/ui.png)

### CLI

<details><summary>`login`</summary><br>

Log in to [Ops](https://dotenvx.com/ops).

```sh
$ dotenvx-ops login
press Enter to open [https://ops.dotenvx.com/login/device] and enter code [D9C1-03BC]... (Y/n)
⠹ waiting on browser authorization
✔ logged in [username] to this device and activated token [dxo_6kjPifI…]
```

</details>
<details><summary>`logout`</summary><br>

Log out of [Ops](https://dotenvx.com/ops).

```sh
$ dotenvx-ops logout
✔ logged out [username] from this device and revoked token [dxo_5ZrwRXV…]
```

</details>
<details><summary>`status`</summary><br>

Check current status of [Ops](https://dotenvx.com/ops) - `on` or `off` (logged in or out).

```sh
$ dotenvx-ops status
on
```

</details>
<details><summary>`settings`</summary><br>

Check and configure various settings for [Ops](https://dotenvx.com/ops) - `username`, `token`, and more.

```sh
$ dotenvx-ops settings
Usage: dotenvx-ops settings [options] [command]

⚙️  settings

Options:
  -h, --help       display help for command

Commands:
  username         print your username
  token [options]  print your access token (--unmask)
  hostname         print hostname
  help [command]   display help for command
```

</details>

&nbsp;

## 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.
>
> ...
>
> [Read the whitepaper](https://dotenvx.com/dotenvx.pdf)

&nbsp;

## Guides

> Go deeper with `dotenvx` – detailed framework and platform guides.
>

* [Languages](https://dotenvx.com/docs#languages)
  * [Node.js](https://dotenvx.com/docs/languages/nodejs)
  * [Python](https://dotenvx.com/docs/languages/python)
  * [Ruby](https://dotenvx.com/docs/languages/ruby)
  * [Go](https://dotenvx.com/docs/languages/go)
  * [PHP](https://dotenvx.com/docs/languages/php)
  * [Rust](https://dotenvx.com/docs/languages/rust)
* [Frameworks](https://dotenvx.com/docs#frameworks)
  * [Astro](https://dotenvx.com/docs/frameworks/astro)
  * [Express](https://dotenvx.com/docs/frameworks/express)
  * [Next](https://dotenvx.com/docs/frameworks/next)
  * [Remix](https://dotenvx.com/docs/frameworks/remix)
  * [Flask](https://dotenvx.com/docs/frameworks/flask)
  * [Sinatra](https://dotenvx.com/docs/frameworks/sinatra)
  * [Rocket](https://dotenvx.com/docs/frameworks/rocket)
* [Platforms](https://dotenvx.com/docs#platforms)
  * [Digital Ocean](https://dotenvx.com/docs/platforms/digital-ocean)
  * [Docker](https://dotenvx.com/docs/platforms/docker)
  * [Fly](https://dotenvx.com/docs/platforms/fly)
  * [Heroku](https://dotenvx.com/docs/platforms/heroku)
  * [Netlify](https://dotenvx.com/docs/platforms/netlify)
  * [Vercel](https://dotenvx.com/docs/platforms/vercel)
  * [Railway](https://dotenvx.com/docs/platforms/railway)
  * [Render](https://dotenvx.com/docs/platforms/render)
* [CI/CDs](https://dotenvx.com/docs#cis)
  * [GitHub Actions](https://dotenvx.com/docs/cis/github-actions)
* [Background Jobs](https://dotenvx.com/docs#background-jobs)
  * [Trigger.dev](https://dotenvx.com/docs/background-jobs/triggerdotdev)
* [Package Managers](https://dotenvx.com/docs#package-managers)
  * [NPM](https://dotenvx.com/docs/package-managers/npm)
  * [PNPM](https://dotenvx.com/docs/package-managers/pnpm)
* [Process Managers](https://dotenvx.com/docs#process-managers)
  * [PM2](https://dotenvx.com/docs/process-managers/pm2)
* [Monorepos](https://dotenvx.com/docs#monorepos)
  * [Nx](https://dotenvx.com/docs/monorepos/nx)
  * [Turborepo](https://dotenvx.com/docs/monorepos/turborepo)
* [Concepts](https://dotenvx.com/docs#concepts)
  * [.env](https://dotenvx.com/docs/env-file)
  * [.env.keys](https://dotenvx.com/docs/env-keys-file)

&nbsp;

## FAQ

#### How does encryption work?

Dotenvx uses Elliptic Curve Integrated Encryption Scheme (ECIES) to encrypt each secret with a unique ephemeral key, while ensuring it can be decrypted using a long-term private key.

When you initialize encryption, a DOTENV_PUBLIC_KEY (encryption key) and DOTENV_PRIVATE_KEY (decryption key) are generated. The DOTENV_PUBLIC_KEY is used to encrypt secrets, and the DOTENV_PRIVATE_KEY is securely stored in your cloud secrets manager or .env.keys file.

Your encrypted .env file is then safely committed to code. Even if the file is exposed, secrets remain protected since decryption requires the separate DOTENV_PRIVATE_KEY, which is never stored alongside it. Read [the whitepaper](https://dotenvx.com/dotenvx.pdf?v=README) for more details.

#### Is it safe to commit an encrypted .env file to code?

Yes. Dotenvx encrypts secrets using AES-256 with ephemeral keys, ensuring that even if the encrypted .env file is exposed, its contents remain secure. The encryption keys themselves are protected using Secp256k1 elliptic curve cryptography, which is widely used for secure key exchange in technologies like Bitcoin.

This means that every secret in the .env file is encrypted with a unique AES-256 key, and that key is further encrypted using a public key (Secp256k1). Even if an attacker obtains the encrypted .env file, they would still need the corresponding private key—stored separately in a secrets manager—to decrypt anything.

Breaking this encryption would require brute-forcing both AES-256 and elliptic curve cryptography, which is computationally infeasible with current technology. Read [the whitepaper](https://dotenvx.com/dotenvx.pdf?v=README) for more details.

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