Databases & services

A database is a container, not a subscription

Backing services run through the exact same primitives as your app: a pinned image, bind-mounted data, a spot on the internal network. Pick an engine and version, bind an app to it, and Sproobo wires the connection string for you.

The engine catalog

Every service is a pinned, choosable version — never an implicit "latest". Today's catalog:

  • PostgreSQL14 · 15 · 16 · 17
  • MySQL8.0 · 8.4
  • MariaDB10.11 · 11.4
  • Redis7
  • MongoDB7.0 · 8.0. The root user lives in the admin auth database, and a bound app's MONGO_URL always carries ?authSource=admin.

The version list is code-defined and versioned with the control plane, so it evolves — the picker always reflects exactly what's offered today, not this page.

On the roadmap: Elasticsearch is planned as a fast-follow engine (it carries a heavier memory and reindex profile than the others), and a custom-service escape hatch — bring your own image with a bind-mounted data dir — is planned too; neither is shipped yet.

Creating a service

From the dashboard's New service flow, or by having an MCP-native client — an AI agent, an editor connector — call the create_service tool over the same audited API. It's plan-first like every other write: a dry run unless the call carries approve: true, and it needs at least a MEMBER role. The CLI's sproobo services command lists what already exists; it doesn't provision a new one:

sproobo services

How a service actually runs

Provisioning compiles a plan from the same primitives as an app deploy — no separate machinery for databases:

01

Pull the pinned image

The exact engine:version you chose, e.g. postgres:16.

02

Bind-mount the data directory

Under /var/lib/sproobo/services/<id>/data — owner-inspectable, and excluded from any prune or cleanup sweep.

03

Start the container on the internal network

On sproobo-int only, with mandatory memory and CPU limits so one service can't starve the host or its neighbors, and a restart policy that can't race a cleanup sweep.

04

Health probe gates readiness

E.g. pg_isready for Postgres — the service isn't considered up until its probe passes.

The data directory outlives the container.

Because the data directory is a stable bind mount, replacing a service's container means a brief moment of unavailability — never data loss. A version upgrade goes one step further: it restores into a fresh, separately versioned data directory and leaves the previous one intact on the box as a rollback. Stateful containers don't get the side-by-side blue-green swap apps do; the bind mount is what makes the replacement safe.

No published ports, ever

Backing services attach only to the internal sproobo-int Docker network — never -p-published to 0.0.0.0. Apps reach a service by its container DNS name on that same network; there's nothing listening on a public port for anything outside the box to find.

Binding an app to a service

Binding is what turns "a Postgres container exists" into "my app has a DATABASE_URL". From the service's page in the dashboard, bind an app in one click. On the app's next deploy, the service's connection string is injected into its environment automatically — DATABASE_URL for the SQL engines, MONGO_URL for MongoDB, REDIS_URL for Redis — pointing at the service's DNS name on sproobo-int.

Today that connection string carries the service's admin credentials — the ones generated when the service was created — so the bound app has full access to the service, including creating its own databases and schemas. The wiring is resolved fresh on every deploy, so it's reproducible rather than a one-off manual step, and unbinding removes it the same way on the next deploy.

On the roadmap: per-app auto-provisioning — a dedicated database plus a least-privilege user for each bound app, instead of the shared admin credentials — is designed but not yet wired into the product.

Version upgrades are never a bare tag bump

Picking a version at create time is free — but upgrading an existing service is its own gated operation, not a container restart with a new image tag. It requires a verified backup first and runs a dump-and-restore recipe into a fresh, separately versioned instance, so the version you're upgrading from is never touched or overwritten. See Backups & restore for the full mechanics — including why upgrade_service is the one write on the whole platform that can never be pre-approved for automation.

Service caps scale with your plan.

Free keeps 2 services per org, Pro up to 10, and Team and Enterprise are unlimited. See Pricing for the full breakdown.

Next

  • Read the full backup, restore, and upgrade mechanics on Backups & restore.
  • See how a service's injected env reaches your app's build and runtime on Apps & deploys.
  • Read the full trust-boundary and data-ownership model on Security model.