Variables

Configuration for your services: service variables, shared variables, and dynamic variables.

Variables are how a service is configured without changing its code. Each one is a key and a value, and the service reads them as ordinary environment variables. Which database to connect to, which API to call, which feature to switch on: all of it lives here rather than in the repository.

A variable belongs to one service. Development and production are separate services in separate environments, so they keep separate variables, which is what lets them point at different databases while running identical code.

Service variables

Open a service and go to its Variables tab. Add a key, give it a value, and save.

Keys start with a letter or an underscore and continue with letters, digits and underscores. DATABASE_URL and _internal are fine, 2fast and my-key are not.

Two conveniences worth knowing about:

  • Paste several at once. Drop KEY=value lines straight into a key field and each line becomes its own variable, so moving a .env file across is one paste rather than twenty.
  • Values are hidden by default. Saved values show as dots until you reveal them, individually or all at once, so a variables tab is safe to have open while screensharing.

Dynamic variables

Databases, key-value stores and buckets each expose a set of variables, such as their hostname, port and credentials. Any service in the same environment can consume them directly.

This means you never have to copy sensitive credentials by hand. You pick the one you want from a dropdown in the dashboard instead, and if a database credential is ever rotated, every service consuming it follows along with no changes on your side.

To create a dynamic variable, open the service's Variables tab, click the link icon in the value field, and pick from the list. Each resource exposes its own set:

ResourceVariables it exposes
PostgreSQLfqdn-uri, host, port, dbname, user, password
Key-value storeuri, host, port, password
Bucketbucket, endpoint, region, accessKeyId, secretAccessKey

fqdn-uri and uri are complete connection strings, which is usually all you need. You can consume one as DATABASE_URL or REDIS_URL and are done. The individual parts are there for libraries that insist on being handed a host and a port separately.

A service can only consume variables exposed in its own environment. A production service cannot reach into development for a value, which is deliberate.

A dynamic variable is read when an instance starts, so a rotated credential reaches the service on its next rollout rather than instantly.

Shared variables

Some values belong to a whole environment rather than one service: an API key three services all need, a log level you want to change in one place.

Set those under the project's Settings, in the Variables section. They belong to the environment you are looking at, so development and production keep separate sets.

A service consumes a shared variable from its own Variables tab, the same way it consumes a dynamic variable. They appear in the picker under Shared.

Build time and runtime

Service variables are available while the service builds as well as while it runs, so anything your build reads, such as NEXT_PUBLIC_* or VITE_* values, is there.

A value read during the build is baked into the image and stays there until the next build. A value read at runtime is picked up on the next rollout, which saving a variable triggers on its own. Editing a build-time variable therefore needs a rebuild before it takes effect.

Keep secrets out of build-time variables that end up in the image. Anything inlined into a client-side bundle ships to every visitor, and anything baked into an image layer is readable by anyone who can pull that image. Read secrets at runtime instead.

What happens when you save

Saving variables restarts the service on the image it is already running. The new instance starts with the new values and only takes over once it passes its health check, so the service keeps answering throughout with no downtime. See rollouts for how that works, and for the exceptions.

Changing configuration never triggers a build. A new image is only made when you deploy, whether that is a push to the tracked branch, the Deploy button in the dashboard, or the CLI. See configuration changes for everything else that behaves this way.

Next steps