Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Branching in Lakebase lets you version, test, and evolve your data environment safely, similar to branching your code in Git. You can instantly create isolated, fully functional branches for development, experimentation, or testing schema changes, without impacting production workloads.
By default, Lakebase creates a single production branch when you create a new project. This is your default branch, meant to house your application's production data.
You can create additional branches as needed to fit your workflow. For example, add a development branch for building and testing, a staging branch for pre-production testing, or create per-developer branches for complete isolation. Each branch operates independently, so changes in a child never affect its parent. With branch reset, you can refresh any child branch from its parent to get the latest schema and data, without data seeding or teardown scripts.
How branches work
Parent-child relationships
Every branch (except the root branch) has a parent. This creates a hierarchy:
production (root branch)
├── staging (child of production)
│ └── feature-test (child of staging)
└── development (child of production)
└── bugfix-branch (child of development)
This hierarchy gives you important isolation: changes you make to a child branch don't affect its parent, and changes to a parent don't automatically appear in children. This isolation extends to Postgres role state and databases as well: roles and databases created, GRANTs and REVOKEs applied, and role attributes modified on one branch have no effect on other branches. When you need updated data from the parent, you can reset the child branch. You can also create branches from any point in the parent's history, which is useful for point-in-time recovery, testing against historical data, or compliance scenarios.
When you create a branch, you choose whether to initialize it from current data or from a specific point in time. See Create a branch for step-by-step instructions and details on each option.
Copy-on-write storage
Lakebase uses copy-on-write technology to make parent-child branching efficient. When you create a new branch, it inherits both the schema and data from its parent, but shares the underlying storage through pointers to the same data. Only when you modify data does Lakebase write new data. This means:
- Your branches appear instantly; the size of your database has no impact on branch creation time
- Creating branches has no performance impact on your production workload
Copy-on-write determines how branches are stored, but how a branch is billed depends on whether it expires. See How branching impacts resource consumption.
production branch child branch (at creation)
┌─────────────────┐ ┌─────────────────┐
│ [Data A] │◄──────│ → Data A │ (shared)
│ [Data B] │◄──────│ → Data B │ (shared)
│ [Data C] │◄──────│ → Data C │ (shared)
└─────────────────┘ └─────────────────┘
After modifying data in child branch:
┌─────────────────┐ ┌─────────────────┐
│ [Data A] │◄──────│ → Data A │ (shared)
│ [Data B] │ │ [Data B'] │ (changed)
│ [Data C] │◄──────│ → Data C │ (shared)
└─────────────────┘ └─────────────────┘
Only changed data is stored separately
Working with branches
Branch reset
Branch reset instantly updates a child branch to match its parent's current state. This is useful when you want to refresh your development or staging branch with the latest data from its parent. The operation completes instantly using copy-on-write technology, and your connection details remain the same.
Branch reset only works one direction (parent → child). To move changes from child to parent, use your standard migration tools to apply schema changes. See Reset a branch for detailed steps and scenarios.
Point-in-time recovery
You can create a branch from a specific point in time within your restore window, which is useful for recovering from data errors like accidental deletions, investigating past issues, or accessing historical data for auditing and compliance purposes. For example, if a critical table was dropped yesterday at 10:23 AM, you can create a branch set to 10:22 AM to extract the missing data. Similarly, you can create branches reflecting your database state at specific dates for financial reconciliations, regulatory audits, or forensic analysis. Unlike branch reset (which updates an existing branch in-place), point-in-time recovery creates a new root branch from historical data while leaving your original branch unchanged and operational. See Point-in-time restore for details.
Special branch types
Default branch
Each Lakebase project is created with a default branch called production, but you can designate any branch as the default. The default branch is exempt from the concurrently active compute limit, ensuring it remains available at all times.
Protected branches
Protected branches have safeguards to prevent accidental changes. They cannot be deleted or reset from their parent, and they're exempt from automatic archival due to inactivity. Protected branches also block project deletion while they exist, ensuring you can't accidentally remove critical infrastructure. In addition, Lakebase prioritizes data for protected branches in its storage cache, prioritizing performance of protected branches over other branches. Each project supports one protected branch. Use protected branches for critical data like production. See Protected branches for details.
How branching impacts resource consumption
With branches, you pay for compute and storage separately.
Compute: Each branch has its own compute that you can scale independently. You pay only for active compute hours. Computes scale to zero when idle. This means a development branch you use occasionally costs far less than running a dedicated development server 24/7.
Storage: How a branch is billed for storage depends on whether it has an expiration:
- An expiring branch is billed only for the data that changes on it. Through copy-on-write, it shares its parent's unchanged data. For example, if you modify 1GB of data on an expiring branch of a 100GB database, you pay for approximately 1GB of storage, not a full 100GB copy.
- A permanent branch, one with no expiration, is billed for its full data size, like an independent database, even when its data differs only slightly from its parent.
Warning
Making a branch permanent means you pay for its full data size, not just the data that changes on it. Setting a branch to never expire is always a deliberate choice: you select Never for Auto-delete when you create the branch, or you remove the expiration from an existing branch. If you only need a short-lived copy, keep an expiration so the branch is billed only for what changes on it. See Branch expiration.
Branch strategies
Here are some common ways teams organize their branches:
Simple (individuals and small teams)
Use your default branch with a single development branch:
production
└── development
Your development branch is where you build new features safely. You can make schema changes, add test data, and experiment without any risk to your production branch. When you're ready, run your tested schema migrations against production (using your migration tool), then reset development to start the next feature with fresh data.
With staging
Add a staging branch for pre-production testing:
production
├── staging
└── development
If you need pre-production testing, maintain a staging branch that mirrors your production branch data. Deploy your application there, run integration and performance tests against realistic data, and gain confidence before going live. Periodically reset staging from production to refresh your test data.
Per-developer branches
Each developer works in complete isolation:
production
└── development
├── dev-alice
├── dev-bob
└── dev-charlie
This pattern prevents developers from interfering with each other's work and allows everyone to test schema changes independently. Each developer can experiment with their own schema changes and data modifications without affecting others, then apply tested migrations to the shared development or production branch when ready.
Note
The staging and per-developer patterns use long-lived branches. A branch with no expiration is billed for its full data size. See How branching impacts resource consumption.
Additional resources
- Manage branches to learn how to create, reset, and delete branches
- Protected branches to safeguard critical branches