Transparent, Git-native encryption for your
.envfiles. Values are encrypted on commit and restored on checkout, so only ciphertext ever lands in Git, with no change to how you use Git or load config.
Jump to: Why · Install · Quick start · Usage · How it works · Security · CI/CD
Note
Built live, in one sitting. Envapor went from an empty repo to this working tool during a live build session - no script, no highlight reel (and one OBS crash 20 minutes in). Watch the full 2.5-hour recording:
Envapor transparently encrypts the values in your .env files inside Git. Plaintext is encrypted on commit and restored on checkout, so your working tree stays exactly as it is today while Git only ever stores ciphertext.
No .env.enc, no wrapper commands, no changes to how your app loads config. After a one-time setup you just use Git.
# your working tree (.env) # what Git actually stores
DATABASE_URL=postgres://user:pass@db/app DATABASE_URL=ENC[v2:9f3a…]
STRIPE_KEY=sk_live_51H8xY2… STRIPE_KEY=ENC[v2:c17b…]
APP_ENV=production # PUBLIC APP_ENV=production # PUBLICVariable names stay readable, so the committed .env is its own manifest. No .env.example to maintain.
Tip
Ship faster with Automaze. We partner with founders to bring their vision to life, scale their business, and optimize for success. Visit Automaze to book a call ›
- Features
- Why
- Install
- Quick start
- Usage
- How it works
- Security
- CI/CD
- Agent skill
- Project layout
- Documentation
| Feature | What you get | Deep dive |
|---|---|---|
| Zero workflow change | git add/commit/push/pull work unchanged after setup |
Quick start |
| One file | A single .env, no parallel encrypted copy to keep in sync |
Usage |
| Readable diffs & clean merges | Deterministic encryption, so only changed keys show up | How it works |
| Git-native | Clean/smudge filters plus a pre-commit guard, nothing at runtime | How it works |
| Public values | Mark readable values with a # PUBLIC comment, fails closed |
Usage |
| Single static binary | macOS, Linux, Windows, no dependencies | Install |
| Agent-ready | Install as an Agent Skill for coding agents | Agent skill |
- Zero workflow change.
git add/commit/push/pullwork unchanged after setup. - One file. A single
.env, no parallel encrypted copy to keep in sync. - Readable diffs & clean merges. Encryption is deterministic, so only variables you actually change show up in a diff, and edits to different keys merge without conflict.
- Git-native. Built on Git clean/smudge filters plus a pre-commit guard. Nothing to run at runtime.
- Single static binary. macOS, Linux, Windows. No dependencies.
# macOS (Homebrew)
brew install automazeio/tap/envapor
# Linux
curl -fsSL https://raw.githubusercontent.com/automazeio/envapor/main/installers/install.sh | sh
# Windows (PowerShell)
irm https://raw.githubusercontent.com/automazeio/envapor/main/installers/install.ps1 | iex
# From source (Go)
git clone https://github.com/automazeio/envapor
cd envapor/src && go install .Verify with envapor --version.
# once per team: generate a shared key
envapor keygen team
# in a repo (new or freshly cloned)
envapor init team # uses ~/.config/envapor/keys/team
# or import a key file from anywhere:
envapor init --pem /path/to/team.pem
# then just use git
git add .env
git commit -m "Add config"
git pushOn clone, teammates run the same envapor init team (or envapor init --pem …) and Git decrypts .env in place. Same command provisions servers and CI, no manual copying of secrets.
Edit .env normally. Values are encrypted on commit and decrypted on checkout automatically.
Public values — anything you want left readable in Git is marked with a PUBLIC comment:
APP_ENV=production # PUBLIC
API_URL=https://api.acme.com # PUBLIC: browser endpointParsing fails closed: a value is left in plaintext only on an unambiguous # PUBLIC marker. Anything ambiguous is encrypted.
Managed files — .env and every .env.* variant are managed by default (.env.local, .env.production, …). Template files (.env.example, .env.sample, .env.template) are always excluded. Coverage is written to .gitattributes by envapor init.
| Command | Purpose |
|---|---|
envapor keygen NAME |
Generate a new key at ~/.config/envapor/keys/NAME |
envapor keys |
List stored keys, marking the current repository's key |
envapor init NAME or --pem PATH |
Configure filters, hook, .gitattributes, and map the repo to a key (by stored name or key file) |
envapor doctor |
Diagnose the setup (filters, hook, mapping, coverage, crypto round-trip) |
envapor verify |
Check that .env files stored in Git contain no plaintext secrets (CI / pre-push) |
envapor status |
Show the mapping and per-file encryption state |
envapor migrate OLDKEY NEWKEY |
Re-encrypt managed values from one key to another (names or PEM paths) |
envapor encrypt / decrypt |
Manually transform managed files (rarely needed) |
envapor install-git-shim |
Enable git envapor … as a Git subcommand |
The installers enable git envapor <command> automatically; with Homebrew or go install, run envapor install-git-shim once to add the shim next to the binary.
Git clean/smudge filters do the work: the clean filter encrypts values on the way into the object store; the smudge filter decrypts them on checkout. A pre-commit hook is a safety net that aborts the commit if any non-PUBLIC value would reach Git as plaintext (for example, before filters are installed on a fresh clone).
Each value is encrypted independently with AES-256-GCM, using encryption/MAC subkeys derived from your 512-bit master key via HKDF. Encryption is deterministic (SIV-style: the nonce is derived from the variable name and the plaintext), which keeps diffs readable and merges clean. Each token is also bound to its variable name, so a ciphertext moved to a different variable fails to decrypt rather than silently supplying the wrong secret. Tokens are versioned (ENC[v2:…]) so the format can evolve; older v1 tokens remain readable.
Read this before adopting Envapor. It makes explicit trade-offs.
- Trust model. The master key is symmetric and shared. Every key holder can decrypt everything. Envapor is for trusted teams sharing a repo, not fine-grained or per-secret access control.
- Deterministic encryption leaks equality. The same value under the same key and variable name always yields the same ciphertext. Anyone with read access to the encrypted repo (no key needed) can tell whether a value is unchanged across commits or whether the same variable holds the same value in two files. This is the deliberate cost of clean diffs and merges. If value-equality leakage is unacceptable for you, Envapor is the wrong tool.
- Keys never touch the repo. They live under
~/.config/envapor/keys/and repo→key mappings are stored locally. Distribute keys over a secure channel (e.g., a password manager), and never commit them. - Key rotation ≠ secret rotation.
envapor migratere-encrypts the working tree and future commits under a new key. It does not rewrite history: past commits stay encrypted under the old key, so anyone holding the old key and an old clone can still read that history. After a compromise, you must also rotate the affected secrets at their source (DB passwords, API keys). Envapor changes the lock; it can't recall copies that have already been distributed. - Offboarding is on you. When someone leaves, rotate the affected secrets and re-issue the key. Envapor doesn't manage this.
Envapor is not a replacement for HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, or Google Secret Manager. It targets repository-based secret sharing, and complements those systems rather than competing with them.
A first-party GitHub Action installs Envapor, imports the key, configures filters, and decrypts the repo:
- uses: automazeio/setup-envapor@v1
with:
key: ${{ secrets.ENVAPOR_KEY }}
- run: go test ./...Store the PEM contents in your CI provider's encrypted secrets.
To guard against plaintext secrets slipping into Git without needing the key, add envapor verify. It inspects the committed (index) content of managed .env files and exits non-zero if any non-PUBLIC value is still plaintext:
- run: envapor verifyCoding agents (Claude Code, or anything that supports Agent Skills) can install Envapor's skill and then set up, operate, and troubleshoot Envapor on their own — including the guardrails (never commit keys, never gitignore .env):
mkdir -p ~/.claude/skills/envapor
curl -fsSL https://raw.githubusercontent.com/automazeio/envapor/main/skills/envapor/SKILL.md \
-o ~/.claude/skills/envapor/SKILL.mdThe skill source lives in skills/envapor/SKILL.md.
envapor/
├── src/
│ ├── internal/
│ │ ├── cmd/ # CLI subcommands (init, keygen, doctor, verify, …)
│ │ ├── config/ # Key store and repo→key mapping
│ │ ├── crypto/ # AES-256-GCM, HKDF, token format
│ │ ├── envfile/ # .env parsing and PUBLIC marker handling
│ │ ├── gitutil/ # Filters, hooks, .gitattributes
│ │ └── pktline/ # Git filter protocol
│ └── main.go # Binary entry point
├── installers/ # install.sh, install.ps1
├── skills/envapor/ # Agent Skill (SKILL.md)
├── docs/ # User guide
├── .github/ # CI workflows and setup-envapor action
└── README.md
Full walkthrough, team/server/CI workflows, and troubleshooting live in docs/user-guide.md.
Apache-2.0 © Automaze
Built with Go · Git clean/smudge filters · AES-256-GCM
