# Template variables

Canopod computes a set of variables per worktree and exposes them two ways: as `${VAR}` templates inside
provisioned file values, and as `$VAR` environment variables for setup, migrate, teardown, custom
commands and services.

## Variable reference

| Variable | Value | Available in |
|---|---|---|
| `WT_SLUG` | The worktree's folder name, lowercased, every non-alphanumeric character turned into `_` | templates + commands |
| `WT_INDEX` | The worktree's stable port index (main checkout = `0`) | templates + commands |
| `WT_DB_NAME` | `<repo slug>_<worktree slug>`, the worktree's isolated database name | templates + commands |
| `WT_<ID>_PORT` | A service's effective port, by service **id**, uppercased | templates + commands |
| `WT_<NAME>_PORT` | The same port, by service **name**, uppercased with non-alphanumerics turned into `_` | templates + commands |
| `WT_PATH` | Absolute path to this worktree | commands |
| `WTM_WORKTREE` | Same as `WT_PATH` | commands |
| `REPO_PATH` | Absolute path to the repository's main checkout | commands |
| `WTM_REPO` | Same as `REPO_PATH` | commands |
| `PORT` | This service's own effective port | a service's own command |
| `WM_PORT_<ID>` | Back-compat alias of `WT_<ID>_PORT` | templates + commands |
| `WM_WT_SLUG` | Back-compat alias of `WT_SLUG` | templates + commands |

## Port variable naming

A service's port is exposed under two names, because ids and names serve different audiences:

```
service { id: "srv-19", name: "Server", basePort: 3000 }
  →  $WT_SRV_19_PORT      (by id)
  →  $WT_SERVER_PORT      (by name)
  →  $WM_PORT_SRV_19      (back-compat alias of the id form)
```

The name form exists so a hand-written template can say `${WT_SERVER_PORT}` whatever the internal id
is. Ids generated by the UI, like `svc-19`, never matched what anyone would actually type. The name
form never overwrites an id-based variable, and if two services produce the same name slug, the first
one keeps it.

## Worked examples

### Isolate the database

```jsonc
"keys": { "PG_DB": "${WT_DB_NAME}" }
```

Repository `tooljet`, worktree folder `fix-history-state`, and you get
`PG_DB=tooljet_fix_history_state`.

### Give a service its own port

In the service's command, not in the env:

```sh
npm start -- --port $PORT
```

`$PORT` is that service's own effective port. Use it whenever the process takes a port flag.

### Point one service at another

```jsonc
"keys": {
  "PORT": "${WT_SERVER_PORT}",
  "VITE_API_URL": "http://localhost:${WT_SERVER_PORT}",
  "TOOLJET_HOST": "http://localhost:${WT_FRONTEND_PORT}"
}
```

Cross-service references belong in the provisioned file, since both services need to agree on the value
and the file is the one thing they both read.

### Use the worktree's paths in a command

```sh
# a custom command
cp $REPO_PATH/.env.secrets $WT_PATH/.env.secrets
psql $WT_DB_NAME -c 'select count(*) from users'
echo "provisioning index $WT_INDEX for $WT_SLUG"
```

## How they are computed

The index is assigned (or looked up) before provisioning runs, so `${WT_INDEX}` and every port variable
are already right when the first file is written, and it's persisted immediately.

The database name is derived from the repository id and the worktree folder name. Nothing queries
Postgres to build it.

Ports apply the override first, then `basePort + index × 10`. A service with no `basePort` produces no
port variable at all.

## Common mistakes

> **Names that look right but aren't substituted:**
Only the variables in the table above are interpolated. Names from earlier design drafts,
`${INT_DB_NAME}`, `${INT_SLUG}` and `${WT_SERVICE_PORT}`, are not substituted by the backend and would
land in the file as dead literal text. (`${INT_*}` and `${WT_SERVICE_PORT}` still appear as examples in
the Settings *Insert variable* menu. Prefer the `WT_*` names in this table, which is what the setup
runner actually resolves.)

`$PORT` only means "this service" inside a service command. There's no "this service" in setup or a
custom command, so use `$WT_<SERVICE>_PORT` there.

Templates use `${…}` braces. Commands can use `$VAR` or `${VAR}`, since your shell expands them.

A variable that doesn't exist is left as it is rather than replaced with an empty string, so a typo
shows up in the resulting file instead of silently blanking a value.

---

Canonical page: https://docs.canopod.com/config-variables.html
Product version: 0.5.0
