Cartopia

self-hosted · postgresql · control panel

Run your Postgres like a DBaaS.

A control plane for a shared PostgreSQL server. Provision databases, enforce quotas, monitor, and restore — all on your own infra, with a single admin login.

Deploy with docker compose. No telemetry, no SaaS dependency.

databaseslive
  • tenant_app
    12 / 20
  • analytics
    8 / 15
  • reports
    READ-ONLY5 / 10
  • staging
    3 / 10
last sweep · 38s ago4 databases

The lifecycle, from zero to restored.

Four steps, all inside the browser. This is the actual user flow — not a marketing funnel.

  1. 1

    Provision

    One click creates a Postgres database with a dedicated owner role, a generated password, REVOKE CONNECT FROM PUBLIC, schema ownership, and connection + statement limits.

  2. 2

    Connect

    Three modes — transaction pooler (6432), session pooler (6433), direct (5432). Copy-as-.env, recommended pooler flagged. Role passwords are AES-GCM encrypted so they can be shown again.

  3. 3

    Monitor

    Live active connections, cache hit ratio, size vs quota, and pg_stat_statements query performance — slowest, most time, most called.

  4. 4

    Restore

    One-click restore from any backup into a fresh managed database — owner role + metadata provisioned, pg_restore streamed from S3, rolled back on failure.

Built for the work, not the demo.

Every capability here ships today. No roadmapped bullets posing as features.

Provision in one click

Creates a Postgres database with a dedicated owner role, a generated password, REVOKE CONNECT FROM PUBLIC, schema ownership, and connection + statement limits. Returns ready-to-use connection strings for all three pooler modes.

Soft quota enforcement

Per-database storage quota with a warn → read-only → recover state machine. Over-quota databases go read-only automatically and kick live sessions; recover when space drops back under 95%.

healthy68%
warn94%
read-only100%

Hysteresis: enforce at 100%, recover under 95%.

Monitoring

Live active connections, cache hit ratio, size vs quota, and pg_stat_statements query performance — slowest, most time, most called.

cache hit97.5%
connections12 / 20

Backups & restore

Daily scheduled pg_dump -Fc streamed to S3 (MinIO), rolling 7-day retention, one-click restore to a fresh database. Download the raw .dump anytime.

Three connection methods

Transaction pooler, session pooler, and direct — each broken out by host, port, database, username, password, and full connection string. Copy-as-.env, recommended pooler flagged.

transaction · 6432session · 6433direct · 5432

Audit log

Every admin action — database created, role added, password reset, restore, quota sweep — recorded with actor and timestamp.

14:32  db.create    tenant_app
14:28  role.reset   analytics_ro
14:15  backup.now   reports
Bring it up
docker compose up -d
# → metadata DB, dataplane Postgres, PgBouncer, Redis, MinIO
# → open https://localhost:3000 → sign in as admin

npm run db:migrate && npm run db:seed
npm run dev      # control panel
npm run worker   # quota + monitor + backup jobs

Five services, one compose file. Your data stays on your node.

Your data stays yours

Cartopia runs entirely on your own infra. Single admin login, no telemetry, no SaaS dependency, no vendor lock-in. Cross-database isolation is enforced — tenant roles can't connect to other databases or to the maintenance databases.

architecture
CONTROL PLANEBrowserCartopiaNext.jsMetadata DBpostgresDATA PLANEappsPgBouncerpoolerDataplane PGtenant dbs

Bring it up in five minutes.

Clone, compose, migrate, sign in. That's the whole setup.