Browse documentation
On this page

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.