Add Postgres, MySQL, Redis or MongoDB to a project in one click: + Create → Database on the project's canvas, then the one you want. It sits on the canvas beside the apps that use it, set up the way a database should be:
The engine's official image on its current major version: postgres:17, mysql:8.4, redis:7 or mongo:8. A new deploy picks up its patch releases; nothing moves it to a new major version by surprise.
A generated password, kept as a secret. MySQL and MongoDB get a separate root password, so the app's never has root's powers (MongoDB's app user owns its own database, app, and nothing else).
A disk of its own: 1 GB for Postgres and Redis, 2 GB for MySQL and MongoDB, billed by its size ($0.10 a GB a month). Make it bigger as it runs, or let it grow by itself, under Volumes.
Private and always running. Only the project's own services reach it, and it never sleeps, so an app's first query doesn't wait for it to wake.
In the region you choose, where there's more than one: it runs on one server there, and stays there with its disk. See choosing regions.
Backed up from the start: a snapshot every day, the last week of them kept, and a copy off the server where the platform has somewhere to put one.
Connecting an app
Open the database and its Connect tab, choose your app and click Connect. The app gets one variable and is deployed with it:
Database
Variable
Looks like
Postgres
DATABASE_URL
postgres://app:…@postgres:5432/app
MySQL
DATABASE_URL
mysql://app:…@mysql:3306/app
Redis
REDIS_URL
redis://default:…@redis:6379
MongoDB
MONGODB_URI
mongodb://app:…@mongodb:27017/app
What's stored on the app is a reference, ${{postgres.DATABASE_URL}}, not a copy of the URL. The app follows the database: change its password and the app has the new one with its next deploy, and the password is never pasted anywhere it could go stale.
To use it in a variable of your own (a framework that wants the host and port apart, say), reference what you need: ${{postgres.HOST}}, ${{postgres.PORT}}, ${{postgres.POSTGRES_PASSWORD}}.
A second database of the same kind gets a name of its own: postgres-2, with its own password and its own URL.
It's sandboxed like everything else. It runs in a virtual machine of its own, with its own kernel, the same as your apps, and so does its terminal. That matters more for a database than it might seem: whoever has its password can run programs in it (Postgres's COPY … FROM PROGRAM is a shell). It costs a little speed on lots of small writes — a commit takes a couple of milliseconds — and a first start takes twice as long.
Its size. Postgres and Redis get xs (a quarter of a core, 256 MB: $1.50 a month), MySQL and MongoDB m (a core, 1 GB: $6; they hold a lot before they have any data). It never sleeps, so it's billed its size all month. Make it bigger under Scaling if it restarts under load: it's given the new size as it runs.
MongoDB runs on its own, not as a replica set, so it has no multi-document transactions. Mongoose and MongoDB's drivers work as they are; Prisma's MongoDB connector needs a replica set and doesn't, yet.
One server. A database lives on one server, with its disk. There's no replica or automatic failover yet: if that server is down, so is the database, and its snapshots are what bring it back somewhere else.
Coding agents can do the same with the add_database and connect_database tools.