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:
- Use your framework’s migration tool (Prisma, Drizzle, Ecto, Alembic, etc.).
- Run migrations as part of your build or startup, or as a separate one-off:
await sandbox.exec({ cmd: "npx", args: ["prisma", "migrate", "deploy"] }) - 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 | State | Meaning |
|---|---|
provisioning | MIOSA is creating storage, credentials, and the database runtime. |
running | The database accepts connections. |
stopped | The database was intentionally stopped. Persistent data remains attached. |
restarting | MIOSA is restoring the desired-running database after maintenance or a restart request. |
error | Recovery 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:
- Shared dev DB. Sandboxes and production both point at the production database. Fast iteration, risk of dev work affecting prod data.
- 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
| Tier | Storage | Connections (PgBouncer) | Memory |
|---|---|---|---|
| small | 1 GB | 100 | 512 MB |
| medium | 10 GB | 200 | 2 GB |
| large | 100 GB | 500 | 8 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