DocsApplications
Environment variables
Application env, linked variable sets, and references to managed database credentials — all resolved when the container is created.
- Layers
- Linked variable sets + secret source + application env
- Applied
- When the container is created, not at build time
- References
- ${{vars.KEY}} · ${{database.<slug>.url}}
The env editor
An application's Environment tab (after Mount) has an Environment variables editor with two modes:
| Mode | For what |
|---|---|
| Per line | One key, one input; values are masked (password input) with a reveal toggle. Good for changing a single value. |
| Text | A free textarea — paste the contents of a .env file as-is. Good for an initial migration. |
Both are stored as KEY=VALUE text, one per line. The API always returns the raw values — masking only happens in the UI.
PORT=3000
NODE_ENV=production
# comment lines are ignored
MESSAGE=values may contain spaces and = in the middle
EMPTY=The tab has its own Save button that saves only the env, so saving other Settings never overwrites it. Viewers see the env without being able to change it.
Secret source (Infisical)
Instead of copying secrets into the env, an application can pull them from Infisical when its container is created.
- Connection: owner/admin add it under Integrations → Secret manager (name, optional URL for a self-hosted instance, the machine identity's Client ID and Client secret). The client secret is stored encrypted and can't be seen again; the test button checks the connection.
- Secret source on the Environment tab: pick the connection, then project ID, environment and path (default
/). View keys lists key names only, never their values. - Reference one secret with
${{secret.KEY}}in the env, or turn on Sync all secrets to the container to pass them all as env. - Values are read when the container is created (deploy, apply config, rollback), not at build time. On a key clash the application's env wins over the secret. Pull request previews don't inherit the secret source.
- If Infisical is unreachable during a deploy, the deployment fails and the old container keeps running.
How env gets merged
- 01variable setsthe linked set environments, in order (lowest)
- 02secret sourceInfisical, when sync is on, overrides it
- 03application envoverrides the same key (highest)
- 04resolve ${{…}}vars, secrets & databases of the same project
- 05containerthe final result goes into the container
- Priority, lowest to highest: the linked variable set environments in their order (a later link wins over an earlier one) < the external secret source (Infisical, when sync is on) < the application's own env. If the same key exists in several, the higher one wins.
- Merging and resolution happen every time the container is created: deploy, rollback, or a recreate triggered by a domain/mount change. Editing a variable set does not change running containers — it applies on the application's next deploy.
- Env is not available at build time. For that, use Build args (non-secret).
References
| Syntax | Resolves to |
|---|---|
${{vars.KEY}} | The merged value of KEY across the application's linked variable set environments (a later link wins), one level deep. See Variables. |
${{secret.KEY}} | One secret from the Infisical source (see above). |
${{database.<slug>.url}} | The managed database's internal connection URL (host = container name). |
${{database.<slug>.host}} | The database container's name, e.g. aoox-db-app-db. |
${{database.<slug>.port}} | The engine's port inside the network (5432, 3306, 6379). |
${{database.<slug>.username}} | Username. |
${{database.<slug>.password}} | Password (redacted in logs). |
${{database.<slug>.database}} | Database name. |
${{database.<slug>.url:<name>}} | Another database on the same server (e.g. one created via a CREATE DATABASE query): same host/user/password, only the database name differs. |
A full example
APP_ENV=production
SENTRY_DSN=https://abc@sentry.example.com/1NODE_ENV=${{vars.APP_ENV}}
SENTRY_DSN=${{vars.SENTRY_DSN}}
DATABASE_URL=${{database.app-db.url}}
REDIS_URL=${{database.cache.url}}
PORT=3000NODE_ENV=production
SENTRY_DSN=https://abc@sentry.example.com/1
DATABASE_URL=postgresql://app_db:s3cr3t@aoox-db-app-db:5432/app_db
REDIS_URL=redis://:s3cr3t@aoox-db-cache:6379
PORT=3000- Databases are only looked up in the same project — an application can't read another project's credentials. The slug is the name shown on the database page.
- Changing the links so that a
${{vars.KEY}}the env references no longer exists is refused with a message naming the key.${{project.KEY}}was renamed to${{vars.KEY}}and is refused. - An unknown reference → 400 when saving Settings; if it only breaks at deploy time (e.g. the database was deleted) → the deployment is
failed. - Rotating a database password → takes effect on the next deploy/rollback, no rebuild needed.
Secrets & logs
- Resolved database passwords and Git tokens are automatically redacted from deployment logs and error messages.
- Other env values are redacted only by the rules in Secret variables (variable sets); don't rely on masking and don't print env to stdout from your application.
- Application env is stored as plain text in aoox's own database; access to the Settings page means access to its values. Variable set values are encrypted at rest and can be protected — see Variables.
Variable sets
Variables shared by several applications (or kept per stage, such as staging and production) live in variable sets: instance-wide groups with their own environments, history, compare/promote and secret flags. On the Environment tab, the Variable sets card links set environments to the application in order; the own env above always wins over them.
Compose stacks
.aoox.env and used as --env-file — a source of ${VAR} interpolation in the compose file, not automatically injected into containers. Pass it through environment: on each service — see Compose stacks.Common pitfalls
| Symptom | Cause & fix |
|---|---|
| New env isn't picked up by the app | No new container yet — deploy or roll back once more. |
| 400 when saving: unknown reference | Wrong database slug, or the database is in another project. |
NEXT_PUBLIC_* / build-time values are empty | Env isn't available at build time. Move it to Build args (if not secret) or read it at runtime. |
| Values carry quote marks along with them | Write it without quotes: KEY=value, not KEY="value". |
Next steps
Found a mistake? Edit this page on GitHub ↗