# Variables

Variables configure your services at runtime. Every variable is a name and a value, encrypted at rest, delivered to your service's environment when it deploys. A variable can be:

- 
- 
-

The console groups connections and aliases under one word — a **reference** — because both draw their value from somewhere else instead of holding one.

## Where variables live

A variable is scoped to a **service**, an **environment**, or a **project**, and a service sees all three — its own, its environment's, and its project's. When the same name is defined at more than one scope, the nearest one wins (service over environment over project), so you can set a project-wide default and override it in a single environment or service.

Manage a service's own variables from the **Variables** tab in its drawer; manage shared ones — project-wide and per-environment — from the project's **Variables** page. Changing a variable needs the editor role or higher — see [Teams & roles](/docs/collaboration/teams-and-roles).

The service's tab has two views. **This service** lists the definitions that live on the service itself; **Merged** shows everything the service actually receives at deploy — each resolved name with the scope it comes from, and the wider definitions it overrides.

Databases never receive variables: a [Postgres](/docs/databases/postgres) or [Redis](/docs/databases/redis) service runs with its own connection settings, and other services read it through a connection variable of their own.

## Sensitive variables

Mark a variable **sensitive** when its value should not be shown casually — a credential, a signing key.

- 
-

Every value — sensitive or not — is **encrypted at rest**: Koo stores ciphertext, never plaintext.

A sensitive value never leaves the environment it was set in. [Clone an environment](/docs/projects/clone-an-environment) and sensitive values you typed don't come across — the clone lists their names, and you re-add each one on the copy so its services see the value. Connection and alias variables do come across, even sensitive ones: they resolve against the clone's own databases and variables, so there is no value to re-type.

## Reference variables

A reference variable draws its value from somewhere else. You name it once and Koo resolves the live value each time the service deploys, so you never copy a credential or a connection string between services. There are two kinds.

### From a database

A **connection** variable reads a database's published connection details. You add it on the consuming service and choose its name — `DATABASE_URL`, say; the value resolves to the database's connection URL by default, or to a single detail like the host. [Connect a database](/docs/databases/connect-a-database) walks through the full flow.

A connection to a credential — the connection URL, the password — is sensitive automatically. Its sensitivity comes from the detail it carries, so you never set it yourself.

```bash
psql "$DATABASE_URL"
```

The host inside the value resolves only on [Koo's private network](/docs/networking/private-networking) — the database is never reachable from the internet.

### From another variable

An **alias** points at another variable by name and resolves to whatever that name resolves to — through the same scope precedence, nearest wins. Use it to expose one value under a second name that a library expects, without defining the value twice.

An alias inherits its target's sensitivity: point at a sensitive variable and the alias is sensitive too. Reading the value — including revealing it — always happens on the variable that actually holds it, never on the alias.

## Import from .env

You can create many variables at once by pasting a `.env` file. Import lives on a service's **Variables** tab — project- and environment-scoped variables are created one at a time from the project's **Variables** page.

1. 
2. 
3. 
4. 
5.

The import never overwrites: a key that already exists in the scope is skipped, so pasting the same file twice is safe. It lands as one atomic batch — either every new key is created or none are — and it follows the same apply rules as any other variable change, described under "When a change takes effect" below.

An import applies a limited number of keys at once. The sheet warns when a paste is over the line and asks you to split it into smaller pastes.

## Deleting a shared variable

A service-scoped change reaches only that service. A project- or environment-scoped variable can reach many services at once, so shared edits show their blast radius first: the console lists the services that actually resolve the name before you save or delete. A service that overrides the name with a nearer definition isn't affected, and isn't listed.

Deleting — or bulk-removing — a project- or environment-scoped variable that services actually use is refused until you confirm that listed impact. Over the [Variables API](/api/variables), the delete is rejected with `variable_in_use` until the request carries `confirmImpact: true`; a service-scoped delete never needs it.

## Batch changes over the API

The batch endpoint applies many changes in one atomic call — a `set` list to create or overwrite, an `unset` list to remove:

```json
{
  "set": [{ "name": "QUEUE_NAME", "value": "jobs" }],
  "unset": ["OLD_FLAG"]
}
```

The batch is deliberately **merge-only** — there is no "replace the whole set" shape. A read is lossy (sensitive values are withheld), so a read → edit → replace cycle would silently drop every sensitive value. A merge cannot express that mistake: keys you don't name are left alone.

Removing a project- or environment-scoped name via `unset` needs the same `confirmImpact` acknowledgement as a delete when services use it.

## When a change takes effect

Variable changes never create a deployment version — the service's image and settings are untouched, and its [deployment history](/docs/deploy/deployments-and-rollback) doesn't grow.

Instead, every service carries a reserved platform variable, `KOO_VARIABLES_REVISION` — a fingerprint of the variable set it receives. When the effective set changes, the fingerprint changes, and the service rolls automatically so its running containers pick up the new values. You cannot create a variable with that name; it is reserved for the platform.

When the roll happens depends on where you make the change:

- 
- 
-

Unlike the service's image and settings, variables are **not** restored by a rollback: rolling back a deployment leaves your current variable values in place.
