age values experimental
Store individual secrets in mise.toml as age encrypted values. mise encrypts and decrypts them itself, so you need only an age identity or an SSH key. Commit the encrypted values and share identities outside the repository.
Experimental
age values are experimental. Enable them with experimental = true under [settings], or run mise settings experimental=true.
Decrypted values behave like other [env] values: your activated shell, tasks and mise env see the plaintext. mise redacts them in task output by default.
Quick start
1. Get an identity
An existing SSH key works: ~/.ssh/id_ed25519 or ~/.ssh/id_rsa, with its .pub file beside it. To use a dedicated age identity instead, create one. Skip age-keygen if age.txt already holds 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 encrypt values for you. age.txt holds the private identity that decrypts them; keep it outside the repository.
2. Encrypt a value
mise set --age-encrypt --prompt DB_PASSWORD
# Enter value for DB_PASSWORD: [hidden input]--prompt reads the value without echoing it, so the plaintext stays out of your shell history. mise writes the ciphertext to mise.toml:
[env]
DB_PASSWORD = { age = "<base64>" }3. Use it
mise decrypts the value before it starts a command or task:
mise exec -- sh -c 'test -n "$DB_PASSWORD" && echo "DB_PASSWORD is available"'mise env and mise set DB_PASSWORD print the decrypted value; mise set with no arguments shows [redacted].
Who can decrypt
Without recipient flags, mise set --age-encrypt encrypts to:
- the public keys of the identities in
~/.config/mise/age.txt, or in the file named byage.key_filewhen that setting is set ~/.ssh/id_ed25519and~/.ssh/id_rsa, when their.pubfiles exist
If none of these exist, the command fails and asks for recipients.
Share with a team
Pass --age-recipient once for each teammate's age public key, or --age-ssh-recipient with an SSH public key or the path to one. --age-key-file adds the public keys of the identities in another key file as recipients. When you pass any of these flags, mise encrypts only to the recipients you name:
mise set --age-encrypt --prompt \
--age-recipient age1... \
--age-ssh-recipient ~/.ssh/teammate.pub \
DB_PASSWORDTo change a value or add a recipient, run mise set --age-encrypt again with the full recipient list. See mise set for every flag.
Decryption identities
mise tries identities from these sources, in order:
- The
MISE_AGE_KEYenvironment variable, which can hold one or more rawAGE-SECRET-KEY-...lines or the contents of an age identity file - The files in
age.identity_files - The file in
age.key_file ~/.config/mise/age.txt, if it exists- The SSH keys in
age.ssh_identity_files, then~/.ssh/id_ed25519and~/.ssh/id_rsa
Paths in age.key_file, age.identity_files and age.ssh_identity_files resolve against the config root of the file that sets them. They support templates, including {{ config_root }} and values from env. Absolute paths and paths that start with ~ keep their meaning.
Decryption is strict by default: when no identity is found, no identity can decrypt a value, or the payload is invalid, mise fails instead of continuing with a partial environment. To skip values it cannot decrypt and resolve the rest, set age.strict to false:
mise settings age.strict=falseDecrypted values are redacted by default. Set redact = false on the variable to opt out:
[env]
DB_PASSWORD = { age = "<base64>", redact = false }Storage format
The stored payload is base64-encoded age ciphertext, not encoded plaintext. mise writes small values as KEY = { age = "<base64>" }. When the ciphertext is larger than 1 KiB, mise compresses it with zstd and writes KEY = { age = { value = "<base64>", format = "zstd" } }. When reading, mise also accepts the table form without format or with format = "raw", which both mean uncompressed.
Settings
Set these under [settings] in a config file, with mise settings set, or with a setting's environment variable where it has one. See which value wins when a setting is set in more than one place.
age.identity_files
Age identity files to try when decrypting.
- Type:
path[] - Default: unset
- Environment variable:
MISE_AGE_IDENTITY_FILES(separated by:(;on Windows))
Used for age-encrypted [env] values and encrypted dotfiles. See
Decryption identities
for the order mise tries identities in.
age.key_file
Age private key file used to decrypt and as the default recipient when encrypting.
- Type:
path - Default:
"~/.config/mise/age.txt" - Environment variable:
MISE_AGE_KEY_FILE
Used for age-encrypted [env] values and encrypted dotfiles. See
Decryption identities.
age.ssh_identity_files
SSH private keys to try when decrypting age values.
- Type:
path[] - Default: unset
- Environment variable:
MISE_AGE_SSH_IDENTITY_FILES(separated by:(;on Windows))
Used for age-encrypted [env] values and encrypted dotfiles. See
Decryption identities
for the order mise tries identities in.
age.strict
Fail when an [env] age value cannot be decrypted, instead of skipping it.
- Type:
boolean - Default:
true - Environment variable:
MISE_AGE_STRICT
Decryption fails when no identity is found, none can decrypt the value, or the
payload is invalid. Set to false to skip those variables and resolve the rest
of the environment.