Introduction

Branch your data
Native Iceberg branch refs — a copy of a 5M-row table costs under 10 ms and zero bytes. Only the change’s blast radius.
Diff the rows
Keyed row-level diffs with live progress — added, removed, changed — against the branch point or main.
Promote, never merge
Fast-forward when your pinned inputs still match main; a scoped re-run when they don’t. No three-way data merges, ever.
DuckDB or Spark
Embedded DuckDB by default; the Spark engine behind the same interface when transforms outgrow a single node.
The problem
Section titled “The problem”Data teams can’t safely try things. Four gaps compound:
- Environments are all-or-nothing. A staging warehouse is a copy of everything, so it’s expensive enough that you share it — and then you queue behind everyone else’s experiments.
- Test inputs drift. By the time your change finishes running against staging, prod has ingested three more hours of data. Your diff is against a world that no longer exists.
- “What rows does this change?” has no answer. Code review sees the SQL; nobody sees the 300 rows the new filter silently drops.
- The modern stack almost had this. Iceberg made branching possible (native branch refs, on any compliant catalog) — but nothing made it usable. You shouldn’t need to run a new catalog server to get a branch.
Reble is the workflow layer on top of that last point: scoped branches, deterministic inputs, row-level diffs, and a promote you can trust.
Is this you?
Section titled “Is this you?”- You need to add a column to a mart 40 models depend on, and the five-minute SQL change costs a week of verification.
- A filter change silently dropped 300 rows and nobody caught it in review.
- Testing anything means queueing for the one staging warehouse everyone shares.
- A backfill means scripts, a maintenance window, and hoping the snapshot was from the right moment.
The loop
Section titled “The loop”pip install reblereble init --catalog sql --namespace analytics # local catalog, no infra
git switch -c fix-orders # branch in git…# ...edit models/stg_orders.sql...reble run # …and the warehouse follows: a zero-copy data # branch of exactly the tables you touchedreble diff # rows, not lines: +1,204 -0 ~312 changedreble status # un-run edits, drifted pins, branch agereble promote # fast-forward main — or a scoped re-run with a # fresh diff if main moved. No merge. Ever.That’s the whole product. Walk it end to end in the Quickstart, understand it in one page with How Reble works, or see what it replaces in your stack in Comparisons.
Where it sits
Section titled “Where it sits”Reble owns the transformation layer (the shape dbt-core has); your scheduler owns when; your catalog and bucket stay yours. State lives in SQLite locally or in Postgres for shared teams — one config line.
What makes it different
Section titled “What makes it different”A branch is metadata only. The tables you’re changing get zero-copy Apache Iceberg branch refs; the upstream inputs are pinned with Iceberg tags at the moment you run, so your inputs hold still while you iterate — even while production keeps ingesting. Branching costs nothing until you write.
There is deliberately no merge. Promote is a fast-forward when your pinned inputs still match production, and a scoped re-run when they don’t. Data merges with conflict resolution silently corrupt warehouses; Reble refuses to build one. The full argument is in where the git analogy breaks.
And it runs against the catalog you already have — Glue, Polaris, Nessie, Hive, or any REST-compliant Iceberg catalog. Reble is not a catalog, not an orchestrator, and not a new thing to operate. How that stacks up against lakeFS, Nessie, and warehouse clones: Comparisons.