PostgreSQL databases
A managed PostgreSQL database for your app. Your agent declares it in while.yaml, and while creates it in France, backs it up every day and restores it to a precise moment when needed.
Updated November 9, 2026.
You, to your agent: Add a PostgreSQL database for the bookings.
What your agent writes
Your agent writes it in while.yaml, at the root of your app:
databases:
- name: main
version: "17"
size: 1Gi
compute: S
What your app receives
Your app receives these environment variables at every deployment:
| Variable | What it holds |
|---|---|
DATABASE_URL | The database address, through the connection pooler. |
DB_MAIN_URL | The same address, under the database’s name (here main): useful when the project has several databases. |
DB_MAIN_USER | The database user. |
DB_MAIN_PASSWORD | Its password, kept by while. |
When to use it
For a project’s data: its accounts, its orders, its bookings. Each environment has its database, and other projects can read it (Read another project’s database).
How it works
Each declared database is a managed PostgreSQL database, backed up continuously and restorable to a precise point in time. Your app connects to it through DATABASE_URL, via a connection pooler.
What to know
A database starts at size S (0.1 vCPU, 256 MB, up to 1 GB) with 1 GiB of disk (size). With compute, it moves to M (0.5 vCPU, 1 GB), L (1 vCPU, 4 GB) or XL (2 vCPU, 8 GB), with PostgreSQL and PgBouncer tuned for each size. A size change restarts the database in about fifteen seconds, and plan_deploy says what it costs per month before applying it. The version field chooses PostgreSQL 16, 17 or 18, 17 by default. The database password is kept by while, and reaches the app in its variables.
A database has one instance by default, on a node’s disk: a failure of that node is repaired by a restore. With instances: 2, a second instance, on its own disk, is kept up to date continuously and takes over by itself in case of failure. With the Enterprise plan, production has high availability by default: two instances for a database that declares none, and at least two for a service that does not sleep and has no scale.min, unless the while.yaml declares otherwise. There is no read replica: replica: true is accepted, but reads go to the primary instance.
A production database never goes to sleep. A preview database without activity for 24 hours goes to sleep (Sleep). The database’s log is archived continuously, and a full backup leaves every day, outside the cluster; your agent restores a backup or a precise point in time (Tested backups).
The query_database tool reads the database in SQL under the PostgreSQL role of your identity, so with your permissions on the data. Each read is a read-only transaction of 10 seconds at most, which returns 200 rows and 40 KB by default (2,000 rows at most in short format), and each query is written to the log, without its values. observe_app { view: "database" } shows the most frequent and the slowest queries (pg_stat_statements).
DATABASE_URL goes through PgBouncer in transaction mode: each transaction can take another server connection, shared with the pooler’s other clients, which resets it after each transaction. A session SET therefore only lasts its transaction: set a setting with SET LOCAL, in a transaction. Named prepared statements work, because PgBouncer tracks them. What belongs to a session, such as LISTEN/NOTIFY, a session advisory lock or a temporary table, does not last beyond a transaction.
An app that needs its session, such as Liquibase migrations (Metabase, Keycloak) or Flyway, which take a session advisory lock, or LISTEN/NOTIFY, declares pool: session on its database. The pooler then keeps one server connection per connected client, as long as it stays connected, and accepts no more clients than the database’s size has connections: 20 in S, 60 in M, 100 in L and 140 in XL.
Outside the app, what needs a real session, such as pg_restore, an administration psql or a migration that runs SETs, goes through a task (crons). It receives DB_<BASE>_DIRECT_URL, the address of the primary instance without a pooler, which accepts only a few connections.
Pricing
These prices are the same on every plan, excluding VAT:
| Resource | Price | Details |
|---|---|---|
| S database | €5 per database·month | 0.1 vCPU, 256 MB |
| M database | €17 per database·month | 0.5 vCPU, 1 GB |
| L database | €65 per database·month | 1 vCPU, 4 GB |
| XL database | €150 per database·month | 2 vCPU, 8 GB |
| Database disk | €0.25 per GiB·month | backups included |
| Database high availability | +40% | of the database and disk price |
Your agent’s MCP tools
Your agent handles it with the backup_database, get_environment, observe_app and query_database tools.
Guides
- Deploy a Node.js API and its PostgreSQL database from your AI agent, over MCP
- PostgreSQL behind PgBouncer: Prisma, Django, Rails and your migrations, with your AI agent
- Restore your PostgreSQL database to a precise moment, or from a pg_dump, from your AI agent
- The best managed PostgreSQL hosting in 2026