Skip to content

Add a database

services:
postgres: 17

That is sufficient as a declaration. Onebox supplies the image, a durable volume, a health check, a credential generated on the server, and the connection details your application reads. You supply no password, no port, and no data path.

Declaring it does not start it. Services live outside the release lifecycle, so ob deploy wires up connections but never creates or replaces a service container — that would make every deploy a potential database restart. Apply the service explicitly:

Terminal window
ob service apply --output ndjson

On a host you have not bootstrapped yet, ob bootstrap does this for you. If you skip it on a live application, the next deploy stops at preflight with service "postgres" is not running — start it with ob bootstrap or ob service apply.

The service’s name is its driver unless driver says otherwise, so a second Postgres is:

services:
postgres: 17
events: {driver: postgres, version: 17}
cache: {driver: redis, version: "7.4"}

Eleven drivers are supported: postgres, mysql, mariadb, redis, valkey, mongodb, rabbitmq, minio, meilisearch, clickhouse, nats. Anything else is refused with unknown_service_driver — guessing an image from a name produces a container that starts and stores nothing durable.

A workload that declares needs receives <SERVICE>_URL and its parts: _HOST, _PORT, _USER, _PASSWORD, _DATABASE.

workloads:
web:
role: application
image: ghcr.io/acme/shop:1.4.0
needs:
- {name: postgres, condition: healthy}
services:
postgres: 17

The right-hand side is a connection part: url, host, port, user, password, database. A part the driver does not have — a database on a cache — is omitted rather than written empty.

needs also decides release order when deployment.order is absent.

  • A service outlives every release. It runs in its own Compose project, so no deploy and no rollback can stop it or remove its volume.
  • Its credential is generated on the server, once. Not in your project, not in the generated runtime, not in the digest. Never rotated by a re-apply.
  • Its version binds into the release digest, so a database upgrade under an untouched application cannot pass unnoticed.

Connections own the credential, not the endpoint. Map only the parts you want and author the host yourself:

needs:
- name: postgres
env:
DB_USER: user
DB_PASSWORD: password
env:
DB_HOST: pgbouncer.internal

An application that reads a single connection URL cannot do this, because the URL carries the credential and the credential never travels.

servicesdaemon workload
ImageOnebox picks it from driver + versionYou name it
CredentialGenerated on the server, onceYours to supply
Release couplingOutlives every releaseRecreated on deploy
Connection wiringAutomatic via needsYou wire it
Available for11 drivers onlyAnything containerised

Use a daemon when you need something outside the driver set, or a topology the driver does not provide.

Full field list: services.