Why You Should Stop Using Dotenv And Switch To Dotenvx Today

Kenji Sato
-
why you should stop using dotenv and switch to dotenvx today

dotenvx: Encrypted .env Files for JavaScript Apps April 4, 2026 | 7 minutesIn This Post If you've used dotenv to manage environment variables in JavaScript projects, you've probably run into its biggest limitation: .env files sit in plaintext on disk. That was always a tradeoff, but it's become a real problem now that AI coding agents like Claude Code, Cursor, and GitHub Copilot routinely read your project files as context. A plaintext .env file means your secrets can end up in model context without you realizing it.

dotenvx is a newer tool from the same creator that solves this. It encrypts your .env files so you can commit them to git, uses public-key cryptography to control who can decrypt them, and introduces environment-specific private keys like DOTENV_PRIVATE_KEY_CI for CI/CD pipelines. Let's look at how it works and how to set it up. How dotenvx Differs from dotenv dotenv reads a plaintext .env file and loads its values onto process.env . It works, but you can't commit .env files because they contain secrets in plaintext.

It's hard to securely share secrets with your team without sharing them in plaintext by email or Slack. Plus, since they're just files on your local machine, AI coding agents can read them just like any other file. dotenvx keeps the same .env interface that developers (and agents) already expect, but adds encryption on top.

The key differences are that: - Encrypted values are stored in the .env files themselves, so you can commit them to git - It uses public-key cryptography (secp256k1, the same curve Bitcoin uses) to protect each secret - Environment-specific keys let you easily scope decryption access: DOTENV_PRIVATE_KEY for development,DOTENV_PRIVATE_KEY_PRODUCTION for production,DOTENV_PRIVATE_KEY_CI for CI/CD - It has cross-platform and cross-language support so you can use it with Node.js, Python, Ruby, Go, Rust, and more Getting Started with dotenvx Install dotenvx with one of these methods: 1# npm (local to project) 2npm install @dotenvx/dotenvx --save 3 4# npm (global) 5npm i -g @dotenvx/dotenvx 6 7# Homebrew 8brew install dotenvx/brew/dotenvx 9 10# Shell script 11curl -sfS https://dotenvx.sh | sh Then use it to run your app, loading .env values automatically: 1echo "HELLO=World" > .env 2echo "console.log('Hello ' + process.env.HELLO)" > index.js 3 4dotenvx run -- node index.js 5# Hello World The syntax is dotenvx run -- <your command> .

Everything after -- is your normal startup command. Encrypting Your .env Files This is where dotenvx really shines.

Run a single command to encrypt your .env file in place: 1dotenvx encrypt This does two things: - Encrypts the values in your .env file, replacing plaintext with encrypted strings - Generates a .env.keys file containing the private key needed for decryption After encryption, your .env file will look something like this: 1#/-------------------[DOTENV_PUBLIC_KEY]--------------------/ 2#/ public-key encryption for .env files / 3#/ [how it works](https://dotenvx.com/encryption) / 4#/----------------------------------------------------------/ 5DOTENV_PUBLIC_KEY="038759c073282f2efa6c5ffea8f66ad9cf0de7a855df8db242771f44d7472b63cb" 6 7# .env 8HELLO="encrypted:BGMyAFNH6UjetjWsYHUkbndQosw..." And your .env.keys file: 1DOTENV_PRIVATE_KEY="bd7c50b352ce23973ec9db355d70212305a0baaade92f0165f02915b213bfbe2" What to Commit (and What Not To) Your encrypted .env file is safe to commit to git, making it easy to share with your team through git.

Your .env.keys file is a different story. It contains the private key that can decrypt everything. Do NOT commit .env.keys . Add it to your .gitignore immediately: 1echo ".env.keys" >> .gitignore Store the private key somewhere secure that your deployment environment can access, like your CI provider's secrets manager (e.g., GitHub Actions secrets, Vercel environment variables, or AWS Secrets Manager).

How Decryption Works at Runtime When you run dotenvx run -- node index.js , dotenvx looks for the private key in two places: - The local .env.keys file (for local development) - The DOTENV_PRIVATE_KEY environment variable (for CI/CD and production) If it finds the key, it decrypts your .env values in memory and injects them into process.env . This means that your application code doesn't need to change at all. It also means that if you're already using dotenv in your codebase, then dotenvx is a drop-in replacement.

dotenvx set to Add New Secrets Using Instead of manually editing and re-encrypting, you can add encrypted values directly: 1dotenvx set API_KEY "sk-my-secret-key" This encrypts the value and updates the .env file in one step. Multiple Environments dotenvx supports multiple environment files out of the box.

Each gets its own encryption key pair: 1# Create and encrypt a production .env 2echo "DATABASE_URL=postgres://prod-server/mydb" > .env.production 3dotenvx encrypt -f .env.production 4 5# Create and encrypt a CI .env 6echo "DATABASE_URL=postgres://test-server/mydb" > .env.ci 7dotenvx encrypt -f .env.ci Each file gets its own keys in .env.keys : 1DOTENV_PRIVATE_KEY="..." 2DOTENV_PRIVATE_KEY_PRODUCTION="..." 3DOTENV_PRIVATE_KEY_CI="..." To run with a specific environment: 1dotenvx run -f .env.production -- node index.js Or set the matching private key as an environment variable, and dotenvx figures out which file to decrypt: 1DOTENV_PRIVATE_KEY_PRODUCTION="your-key-here" dotenvx run -- node index.js The naming convention is the magic: DOTENV_PRIVATE_KEY_CI automatically maps to .env.ci , DOTENV_PRIVATE_KEY_PRODUCTION maps to .env.production , and so on.

DOTENV_PRIVATE_KEY_CI for GitHub Actions Setting Up This is the workflow for using encrypted environment variables in CI. The idea is that you commit your encrypted .env.ci file to the repo, and the CI runner decrypts it at runtime using a secret you store in GitHub (or your CI provider). 1. Create and encrypt your CI environment file 1echo 'DATABASE_URL="postgres://test-server/mydb"' > .env.ci 2echo 'API_KEY="test-api-key"' >> .env.ci 3dotenvx encrypt -f .env.ci .env.keys 2. Copy the CI private key from Look for the DOTENV_PRIVATE_KEY_CI value in your .env.keys file. 3.

Add it as a GitHub Actions secret Go to your repo's Settings > Secrets and variables > Actions and create a new secret called DOTENV_PRIVATE_KEY_CI with the private key value. 4.

Update your workflow 1name: build 2on: [push] 3jobs: 4 build: 5 runs-on: ubuntu-latest 6 steps: 7 - uses: actions/checkout@v4 8 - uses: actions/setup-node@v4 9 with: 10 node-version: 20 11 - run: curl -sfS https://dotenvx.sh/install.sh | sh 12 - run: dotenvx run -- node index.js 13 env: 14 DOTENV_PRIVATE_KEY_CI: ${{ secrets.DOTENV_PRIVATE_KEY_CI }} When the workflow runs, dotenvx sees the DOTENV_PRIVATE_KEY_CI environment variable, uses it to decrypt .env.ci , and injects the values into your process. You'll see a log line like injecting env (2) from .env.ci confirming it worked.

This same pattern works for GitLab CI, CircleCI, or any CI provider that supports secret environment variables. Just set DOTENV_PRIVATE_KEY_CI as a secret in whatever platform you use. Why This Matters for AI Coding Agents This is the part that wasn't relevant when dotenv was first created but has become critical. AI coding agents like Claude Code, Cursor, and GitHub Copilot read your project files to build context. If your .env file is plaintext, those secrets are going straight into the model's context window.

With dotenvx, the encrypted .env file is committed to your repo, but the values are gibberish without the private key. An AI agent reading your project sees: 1API_KEY="encrypted:BGMyAFNH6UjetjWsYHUkbndQosw..." Instead of: 1API_KEY="sk-live-abc123-my-real-key" This is a meaningful improvement over the traditional approach of just .gitignore -ing your .env file, because: - Agents read all project files, not just what's in git. A .gitignore 'd.env file on disk is still readable, so with plain dotenv, your secrets are fully exposed. - Encrypted values are useless without the private key.

An agent can still read .env.keys if it's on disk, so this isn't bulletproof on its own. But it reduces the attack surface: instead of every secret sitting in plaintext, there's a single key file to protect. - CI environments are scoped, so even if an agent has access to your DOTENV_PRIVATE_KEY , it can't decrypt your production secrets if those useDOTENV_PRIVATE_KEY_PRODUCTION .

The dotenvx team has also been building Agentic Secret Storage (AS2), which takes this further by giving each agent its own cryptographic identity for accessing secrets without any human-in-the-loop OAuth or API key flows. It's still early, but it points to where secret management is heading as AI agents become a standard part of development workflows.

Migrating from dotenv If you're already using dotenv, the migration is straightforward: - Install dotenvx: npm install @dotenvx/dotenvx --save - Encrypt your existing .env file:dotenvx encrypt - Commit the encrypted .env file and add.env.keys to.gitignore - Update your start script from node -r dotenv/config index.js todotenvx run -- node index.js - Remove the dotenv package:npm uninstall dotenv Your code doesn't need to change at all. You still read values from process.env the same way. The only difference is how they get there.

Wrapping Up dotenvx solves two problems that have gotten worse over time: sharing secrets across a team without insecure side channels, and keeping secrets out of AI model context. The encrypted-file-in-git approach is simpler than setting up a full secrets manager, and the environment-specific key convention (DOTENV_PRIVATE_KEY_CI , DOTENV_PRIVATE_KEY_PRODUCTION ) makes it easy to scope access for CI/CD pipelines. If you're starting a new project or looking to tighten up an existing one, it's worth the switch.

People Also Asked

Why you should stop using dotenv and switch to dotenvx today.?

dotenvx set to Add New Secrets Using Instead of manually editing and re-encrypting, you can add encrypted values directly: 1dotenvx set API_KEY "sk-my-secret-key" This encrypts the value and updates the .env file in one step. Multiple Environments dotenvx supports multiple environment files out of the box.

From dotenv to dotenvx: Next Generation Config Management?

Migrating from dotenv If you're already using dotenv, the migration is straightforward: - Install dotenvx: npm install @dotenvx/dotenvx --save - Encrypt your existing .env file:dotenvx encrypt - Commit the encrypted .env file and add.env.keys to.gitignore - Update your start script from node -r dotenv/config index.js todotenvx run -- node index.js - Remove the dotenv package:npm uninstall dotenv Y...

The Problems with dotenv and How dotenvx Solves Them?

Wrapping Up dotenvx solves two problems that have gotten worse over time: sharing secrets across a team without insecure side channels, and keeping secrets out of AI model context. The encrypted-file-in-git approach is simpler than setting up a full secrets manager, and the environment-specific key convention (DOTENV_PRIVATE_KEY_CI , DOTENV_PRIVATE_KEY_PRODUCTION ) makes it easy to scope access fo...

dotenvx: Encrypted .env Files for JavaScript Apps?

dotenvx: Encrypted .env Files for JavaScript Apps April 4, 2026 | 7 minutesIn This Post If you've used dotenv to manage environment variables in JavaScript projects, you've probably run into its biggest limitation: .env files sit in plaintext on disk. That was always a tradeoff, but it's become a real problem now that AI coding agents like Claude Code, Cursor, and GitHub Copilot routinely read you...

Dotenvx: Encrypt Environment Variables for Safe Deployments | DeployHQ?

DOTENV_PRIVATE_KEY_CI for GitHub Actions Setting Up This is the workflow for using encrypted environment variables in CI. The idea is that you commit your encrypted .env.ci file to the repo, and the CI runner decrypts it at runtime using a secret you store in GitHub (or your CI provider). 1. Create and encrypt your CI environment file 1echo 'DATABASE_URL="postgres://test-server/mydb"' > .env.ci 2e...