envdrift decrypt¶
Decrypt an encrypted .env file using dotenvx or SOPS, or verify that a vault key can decrypt a file (dotenvx drift detection).
Synopsis¶
envdrift decrypt [ENV_FILE]
envdrift decrypt [ENV_FILE] --verify-vault --provider <p> --secret <name> \
[--vault-url ... | --project-id ... | --region ...]
Description¶
The decrypt command decrypts .env files that were encrypted with dotenvx or SOPS.
It can also verify that a key stored in your vault can decrypt the file without actually decrypting it (useful for catching key drift in CI/pre-commit).
- Local development after cloning a repo
- Viewing encrypted values
- Migrating to a different encryption system
Honest no-op on non-encrypted files (dotenvx backend)¶
With the dotenvx backend, if the target file has no encrypted values
decrypt reports an honest no-op (Nothing to decrypt: <file> has no encrypted
values.) instead of claiming a decryption happened. The file is left
byte-for-byte untouched — dotenvx is not invoked at all — so a plaintext file
(including one with CRLF line endings) or a non-.env binary file is never
silently rewritten or corrupted.
Refuses the key store and companion files¶
envdrift decrypt .env.keys (or any .keys/.example/.sample/.template
target) is refused by name — case-insensitively, so .env.KEYS counts —
with a non-zero exit: the dotenvx private-key store
and plaintext companion files are never encrypted by envdrift in the first
place (envdrift encrypt refuses them too), so "decrypting" one is always a
mistake rather than a no-op worth reporting as success. Leading-dash filenames
(e.g. -dash.env) are passed to dotenvx as ./-dash.env so they decrypt
normally via envdrift decrypt -- -dash.env.
Arguments¶
| Argument | Description | Default |
|---|---|---|
ENV_FILE |
Path to the encrypted .env file | .env |
Options¶
--backend, -b¶
Select the encryption backend (dotenvx or sops). Defaults to auto-detect,
then config, then dotenvx.
SOPS Options¶
--sops-configPath to.sops.yaml--age-key-fileAge private key file for decryption (setsSOPS_AGE_KEY_FILE; the explicit flag overrides an ambientSOPS_AGE_KEY_FILEexport)
Examples¶
Basic Decryption¶
Decrypt with SOPS¶
Verify vault key (drift detection, no decryption performed)¶
Vault verification is only supported with the dotenvx backend. --provider and
--secret are always required with --verify-vault (they are not read from
envdrift.toml). Provider settings use the explicit CLI flag first, then the
matching [vault.<provider>] configuration. HashiCorp additionally falls back
to VAULT_ADDR when neither --vault-url nor [vault.hashicorp] url is set;
surrounding whitespace is stripped and a whitespace-only value is treated as
unset.
# Azure Key Vault: pass the URL explicitly or configure [vault.azure]
envdrift decrypt .env.production --verify-vault --ci \
-p azure --vault-url https://myvault.vault.azure.net \
--secret myapp-dotenvx-key
# HashiCorp Vault: VAULT_ADDR can supply the URL
VAULT_ADDR=https://vault.example.com envdrift decrypt .env.production \
--verify-vault --ci -p hashicorp --secret myapp-dotenvx-key
# GCP Secret Manager: pass the project explicitly or configure [vault.gcp]
envdrift decrypt .env.production --verify-vault --ci \
-p gcp --project-id my-gcp-project \
--secret myapp-dotenvx-key
Exit code 0 if the vault key can decrypt the file, 1 if it cannot.
The vault value is normalized the same way envdrift lock --verify-vault and
envdrift sync parse it: surrounding whitespace, one layer of quotes, and a
DOTENV_PRIVATE_KEY_<ENV>= prefix are stripped. A vault secret stored as the
literal .env.keys line DOTENV_PRIVATE_KEY_PRODUCTION="<hex>" (quoted, as
vault-push writes it) therefore verifies identically to the bare <hex>
value — all three verify commands agree on the same vault secret.
Decrypt Specific Environment¶
Requirements¶
Dotenvx Private Key¶
Decryption requires the private key, which can be provided via:
.env.keysfile (recommended for local development):
- Environment variable (recommended for CI/CD):
dotenvx¶
The dotenvx binary is required. envdrift will:
- Check if dotenvx is installed
- If not, provide installation instructions
Enable encryption.dotenvx.auto_install in config to allow auto-installation.
SOPS Keys¶
SOPS uses your configured key management system (age, KMS, PGP, etc.). For age:
Ensure the sops binary is installed (for example, brew install sops) or enable
encryption.sops.auto_install.
Workflow¶
Local Development¶
After cloning a repo with encrypted .env files:
# 1. Get the private key from your team (securely!)
# 2. Add it to .env.keys
echo 'DOTENV_PRIVATE_KEY_PRODUCTION="your-key-here"' > .env.keys
# 3. Decrypt
envdrift decrypt .env.production
For SOPS, ensure your SOPS keys are available (age/KMS/PGP) and run:
CI/CD Pipeline (decrypt)¶
# GitHub Actions
env:
DOTENV_PRIVATE_KEY_PRODUCTION: ${{ secrets.DOTENV_PRIVATE_KEY_PRODUCTION }}
steps:
- name: Decrypt environment
run: envdrift decrypt .env.production
CI/pre-commit drift check (verify-vault)¶
envdrift decrypt .env.production --verify-vault --ci \
-p azure --vault-url https://myvault.vault.azure.net \
--secret myapp-dotenvx-key
On failure it prints ✗ Vault key CANNOT decrypt this file! followed by repair
steps:
git restore <file>envdrift sync --force -p <provider>to restore the vault key locally. When the current command discovered a TOML config, the hint includes-c <resolved-config>; the effective--vault-url/--region/--project-idvalues are appended after CLI/config/environment resolution.envdrift encrypt <file>to re-encrypt with the vault key
--verify-vault only verifies — it does not fetch the key
This is a read-only CI check: it fetches the vault key, tests decryption
against a byte-for-byte copy of the file in a throwaway temp dir, and discards
everything (the original file is not decrypted and no .env.keys is
written). The copy preserves the file exactly — encoding and line endings
included — on every platform. To actually fetch a key onto a machine and
decrypt for use, see vault-pull.
Error Handling¶
Missing or Wrong Private Key¶
When the private key is missing or does not match the encrypted file, decryption fails with a single line carrying the underlying dotenvx error:
Check that .env.keys exists or DOTENV_PRIVATE_KEY_* is set, and that the key
matches the one used to encrypt the file.
When using --verify-vault, a wrong key returns exit 1 with a message like:
[ERROR] ✗ Vault key CANNOT decrypt this file!
...
To fix:
1. Restore the encrypted file: git restore .env.production
2. Restore vault key locally: envdrift sync --force -p azure
3. Re-encrypt with the vault key: envdrift encrypt .env.production
dotenvx Not Installed¶
[ERROR] dotenvx is not installed
dotenvx is not installed.
Option 1 - Install to ~/.local/bin (recommended):
curl -sfS "https://dotenvx.sh?directory=$HOME/.local/bin" | sh -s -- --version=<pinned version>
(Make sure ~/.local/bin is in your PATH)
Option 2 - Install to current directory:
curl -sfS "https://dotenvx.sh?directory=." | sh -s -- --version=<pinned version>
Option 3 - System-wide install (requires sudo):
curl -sfS https://dotenvx.sh | sudo sh -s -- --version=<pinned version>
After installing, run your envdrift command again.
envdrift substitutes <pinned version> with the exact dotenvx version it pins
(maintained in src/envdrift/constants.json and bumped by Renovate), so the
printed commands always install the version envdrift expects.
SOPS Decryption Failed¶
Check SOPS_AGE_KEY_FILE, your KMS/PGP credentials, and .sops.yaml rules.
Security Notes¶
- Never commit
.env.keysto version control - Add
.env.keysto your.gitignore - SOPS key material is managed outside envdrift (age/KMS/PGP)
- Use secrets management (GitHub Secrets, Vault, etc.) for CI/CD
- Rotate keys if they are ever exposed
- For drift tests, clear cached keys (
.env.keys,DOTENV_PRIVATE_KEY_*dirs, /tmp) or run in a clean temp dir so dotenvx does not silently reuse an old key.