Instant Postgres branching

Create isolated Postgres branches in seconds using copy-on-write storage. Each branch gets independent compute and scales to zero when idle.

  1. Step 01

    Branch in seconds, without copying data

  2. Step 02

    Change schema and data, isolated from the parent

  3. Step 03

    Idle and scale to zero, keeping every change

prod/main
2.4 TB

Creating a branch from the 2.4 TB main database.

Why branching?

Shared staging breaks when development runs in parallel

Shared staging databases

Pull requests, deployment previews, CI runs, and coding agents often change schema and data at the same time. When they share a staging database, those changes collide, tests become unpredictable, and one workflow can break another.

  • A few long-lived databases shared across the team
  • Changes interfere with concurrent workflows
  • Tests depend on data left by previous runs
  • Schema changes require coordination
  • Staging gradually drifts from production

A branch for every workflow

Modern development needs a different model: isolated databases that are created when work begins, run independently, and disappear when the work is done.

  • One isolated database for each PR, preview, test run, or agent
  • Created on demand when work begins
  • Kept only for as long as the workflow needs it
  • Runs independently from every other branch
  • Removed when the workflow ends

What is database branching?

Create a new, isolated Postgres branch from an existing database in about three seconds, regardless of its size. Because Xata separates compute from copy-on-write storage, the branch starts with the parent’s schema and production-like data without copying the full database, then changes independently.

Branch at any size

Create a branch in about three seconds, no matter how large the parent database is.

Production-like data

Start with the parent’s schema and production-like data from the moment it is created.

Copy-on-write storage

Share unchanged data with the parent and store only the blocks that change.

Fully independent

Change schema and data without affecting the parent or any other branch.

How teams use branching

Pull requests

Create a database branch for every PR. Test code against real data before merging.

Preview environments

Give every deployment its own database with real data, no shared staging, no conflicts.

CI & testing

Start every test run from a clean database. No drift, no flaky tests.

Debugging production issues

Reproduce bugs on a production-like branch without touching live data.

Agents & automation

Give every agent its own database. Run in parallel, without multiplying costs.

How copy-on-write branching works

Xata implements data branching at the storage layer. This makes branching extremely fast, even for terabytes of data.

  1. Step 01

    Initial state

    In the initial state, we start with a single branch, the parent branch. The volume associated with this branch is mounted on the PostgreSQL instance. The data is organized into blocks (numbered 1 to 8 in the diagram) and an index is used to keep track of the blocks.

  2. Step 02

    Creating a new branch

    When a new database branch is created, initially only the index is copied. The new child branch references the same data blocks as the parent branch. This is why branching is so fast regardless of the size of the branch, because no significant amount of data is copied at this stage.

  3. Step 03

    Copy only modified blocks

    As writes are received by either the parent branch or the child branch, only the modified blocks are copied. Each branch then references its own copy of those blocks. In the diagram, this has happened for blocks 3 and 6, resulting in significant disk space savings.

Branch-native Postgres
Xata separates Postgres compute from copy-on-write storage, so branching is built into the architecture rather than added on top of traditional database copies.

Separated storage and compute architecture

The Xata platform combines well-known and tested technologies with an innovative storage system to offer a high-performance, scalable, and secure PostgreSQL service.

01

Flexible auto-scaling compute and storage nodes

The PostgreSQL instances run inside a Kubernetes cluster. Because storage is separated, auto-scaling is free to continuously optimize the infrastructure underneath.

02

Logical storage volumes mounted via CSI

A Kubernetes CSI driver is used to mount the logical storage volumes to the PostgreSQL pods.

03

NVMe over Fabrics (NVMe/TCP)

The storage volumes are connected to the PostgreSQL pods via NVMe-oF, which is a high-performance network protocol for block storage.

04

Distributed storage cluster

The storage cluster uses multiple storage nodes (e.g. EC2 instances with either local NVMe drives or EBS drives), and the volumes are automatically distributed across them.

Scale to zero & wake-up

Pay for active branches, not idle environments

Xata branches scale compute to zero when idle and wake automatically when work resumes.

badge 13stg/main-preview-2a3ef
CPU
4 vCPU
RAM
16 GB
Compute
$0.19 / hr

Scale to zero

Idle branches stop consuming compute while their data remains available.

Wake on connect

Branches resume on first connection, with no manual provisioning.

Automate every branch

Create a branch automatically as each workflow starts, and remove it when the work is done.

01

Pull request opens

A developer opens a pull request.

02

Create a database branch automatically

The Xata GitHub App creates an isolated database branch for the pull request.

03

Run tests and previews

Connect CI jobs, migrations, and preview deployments to the branch.

04

Delete the branch when the pull request closes

The Xata GitHub App removes the database branch automatically when the pull request is merged or closed.

A branch for every pull request
Use the Xata GitHub App to create and manage a database branch automatically when a pull request opens, or use GitHub Actions to customize branch creation, configuration, and cleanup inside your existing CI workflow.

Adopt Xata without moving production.

Keep production where it is, or move it to Xata. Either way, every pull request and deployment preview gets its own isolated Postgres branch.

  • Branches from a production clone
  • Production data with built-in anonymization
  • Continuously synced with production
Create a production clone

Give every workflow its own Postgres

Create isolated, production-like branches for every pull request, deployment preview, and coding agent.