engine: sqlite needs no configuration and is always available. Postgres is for apps that need concurrent writers.

Attach a cluster

Use sslmode=verify-full. The admin URL can create roles and databases; it is the most valuable credential on the host after TINY_SECRET_KEY.

What each environment gets

One role and one database. The role is:
nosuperuser
nocreatedb
nocreaterole
capped at 20 connections
able to reach nothing but its own database — public is revoked on both the database and its schema
The generated password is sealed with TINY_SECRET_KEY before it is stored and is never returned by any API — including to the application, which does not receive a connection string at all.

What the app sees

The app sends SQL over its private link under its workload token. The control plane resolves the token to exactly one environment’s binding. Write the dialect Postgres speaks — $1 placeholders rather than ?:
Value type mapping is in the SDK reference. The one that surprises people is date, which arrives as a calendar-day string on purpose.

Snapshots

Snapshots shell out to pg_dump/pg_restore, so install postgresql-client on the control-plane host if you want tiny archive to capture Postgres data.
Without postgresql-client, archiving an app with a Postgres database will not capture its data. Check this before you rely on archive as a backup path.

Without a cluster

Without TINY_POSTGRES_ADMIN_URL the platform still offers SQLite, and a manifest that asks for Postgres is refused at plan time rather than silently given a different database than the one it asked for.

Not implemented here

Replication and point-in-time recovery are the intended next step and are not implemented in this repository. What you get is one role and one database on the cluster you attached — the cluster’s own durability story is yours to provide.

Testing against a real server

One suite reaches further when you give it somewhere to reach:
Point it at a throwaway cluster whose role may create role and create database. tests/postgres-live.test.ts then runs the hand-written driver against a real server — SCRAM, real type OIDs, real privilege grants — creating and dropping its own databases. It is skipped when the variable is unset.