Dotenvx Rust SDK/CLI
======================

What is Dotenvx? [Dotenvx](https://dotenvx.com/) encrypts your .env files—limiting their attack vector while retaining
their benefits.

![Dotenvx Architecture](https://github.com/linux-china/dotenvx-rs/raw/main/dotenvx-architecture.jpg)

dotenvx-rs is a Rust command-line toolchain for [dotenvx]() to make .env files secure and easy to use,
and it's also a crate to load encrypted .env files in your Rust applications.

Please read [dotenvx cheat sheet](https://cheatography.com/linux-china/cheat-sheets/dotenvx/) for quick overview.

# dotenvx library

Run `cargo add dotenvx-rs` to add the dotenvx library to your Rust project.

```rust
use dotenvx_rs::dotenvx;

#[test]
fn test_dotenv_load() {
    // Load the .env file
    dotenvx::dotenv().ok();
    // Check if the environment variable is set
    let value = env::var("HELLO").unwrap();
    println!("HELLO={}", value);
}
```

# dotenvx CLI

### Get Started

- Install: Run `cargo binstall dotenvx-rs` or `brew install linux-china/tap/dotenvx-rs` or download it
  from [releases](https://github.com/linux-china/dotenvx-rs/releases)
- Initialize: Run `dotenvx init` to create `.env` and save private to global `$HOME/.dotenvx/.env.keys.json` file
- Encrypt .env file: Run `dotenvx encrypt` to encrypt the `.env` file.
- Decrypt .env file: Run `dotenvx decrypt` to decrypt the `.env` file.

dotenvx Rust CLI is almost a drop-in replacement for the original [dotenvx CLI](https://dotenvx.com/),
with some differences:

- Smaller and faster and written in Rust: the `dotenvx` executable is only 4MB.
- Global keys store: `$HOME/.dotenvx/.env.keys.json` to prevent AI Agent to scan `.env.keys` file in the project
  directory.
- Spring Boot support: dotenvx CLI can read `application.properties` and spring profile.
- Global `--profile` as first citizen to make it easy to manage different environments
- More smaller features: lint, diff etc.
- No ext sub command

### Migrated to dotenvx CLI

If you have .env files already, you just run `dotenvx init`, and dotenvx CLI will create `.env` file with Dotenvx
format, and save the private key to `$HOME/.dotenvx/.env.keys.json` file.

# .env file specification

Every .env file has three sections: metadata (front matter), public key, and environment variables.

Example as following:

```shell
# ---
# uuid: f7580ac5-0b24-4385-b3ff-819225b687f3
# name: identify-your-dotenv-file
# group: com.example.dotenvx
# sign: +1+y3Eio5OHPcp9xiP125qfXl/CX4Zuxhft91aW59WtTjZJoSDmFs4KPZ2nDop07VdYkE8vF2BWuUpneCU1xlA==
# ---
DOTENV_PUBLIC_KEY="02b4972559803fa3c2464e93858f80c3a4c86f046f725329f8975e007b393dc4f0"

# Environment variables. MAKE SURE to ENCRYPT them before committing to source control
# @example="jdbc:mysql://localhost:3306/test"
JDBC_URL=encrypted:BNexEwjKwt87k9aEgaSng1JY6uW8OkwMYEFTwEy/xyzDrQwQSDIUEXNlcwWi6rnvR1Q60G35NO4NWwhUYAaAON1LOnvMk+tJjTQJaM8DPeX2AJ8IzoTV44FLJsbOiMa77RLrnBv7
```

Explanation:

- Metadata section (front matter): starts with `# ---` and ends with `# ---`
- .env file UUID: a unique identifier for the .env file, used to track changes and versions
- sign: a signature for the .env file, used to verify the integrity of the file and make sure the file is not tampered
- DOTENV_PUBLIC_KEY: the public key used to encrypt data and verify the signature
- Environment variables: the encrypted environment variables, starts with `encrypted:` prefix. 
- [env.spec](https://github.com/dmno-dev/varlock/discussions/17): you can add comments and annotations for variables alike JSDOC.

In metadata section, you can add any key-value pairs to describe the .env file, such as `name`, `group`, etc.

For `.env.keys` files, and spec is similar, and metadata section and keys section are as following:

```shell
# ---
# uuid: 8499c5c3-cee3-4c94-99a4-9c86b2ed5dd9
# name: input your name here
# group: demo
# ---

#  Private decryption keys. DO NOT commit to source control
DOTENV_PRIVATE_KEY="9e70188d351c25d0714929205df9bxxx"
DOTENV_PRIVATE_KEY_EXAMPLE="a3d15e4b69c4a942c381xxx"
```

# FAQ

### What is a profile?

A profile is a way to manage different environments in dotenvx CLI, and you can specify the profile with the following
ways:

- Use `--profile <profile_name>` option to specify the profile, such as `dotenvx -p prod encrypt`
- Get profile from .env file, such as `.env.prod` for `prod` profile, `.env.test` for `test` profile, etc.
- GEt profile from environment variables: `NODE_ENV`, `RUN_ENV`, `APP_ENV`, `SPRING_PROFILES_ACTIVE`.

Different profiles have different `.env` files, such as `.env.prod`, `.env.test`, `.env.dev`, etc.,
and different profiles have different private keys for encryption and decryption,
such as `DOTENV_PRIVATE_KEY_PROD`, `DOTENV_PRIVATE_KEY_TEST`, etc.

If no profile is specified, the CLI will use the `.env` file and `DOTENV_PRIVATE_KEY` private key by default.

**Tips**: you can create alias for a profile, such as `alias prod-env='dotenvx -p prod'` to manage secrets for
production profile.

In dotenvx, three profile styles are supported:

- project specific profile: such as `test`, `prod`, `dev`, etc., and you can use `.env.test`, `.env.prod`, `.env.dev`
  files to manage different
  environments.
- global profile: such as `g_github`, `g_ai`, etc., and profile name start with `g_` to indicate it's a global profile,
  and you can use `.env.g_github`, `.env.g_ai` files to manage different global environments.
- namespace profile: such as `region1_dev`, `region2_prod`, etc., and profile name start with `region1` to indicate it's
  a namespace profile, and you can use `.env.region1_dev`, `.env.region2_prod` files to manage different namespace
  environments.

### How does CLI find a private key?

The CLI looks for the private key in the following order:

- Check the `.env` or `properties` file to find the public key.
- Find the private key from global `$HOME/.dotenvx/.env.keys.json` file.
- If not found, find from `.env.keys` file in the current directory and parent directories recursively, and
  `$HOME/.env.keys` will be checked as well.
- Find from `DOTENV_PRIVATE_KEY` or `DOTENV_PRIVATE_KEY_PROFILE_NAME` environment variable

If you want to use a unified private key for different environments, and you can use the following environment
variables:

- `DOTENV_PRIVATE_KEY` for `.env` file and local development
- `DOTENV_PRIVATE_KEY_PROD` for `.env.prod` file and production
- `DOTENV_PRIVATE_KEY_TEST` for `.env.test` file and testing

**Tips**: you can use `dotenvx init --stdout` to generate a key pair.

**Attention**: Some AI agents read environment variables for code generation by default, so you should avoid using
`DOTENV_PRIVATE_KEY`, and use global `$HOME/.dotenvx/.env.keys.json`. For CI/CD, production deployment,
environment variable for a private key is still a good choice.

### How to manage private keys?

dotenvx CLI uses profile style to manage private keys, and you can use following practices to manage private keys:

- Project specific private keys: use `dotenvx init` to create `.env` file in the project's directory and save the
  private key
  to the `$HOME/.dotenvx/.env.keys.json` file.
- Global private: use `dotenvx init --global` to create a global `$HOME/.env.keys` file to manage unified private keys
  for different projects. If you use `dotenvx set <key> <value>` in a directory, it will create a `.env` with public
  key derived from  `DOTENV_PRIVATE_KEY` from `$HOME/.env.keys` file.
- Team/Production global private keys: use `ABC_TEST`, `REGION1_PROD` as profile names to manage private keys for
  different teams, products, or regions.

### How to rotate/reset key pairs for env files?

If you don't want to use private key from environment variables, or you want to rotate your private key,
you can use the `dotenvx rotate` command to generate a new key pair, examples:

- Rotate the private key for `.env` file: `dotenvx rotate`
- Rotate the private key for `.env.prod` file: `dotenvx rotate -f .env.prod`

### How to decrypt a dotenv file and export variables as environment variables?

You can use the `dotenvx decrypt --export` command to decrypt the dotenv file and output as a shell script.

- `eval $( dotenvx decrypt --stdout --format shell )` command will decrypt a dotenv file and export the variables to the
  current shell.
- `eval $( dotenvx get key --format shell )` command will export key's value from .env as environment variable.

**Tips**: if you use [direnv](https://direnv.net/), and you can add `eval $( dotenvx decrypt --stdout --format shell )`
to the `.envrc` file to automatically load .env as the environment variables when you enter the directory.

If you use [mise](https://mise.jdx.dev/), and you can use dotenvx as environment provider by adding the following to the
`mise.toml` file:

```toml
[env]
_.source = "scripts/env.sh"
```

And create a `scripts/env.sh` file as following:

```shell
eval $( dotenvx decrypt --stdout --format shell )
```

### How to integrate dotenvx with Language SDK?

You can integrate dotenvx CLI with any language SDK by using `dotenvx decrypt --stdout --format shell` command to load
`.env` into the environment variables.

For example, Node.js, Bun and Deno, you can create a wrapper script to integrate Dotenvx support,
such as `node`, `denow`, `bunw`, and example as following:

```shell
#!/bin/bash

# load .env by dotenvx
eval $( dotenvx decrypt --stdout --format shell )
# Execute bun command with arguments
exec $HOME/.bun/bin/bun "$@"
```

In VS Code or WebStorm, then choose `nodew`, `denow`, `bunw` as the interpreter.

Dotenvx has built-in support for Python virtual environment, you can use `dotenvx link .venv/bin/python`
to create a wrapper script as python interpreter.

**Tips**: you can use `luaw`, `phpw`, `perlw` etc. to manage other language SDKs.

### What is dotenvx symbolic link?

Dotenvx symbolic link is a way to run the command with injected environment variables by dotenvx.

For example, you want to run a lua script with environment variables from `.env` file,
you can create a symbolic link `dotenvx link bin/lua`, and then run `./bin/lua demo.lua` to run the lua script with
environment variables from `.env` file.

Another example is to  `mysql`, `psql` command. For example, you have database config in `.env` file already,
and you want to log in mysql, and you should use `mysql -h host -u user -p db` and input password interactively.
Why not read db config and help me log in mysql directly? I can't remember the long password for DB.

You can create a symbolic link `dotenvx link bin/mysql`, and then run `./bin/mysql` to log in mysql automatically.

**Attention**: symbolic link name should be the same as the command name. Now only `mysql` and `psql` are supported.

### Dotenvx for DuckDB secret management?

DuckDB has [built-in Secrets Manager](https://duckdb.org/docs/stable/configuration/secrets_manager),
but you can use dotenvx to manage the secrets for DuckDB as well.

In `.env` file, you can add the following key-value pairs:

```shell
DUCKDB__HTTP_SECRET=secret
DUCKDB__HTTP_SECRET__TYPE=http
DUCKDB__HTTP_SECRET__BEARER_TOKEN=xxxx
```

The above env variables will be detected and convert to `CREATE SECRET http_secret ( TYPE http, BEARER_TOKEN 'xxx');`.
Use `dotenvx link bin/duckdb` to create a symbolic link for `duckdb` command, and then run `./bin/duckdb` to start
duckdb with secrets support.

You can
attach [encrypt-database introduced by DuckDB 1.4.0](https://duckdb.org/2025/09/16/announcing-duckdb-140.html#database-encryption)
with the following env variables:

```shell
DUCKDB__SECRET_DB=attach
DUCKDB__SECRET_DB__TYPE=duckdb
DUCKDB__SECRET_DB__URL=encrypted.db
DUCKDB__SECRET_DB__ENCRYPTION_KEY=123456
```

### How to add encrypted key-value from CLI?

You can use `dotenvx set <key> <value>` to write an encrypted key-value pair to the `.env` file.
If you don't want to shell history to record the sensitive value,
you can use `dotenvx set <key> -` to read the value from standard input (stdin),
and press Ctrl+D on Linux/macOS or Ctrl+Z on Windows to finish input.

**Tips**: you can use `dotenvx set --encrypt my_private_pem - < ./xxx.pem` to encrypt any text file as a key-value pair
in the `.env` file.

### Why sign the.env file?

The `.env` file still text file, and other people or tools can modify it, and let the application load the modified
`.env` file, which may cause security issues.

For example, you have an email, which is a PayPal account to receive payments. Of course, you don't want others to
change the email address to their own PayPal account, and then you will lose your money.

To prevent this, the `.env` file is signed with a signature(secp256k1) and put in the metadata section of the file.
When you load the `.env` file, the CLI will verify the signature with the public key in the `.env` file.

How the signature works:

- The author run `dotenvx encrypt --sign` to sign the `.env` file with the private key,
  and the signature will be added to the metadata section of the file.
- Signature: SHA256 hash of the `.env` trimmed .env file content (without sign line), and then sign the hash with the
  private key to get the signature, and signature is a base64 encoded string and added to the metadata section of the
  file.
- Verification: Load the `.env` file, extract the public key and signature from the metadata section, SHA256 hash
  the .env file-trimmed content (without sign line), and then verify the signature with the public key and the hash.

With this signature, you can ensure that the `.env` file is not tampered, and other people/tools can trust the
`.env` file content and use it safely.

**Attention**: dotenvx will overwrite the environment variables with the values from the `.env` file,
and priority is given to the `.env` file over the environment variables.

### Why introduce `dotenvx --seal` and `dotenvx --unseal`?

dotenvx CLI uses private keys to sign/decrypt the `.env` files, and these private keys are very important and should not
be leaked to the public.

dotenvx CLI read the private keys from `$HOME/.dotenvx/.env.keys.json`, `$HOME/.env.keys` files or `DOTENV_PRIVATE_KEY`,
`DOTENV_PRIVATE_KEY_XXX` environment variables, and these private keys are still as plain text, which is not secure
enough.

With `dotenvx --seal` and `dotenvx --unseal`, you can encrypt the `$HOME/.dotenvx/.env.keys.json` and  `$HOME/.env.keys`
file with AES256 and a password, and other people/tools cannot read the encrypted `.env.keys.aes` file without knowing
the password.

**Attention**: You should remember the password, and it will be used by `dotenvx --unseal` to decrypt the
`$HOME/.env.keys.aes` file.

### How to check the keys' difference between .env files?

You can use the `dotenvx diff key1,key2` command to display the difference values from .env files,
and dotenvx will search all .env files in the current directory and compare the values of the specified keys.

**Tips**: you can use `dotenvx diff --format csv key1,key2` to output the difference in CSV format,
and use other tools to process the CSV data for further analysis.

### How to use dotenvx CLI in GitHub Actions?

Please add `uses: linux-china/setup-dotenvx@main` to your workflow file to set up dotenvx CLI,
and add `DOTENV_PRIVATE_KEY` secret to the `Repository secrets`.

Example workflow file to use dotenvx cli:

```yaml
jobs:
  dotenvx-demo:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: linux-china/setup-dotenvx@main
      - run: npm install
      - run: $HOME/.cargo/bin/dotenvx run -- node index.js
        env:
          DOTENV_PRIVATE_KEY: ${{ secrets.DOTENV_PRIVATE_KEY }}
```

If you use [act](https://github.com/nektos/act) for local GitHub Actions test, please use
`act -j dotenvx-demo --secret-file .env.keys`.

### How to create new `.env` file from `.env.example` file?

Some applications use `.env.example` file to describe the environment variables, and you should create a new
`.env` file from `.env.example` file for local development.

Now you can use `dotenvx sync .env.example .env` command will create a new `.env` file from `.env.example` file,
and the new `.env` file will have the same keys as `.env.example` file with new public key and metadata section.

### How to generate shell completion

Please use `dotenvx completion --shell bash|zsh|fish|powershell` to generate shell completion script.

For oh-my-zsh, please follow the steps to install the completion script:

```shell
$ mkdir ~/.oh-my-zsh/custom/plugins/dotenvx
$ dotenvx completion --shell zsh > ~/.oh-my-zsh/custom/plugins/dotenvx/_dotenvx
```

Then add `dotenvx` to the plugin list in your `.zshrc` file:

```shell
plugins=(dotenvx ...)
```

# Credits

* [Dotenvx](https://dotenvx.com/): encrypts your .env files – limiting their attack vector while retaining their
  benefits.
* [ecies-rs](https://github.com/ecies/rs): Elliptic Curve Integrated Encryption Scheme for secp256k1/curve25519 in Rust
* [dotenvy](https://github.com/allan2/dotenvy): a well-maintained fork of the dotenv crate

# References

* Practical Cryptography for Developers: https://cryptobook.nakov.com/
* Command Line Interface Guidelines: https://clig.dev/
* [GoFr Config](https://gofr.dev/docs/references/configs): GoFr Configuration Options
