# Databases

> A managed Postgres per app — how it is created, backed up, restored and browsed.

Turn a database on when you create an app, or any time afterwards, and Roar creates a Postgres database for it and hands the app the connection string. There is nothing to install, size or connect.

## How your app gets it

The connection string arrives as an ordinary environment variable, `DATABASE_URL`. Almost every framework reads that name already, so most apps need no code at all — and an app that already ran against Postgres somewhere else usually needs no change.

<CodeCard caption="What your app sees">

```bash
DATABASE_URL=postgres://…
```

</CodeCard>

<Note>
**Never paste this into your code.** Read it from the environment. It is rotated when the database moves, and a copy hardcoded in a repository is a copy that stops working — and one that anybody with the repository can read.
</Note>

The database lives **in the same region as the app**. That is an architectural constraint rather than a setting: an app and its database on opposite sides of the world would pay the round trip on every query, and a database in another country is a different answer to a question about where your data is.

## Your first database

1. **Ask for one when you create the app.** On the wizard's Database step, choose **Create a database for me**. Roar creates an empty Postgres database in the app's region and sets `DATABASE_URL` for you.
2. **Let your app create its tables.** A new database has no tables in it. Your app's migrations create them (see [Schema changes](#schema-changes) below), and on an app created with a Roar database they run on the first deploy, before the app takes any traffic.
3. **Check what is there.** After the first deploy, open the app's **Database** tab. The tables you expect should be listed.

If your repository sets up its database with a plain SQL file instead of a migration tool, such as `db/init.sql` or a script in `docker-entrypoint-initdb.d/`, Roar does not run it for you. Turn it into a migration with one of the tools below, or paste it into a `migrate` script in `package.json` that runs it against `DATABASE_URL`.

<Note>
**Roar provides Postgres and nothing else.** An app that also needs Redis, MySQL or MongoDB has to connect to one you run elsewhere. Add its address as an environment variable, the same way as any other setting.
</Note>

## Schema changes

Roar looks in your repository for your app's migration step and shows you what it found before running anything. It recognises:

- **Prisma**, **Drizzle**, **Alembic**, **Django**, **Rails** and **Laravel** migrations
- a `migrate` or `db:migrate` script in `package.json`

You choose when it runs:

| Setting | What happens |
| --- | --- |
| **Apply on deploy** | The migration runs as part of every deploy, before the new version takes traffic. |
| **Leave it to me** | Nothing runs automatically. You press the button when you want it. |

**An app created with a Roar database starts on Apply on deploy.** Its database is brand new and empty, so there is no existing data to protect, and without its tables the app cannot start at all.

**Every other app starts on Leave it to me.** That includes an app that gets its database added later, and an app that uses a database of your own. Applying a schema change to data that already exists is something you decide on, not something that should surprise you. You can change the setting either way on the app's **Database** tab.

## Backups

**Twice a day**, and every backup is copied off the machine that made it. A backup that only exists on the server it came from does not survive the case you keep backups for. The off-site copy is kept for ninety days.

So the most you can lose is the work since the last one — up to twelve hours. If that is too much for what you are building, tell us before you rely on it rather than after.

## Restores

You can see every point your database can be restored to, in the app's **Database** tab. Starting a restore is a **request**, not a button that acts immediately — you ask, and one of our engineers runs it.

That is deliberate, and worth understanding rather than working around: the key that decrypts your backups exists on **no Roar server**. Nothing running in our platform can read your backup archive on its own, which is the property that makes an off-box backup worth having. A one-click restore would mean putting that key somewhere a machine could reach — and then a compromise of the platform would be a compromise of every customer's history too.

Two people, on purpose. In exchange, a restore is a conversation and not instant.

## Browsing your data

The **Database** tab lets you look at what is actually in there without a client, a tunnel or a password:

- **Tables and columns**, read from the live database rather than from your code — so it is what is there, not what you meant.
- **Read queries**, run against it and returned as rows.
- **Row edits**, for fixing one wrong value without writing a migration.

Every edit is **recorded** — what changed, from what, to what, and who did it. A change to live customer data should be answerable afterwards, and asking six weeks later is not the time to discover nobody wrote it down.

<Note>
**Reading and writing are separate permissions.** An API key can be granted `data:read` to query and browse; **editing rows, dropping a database and starting a restore cannot be done with a key at all** — they are console actions by a signed-in person. A key that may deploy your app can never rewrite what is inside it.
</Note>

## When you start paying for it

Your database is set up with your app's first deploy, so your app can connect to it the moment it starts. **You pay nothing for it until that deploy succeeds.** If the first deploy fails, the database waits, unbilled, and the next deploy uses the same one, so you never end up with two.

## Removing one

Deleting an app's database is a console action, and it is not undoable from our side beyond the restore points that already exist. If you are clearing up, take an export first.
