# Databases

Postgres is the platform database. Here is what happens when your AI wrote something else.

Every app that needs a database gets its own Postgres database, reachable only from the app, with a copy taken before each deploy that changes its shape and, on the paid plans, every day.

## If your AI used Postgres

Nothing to do. Drizzle, Prisma, Kysely, TypeORM, Sequelize, Knex or the plain `pg` driver all work: the app receives `DATABASE_URL`. Its database changes run as part of each deploy, before the new version goes live, with the same settings the app runs with. Prisma, Drizzle, Knex (with a `knexfile`), Sequelize (with `sequelize-cli`), node-pg-migrate, db-migrate, kysely-ctl, Alembic, Rails, Laravel (`php artisan migrate`) and Django (`manage.py migrate`, for an app whose settings name a Postgres database) are found by themselves. For anything else, including TypeORM and Kysely's own migrator, put the command in package.json's scripts as `migrate` (or `db:migrate`) and it runs instead.

A Rust app with a Postgres driver (sqlx, Diesel or SeaORM with their Postgres feature, tokio-postgres, deadpool-postgres) gets its database the same way. The copy of the app that runs has no Cargo, so its migrations run from its own program: give it a `migrate` mode that runs them (sqlx's `migrate!()`, Diesel's `embed_migrations!`, refinery or SeaORM's `Migrator`) and exits, and name it in `deploy.json` as `"database": { "migrate": "./bin/<name> migrate" }`. The platform runs it once before each version goes live, after copying the database, as it does for every other stack. Turn the migrator's own lock off (sqlx: `set_locking(false)`): one deploy migrates at a time, and through the connection pool described below a lock can be left held. The platform does this for Prisma by itself.

A Laravel app is given `DB_CONNECTION` and `DB_URL` for its database as well, because Laravel reads those rather than `DATABASE_URL`. A Java app is given `SPRING_DATASOURCE_URL`, `SPRING_DATASOURCE_USERNAME` and `SPRING_DATASOURCE_PASSWORD`, which Spring Boot reads by itself, so it needs no database settings at all, and `JDBC_DATABASE_URL`, `JDBC_DATABASE_USERNAME` and `JDBC_DATABASE_PASSWORD`, the names Heroku uses.

`DATABASE_URL` starts with `postgresql://`, the form every driver reads, SQLAlchemy included (with psycopg 3, write `postgresql+psycopg://`). Drivers that prepare statements, such as Java's, psycopg 3, asyncpg, postgres.js and Prisma, need no special setting. A setting sent while connecting, such as node-postgres's `statement_timeout`, is refused by the connection pool in front of the database: set it inside a transaction with `SET LOCAL` instead. The pool works in transaction mode: between two transactions, or two statements outside one, the app may be on a different connection, so nothing a connection remembers lasts beyond a transaction — a `SET`, a lock taken with `pg_advisory_lock`, `LISTEN`, a temporary table. Take locks with `pg_advisory_xact_lock` inside a transaction, and run migrations the platform's way (once per deploy, above) rather than at every start, where several copies starting together each take a migration tool's lock.

## If your AI used MySQL or MongoDB

The deploy stops with `ENGINE_CONVERSION_REQUIRED` and a fix written for the ORM in use, for example:

> In prisma/schema.prisma change the datasource provider to "postgresql", replace MongoDB-specific attributes with relational equivalents, run `prisma migrate dev --name init`, then re-run deploy.

Your AI does this in a minute or two. It is a mechanical change and the kind of thing it does all day. You will not notice.

Why not just host MySQL and MongoDB? Because doing it well for one app costs more than the whole Personal plan, and the price you pay is only possible because every app speaks the same database.

## If your AI used SQLite

Switch to Postgres before you deploy. Ask your AI: "move this app from SQLite to Postgres".

SQLite keeps everything in a file next to the app. Apps here do not have a disk that survives — the machine running your app is created when someone visits and thrown away afterwards, and there can be several at once. A SQLite file will look like it works while you are testing, then lose what people wrote.

The platform gives every app a Postgres database, included, with backups. It is the same kind of change as the MySQL one above and your AI does it in a minute or two.

## Copies of your data

A copy of the database is taken before every migration and, on the paid plans, once a day. Each copy is kept for 30 days. Getting one back yourself is not available yet; [going back to a version](/docs/versions-and-rollback) puts back the code and keeps today's data.
