Intermediate·Lakebase

Projects, branches and point-in-time restore

kept in this browser

How a Lakebase project is organised into copy-on-write branches, each with its own computes, roles and databases, and how expiry, protection, reset and point-in-time restore work on them.

On this page12

What it is

A project is the top-level container of Lakebase: one per application or team, created in the workspace’s region. Inside it, the unit you actually work with is the branch. A branch is a complete, isolated Postgres environment — its own data, its own computes, its own roles, databases and grants — that starts as a copy of another branch.

Every project begins with a root branch called production, which cannot be deleted, holding a database called databricks_postgres.

Why it exists

Anyone who has tested a schema migration against a copy of production knows the cost: dump, restore, wait, pay for a second server, and throw the copy away later if anyone remembers. With data in the tens of gigabytes the copy is already the slow part of the change.

Lakebase branches remove the copy. Because compute and storage are separate, a branch does not duplicate the data: it shares its parent’s storage and records only the pages that change afterwards (copy-on-write). Creating one takes the same time whether the database holds a megabyte or a terabyte. That makes a full copy of production cheap enough to create per pull request, per test run or per developer, and to throw away when it expires.

How it works

The shape of a project

project
└── branch: production (root)
    ├── computes    one primary read-write, optional read replicas
    ├── roles       Postgres roles
    └── databases   databricks_postgres, and any you create
    └── branch: dev (child)
        ├── computes
        ├── roles
        └── databases

A child starts with everything its parent had at that moment — data, roles, databases, grants — and from then on the two are independent. Writes on one are invisible to the other.

Creating a branch

A branch can start from the parent’s current data or from a past point in time within the project’s history window. From the CLI, a creation always states when the branch goes away:

databricks postgres create-branch projects/my-app dev \
  --json '{"spec": {"source_branch": "projects/my-app/branches/production", "ttl": "604800s"}}'

The expiration is one of ttl (a duration), expire_time (a moment) or no_expiry. The maximum is 30 days from now, it can be extended, and when it arrives the branch is deleted, permanently. Expiry is not allowed on a protected branch, on the project’s default branch, or on a branch that has children.

Reset from parent

Reset replaces a child’s data with its parent’s latest state. It is a full overwrite in one direction only, parent to child: whatever was done on the child is lost. Connections drop for a moment, and the connection details stay the same, so an application reconnects to the refreshed data without being reconfigured. A root branch has no parent and cannot be reset.

The intended rhythm is: branch, change, test, reset, test again. Nothing flows back from child to parent; a schema change that passed on a branch is applied to production the same way it was applied to the branch, by running the migration there. The schema diff view helps check that, and compares DDL only, not data.

Protected branches

One branch per project can be protected, normally production. A protected branch cannot be deleted or reset, and it also blocks the deletion of its project and of its computes. It is never archived for inactivity and gets priority in the storage cache. When a child is created from it, roles on the child are given new passwords, so credentials that work on production do not work on a copy of it.

Point-in-time restore

Lakebase keeps a history of changes for every project, between 2 and 30 days, 7 by default. The window applies to the whole project and the history adds to storage.

A restore does not rewind the branch you are looking at. It creates a new root branch from the chosen moment, and leaves the original untouched. You inspect the restored copy, then either move the application to it or copy the rows you need back. A project can have at most three root branches, which caps how many restores can be kept side by side.

Limits worth knowing

LimitValue
Projects per workspace1,000
Branches per project500
Roles per branch500
Databases per branch500
Root branches per project3
Protected branches per project1
Active computes per project20, not counting the default branch
Manual snapshots10

A deleted project is soft-deleted and can be recovered for 7 days; deleting with --purge removes it at once.

Who may do what

Project permissions are CAN CREATE, CAN USE and CAN MANAGE, and by default workspace users have CAN CREATE. These govern the platform objects — projects, branches, computes. What a person can read inside a database is a separate question, answered by Postgres roles and grants on that branch (see Connecting to Lakebase, roles and permissions).

Example

A migration rehearsed on a short-lived branch:

# A copy of production for this change, gone in four hours
databricks postgres create-branch projects/shop pr-482 \
  --json '{"spec": {"source_branch": "projects/shop/branches/production", "ttl": "14400s"}}'

# Run the migration against the branch's compute, then the test suite.
# Something wrong? Put the branch back to production's current data and try again:
databricks postgres reset-branch projects/shop/branches/pr-482

The same branch pattern fits CI: one branch per pipeline run, with a TTL of a few hours so a failed run never leaves a database behind.

Common mistakes

  • Expecting merge. Branches do not merge back. Schema changes reach production by running the same migration there; data changes made on a branch stay on it.
  • Resetting a branch with work on it. Reset is an overwrite, not a rebase. Anything written on the child since it was created or last reset is gone.
  • Leaving branches without expiry. A forgotten no_expiry branch keeps its compute, its storage and its history. Give development branches a TTL.
  • Restoring “in place”. Point-in-time restore creates a new root branch. The application keeps talking to the old one until you point it at the new one.
  • Confusing the two permission layers. CAN USE on a project does not grant SELECT on a table, and a Postgres superuser-like role does not let someone delete a branch.
Report a problem with this page
What kind of problem?

Reports about "Projects, branches and point-in-time restore" go to the maintainer, not to a public thread.

Suggest a resource
What kind?

Nothing appears on the site automatically. A person reads every suggestion, checks the link and writes the note that goes with it.