Test every migration before it merges

Every pull request gets its own Postgres branch, copied from production or staging. It is created when the pull request opens and deleted when it closes.

  • Copy-on-write

    A branch starts from its parent’s data without copying it.

  • Its own connection string

    Each pull request gets an isolated Postgres database.

  • Deleted on close

    The branch goes away when the pull request merges or closes.

The problem

Schema changes are the ones nobody wants to merge blind

Most teams share one staging database. Access gets limited to a few people, the data goes stale, and seed scripts stop matching production. Two pull requests that both change the schema collide there.

Testing a migration on a real copy of the data means a dump and restore that nobody has time for, so the change gets reviewed against data that does not look like production.

shared test databaserunning checks...
pr/#101
unit
integration
e2e
pr/#102
unit
integration
e2e
pr/#103
unit
integration
e2e
waiting for shared DB lock...

A branch copies no data

Creating a branch does not copy your database. The branch reads its parent’s data and keeps only what the pull request changes, so it is ready in about three seconds with the full schema and rows.

1

Pull request opens

A developer or a coding agent opens a pull request.

2

A database branch is created

The Xata GitHub App creates a branch from the root branch you picked, staging if you have one and production otherwise, and comments the branch name on the pull request.

3

Review against real data

Run the migration on the branch with xata roll migrate and point the app at it. Reviewers see the change against the real schema and real rows.

4

The branch is deleted on close

When the pull request merges or closes, the GitHub App deletes the branch. Nothing is left running.

How copy-on-write branching works
Xata separates Postgres compute from copy-on-write storage. See the architecture.
Set it up

Two ways to set it up

With GitHub

GitHub App or GitHub Actions

Link the repository to a Xata project once and every pull request gets a branch, with no API key stored in GitHub. Use the Actions workflows when you need your own branch names, seed data, or a check that blocks the merge until the migration applies cleanly.
With a coding agent

Let the agent open a PR with a database behind it

When an agent writes the change, it can also create the branch, run the migration against it, check the result and open the pull request. The reviewer gets a pull request that already has a working database.
Coding agents

Your agent can run the whole workflow

Connect the Xata MCP server or install the CLI, and your coding agent can create branches, apply migrations and read schema without touching production.

  • Claude Code
  • Cursor
  • Codex
  • VS Code (Copilot)
  • Windsurf
  • Cline
  • OpenCode
  • Zed
  • Xata for coding agents

    CLI, MCP and agent skills in one place.

    Read the guide
  • MCP server

    Setup for every supported client.

    Connect MCP
Before and after the merge

Real data in review, no downtime in production

  • Real data you are allowed to use

    If production holds personal data, copy it into Xata with masking rules applied and branch pull requests from the masked copy.

    Learn more
  • Ship the migration without downtime

    Rehearse the migration on the branch, then apply it to production with pgroll, which serves the old and new schema side by side.

    Learn more

More branching workflows

  • One branch per preview

    A database for every Vercel and Netlify preview.

    Learn more
  • One branch per CI/CD

    A clean database for every test run.

    Learn more
  • Database Branching

    How Xata branches Postgres.

    Learn more

Give every pull request its own database

Run every migration on a branch with real data before it reaches production.