Skip to content

Go to the docs contents

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.

View as Markdown

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:

while.yaml
databases:
  - name: main
    version: "17"
    size: 1Gi
    compute: S

What your app receives

Your app receives these environment variables at every deployment:

VariableWhat it holds
DATABASE_URLThe database address, through the connection pooler.
DB_MAIN_URLThe same address, under the database’s name (here main): useful when the project has several databases.
DB_MAIN_USERThe database user.
DB_MAIN_PASSWORDIts 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:

ResourcePriceDetails
S database€5 per database·month0.1 vCPU, 256 MB
M database€17 per database·month0.5 vCPU, 1 GB
L database€65 per database·month1 vCPU, 4 GB
XL database€150 per database·month2 vCPU, 8 GB
Database disk€0.25 per GiB·monthbackups 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

Connect your agent, it takes care of the rest

To paste into your agent

Read while.sh/agents, then deploy my app with while.

Copy the instructions

No account needed to try: your app is live right away. To keep it, sign in.

A project for your company? Talk to the team: hello@while.sh