Skip to content

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.

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.

Terminal window
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-42

Body fields:

  • name (optional) — display name. Defaults to <parent name> (<ref>).
  • region (optional) — region hint, only honored on first create. Defaults to auto.
  • 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.

Terminal window
curl --cookie cookies.txt \
https://api.persql.com/api/namespaces/acme/databases/main/branches
Terminal window
curl -X DELETE --cookie cookies.txt \
https://api.persql.com/api/namespaces/acme/databases/main/branches/pr-42

The database is destroyed and the registry row removed.

Refs must be 1–64 characters, start with an alphanumeric, and contain only A-Z, a-z, 0-9, ., _, -, and /. Examples:

  • pr-42
  • feat/login-redesign
  • release-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.

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.

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; ttlDays auto-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.