Documentation
Environment
Variables reach your service two ways: set once for the whole app, or set on the service itself. Both arrive as ordinary environment variables.
App-level and per-service
Most variables belong to the app — a shared secret, an external API token, a feature flag. Set those once and the service gets them.
The per-service level exists because the two are different scopes, and it is where a value that belongs to the running code rather than to the app goes. Prefer app-level: it is one place to look when a value is wrong.
Some variables you never set at all. A database fills in its own connection variable — see Database.
Three rules worth knowing before you edit
A write replaces the whole list
Saving the environment is not a merge. What you send becomes the app's environment entirely, so a variable you removed from the editor is deleted — which is what lets you delete one through the same control that shows it. Clearing the list clears everything.
An empty secret means “unchanged”
A secret's value never leaves the server. The editor therefore shows it as empty, and sends it back empty — so an empty secret is read as “keep what is stored” rather than as a new blank value. Without that rule, editing one unrelated variable would wipe every secret in the app the first time you pressed save.
The consequence is the bit to remember: to genuinely empty a secret, untick secret. Then the empty string is something you can see you are sending, and it is taken literally.
There is a ceiling, and you will not meet it
The whole app's environment is capped at 256 KB. No ordinary application comes close — the limit exists so that something generating variables in a loop cannot push the app's memory around, not to ration anything you would reasonably use. If you hit it, the cause is a bug in whatever produced the list.