Profiles
Choosing which of the 31 services your self-hosted instance actually runs
In this page
The self-hosted stack defines 31 services, but a working instance only needs 13 of them. The rest are opt-in: extra Temporal workers, a workflow dashboard, and the replication pipeline that feeds analytics. A profile is the tag that decides which group you get, set once in the .env file and read by every docker compose command after that.
An empty .env gives you 13 services, which is a complete, usable instance. Three profiles add to that: workers, observability, and full. Name them in COMPOSE_PROFILES and their additions stack.
%%{init: {"flowchart": {"curve": "linear"}}}%%
flowchart TD
accTitle: Three optional profiles stack on top of the always-on core
accDescr: The core stack of 13 services always runs, and the workers, observability and full profiles each add more services on top of it.
C["Core stack: 13 services, always on"] -->|"workers"| W["Six per-queue workers"]
C -->|"observability"| O["Temporal UI and admin tools"]
C -->|"full"| F["Ten PeerDB services"]
The core stack
Thirteen services carry no profile, so they always run:
- Application:
frontend,backend,worker,agentcc-gateway,serving,code-executor - Data layer:
postgres,clickhouse,redis,rabbitmq,minio,temporal,fi-collector
This is a complete instance. You can sign in, send traces, and run evaluations with nothing else enabled.
The profiles
Leave COMPOSE_PROFILES unset and you get those 13. Three profiles exist to add to them, each one independent.
| Profile | What it adds | Total services |
|---|---|---|
workers | Six per-queue Temporal workers | 19 |
observability | Temporal UI and admin tools | 15 |
full | The ten-service PeerDB replication stack | 23 |
Combine them with commas, and the additions stack: COMPOSE_PROFILES=workers,observability runs 21 services, and naming all three runs all 31.
workers
Adds six Temporal workers, each pinned to a single task queue: default, tasks_s, tasks_l, tasks_xl, trace_ingestion, and agent_compass. Each carries its own concurrency limit, so a handful of very large jobs can’t starve everything else. Reach for this when one slow job type is holding up the rest. The per-queue limits are listed under System configuration.
observability
Adds temporal-ui on port 8085 and temporal-admin-tools, a shell with the tctl CLI. Both are for inspecting workflow state when a background job misbehaves. Nothing depends on them, so they’re safe to enable and disable at will.
full
Adds the ten PeerDB services that replicate Postgres tables into ClickHouse through change data capture, covering datasets, prompts, simulation runs, and trace metadata. It’s the heaviest option, roughly doubling your container count, and ./bin/install --full is the shortcut for turning it on during installation.
Stay light and those ClickHouse copies never get written, so the dataset and simulation-run dashboards built on them have nothing to read. Tracing is unaffected either way: fi-collector writes spans straight to ClickHouse, and it’s one of the always-on 13.
Setting a profile
Any of these work. The .env entry is the one that persists.
# Applies to every docker compose command in this directory
COMPOSE_PROFILES=full COMPOSE_PROFILES=workers,observability docker compose up -d docker compose --profile workers --profile observability up -d ./bin/install --full # writes COMPOSE_PROFILES=full into .env A changed profile takes effect on the next docker compose up -d. Containers from a profile you removed are not stopped for you, so take them down first if you want them gone:
docker compose --profile observability down # stop what that profile started
docker compose up -d # bring the rest back on the new set
Where profiles catch people out
full does not mean everything. It adds only the PeerDB stack, taking you to 23 services. It does not enable workers or observability. For all 31, list every profile: COMPOSE_PROFILES=workers,observability,full.
There is no peerdb profile. The PeerDB services are tagged full, so COMPOSE_PROFILES=peerdb matches nothing and silently leaves you on the default 13. Compose reports no error for an unknown profile name.
The all-queue worker always runs. It carries no profile and polls every queue via TEMPORAL_ALL_QUEUES, which defaults to true. Enabling workers does not replace it, so the six dedicated workers run alongside it. Setting TEMPORAL_ALL_QUEUES=false doesn’t take it out of the picture either: the service sets no TEMPORAL_TASK_QUEUE, so it falls back to polling default on its own, overlapping worker-default instead of every queue. The overlap is wasteful rather than harmful, since Temporal hands each task to one worker, but it does mean the default queue gets two pollers and no queue gets none. Leave TEMPORAL_ALL_QUEUES at its default unless you’re running the workers profile.
The dev overlay ignores profiles completely. docker-compose.dev.yml resets the profile tag on all 18 tagged services, so docker compose -f docker-compose.yml -f docker-compose.dev.yml up starts every service unconditionally: all 31, plus two that exist only in the overlay, pgbouncer and docker-proxy, for 33. COMPOSE_PROFILES has no effect in this mode.
A profile is not a launch mode. The choice the first-run screen asks you to make is a launch mode, and it can’t change which services run.
Checking what will run
Both commands read the config only, so they work with the stack down.
docker compose config --profiles # list every profile name
COMPOSE_PROFILES=full docker compose config --services # resolve a profile set to services
Counting the second command’s output is the quickest way to confirm you’re getting what you expect before pulling images.
Dive deeper
Questions & Discussion