kisenon

Branches

Copy-on-write Postgres branches in Kisenon — fork-at-LSN, lifecycle, and cascade.

A branch is a pointer to a Log Sequence Number (LSN) in the project's storage. Creating one is an O(1) row insert; it does not copy data. Branches diverge as you write to them, and only the delta is stored.

The model

Every project has a main branch from creation. From main (or any existing branch) you can fork a new branch:

  • At HEAD — the new branch starts from the parent's current LSN.
  • At a specific LSN — the new branch starts from a historical LSN within the parent's WAL retention window. This is the "time-travel" case: you can branch off a point in the past as long as the WAL is still retained.

Reads on a branch fall through to the parent's pages until the branch diverges. Writes record only the delta. The result:

  • A 100 GB project with ten small branches is billed as ~100 GB total.
  • Spawning a branch is sub-second.
  • Branches are disposable. Run a destructive migration, throw the branch away, the parent is untouched.

Naming

Branch names are user-visible labels, scoped to the parent project. Constraints match project names:

  • 1–63 characters.
  • ^[a-zA-Z][a-zA-Z0-9_-]*$.
  • Unique within the project.

The internal branch id (br_<24 hex>) is the stable reference. Use the id, not the name, when scripting against the API; names can be renamed.

State machine

A branch transitions through:

creating → ready → deleting → deleted
  • creating — control plane is registering the branch with the pageserver tenant. Typically sub-second; longer if the pageserver is under load.
  • ready — branch can be attached to endpoints and accept writes.
  • deleting — cascade in progress: every endpoint on this branch is being stopped and removed.
  • deleted — terminal. The row is retained for auditability for a short period, then garbage-collected.

The CLI shows the current state for every branch:

keon branches list --project <project-id>

Create

keon branches create --project <project-id> --name my-feature --parent main

To branch at a historical LSN, pass --parent-lsn <lsn>:

keon branches create \
  --project <project-id> \
  --name pre-migration \
  --parent main \
  --parent-lsn 0/1A2B3C4D

The LSN must be within the project's WAL retention window. If it has been compacted past, the branch creation fails.

Delete

Deleting a branch cascades to every endpoint attached to it:

  1. All endpoints on the branch are stopped and removed.
  2. The branch itself is torn down.
  3. Storage is reclaimed asynchronously by pageserver compaction.
keon branches delete <branch-id>

You cannot delete the main branch of a project — delete the project instead. You can delete any other branch even if it has children; in that case the children are reparented to the deleted branch's parent at the deletion LSN.

  • Projects — what owns the branch.
  • Endpoints — what attaches to a branch to accept client traffic.
  • Concepts — the storage / compute split that makes branches free.