create-key
Generate a per-repository key that gives envi pack / envi unpack a stable shared secret and adds opt-in at-rest encryption to ~/.envi/store/.
Usage
envi create-key
envi create-key --forceDescription
create-key generates a cryptographically random key and writes it to envi.config.maml at the repository root. envi.config.maml is meant to be committed to the repository so every collaborator inherits the key automatically.
This is a convenience feature, not a security one. It exists to solve two specific annoyances:
envi pack/envi unpackget a key that doesn't change when your manifest does, so blobs don't break the next time someone runspnpm install.envi capturewrites encrypted entries to~/.envi/store/instead of plaintext — mainly useful when you back that store up to GitHub viaenvi global github enable, so a leak of the backup doesn't expose env values without also leaking the source repo.
If neither of those bothers you, you don't need envi.config.maml — envi pack / envi unpack work fine using a manifest-derived key, and envi capture is fine writing plaintext locally.
Why a Key File?
The two situations where running create-key is worth it:
- Shared blobs that outlive dependency updates. The default for
envi packderives the key frompackage.json/Cargo.toml/ etc., so the key changes on every dependency bump. A committedenvi.config.mamlis stable across those changes. - Encrypted GitHub backup. When
~/.envi/store/is pushed to GitHub viaenvi global github enable,envi.config.mamlmakes the backup encrypted instead of plaintext. The source repo holds the key, so a backup-only leak isn't enough to decrypt. - No secret to share. Every collaborator who clones the repo automatically has the key — no out-of-band exchange.
What It Does
- Finds repository root - Same logic as
capture/restore - Refuses if already set - If
envi.config.mamlalready contains anencryption_key, the command exits unless--forceis passed - Generates 32 bytes of random data as a base64url string
- Writes
envi.config.maml- Creates a new file with a header comment, or inserts the key into an existingenvi.config.mamlwhile preserving other content
File Format
A freshly created envi.config.maml looks like:
{
# Generated by `envi create-key`. Team-shared encryption key meant to be
# committed. Convenience, not security: gives `envi pack` / `envi unpack`
# a stable key that survives manifest changes (so shared blobs don't
# break after `pnpm install`), and encrypts `~/.envi/store/` — mainly
# useful with the GitHub backup (`envi global github enable`).
#
# Anyone with repo access can decrypt, so this repo should be private.
# On a public repo this gives no confidentiality; use a custom secret
# with `envi pack` instead.
#
# See: https://envi.codecompose.dev/commands/create-key
encryption_key: "u3qZKY9GgqOMcKQ9s51G81HjpIB4WuKkn9Zh1Qkon_0"
}envi.config.maml is also where per-repo Envi configuration lives — for example, the optional capture_patterns array that extends which files envi capture picks up.
Legacy filename
Earlier versions of Envi called this file envi.maml (no config segment). The legacy filename is still read so already-committed files keep working — Envi prints a one-line hint suggesting you rename to envi.config.maml the first time it sees the legacy file in a session. New files written by envi create-key always use the canonical name; if you have a legacy file checked in, edit it in place or rename and commit envi.config.maml whenever it's convenient.
Examples
First-time setup
$ envi create-key
◐ Finding repository root...
ℹ Repository root: /Users/you/projects/myapp
✔ Wrote encryption_key to envi.config.maml
ℹ
ℹ Next steps:
ℹ 1. Commit envi.config.maml so collaborators can decrypt.
ℹ Do NOT add envi.config.maml to .gitignore — it must be tracked.
ℹ 2. Make sure this repository is private. Anyone with read access
ℹ can decrypt env values captured with this key.
ℹ 3. Run `envi capture` to write encrypted env values.Refusing to overwrite
$ envi create-key
ℹ Repository root: /Users/you/projects/myapp
ERROR envi.config.maml already contains an encryption_key. Re-run with --force to replace it.
WARN Replacing the key will make any previously captured stores unreadable until re-captured.Forced rotation
$ envi create-key --force
ℹ Repository root: /Users/you/projects/myapp
✔ Wrote encryption_key to envi.config.mamlAfter rotating the key, run envi capture to re-encrypt the store with the new key. Any previously stored data encrypted with the old key cannot be restored.
Security Considerations
Repo visibility matters
Anyone with read access to the source repository can decrypt env values captured with this key, so the repo should be private (and you should trust the access list).
On a public repo this key offers no confidentiality — anyone who can read the repo can read the key. The manifest-derived fallback used by envi pack / envi unpack doesn't fix this either: it's md5(package.json) (or Cargo.toml, etc.), which is also publicly computable. For real shared-blob confidentiality on a public repo, use a custom secret with envi pack and distribute it out of band.
Skipping create-key also means envi capture / envi restore won't encrypt ~/.envi/store/ at rest. That mostly only matters when you also use envi global github enable — see GitHub Integration → Defense in Depth.
Key rotation
The key is 32 bytes of cryptographically random data. There's no built-in incremental rotation — --force generates a brand-new key and any data captured under the old key becomes unreadable. After rotating, re-run envi capture from a checkout that has the original env files.
Related Commands
envi capture- Encrypts whenenvi.config.mamlis presentenvi restore- Decrypts usingenvi.config.mamlenvi pack- Prefersenvi.config.mamlover manifest-derived keysenvi unpack- Triesenvi.config.mamlfirst when decrypting
See Also
- Sharing Environment Configurations - Full sharing guide including
envi.config.mamlworkflow - GitHub Integration - Why encrypting at rest matters for the GitHub backup