Secrets and environment variables
A secret is a named value, such as a database password, stored in one environment and injected into deploys as an environment variable. Values are write-only: once saved, neither the dashboard nor the API will show them again.
How secrets are scoped#
Secrets belong to an environment. There are no organisation-wide or project-wide secrets: staging and production each hold their own set, even when the names match.
A deploy can only reference secrets in the environment it runs in. That lets the same build run in both environments with different credentials: give each environment a DATABASE_URL, and each deploy picks up its own.
Plain variables and secret references#
A deploy's Environment variables list holds two kinds of row:
| Row type | What you enter | Where the value lives |
|---|---|---|
| Plain | A KEY and a value | On the deploy itself. Visible to anyone who can edit the deploy. |
| Secret | The name of a secret in the deploy's environment | In the environment's secret store. Never shown after saving. |
Use plain variables for non-sensitive settings such as LOG_LEVEL=info or PORT, and secrets for anything you'd rotate if it leaked. The deploys table summarises each deploy's list in its Variables column, for example “2 vars · 1 secret”.
Create a secret#
Setting and deleting secrets needs the Manager or Admin role. Members with the User role see the list of keys but not the form.
Open Secrets and pick the environment
Secrets (under Infrastructure), then choose the Project and Environment.
Fill in Set a secret
Enter a Name such as
DATABASE_URLand the Value. The value field is masked.Save
Choose Save secret. You'll see “Secret "DATABASE_URL" saved.” and the key appears under Existing secrets.
With the API (values go in the request body, never the URL):
POST /v1/projects/{project_id}/environments/{environment_id}/secrets/DATABASE_URL
{"value": "postgres://app:••••@db.internal:5432/app"}
Naming rules#
- Letters, numbers and
._=-only. No spaces, slashes or other characters. - At most 253 characters.
- The dashboard checks the name as you type and won't let you save an invalid one.
Because the secret's name becomes the environment variable's name (see below), stick to the usual UPPER_SNAKE_CASE your application expects.
Reference a secret from a deploy#
- Open Deployments→New deploy, or Edit an existing deploy.
- Under Environment variables, choose + Secret.
- Pick the secret from the — select secret — list. It lists the keys stored in the environment you selected for the deploy.
- Choose Create deploy or Save deploy.
The container receives an environment variable with the same name as the secret. A secret row stores only the name, so the value is read from the environment's store rather than copied onto the deploy.
$ printenv DATABASE_URL
postgres://app:••••@db.internal:5432/app
Update a secret#
Saving a secret under an existing name replaces its value. In Existing secrets, choose Set value next to the key: the name is filled in for you, and you enter the new value and choose Save secret.
When an updated value takes effect#
Environment variables are read when a container starts, so running replicas keep the value they started with until they are replaced.
Delete a secret#
Choose Delete next to the key and confirm “Delete secret "…" from this environment?”. Remove the matching row from any deploy that references it first.
Security behaviour#
- Write-only values. The API never returns a secret's value; listing an environment's secrets returns keys only. The dashboard never shows a value after saving.
- Encrypted by the platform. The dashboard states that values are stored encrypted.
- Role-gated writes. Only Managers and Admins can set or delete secrets. See Members and permissions.
- Visible to your code. Once injected, a secret is an ordinary environment variable in your container. Anything your application logs, the Watch logs viewer shows, so don't print secrets at start-up.
Common errors#
- “Use only letters, numbers, and . _ = -”
- The name has a space, slash or other character. Rename it, for example
API KEY→API_KEY. - “Name must be at most 253 characters.”
- Shorten the name.
- No Set a secret form
- Your role is User. Ask a Manager or Admin, or ask an Admin to change your role on the Team page.
- “No environment”
- The selected project has no environment yet. Create one on the Projects page.
- “Secrets referenced by deploys”
- The secret list couldn't be loaded, so the page shows the keys your deploys reference instead. Values are still never shown. Refresh later.
- Secret missing from the deploy form
- The deploy is in a different environment from the secret. Secrets don't cross environments; set it in the deploy's environment too.