Skip to content

Guides

Postgres

Markdown

Create a Postgres database, connect an app or your laptop to it, branch it for an experiment, fork it from a point in time, restore it in place, and set when it sleeps.

A Rytiv database is PostgreSQL 16 on a machine of its own, with its data on a volume and a continuous archive of its write-ahead log. Only apps you attach can reach it, always over TLS. Every database can be branched (a copy-on-write copy of its disk, ready in seconds) and forked (a full copy from its archive, from now or from a moment in the past), so an agent can change a schema without touching the original.

ry postgres create appdb
ry postgres create appdb --size 20 --locale en-US

Your agent uses the tool create_postgres, which never returns the password.

Field Type Default Notes
name string required Like an app name, unique across Rytiv
kind string required postgres
memoryMb integer 1024 128 to 16384
sizeGb integer 10 Size of the data volume, 4 to 500
locale string de-DE ICU locale for sorting and comparing text, such as en-US. Fixed once the database exists.
durability string standard standard: one machine. host-redundant: a standby on a second host (API only; a redundant database cannot be branched or forked).
suspendPolicy object suspend after 300 s When the database sleeps, see Sleep. {"mode": "off"} keeps it always on.

POST /v1/resources answers 201 with name, kind, port, secretKey (DATABASE_URL) and url. The url contains the password and is returned only here; the CLI shows it only with --json. You do not need to store it if you attach the database to an app: the app gets it as a secret.

ry attach appdb --to web
ry deploy web

POST /v1/apps/:name/attach with {"resource": "appdb"} gives the app a managed secret DATABASE_URL. A running machine keeps the environment it started with, so deploy the app again (or stop and start its machine) after attaching. The URL looks like this:

postgres://postgres:<password>@appdb.internal:5432/appdb?sslmode=verify-full&sslrootcert=/etc/rytiv/ca/postgres.crt
  • appdb.internal resolves only inside apps that are attached to the database. Everyone else cannot reach it.
  • The database accepts TLS connections only. The certificate authority is at /etc/rytiv/ca/postgres.crt in every machine, so verify-full works without setup.
  • The database name is the resource name with - replaced by _.

A database has no public address. Open a tunnel with the CLI and connect to the local end:

ry proxy appdb 15432:5432
psql -h 127.0.0.1 -p 15432 -U postgres appdb

The first connection wakes a sleeping database.

A branch is a copy-on-write copy of the database as it is now, taken on its host. It is ready in seconds, takes almost no space at first, and is a database of its own with its own password: writes to the branch never reach the source.

ry postgres branch appdb appdb-try --expires-in 1d
Field Type Notes
name string Name of the new database
ttlSeconds integer Delete the branch after this long, 60 to 2592000 (30 days)
expiresAt string Or: delete it at this moment (ISO 8601). Not together with ttlSeconds.
ephemeral boolean Ready faster, without an archive of its own, and lost if its host fails

The answer is 202 with state: "restoring". Poll GET /v1/resources/:name until state is ready; the CLI waits for you. A database can have up to 15 branches.

This is where an agent changes a schema or tries a migration. Through MCP, create_branch makes one, and execute_sql only writes when you name a branch of the database; on the database itself it runs read-only.

A fork is a full copy made from the database’s archive, on any host. It takes longer than a branch, minutes for a large database, and can start from any moment the archive covers (7 days):

ry postgres fork appdb appdb-yesterday --at 2026-10-19T09:00:00Z

POST /v1/resources/:name/fork takes name, an optional asOf (ISO 8601) and the same ttlSeconds or expiresAt as a branch.

A branch or fork has its own password. Attach it to an app like any database, or fetch its URL once:

curl -X POST "https://api.rytiv.app/v1/resources/appdb-try/url" \
-H "Authorization: Bearer $RYTIV_TOKEN"

The answer is {name, url}. A second call answers 409 with url-handed-out: the URL is handed out exactly once. For the original database, the URL came with the create answer and this route answers 409 with not-a-copy. The CLI asks for it right after a branch or fork is ready and prints it with --json.

ry postgres restore appdb --at 2026-10-19T09:00:00Z

POST /v1/resources/:name/restore with {asOf} puts a database back to that moment. Name, URL and password stay the same; open connections end once, at the switch. The state before the restore is kept as a branch named <name>-old-<timestamp>, or the name you pass as backupName. The CLI asks before it does this; pass --yes in scripts.

PATCH /v1/resources/:name with ttlSeconds or expiresAt sets when a branch or fork is deleted; "expiresAt": null keeps it. Only copies can expire.

ry postgres expire appdb-try --in 12h
ry postgres expire appdb-try --never

A standalone database carries a sleep policy: by default it is suspended after 300 seconds without a running query, an open transaction or traffic, and stopped a day after that; the next connection wakes it. A redundant database never sleeps.

ry postgres sleep appdb --after 10m
ry postgres sleep appdb --off
ry postgres create reports --always-on

PATCH /v1/resources/:name with suspendPolicy changes the rule; {"mode": "off"} keeps the database always on. The policy is stored with the database and shown by ry postgres list; whether a region’s hosts act on it is part of the region’s configuration, so do not build on a database being asleep.

Method Path What it does
GET /v1/resources Your databases, with state (restoring, ready, failed), sourceName and expiresAt for copies. Never a URL.
GET /v1/resources/:name One database
DELETE /v1/resources/:name Deletes the database, its machine and its volume, and detaches it from every app. It cannot be undone.
ry postgres list
ry postgres destroy appdb-try
Status Code When
409 name-taken The name is used somewhere on Rytiv
400 name-reserved The name is reserved for the platform
503 no-capacity No room right now, try again
409 url-handed-out The URL of this copy was handed out already
409 not-ready The copy is still restoring, or failed
409 conflict The database already has 15 branches: delete one, or fork

See Postgres in the API reference for every field, and the CLI reference for every flag of ry postgres.