# Environment variables and secrets for your app Set environment variables and secrets in the dashboard or with ox vars, reference one in another, see the keys ox provides and hides, restore old ones. To set an environment variable or a secret for your app, add it on the project's **Variables** tab, or run `ox vars set KEY`, which asks for the value so it never lands in your shell history. Saving redeploys the app with the new value. ox keeps variables out of your repo, provides some keys such as `DATABASE_URL` itself, and hides secret values in logs. ## Set an environment variable or secret In the dashboard, open the project and pick the **Variables** tab. Type the key and the value, press **Add variable**, and then choose **Save & deploy** or **Save, deploy later**. To paste many at once, use **Edit as .env**. From a terminal, give only the key. ox asks for the value and does not show it as you type, so it never lands in your shell history: Set a variable: ```sh ox vars set shop STRIPE_KEY ox vars set shop --from-file .env.production ``` Writing `KEY=value` on the command line is refused for that reason (every `ox vars` flag is in the [CLI reference](https://deploywithox.com/docs/cli#variables-and-services)). In a script, pipe the value in: one key reads the raw value from standard input, and several keys read `KEY=value` lines. A save redeploys the app so the new value goes live. Add `--no-deploy` to save now and use it at the next deploy, and `--wait` to follow the redeploy. Other changes: ```sh ox vars unset shop OLD_KEY ox vars import shop .env ox vars pull shop ``` `import` shows the changes and asks before it saves. `pull` writes your values to `.env.local`, or the file you give with `-o`; it will not write over a file that exists unless you add `--force`. ## List variables and where they come from List variables: ```sh ox vars shop ox vars shop --reveal ``` The list shows each key and where it comes from: yours, provided by ox, or still needed. Values show as `********`. `--reveal` shows them, and that is written to your audit log. The dashboard hides values the same way until you click to reveal them. ## Use one variable inside another Write `${NAME}` inside a value, and ox fills it in when it deploys: A reference: ```text CELERY_BROKER_URL=${REDIS_URL} API_URL=${PUBLIC_URL}/api ``` You can name your own keys and the keys ox provides. `${postgres.host}` names one part of a service: `host`, `port`, `user`, `password`, `database` or `url`. Write `$${` for a plain `${`. A bare `$NAME` is left as it is. ox checks references when you save, and refuses the save with one of these: Reference errors: ```text references form a cycle: A -> B -> A ${X} is not set (neither provided by ox nor one of your variables) ${PORT} is set per process and cannot be referenced; use $PORT in the command instead ``` `PORT` and `OX_RELEASE` differ per process and per release, so they cannot be referenced. Before the first deploy, a reference to a key that does not exist yet is allowed. ## Keys ox provides: PORT, DATABASE_URL and more | Key | When | | --- | --- | | `PORT`, `HOST` | Always: where your app must listen. | | `OX_ENV`, `OX_PROJECT`, `OX_RELEASE`, `OX_DATA_DIR` | Always. | | `PUBLIC_URL`, `PUBLIC_HOST` | For an app or a static site that is not internal. | | `DATABASE_URL` | With a `postgres` service. | | `REDIS_URL` | With a `redis` service. | | `MYSQL_URL`, `QDRANT_URL`, `NEO4J_URI`, `NEO4J_USER`, `NEO4J_PASSWORD` | With that service. | | `_URL` | For a worker that listens on a port. | | `HF_HOME` | With `[models]`. | When a service entry has a name other than its type, its keys get the name in front, like `ANALYTICS_DATABASE_URL`. You cannot set a key ox provides yourself; to use your own database, remove the service from ox.toml. The [config reference](https://deploywithox.com/docs/config#variables) has the full rules. ## Which secrets are hidden in logs In run logs and in your app's logs, ox replaces these with `[redacted]`: - Every value of yours that is 6 characters or longer, and each line of a value with many lines. A shorter value like `true` stays, or it would break up every line it matched. - Values ox provides that hold a secret, like a database password or a `DATABASE_URL`. - The credentials ox uses itself, such as for git and your S3 bucket. A value that is a path, like `/var/lib/data`, stays visible, because a path carries no secret and often explains a failure. ## Variables at build time and run time ox does not split them. Your install, build and migrate steps get the same variables your app gets, including the keys ox provides, except `PORT`. They also get `CI=true`. So a variable you set is there both when the app builds and when it runs, and a change goes live at the next deploy. ## Variable history and restoring an old version Every save is a new version, and ox keeps the last 20, plus any version a kept release uses. In the dashboard, open **History**, then **Compare with now** and **Restore this version**. From a terminal: Go back to an older version: ```sh ox vars history shop ox vars restore shop 12 ``` The restore shows what it changes and asks first; `--yes` skips the question. A [rollback](https://deploywithox.com/docs/operate/rollback#variables) can bring back a release's variables too. ## If a variable does not work - **The deploy says** `set these before deploying: SECRET_KEY`: set that key, then deploy again. [Build failed](https://deploywithox.com/docs/troubleshooting#build-failed) shows the whole message. - `STRIPE_KEY=… on the command line would stay in your shell history`: run `ox vars set shop STRIPE_KEY` and type the value when asked. - `DATABASE_URL: provided by ox; remove your value`: delete your own value, or remove the service from ox.toml to use your own. - **The app still sees the old value:** you saved with `--no-deploy` or **Save, deploy later**. Deploy to make it live. Last updated 2026-10-08. The page as HTML: https://deploywithox.com/docs/operate/variables