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.

PostgreSQL gets a 1 GiB /dev/shm ceiling for parallel queries; with a positive resources.memory limit, it gets one quarter of that limit, bounded between 256 MiB and 1 GiB, but never more than half the limit. A zero limit means unlimited. This tmpfs uses memory only as PostgreSQL writes to it, and those pages count against the container’s memory limit.

Managed services get up to 2 minutes to shut down cleanly. The first ob service apply after upgrading recreates every service to install this shutdown window; deploy does so for PostgreSQL services with declared extensions.

Declaring it does not start it. Services live outside the release lifecycle, so ob deploy wires up connections. For services with declared extensions, deploy also converges their configuration and recreates containers when it changes. Apply a service explicitly with:

Terminal window
ob service apply --output ndjson

A running PostgreSQL service keeps its current /dev/shm ceiling until ob service apply recreates it, or deploy does for services with declared extensions.

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"}

PostgreSQL 18 uses ghcr.io/labstack/onebox-postgres:18. No optional extension is installed by default. Declare the extensions the application requires and Onebox installs them in its managed database before application migrations run:

services:
database:
driver: postgres
version: 18
features:
extensions:
pg_trgm: {}
vector: {}

The application does not need a separate CREATE EXTENSION migration. Onebox creates only missing extensions; it never upgrades or removes an installed extension during an ordinary apply. An extension absent from the selected image is reported before application migrations start. A deploy automatically converges a database with declared extensions before running migration jobs.

The PostgreSQL 18 image includes the common built-in extensions plus a curated 2026 set: pgvector, pgvectorscale, PostGIS, pg_cron, pgAudit, pg_repack, pg_partman, and HypoPG. Onebox automatically configures required preload libraries for pg_cron, pgAudit, and pg_stat_statements. Optional PostGIS extensions such as postgis_topology are available through the same declaration.

Use the PostgreSQL extension name in the declaration. For example, the pgvector project provides vector, while pgvectorscale provides vectorscale. Declaring vectorscale automatically establishes its vector dependency:

features:
extensions:
vectorscale: {}

TimescaleDB is not bundled in this first distribution. Its Apache-only package currently creates a maintenance job that repeatedly fails, while its Community package has a license unsuitable for a general customer database image. Use a dedicated TimescaleDB service until the upstream Apache package is clean.

An existing backup-protected PostgreSQL 18 service may still be pinned to the older official image. To migrate it: disable backup while the old project file is still active, add the extension declaration and deploy, then enable backup again:

Terminal window
ob backup disable database --confirm database
# add features.extensions to onebox.yml
ob deploy
ob backup enable database

The off-host backup repository is retained throughout this one-time image transition.

Eleven drivers are supported: postgres, mysql, mariadb, redis, valkey, mongodb, rabbitmq, minio, meilisearch, clickhouse, nats. Anything else is refused with unknown_service_driver; see the driver catalogue.

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. Deploy can recreate PostgreSQL services with declared extensions when their configuration changes; otherwise, deploy and rollback leave services running. Neither removes their volumes.
  • Its credential follows the driver credential contract.
  • 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.