EnvSeal v6.1.0

Git for secrets.

A single encrypted file that travels with your repo. Switches with your branch. Merges like code. No cloud. No accounts. No shared master password.

Read the docs
~/your-project — envseal
$envseal init --local && envseal git-setup
vault created at .envseal
pre-commit shield installed
merge driver registered
$envseal set DATABASE_URL
value: ••••••••••••••••••••••••
encrypted and stored
$envseal run -- npm start
loading 4 secrets from .envseal
injecting DATABASE_URL → child
injecting STRIPE_SECRET → child
injecting JWT_SIGNING_KEY → child
injecting AWS_ACCESS_KEY_ID → child
> app@1.0.0 start
> node server.js
listening on :3000
01 — The problem

If you've built anything with more than one contributor, you've probably lived one of these: a teammate adds a key to their local .env and forgets to send it. Someone pastes a database URL into a Discord DM. You check out a branch and accidentally run it against production. A sleepy git add . scoops up a raw key and it sits in Git history forever.

None of these are exotic. They're what happens when secrets live outside version control and the code that needs them doesn't.

The fix isn't a better .env file. It's putting your vault somewhere Git already knows how to move. EnvSeal makes your secrets a file in your repo — encrypted for the people who need them, switched by branch, and reviewed in pull requests like anything else you commit.

02 — The workflow

Two columns. That's the whole pitch.

You set up the vault, commit it, and push. Your teammate pulls, runs their app, and it works. Same keys, correct branch, zero DMs.

You Setting up
~/api — bash
$envseal init --local
$envseal git-setup
$envseal set DATABASE_URL
$git add .envseal .gitattributes
$git commit -m "seal secrets"
[main 3f9c2a1] seal secrets
$git push
→ main → main
# vault travels with the repo.
# no DM. no screenshot. no password.
Teammate Onboarding
~/api — bash
$git clone …
Cloning into 'api'…
$envseal recipient id
age1ql3z7hjy54pw3hyww5ayyf…
# you run, once:
$envseal recipient add @them
$envseal run -- npm start
secrets injected
listening on :3000
03 — What's inside

Six decisions that shape everything else.

01
Git-native by design
The vault is a file in your repo. Pull requests, git blame, and history apply to secrets the same way they apply to code.
02
Branch-aware
envseal run reads git rev-parse --abbrev-ref HEAD and applies the matching tag automatically. No manual swapping.
03
Per-recipient access
The vault is sealed to individual public keys. Adding or removing a teammate is a Git commit, not a shared-key redistribution.
04
Ephemeral runtime
Secrets decrypt into the child process and evaporate on exit. Zero plaintext on disk, zero leakage into your interactive shell.
05
Pre-commit shield
A hook blocks staged .env, .env.local, and .env.staging files before they reach Git history. The encrypted vault passes through.
06
Merge driver included
Two people editing secrets on different branches usually resolve silently. Same key, different values? You pick ours or theirs.
04 — Compare

No secrets tool is perfect for every setup.

If your team needs a dashboard, an audit log, or SSO, use Doppler or Infisical — they're good at that, and that's a different problem. If you're deep in Kubernetes and cloud KMS, SOPS fits your pipeline better. EnvSeal is for the team in between.

Plain .env dotenvx Mozilla SOPS EnvSeal Doppler / Infisical
Cost Free Free; paid tiers from ~$3 to $299/mo Free Free, no account needed Free tier; paid from ~$8–46/seat/mo
Works offline Yes Yes — local CLI Yes with age. Cloud KMS modes need connectivity Yes, fully Cached fallback after first fetch. Self-hosted available at Enterprise tier
Auto-switches per branch No No — manual -f selection No Yes No — requires dashboard/API config
Stops accidental commits No Partial (dotenvx precommit) No Yes, built-in hook Yes, via CLI wrapper
Team onboarding Manual file sharing Manual .env.keys sharing Manual age key exchange + sops updatekeys Add a GitHub handle (or exchange age keys) Invite via dashboard
Merge conflicts N/A N/A — shared key, not file No built-in driver (Clef third-party) Built-in ours / theirs N/A — cloud-managed
Best suited for Solo hackathon, no real secrets Solo/small teams wanting encrypted .env K8s / GitOps teams on cloud KMS Small-to-mid teams who want secrets to live in Git Orgs wanting GUI, audit logs, and a budget

Verified early 2026. dotenvx does more than a table row can capture — it has real encryption, rotation, and git-diff audit. The architectural difference: dotenvx uses a single shared private key per environment, while EnvSeal seals to individual recipients.

05 — The deal

Read this before you trust any encryption tool.

Most encryption tools hide their limits in the fine print. We put them on the landing page. If any of them is a dealbreaker, EnvSeal is not for you — and that's fine.

Where EnvSeal genuinely wins
  • Git-native by design. The vault is a file in your repo, not a parallel system you have to remember to sync.
  • Free and offline. No accounts, no cloud, no telemetry. Works on a plane or behind a corporate firewall.
  • Branch-aware. The only option in its class that switches secrets automatically on git checkout.
  • Per-recipient access. Adding or removing a teammate is a Git commit, not a shared-key redistribution.
Where it's honestly not the best fit
  • No web dashboard, no audit log. If you need to see who accessed what and when, use a cloud tool.
  • No non-technical UI. Everyone on the team touches a terminal. If that's a dealbreaker, look at Doppler or Infisical.
  • You can lock yourself out permanently. Zero-trust means zero recovery. Back up your key.
  • Kubernetes / cloud-KMS shops. SOPS fits your existing pipeline better than bolting EnvSeal on.
06 — Reference

The whole CLI, at a glance.

Every command, every flag. If you've used Git, this will feel familiar — every command is a single verb, and most have a natural Git analogue you already know.

Core

envseal init [--local] [--git] [-r RECIPIENT]
Initialize a project-local vault or a global vault. -r adds an initial recipient.
envseal git-setup [--init]
Register the merge driver and pre-commit shield in the current repo.
envseal set [-g GROUP] [-t TAG] KEY
Store a secret. Prompts for the value without echoing it.
envseal get [-g GROUP] [-t TAG] [--token TOK] KEY
Print one decrypted value. Use sparingly.
envseal run [-g GROUP] [-t TAG] [--token TOK] -- CMD (alias: exec)
Run a command with secrets injected into the child process.
envseal load [-g GROUP] [-t TAG] [--token TOK] [KEYS...]
Print shell export statements for eval. Prefer run.
envseal list [-g GROUP] [-t TAG] (alias: ls)
List key names without revealing values.
envseal edit [-g GROUP] [-t TAG]
Edit key/value pairs in your default editor. Faster than many set calls.
envseal remove [-g GROUP] [-t TAG] [--force] [KEY] (alias: rm)
Delete a key, tag, or group. --force skips confirmation.
envseal link GROUP
Bind a global vault group to the current working directory.
envseal clear
Wipe cached master keys from the OS keyring session.

Access & CI

envseal recipient id
Print your local public identity key. Share it once with the vault owner.
envseal recipient add <@user | KEY | FILE>
@user fetches GitHub SSH keys. Falls back to a manual age key if they have none.
envseal recipient ls
List all authorized recipient keys.
envseal recipient rm <NAME | INDEX | KEY>
Revoke access and re-encrypt the vault for the remaining recipients.
envseal token [-t TAG] [-o PATH] [--exp S] [KEYS...]
Mint a scoped, offline CI token. Limit by tag, by key, and by expiry.
envseal rotate
Rotate the encryption key. Every existing token becomes unreadable.
envseal import [-t TAG] PATH
Import variables from an existing .env file. Original left in place.
envseal export [-t TAG] [-o PATH] [KEYS...]
Decrypt to a .env file with strict 0600 permissions.

Global flags

-e, --env PROFILE
Target a specific profile file. -e staging loads .staging.envseal.
-G, --global
Target the system-wide vault. Comes before the subcommand: envseal --global init.
--no-env
Disable reading fallback identity keys from ENVSEAL_IDENTITY.

Your secrets already live in the repo.
They're just not encrypted yet.

One file. One command. No more "does anyone have the new key?"