Make it real
Keys and secrets — set once, never shown back
Every app ends up holding something it must not publish. Here is where it goes, why writing it into your code is refused before anyone can see it, and what the platform will not do for you.
1. Ordinary values
Set, and the app restarts with them. They live encrypted, they are never written into the running container's description, and you can see which names exist without seeing what is in them:
Names only. That is the default and it is deliberate — a list that printed values would turn every screen-share and every log of a terminal session into a leak.
2. Why the key in your code never ships
Before a deploy builds anything, the code is read for credentials that look real: AWS keys, Google service accounts, Stripe live keys, private keys, a password assigned in a line of source. Finding one stops the deploy.
It stops rather than warns because this is the one mistake whose cost lands on somebody else — a leaked key is charged to your account by a stranger, and once it is in a public repository or a bundled site it is already gone. A warning you can scroll past is not protection.
Two things it deliberately does not do. Documentation and example files are not scanned: a password="test" in a test is correct, and a gate that refuses every real project is a gate people learn to ignore. And a value that reads as a placeholder — one containing your, example, changeme, an ALL_CAPS name, a lowercase-hyphenated slug — is not treated as a credential.
That runs the same gate without deploying, which is the fast way to find out before you push.
3. When it must not be readable at all
A secret is write-only: typed at a hidden prompt, stored, and never returned by anything — not by the CLI, not by the API, not by your agent. An environment variable can at least be listed by name and replaced; a secret cannot be read back at all, only rotated or deleted.
Use it for the values where being readable is itself the risk — a payment key, a signing key, a token that spends money. Use a plain variable for the rest, because a value nobody can read back is also a value you cannot check when something is wrong.
What is yours, still
Rotating a key at the provider when somebody leaves. Deciding which of your app's own users may see what. Anything a key can do once your code has it — the platform holds the value and cannot hold your intent.