Deployment
Accessories
Accessories are long-lived support containers that your app depends on but that aren’t part of the rolling application deploy. Think databases, caches, and search indices. wheels deploy boots them once, leaves them alone, and lets you manage their lifecycle independently of the app.
You’ll learn:
- When to use an accessory versus an externally-managed service
- How to declare a Redis or Postgres accessory in
deploy.yml - The independent lifecycle verbs —
boot,reboot,start,stop,logs,remove - How accessories fit into the on-server label and naming scheme
When to use an accessory
Section titled “When to use an accessory”Accessories are convenient, not magical. They’re a good fit when:
- You’re running a single-instance service (one Redis, one Postgres) and managing it alongside the app is simpler than running a managed service.
- Your staging or dev environment shouldn’t pay for managed Redis / RDS.
- You want the database and the app rebuilt together when you tear down an environment (
wheels deploy remove).
Use a managed service — not an accessory — when:
- You need HA, automated failover, or point-in-time recovery.
- The service has its own ops story your team already runs (RDS, ElastiCache, Opensearch Service).
- You’re on Kubernetes and the cluster already has operators for the thing.
Accessories are pinned to one host by default. They’re not a clustering or replication story.
Minimal — Redis
Section titled “Minimal — Redis”accessories: redis: image: redis:7 host: 192.0.2.20 port: 6379wheels deploy accessory boot redis on first deploy. Produces a container named <service>-redis on the named host, published on 6379. From the app side, connect to redis://192.0.2.20:6379.
Postgres with volume and env
Section titled “Postgres with volume and env”accessories: db: image: postgres:16 host: 192.0.2.20 port: 5432 env: clear: POSTGRES_USER: app POSTGRES_DB: myapp_production volumes: - /data/pg:/var/lib/postgresql/dataenv.clear:values becomedocker run -eflags on the accessory container.volumes:persists/var/lib/postgresql/datato the host so the database survivesdocker rm.
Named containers and labels
Section titled “Named containers and labels”Accessory containers are named <service>-<accessory> — the example above yields myapp-db and myapp-redis. Their service= label uses that same combined value (service=myapp-db), not the app containers’ bare service=myapp — so a docker ps --filter label=service=myapp won’t catch them. wheels deploy details still lists them alongside everything else because it inspects each declared accessory container by name rather than relying on the shared label.
Multi-host accessories
Section titled “Multi-host accessories”Declare multiple hosts to run independent copies:
accessories: redis: image: redis:7 hosts: - 192.0.2.20 - 192.0.2.21Each host gets its own independent container. There is no clustering, no replication, no leader election — that’s the accessory’s job. If you need a Redis cluster, either configure it manually across the hosts or run it as a managed service.
Lifecycle verbs
Section titled “Lifecycle verbs”Every accessory has an independent lifecycle, scoped by name:
wheels deploy accessory boot db # first-time installwheels deploy accessory reboot db # stop + remove + bootwheels deploy accessory start db # docker startwheels deploy accessory stop db # docker stopwheels deploy accessory restart db # docker restartwheels deploy accessory details db # docker ps filteredwheels deploy accessory logs db --tail=100 # tail container logswheels deploy accessory remove db # stop + rmPass all instead of a specific name to fan out:
wheels deploy accessory boot allwheels deploy accessory stop allwheels deploy setup does not boot accessories in the current Phase 1 CLI — it’s an alias for wheels deploy, and full first-run orchestration is tracked in #2957. Run wheels deploy accessory boot all explicitly as part of first-run. wheels deploy remove does tear them down.
Accessories and wheels deploy
Section titled “Accessories and wheels deploy”Accessories are deliberately not part of the rolling wheels deploy flow. Running wheels deploy does not restart Redis, does not upgrade Postgres, and does not reboot anything under accessories:. That separation is the whole point — app deploys happen ten times a day, accessory changes happen rarely, and mixing the two is how you accidentally take the database down during a routine rollout.
When you do want to change an accessory — a Redis version bump, a Postgres config reload — run the accessory verb explicitly.