Skip to content
App hosting

Databases

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

View as Markdown

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.

What your app sees
DATABASE_URL=postgres://…

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.

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 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.

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.

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:

SettingWhat happens
Apply on deployThe migration runs as part of every deploy, before the new version takes traffic.
Leave it to meNothing 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.

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.

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.