Database Branching for AI Agents: PostgreSQL Copies in Milliseconds, Not Minutes

Database Branching for AI Agents: PostgreSQL Copies in Milliseconds, Not Minutes

• By , founder of Solanica and maintainer of OpenEverest (CNCF Sandbox)

When developers need a database, they get it from some kind of DBaaS: a managed cloud service, a ticket to the DBA team, or a private platform such as OpenEverest. Usually a development database starts from a backup: the schema plus some data, obfuscated if it contains PII. How long that takes depends on the infrastructure and the amount of data. With a few gigabytes it takes minutes, sometimes tens of minutes. Without a DBaaS, it takes hours.

Now give those developers AI agents, or make the agents the developers. They call the DBaaS API, or a script you wrote, and each agent gets a database of its own. That works for one agent. For hundreds or thousands it means hundreds or thousands of instances: compute and storage for each, which is a large bill in the cloud and wasted hardware on-prem. And an agent that waits 15 minutes for its database spends most of its time waiting: the database becomes the bottleneck.

That’s why “agentic databases” and “databases for AI agents” are suddenly everywhere. The usual way of handing out databases is too slow and too expensive for agents.

Agents branch the app database: one passes its tests and is promoted, one makes a mistake and its branch is deleted, one is reset, passes and is promoted

What an agent needs from a database

Agents work in loops. They try something, check the result, throw it away and try again. A database that fits that loop has to be:

  • Instant. A copy of production-sized data in seconds, not minutes.
  • Cheap. A copy costs nothing until it changes. Most agent copies change very little.
  • Disposable. Created and deleted by an API call or a manifest, with no ticket.
  • Undoable. A save point before a risky step, and a way back to it.
  • Mergeable. When the agent gets it right, and a human agrees, its work becomes the real database.

That’s branching: a writable copy of a database, as of now, that shares its data with the source until either side writes.

A full copy writes every block again; a branch shares the source’s blocks and stores only what changes

Neon made the idea popular for PostgreSQL, built on its own storage engine. We wanted the same experience on standard PostgreSQL, on your own Kubernetes, with the databases you already run through OpenEverest.

What we built

plugin-branching is an OpenEverest plugin. It adds a Branches tab to the instance page: branches, restore points and recent operations in one place.

The Branches tab of an instance in OpenEverest: branches, restore points and recent operations

Everything in the tab is a Kubernetes resource, so an agent, a CI job or GitOps can do the same with a manifest or an API call:

apiVersion: plugin-branching.plugins.openeverest.io/v1alpha1
kind: Branch
metadata:
  name: agent-19
  namespace: team-a
spec:
  instanceRef:
    name: orders            # the PostgreSQL instance to branch
  source:
    database: app
  database: app_agent_19    # the branch, ready in milliseconds

A branch isn’t only a copy. Each one comes with the rest of the loop:

  • Reset: the branch gets a fresh copy of its source, as of now.
  • Restore point: a save point before a risky change.
  • Rollback: go back to a restore point.
  • Promote: the source gets the branch’s data. A restore point is taken first, so a promotion can be undone.

The actions of a branch: Reset, Promote and Delete

The plugin needs neither the superuser nor the application’s credentials. Every request from the UI or API is checked against OpenEverest’s RBAC as the user who made it.

Two kinds of branch

“Branch” can mean two different things, and the plugin does both.

A database branch is a new database in the same server, sharing its disk; an instance branch is a new server whose disk starts from a snapshot of the source’s

A database branch (method: Clone) is a new database in the same PostgreSQL server. PostgreSQL 18 can create a database from another one by asking the file system to clone its files (file_copy_method = clone) instead of copying them. On a file system with reflinks, such as XFS, Btrfs or ZFS, the new database shares every block with the source. No new pods, no new volume, nothing to start:

  • Made in about 0.1 seconds on XFS, whatever the size, so hundreds of branches are cheap.
  • Same credentials. The branch has the same owner as its source, so the application only changes the database name.
  • Shared server. It shares the server’s CPU, memory and connections. It covers one database, and roles are shared with the source.
  • Briefly blocks the source. PostgreSQL copies a database only while nobody else is connected to it, so the source’s sessions are disconnected for the duration of the copy.

An instance branch (method: Snapshot) is a new PostgreSQL instance of its own. Its volume is a copy-on-write snapshot of the source’s: a standby’s when there is one, so the primary isn’t touched. This is the model Neon made popular, with its own compute on shared storage:

  • Its own compute. Its own pods, CPU, memory, configuration and endpoint, with every database and role of the source.
  • No effect on a busy source. The snapshot is taken from a standby.
  • Ready in about 25 seconds, whatever the size.

That’s the honest difference from Neon. Neon separates storage from compute in its own engine, so its compute starts almost at once. An instance branch is a standard PostgreSQL on standard Kubernetes storage, and most of the 25 seconds is that PostgreSQL starting up. In exchange, there’s no new storage engine to run, and the data stays on your volumes.

Instance branches need the right storage under the hood. An instance branch is only as fast and as cheap as the volumes it's made of. Your Kubernetes storage has to snapshot a volume and create a new volume from that snapshot without copying the data: copy-on-write snapshots and clones, exposed through the CSI snapshot API.

We used OpenEBS ZFS LocalPV. Its snapshots and clones are instant, but they live on the node of the source volume, so every instance branch runs on that node. To branch at scale across nodes, use a storage platform with instant, space-efficient snapshots and clones, such as Portworx, Ceph RBD through Rook, or NetApp ONTAP through Trident.

Storage that "clones" a volume by copying it, as some cloud block storage does, gives you a copy, not a branch: minutes per branch, and the full size every time. Database branches don't have this requirement: a file system with reflinks, such as XFS on ordinary block storage, is enough.

Creating a branch: a database into a new database in this instance, or the whole instance into a new instance

Which one to use

You needDatabase brancha new database, same serverInstance brancha new instance, its own server
A database for an agent task or a CI job0.1 s, no new podsworks, but ~25 s and a server each
Hundreds of short-lived copiesnearly freea server for each one
To branch a busy production databasepauses its clients for secondsno effect on the primary
Load tests or heavy queriescompetes with the source for CPUits own CPU and memory
Different configuration or extensionsthe source's settingsits own
A preview environment with its own endpointsame endpoint, another databaseits own endpoint
Every database and roleone databasethe whole instance

In short: database branches for volume and speed, instance branches for isolation. An agent that runs a thousand tasks a day wants database branches. A pull request that needs a preview environment next to a busy production database wants an instance branch.

The numbers

We measured both kinds on a three-node Kubernetes cluster with 4 vCPUs and 8 GB of memory per node:

  • Database: PostgreSQL 18.6 on CloudNativePG, a primary plus a standby, holding a 10 GB pgbench database (70 million accounts).
  • Storage: database branches ran on network block storage formatted as XFS. Instance branches ran on local disks with ZFS (OpenEBS ZFS LocalPV).

Copying 10 GB

HowTimeExtra space
CREATE DATABASE … TEMPLATE (PostgreSQL’s default)86 s+10.3 GB
The same, copying files instead of WAL61 s+10.2 GB
Database branch0.13 s+0 bytes

That’s a few hundred times faster, and the standby clones the branch as well instead of copying it. From kubectl apply to a Ready branch it’s about a second; most of that is Kubernetes noticing.

Ten agents at once

Ten database branches of the 10 GB database, requested at the same moment, were all ready in 6.8 seconds: 100 GB of databases in zero extra bytes. Deleting all ten took 4 seconds.

Every operation, both kinds

How long each operation took on the 10 GB database, with no clients connected:

Time per operation on a 10 GB database: database branches take 0.13 to 2.4 seconds, instance branches 4 to 33 seconds

Branching production

We created an instance branch while the source was serving about 1,450 transactions per second. The branch was ready in 35 seconds, and the source’s clients saw no errors and no pause longer than 84 ms, which is ordinary jitter.

An agent’s loop, end to end

Here’s what we scripted against the 10 GB database. The agent’s task was a schema change: add a column, backfill it and index it.

  1. Branch app into app_agent_19: 0.14 s.
  2. The agent makes a mistake: a DELETE without a WHERE, then a dropped table.
  3. Reset the branch: 0.7 s. The data is back as it is in app.
  4. The agent runs the right migration and its tests pass on the branch. The migration took 71 s; that’s PostgreSQL building an index on 70 million rows, not branching.
  5. A human approves and the branch is promoted: 2.5 s. A restore point of app is taken first. app now has the new column, and the application keeps its connection string.
  6. Changed your mind? Rolling back to that restore point takes 0.4 s.

Where the agent loop’s 75 seconds went: 71 seconds were the migration itself, 3.7 seconds were branching operations

The mistake never reached app, and branching took 3.7 seconds of the loop. The rest was the migration itself.

What to know

  • A database branch briefly blocks its source database.
    • The copy takes milliseconds, but a source under heavy writes first flushes its dirty data to disk. In our tests that meant a 2–8 second pause for that database’s clients.
    • Branch development and staging databases this way, or sources that are idle at the moment. To branch a busy production database, use an instance branch.
  • The storage matters.
    • Database branches are instant on file systems with reflinks: XFS (the default of modern mkfs.xfs), Btrfs and ZFS. On ext4, the default of most CSI drivers, a branch is a full copy.
    • XFS on ordinary block storage is the sweet spot for database branches. On ZFS a cloned database shares blocks in the pool, but counts in full against the volume’s size, on the primary and on every standby. In our tests 39 branches of a 1.5 GB database filled a 10 GB volume and stopped both servers. ZFS volumes are thin-provisioned, so size them for the databases and all their branches: it costs no disk.
    • Instance branches need copy-on-write snapshots and clones in your Kubernetes storage (see Two kinds of branch).
  • Branches aren’t free forever. A branch owns only what it writes. The source’s blocks that change after the branch point stay allocated while the branch exists, so give branches a lifetime.
  • Rolling back or promoting an instance branch restarts the instance. Clients see about 20–35 seconds without service while the volumes are swapped, even with connections still open when it starts.

Where it fits

  • Agent sandboxes. Each task gets a database branch, and the agent can break it freely and reset it in a second.
  • Many agents, one winner. Several agents try different indexes or query rewrites on their own branches. You benchmark them and promote the best one.
  • CI. Each job gets a database with real data and no fixture loading.
  • Preview environments. Each pull request gets an instance branch of its own, deleted when the PR closes.
  • Migration rehearsals. See how long a migration takes, and what it locks, on production-sized data.
  • Incident debugging. Branch production as of now with an instance branch, and dig in without touching it.

Try it

plugin-branching works with PostgreSQL instances on OpenEverest through provider-cloudnative-pg, and with MariaDB instances through provider-mariadb. MariaDB gets instance branches, with replication or Galera, from the same Branches tab; rolling back or promoting a Galera cluster can take several minutes while its nodes resynchronize. The plugin-branching docs cover both kinds of branch, the operations, the HTTP API and the custom resources, and Databases for AI Agents sums up what the plugin does for agents, CI and preview environments.

The plugin is not open source. We’re looking for teams to try it on their own clusters and tell us what their agents, CI and developers need from database branches. If that’s you, let us know.

See Also

Database Branching for Microsoft SQL Server

Database Branching for Microsoft SQL Server

· Sergey Pronin Sergey Pronin

SQL Server runs the systems AI agents could help with most, and has no way to hand them a safe, writable copy. We added SQL Server to our branching plugin for OpenEverest: a branch of a standalone instance or an Always On Availability Group in under 40 seconds, whatever the size, cleaned up so it can’t touch production, plus reset, restore points and rollback.

Redis to Valkey Migration on Kubernetes with RedisShake and OpenEverest

Redis to Valkey Migration on Kubernetes with RedisShake and OpenEverest

· Sergey Pronin Sergey Pronin

OpenEverest can now move a live Redis or Valkey database into a Valkey instance it manages, with a snapshot, ongoing replication and an exact cutover, built on RedisShake. We migrated a 50 GiB Redis cluster and a 150-million-key one while an application kept writing to them, then compared every key on both sides. None were missing or different, every TTL survived, and the same data took 10-20% less memory on Valkey.

CrashLoopBackOff: Why Databases Crash-Loop on Kubernetes and How to Fix It

CrashLoopBackOff: Why Databases Crash-Loop on Kubernetes and How to Fix It

· Sergey Pronin Sergey Pronin

We broke PostgreSQL 18 and MySQL 8.4 on Kubernetes 22 different ways - OOM kills, failed probes, bad Secrets, PVC and disk problems, config typos and version changes - and wrote down exactly what CrashLoopBackOff looked like each time, how to diagnose it in a minute, and which fixes actually work. Several ‘fixed’ pods came back Ready but broken.