Branches
A branch is a schema-only fork of a database that carries a stable
external identifier (a ref — typically a PR number or a git branch
name). It copies the parent’s schema into empty tables; rows are not
copied. The (parent, ref) pair is unique, so a CI pipeline can PUT the
same ref repeatedly and either create the branch the first time or
reset it to the parent’s current schema every other time.
For each pull request:
- First commit:
PUT /branches/pr-42→ branch is forked from parent. - Every later commit:
PUT /branches/pr-42→ branch is reset back to the parent’s current state. - PR closes:
DELETE /branches/pr-42→ branch is gone.
No “is this the first run?” branching in your workflow, no collisions if two jobs race, no manual cleanup of stale forks.
Console
Section titled “Console”Each database has a Branches tab. Click New branch, give it a ref, and PerSQL forks the parent for you. Each row shows the ref, status, fork timestamp, and an optional auto-delete date. Reset and delete actions live next to each branch.
Create or reset a branch
Section titled “Create or reset a branch”curl -X PUT \ --cookie cookies.txt \ -H 'Content-Type: application/json' \ -d '{"ttlDays": 7}' \ https://api.persql.com/api/namespaces/acme/databases/main/branches/pr-42Body fields:
name(optional) — display name. Defaults to<parent name> (<ref>).region(optional) — region hint, only honored on first create. Defaults toauto.ttlDays(optional, 1–30) — branch is auto-deleted after this many days by the daily 04:00 UTC cron. Reset on every PUT.
Returns the branch’s full database row, including branchRef,
forkedFrom, and expiresAt.
List branches
Section titled “List branches”curl --cookie cookies.txt \ https://api.persql.com/api/namespaces/acme/databases/main/branchesDelete a branch
Section titled “Delete a branch”curl -X DELETE --cookie cookies.txt \ https://api.persql.com/api/namespaces/acme/databases/main/branches/pr-42The database is destroyed and the registry row removed.
Ref format
Section titled “Ref format”Refs must be 1–64 characters, start with an alphanumeric, and
contain only A-Z, a-z, 0-9, ., _, -, and /. Examples:
pr-42feat/login-redesignrelease-2026.04
The branch’s slug is derived from the parent’s slug + a sanitized
ref (e.g. main + pr-42 → slug main-pr-42). Slugs collide
gracefully with a short suffix.
What we copy
Section titled “What we copy”Same as a regular fork — schema only:
- Tables, indexes, triggers, and views.
Rows are not copied; the branch starts empty. Seed it with fixtures or a migration.
We also don’t copy:
- Saved queries, migrations history, schedules — those live on the parent and stay there.
- Custom hostnames.
API tokens are workspace-scoped and apply to the branch automatically.
What it costs
Section titled “What it costs”There is no per-branch fee. Branches bill against the same usage meters as any other database:
- Requests / rows read / rows written — only when the branch is queried. An idle branch costs nothing on these meters.
- Storage — metered on what you write into the branch, not the
parent’s data (none of which is copied). A fresh schema-only branch is
near-zero storage and grows only as you seed it;
ttlDaysauto-delete keeps a long-lived preview’s bill bounded. - AI tokens — only if you use the plain English → SQL helpers against the branch.
Because a branch never carries the parent’s rows, branching a large production database is as cheap as branching an empty one.
See also
Section titled “See also”- Forking — the underlying primitive
- PR preview databases — full CI workflow