On this page

Provision

When a project is created with data: { postgres: true }, MIOSA provisions a logical database in a managed Postgres cluster, generates credentials, and injects them as env vars.

const project = await miosa.projects.create({
  name: "Smile Dental",
  data: { postgres: true },
})

// Sandboxes and runtime instances under this project boot with:
// DATABASE_URL = postgresql://user:pass@host:port/proj_xxx

You can also add Postgres to an existing project:

await miosa.projects.dataServices.create(projectId, {
  type: "postgres",
  size: "small",  // small | medium | large
})

Create it your way — API, CLI, or SDK

You don’t need an SDK. The same managed database can be created and used three ways. All of these hit the same API.

Raw API (curl):

# 1. Create a Postgres database
curl -X POST https://api.miosa.ai/api/v1/databases 
  -H "Authorization: Bearer $MIOSA_API_KEY" 
  -H "Content-Type: application/json" 
  -d '{"name": "my-db", "engine": "postgresql"}'
# → { "id": "db_...", "state": "provisioning", ... }   (reaches "running" in ~30-60s)

# 2. Get the connection string once it's running
curl https://api.miosa.ai/api/v1/databases/DB_ID/credentials 
  -H "Authorization: Bearer $MIOSA_API_KEY"
# → { "data": { "recommended_url": "postgresql://user:pass@host:port/miosa_db", ... } }

# 3. Connect with anything that speaks Postgres
psql "postgresql://user:pass@host:port/miosa_db"

Other engines: pass "engine": "mysql", "redis", or "qdrant".

CLI:

miosa db create postgres --name my-db   # create
miosa databases list                     # see them + their state
miosa db connect <id>                    # open a shell to it
miosa db logs <id>                       # tail logs
miosa db backup <id>                     # snapshot
miosa db restore <id> --backup <backup-id>  # restore

SDK (Python example below; TypeScript/Go/Elixir SDKs have the same methods).

Connection management

Use a bounded application connection pool and size it for the database plan. Treat the connection URL returned by the credentials endpoint as authoritative. Do not assume a separate session or transaction pooler unless the returned database configuration explicitly advertises one.

Schema management is yours

MIOSA doesn’t run migrations for you. The recommended workflow:

  1. Use your framework’s migration tool (Prisma, Drizzle, Ecto, Alembic, etc.).
  2. Run migrations as part of your build or startup, or as a separate one-off:
await sandbox.exec({ cmd: "npx", args: ["prisma", "migrate", "deploy"] })
  1. Make migrations backward-compatible (expand → migrate → contract). This keeps rollback working - see Rollback.

Backups

MIOSA supports scheduled backups and on-demand backups stored outside the database runtime. Retention depends on the database plan.

Create an on-demand backup:

miosa db backup <database-id> --json

Restore from a selected backup:

miosa db restore <database-id> 
  --backup <backup-id> 
  --json

Restore replaces database contents. Review the target database and backup ID before confirming the operation.

Lifecycle and recovery

provisioning -> running <-> stopped
                       -> restarting -> running
                       -> error
StateMeaning
provisioningMIOSA is creating storage, credentials, and the database runtime.
runningThe database accepts connections.
stoppedThe database was intentionally stopped. Persistent data remains attached.
restartingMIOSA is restoring the desired-running database after maintenance or a restart request.
errorRecovery did not complete and operator action is required.

During host maintenance, MIOSA preserves the database ID, credentials, persistent volume, bindings, and desired state. A database that was running is restarted and verified before its host returns to active service. An intentionally stopped database remains stopped.

Sandboxed development with the same DB

When you create a sandbox under a project that has Postgres, the sandbox also gets DATABASE_URL - pointing at the same managed database. Two options:

  1. Shared dev DB. Sandboxes and production both point at the production database. Fast iteration, risk of dev work affecting prod data.
  2. Per-environment DB. Production gets one DB, staging/dev get another. Configured via Environments.

Default is (2) once per-environment isolation lands. Until then, sandboxes share the production DB; use schema namespacing or be careful with destructive queries.

Connecting from a sandbox

await sandbox.exec({
  cmd: "psql",
  args: [process.env.DATABASE_URL, "-c", "SELECT 1"],
})

The sandbox’s DATABASE_URL is the same shape the runtime would see in production. Whatever code works in the sandbox works in the deployment.

Limits

TierStorageConnections (PgBouncer)Memory
small1 GB100512 MB
medium10 GB2002 GB
large100 GB5008 GB

Storage, connection, and memory limits depend on the database plan. Inspect the database response and metrics rather than assuming automatic storage growth.

Costs

Postgres pricing is in two parts:

  • Compute - per-hour while the DB is running (always-on by default for production; can be paused for sandboxed dev DBs).
  • Storage - GB-month for data plus WAL.

See Usage & Billing. Per-database metering carries attribution, so platforms can charge back per end-customer.

Bring your own Postgres?

If you’d rather use an external Postgres, just set DATABASE_URL as an env var on the deployment and skip the managed offering:

await miosa.deployments.env.set(deploymentId, {
  environment: "production",
  vars: { DATABASE_URL: "postgresql://...your-external-db..." },
})

MIOSA’s runtime injects whatever you set. The managed Postgres is convenience; bringing your own is supported.

Python SDK

See also

  • Overview — the broader data plane
  • MySQL — if you need MySQL compatibility instead
  • Environments — per-env credentials
  • Rollback — why backward-compatible migrations matter

Was this helpful?