> ## Documentation Index
> Fetch the complete documentation index at: https://docs.reliantlabs.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Secrets

> Setting secrets for a hosted environment, how they reach your workloads, and why you can never read one back

A hosted environment's secrets — API keys, database passwords, signing keys — live in Reliant's **managed store**, encrypted at rest and delivered to your workloads at deploy time. This page covers how to set them, how they reach your code, and the one rule that surprises people: you can write a secret, but nothing can ever read it back to you.

## Setting a secret

Open your project's **Forge** area, pick an environment, and find the **Secrets** section. Each secret your workloads declare appears there with its current state:

| State | What it means |
| - | - |
| **Set** | The store holds a value. You can replace it with a new version. |
| **Not set** | A workload asks for this secret and nothing has ever been stored for it. Deploys that need it will fail until you set it. |
| **Deleted** | The current version is soft-deleted. Nothing can read it, and **Undelete** brings it back. |
| **Destroyed** | The value is permanently gone. The history row remains; the bytes do not. |

Press **Set value** on any row, type the value, and save. That is the whole flow.

### You can set secrets before your first deploy

You do not have to deploy first. An environment that has never been deployed still accepts secrets — Reliant creates the environment record on your first write, and the values sit waiting until a deploy asks for them.

This matters because the alternative is a deadlock: your first deploy needs `STRIPE_SECRET_KEY`, but you cannot set `STRIPE_SECRET_KEY` until you have deployed. Set your secrets first, then deploy, and the deploy has everything it needs.

<Note>
  Setting a secret on a never-deployed environment creates the environment record but does **not** deploy anything and does not start any billable infrastructure. Nothing runs until you deploy.
</Note>

## You cannot read a secret back

Reliant will tell you that a secret **exists**, when it was last written, and how many versions it has. It will never show you the value — not in the UI, not through the API, not to support staff.

This is enforced by the storage engine rather than by our UI being careful. The credential Reliant's servers hold can list and read secret *metadata* and has no permission to read secret *data* at all; the storage layer refuses the request. There is no "reveal" button to find because there is no API call that could serve one.

The practical consequence: **keep your own copy** of anything you cannot regenerate. If you lose a value, you rotate it at the source (issue a new Stripe key, for instance) and set the new one here.

## How secrets reach your workloads

You declare which secrets a workload needs in your forge configuration, as environment variables backed by a managed secret. At deploy time the platform resolves each declared name against your environment's store and delivers the values to your workload as ordinary environment variables. Your code just reads `process.env.STRIPE_SECRET_KEY` (or your language's equivalent) and does not know or care where the value came from.

Two consequences worth knowing:

* **A secret nothing declares is never delivered anywhere.** It sits in the store unused. The UI marks these so you can clean them up.
* **Changing a secret does not change a running workload.** Environment variables are set when a container starts, so a new version reaches your code on the next deploy or restart.

## Versions, delete, and destroy

Every write creates a new version rather than overwriting the last one, so a bad value can be rolled back by setting the previous one again.

**Delete** and **Destroy** are deliberately different operations:

* **Delete** is reversible. It soft-deletes a version — nothing can read it, but the data is still there and **Undelete** restores it. This is what you want when retiring a secret you might need back.
* **Destroy** is permanent. The bytes are erased and no one, including us, can recover them. The version's history row survives so the audit trail stays honest.

Reach for Delete unless you specifically need the value gone forever.

## Scope and isolation

Secrets are scoped to a single **environment**, not shared across your project. Your `staging` and `prod` environments have entirely separate stores, so a value set in one is invisible to the other.

This is why you set the same secret name once per environment, and it is deliberate: it means a preview or staging workload cannot read your production database password, even if someone deploys the wrong code to the wrong place.

## Who can set a secret

Setting, deleting, or destroying a secret requires the **admin** role in the organization that owns the environment. Members can see which secrets exist and whether they are set, which is what they need to diagnose a failing deploy, without being able to change them.

## Troubleshooting

**"Deploys that need it will fail until it is set."**
A workload declares this secret and nothing is stored for it. Set a value, then deploy.

**The Set value button is missing.**
Either you are not an admin in the owning organization, or this environment does not use the managed store — an environment whose forge config names a different secret provider (an external secret manager, or a local file for development) is managed there instead, and Reliant does not hold its values.

**"This environment is hosted on a different control plane."**
The environment belongs to another Reliant deployment, so this console cannot read or write its store. Set the value from a console signed in to that deployment.
