Secrets
Encrypted values a function may read, managed by realm administrators.
A function that needs a third-party API key, or any value it shouldn’t hold in its own code, declares it in function.yaml’s secrets list and reads it from ctx.secrets, decrypted, at call time — never from an environment variable, which the function’s process doesn’t have.
secrets: [STRIPE_KEY, realm.SHARED_WEBHOOK_SECRET]
NAME(upper-case letters, digits and_, starting with a letter) is scoped to the function’s own database;realm.NAMEis scoped to the realm, shared by every database’s functions. There’s no fallback between them, and a database’s functions can never read another database’s secrets.ctx.secretsis keyed exactly as declared:ctx.secrets.STRIPE_KEYandctx.secrets["realm.SHARED_WEBHOOK_SECRET"].- A secret with no stored value makes
backdwarn at startup (naming the function) and the function answer500 secret_missinguntil one is set. Declaring a secret in a realm withauth: disabledis refused at startup: there’s nowhere to store it.
Setting values
Realm administrators manage values through the admin API or its CLI client:
backd secret set --realm blog --database shop --name STRIPE_KEY --url https://api.example.com
# Password: (the value, read without echo — or piped in, e.g. printf '%s' "$KEY" | backd secret set …)
backd secret set --realm blog --name SHARED_WEBHOOK_SECRET --url https://api.example.com # realm scope: no --database
backd secret list --realm blog
backd secret delete --realm blog --database shop --name STRIPE_KEY
Values are write-only: backd secret list and GET /_admin/secrets show only the scope, name and who last changed a secret, never its value. A changed or deleted value reaches running functions within about a minute (decrypted values are cached briefly, so backd doesn’t decrypt on every call).
Storage and the master key
Secrets are stored in <realm>___system.secrets, encrypted with AES-256-GCM under a master key backd never persists: the environment variable BACKD_SECRETS_KEY (32 characters or more), or BACKD_SECRETS_KEY_FILE naming a file that holds it. Without one configured, backd refuses to start if any function declares secrets.
To rotate the master key (for example after a suspected leak, or on a schedule), generate a new one and run, where backd runs:
BACKD_SECRETS_KEY=$OLD_KEY BACKD_SECRETS_NEW_KEY=$NEW_KEY \
docker compose exec backd /backd secret rotate-key
This re-encrypts every realm’s secrets in place — unlike set/list/delete, it writes to MongoDB directly, so it needs CONFIG_DIR and MONGO_URI, not a session or API key. Afterward, restart every backd, worker and CLI use with BACKD_SECRETS_KEY set to the new key; the old one is no longer needed.