Skip to content

Branching time-series databases

6 min readBranchingQuestDBInfluxDBTime Series

Short version: you can now fork a running QuestDB or InfluxDB into an isolated, writable copy with its own connection string, in seconds, on Layerbase Cloud or locally with the CLI. That matters more for telemetry than for a users table, because eight months of sensor readings cannot be reseeded from a script, and most time-series maintenance work is operations whose whole job is deleting data. Rehearse the retention rule on the branch, count what survives, throw the branch away.

Database branching stopped being exotic years ago. Neon made "fork the database like you fork your code" normal for Postgres, PlanetScale did it for MySQL, and every preview-deploy workflow since assumes a database can be copied in seconds.

Time-series databases never got the memo. There is no managed QuestDB with branching. InfluxDB Cloud does not offer it. If your telemetry lives in a time-series engine and you want to test a retention change or a new downsampling job, your options are the same as a decade ago: run it against production and hope, or run it against a sample CSV that stopped resembling production months ago.

That gap just closed. QuestDB and InfluxDB both branch on Layerbase Cloud, alongside 14 other engines. Fork a running instance into an isolated, writable copy with its own connection string, do the scary thing to the copy, and delete it.

Why time-series data makes this matter more, not less

The usual argument for branching is convenience. For time-series workloads it is closer to necessity, for three reasons.

The data is unreproducible. A Postgres table of users can be seeded from a script. Eight months of sensor readings, tick data, or request latencies cannot. If a test corrupts it, there is no seed.sql that brings it back. Testing against a copy is the only honest option, and until now making that copy meant a full export and import.

The dangerous operations are routine. Retention policies, downsampling jobs, deduplication settings, partition drops. Time-series maintenance is a steady stream of operations whose entire purpose is deleting data. You want to watch a new retention rule eat 90 days of history on a copy before it runs anywhere real.

The data is big and append-heavy. Copying a 50 GB metrics store to test one query is absurd, which is why nobody did it. A branch on copy-on-write storage shares blocks with its parent, so forking that 50 GB store writes almost nothing and takes seconds. You pay for the blocks you change, not for the copy.

Try it locally first

The Layerbase CLI runs the same branching workflow on your machine. QuestDB speaks the Postgres wire protocol, so the whole loop works with tools you already have:

bash
npm i -g layerbase

lbase create metrics --engine questdb --start
lbase query metrics "CREATE TABLE sensors (ts TIMESTAMP, device SYMBOL, temp DOUBLE) timestamp(ts) PARTITION BY DAY"
lbase query metrics "INSERT INTO sensors VALUES (now(), 'dev-1', 21.4)"

Now fork it:

bash
lbase branch metrics metrics-test
lbase query metrics-test "SELECT count() FROM sensors"
text
count
1

The branch has the parent's data. Now prove it is really isolated:

bash
lbase query metrics-test "INSERT INTO sensors VALUES (now(), 'dev-99', 999.9)"
lbase query metrics "SELECT count() FROM sensors"
text
count
1

The write landed on the branch and the original never saw it. On APFS and other copy-on-write filesystems the fork is instant regardless of size; elsewhere the CLI falls back to a byte copy. lbase branch reset metrics-test re-forks the branch from the parent's current state between test runs, and lbase branch delete metrics-test throws it away.

InfluxDB works the same way. InfluxDB 3 speaks SQL, so lbase create telemetry --engine influxdb --start, write some line protocol, lbase branch telemetry telemetry-test, and query both sides to watch them diverge.

What this looks like in practice

Rehearse the retention change. Branch the metrics store, apply the new retention rule to the branch, whether that is a shorter retention period or a partition drop, and count what survives. If the rule is wrong, you found out on a disposable copy.

Test downsampling against real cardinality. Sample data lies about cardinality, and cardinality is where time-series performance goes to die. A branch has production's real tag explosion in it, so the downsampling job you benchmark against it behaves like it will in production.

Point the staging dashboard at real-shaped data. A Grafana board built against synthetic metrics looks right until real data hits it. Point staging at a branch: real gaps, real spikes, real cardinality, zero risk to the store your alerts read from.

Give every preview deploy its own metrics store. The same branch API drives the Vercel integration and a GitHub Actions workflow, so a pull request can get a disposable fork of the telemetry store the way it already gets a disposable frontend.

In the cloud

Layerbase Cloud runs branch-ready databases on copy-on-write storage, so a branch of a QuestDB or InfluxDB instance is created in seconds, shares its parent's blocks, and costs only what you change. Free includes one branch per database, Solo three, and Pro ten. The branch inherits the parent's credentials and gets its own connection string, and a branch of a 50 GB metrics store that changes one partition costs you one partition.

The mechanics behind branching every engine the same way are covered in Branching with any database. The short version: branching happens at the filesystem, not inside the engine, which is exactly why it was never limited to Postgres.

FAQ

Does InfluxDB Cloud or QuestDB Cloud offer branching?

Neither does. InfluxDB Cloud has no branch or fork primitive, and QuestDB's self-serve cloud is gone entirely, leaving the sales-gated Enterprise and BYOC path. That is the gap this post is about: if your telemetry lives in a time-series engine, the historical answer to "give me a safe copy to test against" was an export and an import.

How long does branching 50 GB of metrics take?

Seconds, on branch-ready copy-on-write storage. The branch shares its parent's blocks and writes only what diverges, so the size of the parent is close to irrelevant to how long the fork takes. Locally, APFS and reflink-capable Linux filesystems behave the same way; on a filesystem without copy-on-write the CLI does a byte copy, which is proportional to size.

Is a branch really isolated from the parent?

Yes, and it is worth proving to yourself in two commands. Insert a row into the branch, count rows on the parent, and the parent's count does not move. The branch inherits the parent's credentials but gets its own connection string, so nothing you do on it reaches the original.

How many branches do I get?

One per database on Free, three on Solo, ten on Pro. In practice you rarely need many at once, because lbase branch reset <name> re-forks an existing branch from the parent's current state, which is usually what you want between test runs anyway.

What should I actually use a metrics branch for?

The four that come up most: rehearsing a retention or partition-drop change before it runs anywhere real, benchmarking a downsampling job against production's real tag cardinality rather than sample data that understates it, pointing a staging Grafana board at data with real gaps and spikes in it, and handing each preview deploy its own disposable telemetry store.

Create a QuestDB or InfluxDB database and branch it. The whole loop, create, fork, break the fork, delete it, takes about two minutes.