# Databases on Demand | Volcano

URL: https://volcano.dev/solutions/databases

> Create PostgreSQL 16 through 18 databases on demand with Volcano: branch a copy in under a minute, apply row-level security tied to your users, connect with psql or your ORM, and add Superagent backups with point-in-time restore.

## A database whenever you need one

Create real PostgreSQL in a command, branch a copy of it for every pull request, and roll it back when a migration goes wrong.

```console
$ volcano cloud databases create app --region us-east-1 --pg-version 16
app  active  postgresql 18  volcano-db-xs
$ volcano cloud databases migration up --all -d app
001_schema.sql  002_policies.sql  ok
$ volcano cloud databases branches create app pr_482 --ttl 72h
✓ Branch 'pr_482' of database 'app' created
# one command to fork, and it deletes itself in three days
```

## Environments get rationed because databases are a project

When a new database means a provisioning step and someone else's calendar, teams end up sharing one staging environment. Pull requests queue behind each other, a load test poisons someone else's data, and the honest answer to whether a migration is safe is that nobody tried it on real data in isolation.

Volcano databases are created in one command, and any of them forks into a copy-on-write branch of its schema and rows in under a minute. When a copy of production is that cheap, a database per pull request stops being an indulgence. And when a change does go wrong, a restore puts the database back without changing its connection string.

## One command, not a provisioning ticket

*On demand*

Name it, pick the Postgres version and the tier, and it is ready to connect to. It is ordinary PostgreSQL on port 5432 over TLS, so Prisma, Sequelize, TypeORM, psql and pg\_dump work against it without anything to work around.

- Six tiers, volcano-db-xs through volcano-db-2xl
- Compute moves with load inside the tier
- 1 database on Hobby or up to 10,000 on Superagent

Image: A project's databases, each with its own region, version and tier.

## A copy of production per pull request

*Branches*

A branch forks a database's schema, rows, roles and policies behind its own connection string and password. It shares pages with its parent, so it is charged only for what it changes, and it expires on a deadline so nobody has to remember to clean it up. Reset it before each CI run instead of creating a new one.

- Usually forked in under a minute
- Reset to the parent's current data in one call
- Up to 10 branches on Hobby or 25 on Superagent

```console
# name        status   storage    expires in
pr_482      active   12.0 MiB   2d
pr_487      active   0 B        6d
nightly_ci  active   4.0 MiB    23h
# each has its own password; none can reach the parent
```

## The connection knows who is asking

*Access*

Volcano establishes the caller's identity on the connection before your first statement, so auth.uid() resolves inside your policies. One connection string covers migrations, queries on behalf of a signed-in user, and anonymous reads — you choose the access mode when you connect.

- Full access for DDL, migrations and backfills
- As a signed-in user, with policies enforced
- As an anonymous visitor, for public reads

```console
# same database, same query, different caller
full access       → migrations, admin
user 8f1c…        → auth.uid() = 8f1c…
anonymous         → auth.uid() is NULL
policies do the rest
```

## How it works

1. **Create it**: Name it, pick the Postgres version and the tier, and apply plain .sql migrations from volcano/migrations.
2. **Protect it**: Turn on row-level security and write policies against auth.uid() before you expose it.
3. **Branch it**: Fork a branch per pull request or test suite, run the migration there first, and let it expire when you are done.
4. **Back it up**: On Superagent, schedule backups and restore in place, to a backup or to any point in the seven-day restore window.

## Create, branch, migrate, secure, query

### Create and branch

```bash
volcano use my-project

# --region and --pg-version are required; 16 through 18 are available
volcano cloud databases create app --region us-east-1 --pg-version 18

# The string works with psql, your ORM, anything speaking the wire protocol
volcano cloud databases get app --show-connection-string

# A copy for the pull request: its own credentials, gone in three days
volcano cloud databases branches create app pr_482 --ttl 72h
volcano cloud databases branches get app pr_482 --show-connection-string

# In CI, rewind the same branch before each run instead of forking a new one
volcano cloud databases branches reset app nightly_ci --yes

# On Superagent, schedule a nightly backup or restore within seven days
volcano cloud databases backup-schedule set app --frequency daily --hour 3
volcano cloud databases restore app --to 2026-09-22T09:30:00Z
```

### Migrate

```sql
-- Applied in alphabetical order by 'volcano cloud databases migration up'.
-- There is no tracking table, so every statement should be idempotent.

create extension if not exists "uuid-ossp";

create table if not exists projects (
  id         uuid primary key default gen_random_uuid(),
  owner_id   uuid not null,
  name       text not null,
  created_at timestamptz not null default now()
);

create table if not exists tasks (
  id         uuid primary key default gen_random_uuid(),
  project_id uuid not null references projects(id) on delete cascade,
  owner_id   uuid not null,
  title      text not null,
  done       boolean not null default false
);

create index if not exists tasks_project_idx on tasks (project_id);

-- Adding a column later follows the same rule.
alter table tasks add column if not exists due_on date;
```

### Secure

```sql
alter table projects enable row level security;
alter table tasks    enable row level security;

-- auth.uid(), auth.email(), auth.role() and auth.is_authenticated() are
-- installed already, and resolve to whoever opened the connection.
drop policy if exists own_projects on projects;
create policy own_projects on projects
  for all to authenticated
  using (owner_id = auth.uid())
  with check (owner_id = auth.uid());

drop policy if exists own_tasks on tasks;
create policy own_tasks on tasks
  for all to authenticated
  using (owner_id = auth.uid())
  with check (owner_id = auth.uid());

-- Anonymous visitors get an explicit, narrow read instead of nothing.
drop policy if exists public_projects on projects;
create policy public_projects on projects
  for select to anon
  using (name like 'public/%');

-- Migrations connect with full access, which bypasses these policies.
-- Application traffic never should.
```

### Query

```typescript
import { VolcanoAuth } from '@volcano.dev/sdk';

const volcano = new VolcanoAuth({
  apiUrl: process.env.NEXT_PUBLIC_VOLCANO_API_URL!,
  anonKey: process.env.NEXT_PUBLIC_VOLCANO_ANON_KEY!,
});

// Pick the database once, before the first query.
volcano.database('app');

export async function openTasks(projectId: string) {
  // No endpoint behind this. The policy decides what comes back.
  const { data, error } = await volcano
    .from('tasks')
    .select('id, title, due_on')
    .eq('project_id', projectId)
    .eq('done', false)
    .order('due_on', { ascending: true })
    .limit(50);

  if (error) {
    return { tasks: [], error: error.message };
  }

  return { tasks: data, error: null };
}
```

## What changes when a database takes seconds

- **\< 1 min to branch a database**: A copy-on-write fork, charged only for what it changes, so one per pull request is affordable.
- **7 days of restore on Superagent**: Roll back to any moment in that window without having taken a backup first.
- **6 tiers from xs to 2xl**: Size staging and production independently instead of sharing one instance.

## Outcomes

- **A database per pull request**: Branches fork in under a minute and expire on their own.
- **Migrations you rehearse**: Run each migration on a branch before production sees it.
- **A way back**: Restore in place when a change goes wrong, with the same connection string.

## Built on Volcano

- [The database](https://volcano.dev/features/postgres): PostgreSQL 16 through 18 on autoscaling compute, with branches, extensions and direct connections, plus backups on Superagent.
- [Who auth.uid() returns](https://volcano.dev/features/authentication): Sessions Volcano applies to the connection before your first statement.
- [Server-side access](https://volcano.dev/features/edge-functions): Functions read DATABASE\_URL from a project variable and query as the caller or as an admin.
- [Changes as they happen](https://volcano.dev/features/realtime): Subscribe to row events on any table, filtered per subscriber by the read policy.

## Frequently asked questions

### Is this real PostgreSQL?

Yes — version 16, 17 or 18, chosen when you create the database, with 18 as the default. It listens on port 5432 over TLS, so psql, pg\_dump and ORMs like Prisma, Sequelize and TypeORM connect to it the way they would to any Postgres. Querying over HTTP with the SDK is an option, not the only door in.

### Can I connect from my laptop or from CI?

Yes. The string from volcano cloud databases get --show-connection-string works anywhere that can reach the internet over TLS, so local development, CI jobs and GUI clients connect the same way your deployed functions do.

### How do I run a long backfill?

As a durable function that updates one batch per step. A failed batch retries on its own, a crash resumes at the next batch, and a finished batch is never run twice. Migrations themselves are .sql files under volcano/migrations, applied in alphabetical order by volcano cloud databases migration up, so write them to be safe on a second run.

### How many databases can I create?

One database per project on Hobby or up to 10,000 on Superagent, each sized on its own tier from volcano-db-xs to volcano-db-2xl. Branches are counted separately, with up to 10 per database on Hobby or 25 on Superagent.

### Are there automatic backups?

Yes, on Superagent. Set a daily, weekly, or monthly schedule per database, and take a backup by hand whenever you want one. Restoring is in place: the database keeps its connection string, and you can restore to any point in the seven-day window rather than only to a backup you took. Hobby does not include backups or point-in-time restore.

### Can I branch a database from production?

Yes. volcano cloud databases branches create makes a copy-on-write fork of the schema, rows, roles and policies, usually in under a minute. The branch has its own connection string and password, lives for one hour to 30 days, and can be reset to the parent's current data whenever you need a clean slate.

## Get started

Ready to create a database? Create a free account at https://volcano.dev/signup, or have your coding agent follow the setup playbook at https://volcano.dev/setup.md.
