Cosmoner Docs
API Reference

Shared Databases

Multi-tenant database access — provision isolated databases on a shared PostgreSQL cluster.

Overview

Shared Databases let you sell cheap, isolated database access to end-clients on a single DigitalOcean Managed PostgreSQL cluster. Each client gets a dedicated logical database with its own PostgreSQL role and connection pool — completely isolated from other tenants.

Clients connect directly to PostgreSQL using the credentials returned at provisioning time. Each tenant's role is restricted to its own database with REVOKE ALL FROM PUBLIC, so there is no risk of cross-tenant data access.

Architecture

┌─────────────┐     ┌───────────────────┐     ┌───────────────────┐
│ End-Client   │────▶│ PgBouncer Pool    │────▶│ PostgreSQL        │
│ (credentials)│     │ (per-tenant)      │     │ Cluster (shared)  │
└─────────────┘     └───────────────────┘     └───────────────────┘

Tiers

TierMax ConnectionsStorage LimitPool Size
MICRO22 GB3
STARTER35 GB5
GROWTH1020 GB15
SCALE2550 GB30

Management Endpoints

These endpoints require session authentication and project membership.

List tenant databases

GET /v1/projects/:projectId/databases/shared

Returns all active shared database tenants for the project.

Get tenant detail

GET /v1/projects/:projectId/databases/shared/:tenantId

Returns tenant details including connection info.

List tier prices

GET /v1/projects/:projectId/databases/shared/prices

Returns the recurring monthly list price for each tier, sourced from Stripe. Amounts are in minor units (e.g. cents) alongside an upper-case ISO currency code.

Response:

{
  "success": true,
  "data": [
    { "tier": "MICRO", "monthly": 500, "currency": "USD" },
    { "tier": "STARTER", "monthly": 900, "currency": "USD" },
    { "tier": "GROWTH", "monthly": 2900, "currency": "USD" },
    { "tier": "SCALE", "monthly": 9900, "currency": "USD" }
  ]
}

Provision a tenant database

POST /v1/projects/:projectId/databases/shared

Body:

FieldTypeRequiredDescription
dbNamestringyesLogical database name (lowercase, letters/numbers/underscores)
tierstringnoMICRO, STARTER (default), GROWTH, or SCALE
poolModestringnoTRANSACTION (default), SESSION, or STATEMENT

The platform automatically selects an available shared PostgreSQL cluster. The prorated amount is charged to the project's payment method off-session — there is no checkout redirect.

Response: Returns tenant credentials including dbPassword, connectionUri, and optional poolConnectionUri. The password is shown once — store it securely. If the cluster is still being set up, returns { tenantId, status: "PROVISIONING" } instead — poll the detail endpoint until the status becomes ACTIVE.

If the project has no payment method, the request returns 402 with a code of ORG_PAYMENT_METHOD_REQUIRED (you are the biller — add a card and retry) or BILLER_PAYMENT_METHOD_REQUIRED (ask your biller to add one). See Billing → Deploy Payment Errors.

Rotate password

POST /v1/projects/:projectId/databases/shared/:tenantId/rotate-password

Generates a new password for the tenant's database role and returns the new credentials. The old password stops working immediately.

Update tier

PATCH /v1/projects/:projectId/databases/shared/:tenantId/tier

Body:

FieldTypeRequiredDescription
tierstringyesMICRO, STARTER, GROWTH, or SCALE

Deprovision tenant

DELETE /v1/projects/:projectId/databases/shared/:tenantId

Revokes database access and removes the connection pool. The logical database is retained for data recovery.


Connecting as a Client

Clients connect directly to their PostgreSQL database using any standard PostgreSQL client or ORM. Use the credentials returned during provisioning.

Connection string

postgresql://<dbUser>:<dbPassword>@<host>:<port>/<dbName>?sslmode=require

Pool connection string

When a PgBouncer pool is configured, clients can also connect through the pool for better connection management:

postgresql://<dbUser>:<dbPassword>@<host>:<poolPort>/<poolName>?sslmode=require

Example (Node.js)

import pg from "pg";

const pool = new pg.Pool({
  connectionString: "postgresql://tenant_abc:secret@host:25060/tenant_abc_db?sslmode=require",
});

const result = await pool.query("SELECT * FROM users WHERE id = $1", [userId]);

Security

Each tenant's PostgreSQL role is locked down:

  • Database isolationREVOKE ALL ON DATABASE ... FROM PUBLIC prevents access to other tenants' databases.
  • Schema isolationREVOKE ALL ON SCHEMA public FROM PUBLIC within each database.
  • Connection limits — enforced at the PostgreSQL role level per tier.
  • SSL required — all connections require sslmode=require.

On this page