Neon's database branching is its most distinctive feature. A branch is an instant copy-on-write clone of your database — schema and data included — that diverges from its parent as you make changes. Create a branch for every pull request, test your migration against real data, and delete it when the PR closes. No separate test database needed.
How Branching Works
Neon branches use copy-on-write: creating a branch is instant regardless of database size because no data is actually copied. Data is shared with the parent until it diverges. This means a branch of a 10 GB database takes milliseconds to create and uses no additional storage until you start writing to it.
Creating Branches
# Install Neon CLI
npm install -g neonctl
neonctl auth
# Create a branch from main
neonctl branches create --name preview/pr-42
# List branches
neonctl branches list
# Get connection string for a branch
neonctl connection-string --branch preview/pr-42
# Delete a branch
neonctl branches delete preview/pr-42Recipe: Automatic Branch per Pull Request (GitHub Actions)
# .github/workflows/preview.yml
name: Preview Database
on:
pull_request:
types: [opened, synchronize]
jobs:
create-db-branch:
runs-on: ubuntu-latest
steps:
- uses: neondatabase/create-branch-action@v5
id: create-branch
with:
project_id: ${{ secrets.NEON_PROJECT_ID }}
branch_name: preview/pr-${{ github.event.pull_request.number }}
api_key: ${{ secrets.NEON_API_KEY }}
- name: Run migrations on branch
run: npx drizzle-kit migrate
env:
DATABASE_URL: ${{ steps.create-branch.outputs.db_url_with_pooler }}
- name: Output branch URL
run: echo '${{ steps.create-branch.outputs.db_url_with_pooler }}'# .github/workflows/cleanup.yml
name: Cleanup Preview Database
on:
pull_request:
types: [closed]
jobs:
delete-db-branch:
runs-on: ubuntu-latest
steps:
- uses: neondatabase/delete-branch-action@v3
with:
project_id: ${{ secrets.NEON_PROJECT_ID }}
branch: preview/pr-${{ github.event.pull_request.number }}
api_key: ${{ secrets.NEON_API_KEY }}Testing Migrations Against Real Data
The critical value of database branching for AI applications is testing schema changes and new embedding pipelines against real production data — without touching production.
- Create a branch from main (inherits all production data)
- Point your migration script at the branch connection string
- Run the migration — adds new columns, changes types, reindexes embeddings
- Test your application against the branch
- If anything breaks, delete the branch — production is untouched
- Once verified, run the same migration against production main
For embedding schema changes (different model, different dimensions), branching lets you re-embed all documents on a copy of your data before committing to the change in production.Using Branches for Staging Environments
Create a long-lived branch named staging alongside your main branch. Point your staging deployment at this branch. Changes flow: feature branch → staging branch → main (production). The staging branch can be reset to match main at any time.
# Reset staging branch to match main
neonctl branches reset staging --parent main
# This discards all changes on staging and creates a fresh copy of main
# Takes milliseconds regardless of database size| Metadata | Value |
|---|---|
| Title | Neon Database Branching: Isolated Environments for Every Pull Request |
| Tool | Neon |
| Primary SEO keyword | neon database branching |
| Secondary keywords | neon branch per PR, neon preview environment, neon github actions, neon staging |
| Estimated read time | 7 minutes |
| Research date | 2026-04-14 |