branching

a branch is a real, independent copy of a postgresql database. it is independent from the moment it exists — nothing you do to it can reach the original. a 256 mb database copied in 524 milliseconds.

what a branch is

A branch is a second database containing everything the first one contained at the moment you asked. It has its own name, its own connection string, its own credentials, and its own future. Write to it, drop every table in it, run the migration you are frightened of — the parent does not notice and cannot be reached from it.

That is the whole idea, and it is worth being precise about it, because the word “branch” is borrowed from version control and version control does one thing briven does not: it merges. A briven branch is for trying something and then throwing it away, or for promoting by pointing your application at it. There is no path back into the parent.

A branch is a full database in its own right. It occupies a slot against your plan’s branch limit, it appears in your database list, and you connect to it exactly the way you connect to anything else — see connecting.

taking one

Three ways in, all doing the same thing. The API is the one to use from a CI job; the CLI is the one to use from a terminal; the dashboard at /branches is the one to use when you want to see the list while you work.

bash

curl -sS -X POST https://briven.tech/api/v1/databases/$DATABASE_ID/branches \
  -H "Authorization: Bearer $BRIVEN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"pr-421"}'

response · 201

{
  "branch": { "id": "...", "name": "pr-421" },
  "fileCopyMethod": "clone",
  "cloneMilliseconds": 524,
  "terminatedBackends": 3
}

The same thing from a terminal. The CLI reads your key from its own configuration, so the key never appears in your shell history — the cli page covers setting that up.

bash

node cli/briven.ts branches create <database-id> pr-421

what it costs

There are two mechanisms, and which one you get is decided by the tier the parent database runs on. The difference is not academic: one of them briefly disconnects everyone using the parent, and the other does not.

shared tier

PostgreSQL copies the parent with CREATE DATABASE … TEMPLATE … STRATEGY = FILE_COPY, and briven sets file_copy_method to clone. On a filesystem that supports reflinks — XFS formatted with reflink=1, or Btrfs — the two databases then share the same blocks on disk, copy-on-write, and only diverge as you write. That is where the 524 milliseconds comes from. If the filesystem refuses, PostgreSQL falls back to a plain copy, which is slower but correct. The fileCopyMethod field on the response tells you which one you actually got.

The cost you must plan for: taking a branch on the shared tier terminates the parent’s sessions for a moment. PostgreSQL refuses to use a database as a TEMPLATE while anyone is attached to it, and there is no flag that relaxes that. The terminatedBackends field on the response is the count of connections that were dropped. Do not branch a production database in the middle of a busy minute.

dedicated tier

On dedicated, the whole data directory is copied between pg_backup_start() and pg_backup_stop() into its own container. The parent never drops a connection. If branching a live database without a blip is something you need, that is the tier that does it.

listing the branches you have

bash

curl -sS https://briven.tech/api/v1/databases/$DATABASE_ID/branches \
  -H "Authorization: Bearer $BRIVEN_API_KEY"

response

{
  "items": [
    {
      "id": "...",
      "name": "pr-421",
      "parentDatabaseId": "...",
      "parentName": "notes",
      "branchedAt": "2026-08-17T10:46:55.000Z",
      "branchMethod": "clone"
    }
  ]
}

Not paginated. Every entry carries where it came from and how it was made, so a list of branches is also a record of what each one cost to take.

deleting a branch

There is no delete-branch endpoint, and that is not an oversight. A branch is an ordinary database, so you delete it the way you delete an ordinary database.

bash

curl -sS -X DELETE https://briven.tech/api/v1/databases/$BRANCH_ID \
  -H "Authorization: Bearer $BRIVEN_API_KEY"

The one thing that differs: deleting a branch refunds your branch quota rather than your database quota. Delete fifteen branches on pro and you can take fifteen more; your database allowance is untouched either way.

there is no merge

You cannot merge a branch back into its parent. Nothing in briven moves rows or schema from a branch to the database it came from. If the work on a branch is the work you want, promote the branch by pointing your application at its connection string — or replay the migration against the parent yourself.

This is stated plainly because the alternative is worse. A half-working merge that resolves conflicts by guessing would quietly destroy data that somebody else wrote, and an undo you cannot trust is worse than no undo — the same principle history and undo is built on.

limits and refusals

How many branches you may hold at once is set by your plan: one on free, three on starter, fifteen on pro, and unlimited on enterprise. Deleting a branch frees its slot immediately.

Two refusals you should expect to handle. A 409 database_not_ready means the parent is still provisioning or is otherwise not in a state that can be copied — wait and retry. A 409 name_taken means you already have something by that name; branch names live in the same namespace as your databases, because a branch is one.

Next: the rest of the management API is on the api page, connecting to the branch you just made is on connecting, and if all you want is to run one statement against it, that is sql over http. A branch inherits pgvector from its parent, so vector search works on a branch with nothing to install.