PRODUCTS

KEYWORDS

Version Control Database Spotlight: Argon

DumboDB Logo

Here at DoltHub, we think version control for databases is a critical feature that is long overdue. That’s why when we learn about another entry into the field, we get excited. It means more people are seeing the value in version-controlled databases.

Argon is exactly the type of project I’m talking about. Their README sums it up with this:

Argon README: Git for MongoDB, built for AI agents

Three ideas, thirty seconds:

  1. A branch is a pointer, not a copy — created with a metadata write. Checkout separately materializes the data.
  2. checkout turns a branch into a real MongoDB database — pymongo, mongoose, mongosh, indexes, aggregation, transactions: all real, and supported document writes become history while capture is healthy.
  3. Review and recover changes — diff, merge, undo and pin states within the configured retention and capture guarantees.

We’ve been working on DumboDB for the last several months, and it’s a full rewrite of MongoDB’s API without any shared code. We wanted to highlight the Argon project today, and discuss their approach to the problem space. Let’s dive in!

How Argon Works#

Argon does its work by watching a Mongo Replica Set. Argon isn’t a member of the replica set, and it isn’t a database either. It’s a client that reads the replica set’s change stream and records each document change in its own log.

mongod existing database copied once by argon import argon_br_<id-1> argon_br_<id-2> argon_wal wal_log: before + after copies branches, counters, snapshots Argon Go process Argon proxy optional app app one-time import change stream change stream checkout append replay reads, writes reads, writes project~branch
  1. Create a branch: one metadata document is written, and no data moves.
  2. Check it out: Argon rebuilds the branch’s documents in memory from its log, then bulk-inserts them, 1,000 at a time, into a new database argon_br_<id> on your mongod.
  3. Connect: the app talks to that database directly, or through Argon’s proxy, which only renames the database in each request. mongod handles every query.
  4. Capture: argon watch opens a change stream on the database and appends each changed document, before and after, to its log.

Side by Side#

ArgonDumboDB
Query engineStock mongod 6+, run as a replica setIts own, parity-tested against MongoDB 8.0
History unitEvery captured write gets a sequence number; no commitsExplicit commits over a working set, like Git
History retentionargon gc, run on a schedule, deletes history older than the retention window (default 7 days); pins protect chosen pointsEvery commit is kept; dumboGC only reclaims data that no commit or branch references
Branch accessCheckout copies the branch into a new databasedb@branch in the database name, on the same port
Querying the pastRebuilt in memory, with no indexes or aggregationdb@main~1 or db@<hash>, with the full query engine and indexes
MergeChild into parent only; whole-document comparison; one resolution for the whole mergeAny branch into any branch; four merge modes; per-document conflict resolution
What is versionedDocuments only; indexes, validators and collection options are notDocuments and validators
ConsistencyHistory lags the write, and capture can fall behind or have gapsA commit is atomic
Branch storageEach checked-out branch is a full copy in mongodBranches share storage

Branch AND Merge Support#

Here at DoltHub, we are a little particular about what we call a “branch.” Many databases claim that they have branching support, and virtually none of them support merging. Merging is a critical feature if you are going to claim you support branches. Don’t listen to us, listen to Wikipedia:

Branching generally implies the ability to later merge or integrate changes back onto the parent branch.

Argon supports merging, to an extent. You can import an existing database, and from that point forward your copy is fixed in time. The argon_br_<id> database it creates does allow for branch and merge support, which is pretty neat!

The Write-Ahead Log (WAL) in Argon is the source of truth. When you want to show a diff between two branches, Argon uses the events in the WAL to rebuild the full state of each branch, then compares them document by document. The same goes for merging. When you merge one branch into another, it rebuilds three states (the fork point, the source branch and the target branch), works out what happened to each document, and writes the result into the target branch.

Here is a branch and merge in action, on a shop project whose main branch is already checked out and has three products in it:

$ argon branches create price-update -p shop --from main
⚡ Created branch 'price-update' (a metadata write, no data copied)
   Project: shop
   Based on: main
   Ready for instant experimentation!

$ argon checkout -p shop -b price-update
Checked out at LSN 5: 1 collection(s), 3 document(s)
Connection string:
  mongodb://127.0.0.1:27120/argon_br_6af38338d2fdd6e63afb6612?replicaSet=rs0
Run "argon watch" for this branch to capture direct writes into the WAL.

$ argon watch -p shop -b price-update &
Watching for changes (Ctrl-C to stop)...

$ mongosh "mongodb://127.0.0.1:27120/argon_br_6af38338d2fdd6e63afb6612?replicaSet=rs0" --quiet \
    --eval 'printjson(db.products.updateOne({_id: 1}, {$set: {price: 15}})); printjson(db.products.insertOne({_id: 4, name: "teapot", price: 30}))'
{
  acknowledged: true,
  insertedId: null,
  matchedCount: 1,
  modifiedCount: 1,
  upsertedCount: 0
}
{
  acknowledged: true,
  insertedId: 4
}

$ argon diff -p shop -b price-update
Merging price-update → main
  put    products/~argon:bson:DAAAABBpAAEAAAAA
  put    products/~argon:bson:DAAAABBpAAQAAAAA
2 change(s), 0 conflict(s)

$ argon merge preview -p shop -b price-update
Merging price-update → main
  put    products/~argon:bson:DAAAABBpAAEAAAAA
  put    products/~argon:bson:DAAAABBpAAQAAAAA
2 change(s), 0 conflict(s)

Plan 6af3834c3c0ca05da0c91d68 saved (pending).
Apply with: argon merge apply 6af3834c3c0ca05da0c91d68

$ argon merge apply 6af3834c3c0ca05da0c91d68
Merged: 2 change(s) applied.

Benchmarks#

Comparing the performance behaviors of each server highlights how each approach has the expected results based on design goals. DumboDB’s use of Prolly Trees gives it algorithmic benefits when performing diff and merge operations. It may be the case that this is a secondary access pattern compared to regular MongoDB queries, which Argon will be better at given it is Mongo native.

Argon is faster for all of the things you would expect MongoDB to be faster for:

StepDocumentsArgonDumboDB
100 bulk updates on a branch100k25 ms43 ms
10,000 bulk updates on a branch100k2.2 s4.1 s
Point read by _id1M344 µs783 µs
Initial load1M230 s399 s

DumboDB is faster on operations which leverage the shared storage of Prolly Trees:

StepDocumentsArgonDumboDB
New branch to first read10k / 100k / 1M500 / 4,000 / 47,200 ms3 / 3 / 4 ms
Diff10k / 100k / 1M500 / 2,200 / 23,700 ms4 / 4 / 5 ms
Merge10k / 100k / 1M500 / 2,300 / 24,100 ms3 / 4 / 4 ms

For select Mongo operations where Dumbo is slower, you pay about a 2X tax for version control compared to Argon. But with Dumbo you get fast version control at scale: on a million-document database, diff and merge are thousands of times faster than Argon (up to 6,000X), and a new branch is ready to read nearly 12,000X sooner. This is by design.

This makes sense, and it’s why DoltHub and all of its products use Prolly Trees. The operations of diff and merge require storage to be optimized for them. If you have an application which does those operations a lot, DumboDB may be the right choice. If your application branches and merges very rarely, Argon may be a better choice.

Takeaways#

The first takeaway is that version-controlled databases are here and you should use them. Dolt may have been early in the space, but it seems like we are regularly seeing people interested in solving this problem.

Where Argon shines: Full MongoDB compatibility because it is real mongod, it fits beside an existing deployment, it has focused agent tooling (sandboxes, MCP server, SDK, console), and plain reads and writes on a checked-out branch are faster because it’s native MongoDB.

Where DumboDB shines: Branching directly off production. Immediate ability to query on a new branch. diff and merge perform proportionally to the size of the delta.

Join us on our Discord and tell us what you’re building!