Environment variables
Last updated
Environment variables are the main way to configure an app and the correct place for secrets. Set them on the app's Env Vars panel.
Saving restarts the app
Changing a variable recreates the container. That's a brief interruption, and it clears anything held in memory — sessions, caches, counters, queued work.
So batch your edits rather than saving five times in a row.
They are runtime-only
The image build does not receive them. Anything read at build time gets nothing, which matters for frameworks that inline configuration into a bundle:
NEXT_PUBLIC_*(Next.js),VITE_*(Vite) and similar are baked in when the image is built. Setting them on the app has no effect on what the browser receives, and there's no error — the value is simplyundefined.
If you need build-time values, build the image in CI where you can supply them, then push the image. See Configuration.
Secrets
This is the right place for tokens, API keys and passwords — not source code, and not the Dockerfile. ENV in a Dockerfile is stored in an image layer and readable by anyone who can pull the image, without running it.
If a secret has already been committed or built into an image, rotate it. Removing it from a later commit doesn't un-publish it.
Read required secrets at startup and exit clearly if they're missing:
TOKEN = os.environ.get("BOT_TOKEN")
if not TOKEN:
sys.exit("BOT_TOKEN is not set - set it as an environment variable on the app")
Rules and limits
DF_is reserved. The platform injects variables with that prefix — including your app's own public URLs — and will reject your own names that use it.- Values can be large, and newlines are allowed, so a multi-line private key or certificate works as a single variable.
=is not allowed in names, and control characters other than newlines and tabs are rejected in values.
Useful things to make configurable
Anything you'd otherwise redeploy to change:
- Intervals and limits —
INTERVAL_SECONDS,MAX_TOKENS, rate-limit ceilings - Feature toggles, including a kill switch your handler checks
- Paths for data, so the same code runs locally and here —
DB_PATH=/data/app.db - Log level, so verbose output is one setting away rather than a deploy away
Some frameworks need PYTHONUNBUFFERED=1 (or an equivalent) to make output appear in logs promptly.
Related
- Config files — for tools that must read a file from a path