docs/environments/secrets/age.md
Encrypt individual environment variable values directly in mise.toml using age encryption. Encryption and decryption are built into mise. The optional age-keygen command below comes from the separate age CLI.
This is a simple way to store encrypted environment variables directly in mise.toml. Run mise set --age-encrypt <key>=<value> to use it. By default, mise uses your SSH key (~/.ssh/id_ed25519 or ~/.ssh/id_rsa) if one exists.
mise.tomlmise settings set experimental=true
age.txt already contains an identity you want to keep:mise use -g age
mkdir -p ~/.config/mise
mise exec -- age-keygen -o ~/.config/mise/age.txt
# Public key: age1...
The public key is a recipient: share it with people who need to encrypt for
you. age.txt contains the private identity needed to decrypt; keep it outside
the repository.
mise set --age-encrypt --prompt DB_PASSWORD
# Enter value for DB_PASSWORD: [hidden input]
::: warning
Use --prompt so the plaintext does not become part of the command or shell history.
:::
mise.toml as an age directive:[env]
DB_PASSWORD = { age = { value = "<base64>" } }
# Bash example: checks availability without printing the password
mise exec -- bash -c 'test -n "$DB_PASSWORD" && echo "DB_PASSWORD is available"'
mise env and mise set DB_PASSWORD print the decrypted value. Use them only when
that plaintext output is intended; see redaction.
--age-encrypt — enable age encryption for the value--age-recipient <KEY> — x25519 recipient (can be set multiple times)--age-ssh-recipient <PATH|KEY> — SSH public key or path to .pub/private key (can be set multiple times)--age-key-file <PATH> — use recipients derived from an age identity file--prompt — prompt for the value to avoid accidentally exposing it to your shell historyIf no recipients are provided explicitly, mise tries the defaults (see below).
The stored payload is base64-encoded ciphertext, not an encoded plaintext secret.
The format field identifies the payload representation:
format = "raw" — uncompressed ciphertext (typically for small values)format = "zstd" — zstd-compressed ciphertext (used when ciphertext > 1KB)mise looks for identities in this order:
MISE_AGE_KEY environment variable
AGE-SECRET-KEY-... lines, or an age identity file payloadsettings.age.identity_files (list of paths)settings.age.key_file (single path)~/.config/mise/age.txt if it existssettings.age.ssh_identity_files and common defaults (~/.ssh/id_ed25519, ~/.ssh/id_rsa)Paths configured in settings.age.key_file, settings.age.identity_files, and
settings.age.ssh_identity_files are resolved relative to the config root of
the file that declares them. They also support Tera templates, including
<span v-pre>{{ config_root }}</span> and values from env. Absolute paths and paths beginning
with ~ keep their existing meaning.
Decrypted values are always marked as redacted.
Age decryption is strict by default. If no identities are found, no available identity can decrypt the value, or the age payload is invalid, mise fails instead of continuing with a partially resolved environment.
To allow commands and tasks to continue when an age value cannot be decrypted, disable strict mode:
mise settings set age.strict=false
In non-strict mode, mise skips values that cannot be decrypted and continues resolving the rest of the environment.
When --age-encrypt is used without explicit recipients, mise attempts to derive recipients from:
~/.config/mise/age.txt.pub file existsIf none are found, the command fails with an error asking you to provide recipients or configure settings.age.key_file.
mise set KEY prints the decrypted value.