Peren documentation
Secrets
Declare Worker secrets that appear as strings on env without embedding values in the fleet file.
A declared Worker secret becomes a string on env. Peren resolves the value before listeners open. Provider credentials such as api_key_env on AI or vector bindings stay host-owned and are not Worker secrets.
Prerequisites
- A fleet file with
[node],[bucket],[mtls], one service, and one socket - Either a process environment variable that holds the secret value, or a value already written with
peren secrets put
Declare a secret from the environment
Write fleet.toml:
[node]
node_id = "00000000-0000-0000-0000-000000000001"
advertise_addr = "127.0.0.1:7000"
listen = "127.0.0.1:7000"
[bucket]
kind = "memory"
[mtls]
ca_cert_path = "./certs/ca.pem"
leaf_cert_path = "./certs/leaf-cert.pem"
leaf_key_path = "./certs/leaf-key.pem"
[[services]]
name = "api"
worker_bundle_path = "worker.js"
compatibility_date = "2026-01-01"
[services.secrets]
STRIPE_SECRET_KEY = "STRIPE_SECRET_KEY"
[[sockets]]
name = "public"
listen = "127.0.0.1:8080"
service = "api"
The string value names the process environment variable Peren reads. The binding name on the left becomes the key on env.
You can write the same declaration as an object:
[services.secrets]
STRIPE_SECRET_KEY = { source = "env", name = "STRIPE_SECRET_KEY" }
Set STRIPE_SECRET_KEY in the process environment, then write worker.js:
export default {
async fetch(request, env) {
return new Response(typeof env.STRIPE_SECRET_KEY);
},
};
env.STRIPE_SECRET_KEY is a string. It is not a method object.
Success
The Worker reads the secret as a string. typeof env.STRIPE_SECRET_KEY is "string".
Failure
If the named environment variable is missing and no active local-store value exists for the declaration, the process fails before listeners open.
Store-backed secret
Point the declaration at a store name:
[services.secrets]
STRIPE_SECRET_KEY = { source = "store", name = "services/api/STRIPE_SECRET_KEY" }
source must be store. name is the store entry. Put or rotate the value with the operator CLI:
peren secrets put fleet.toml --name services/api/STRIPE_SECRET_KEY --value "$STRIPE_SECRET_KEY"
peren secrets rotate fleet.toml --name services/api/STRIPE_SECRET_KEY --value "$STRIPE_SECRET_KEY"
peren secrets list fleet.toml
peren secrets get fleet.toml --name services/api/STRIPE_SECRET_KEY
peren secrets delete fleet.toml --name services/api/STRIPE_SECRET_KEY
CLI output is metadata only. It does not print the secret value. Full operator procedure lives under Rotate secrets.
Secrets store map and refs
Fleet-level [secrets_store] maps a store name to an environment variable used when no active local-store value exists:
[secrets_store]
DB_PASSWORD = "DB_PASSWORD"
[services.secrets_store_refs]
DB_PASSWORD = "DB_PASSWORD"
secrets_store_refs maps the Worker env name to a store name that must exist in [secrets_store]. Config validation refuses an unknown store name.
Secrets store binding
A binding can also inject a store value as a string:
[secrets_store]
prod-api-key = "SECRET_VALUE"
[services.bindings.API_KEY]
type = "secrets_store_secret"
secret_name = "prod-api-key"
type must be secrets_store_secret. secret_name must name an entry in [secrets_store]. The Worker sees env.API_KEY as a string. A missing value fails the process before listeners open.
Worker secrets versus host credentials
| Kind | Where it is declared | What Worker code sees |
|---|---|---|
| Worker secret | [services.secrets], secrets_store_refs, or type = "secrets_store_secret" |
a string on env |
| Host provider credential | fields such as api_key_env on AI or vector providers |
nothing; Peren attaches the credential in the node process |
Do not place provider API keys in [services.secrets] unless the Worker itself must send that value. Keep host-owned provider credentials in provider fields. See Credentials and secrets.