PRODUCTS

KEYWORDS

Why DoltLite?

We shipped DoltLite, a version-controlled SQLite. We already have Dolt. Dolt is free and open source. Dolt clones, branches, pushes, pulls, and merges. Why ship a second product? This article explains.

DoltLite Logo

Local-first Software#

Local-first software, coined by Ink & Switch in 2019, has inspired a lot of software, mostly based on SQLite. SQLite puts the “local” in “local-first”. SQLite delivers complex tabular data and SQL query power as a C-library, embeddable in any language.

Local-first defines seven ideals:

  1. Fast
  2. Multi-device
  3. Offline
  4. Collaboration
  5. Longevity
  6. Privacy
  7. User control

SQLite gives you “Fast”, “Offline”, “Privacy”, and “User Control”.

How do you get “Multi-device” and “Collaboration” from SQLite? You need a sync engine. There’s been a number of sync engines based around SQLite in the over half-a-decade since Ink & Switch published this essay: Turso, Powersync, ElectricSQL, and cr-sqlite to name a few.

But, the fundamental problem with sync engines is “What do you do with conflicts?”. The Local-first software essay suggests Conflict Resistant Data Types (CRDTs) as the solution, rejecting Git because “Git has no capability for real-time, fine-grained collaboration, such as the automatic, instantaneous merging” and “other (non-text) file formats are treated as binary blobs that cannot meaningfully be edited or merged”.

Enter DoltLite, a version-controlled SQLite. DoltLite enables a new class of local-first application by supporting Git-style merging on tabular data directly accessible as a C-library.

But Dolt?#

Dolt already existed and has been stable for years. Why not just use Dolt?

Because Dolt is a server. To use Dolt from your application you stand up dolt sql-server, point a MySQL client at port 3306, and talk wire protocol. That’s a fine model if you’re replacing MySQL or Postgres. It’s the wrong model for local-first.

The whole point of local-first is the database lives on the user’s device. Asking the user to run a server defeats the purpose. Running a local server is a pain. There’s a process to manage, a port to not collide with, a daemon that can crash. SQLite has none of that. SQLite is a .dylib your application links in. That’s the model local-first wants.

DoltLite is that model with version control. People have been asking us for an embedded Dolt for years.

SQL and Version Control in Any Language#

Dolt is written in Go. Go is great for a server. It is bad for a library you embed in someone else’s runtime, unless it’s a Go runtime.

Go binaries are big. Go is awkward to link into iOS apps, Python C extensions, Ruby gems, Node addons, Erlang NIFs, and Rust crates. And Go’s WebAssembly (WASM) story produces multi-megabyte bundles with a runtime that doesn’t play well with the browser’s threading and storage primitives.

C compiles to all of those. iOS, Android, Python, Ruby, Node, Rust, Erlang, and the one that matters most for local-first: a .wasm bundle that runs inside a browser tab. DoltLite compiles SQLite’s WASM target.

WASM is what local-first looks like in 2026. The user opens a webpage. The webpage downloads a .wasm file. The .wasm is a full version-controlled SQL database backed by the browser’s private filesystem. The user’s edits commit to a local branch. When they hit publish, the branch pushes to a DoltLite remote. When a teammate’s branch lands, the user pulls and merges.

-- alice's laptop
SELECT dolt_clone('https://dolthub.com/team/users', 'users.db');
INSERT INTO users VALUES (1, 'alice');
SELECT dolt_commit('-Am', 'add alice');                                       
SELECT dolt_push('origin', 'main');                                
                                                                                
-- bob's browser tab (WASM)                                        
SELECT dolt_clone('https://dolthub.com/team/users', 'users.db');
INSERT INTO users VALUES (2, 'bob');                                          
SELECT dolt_commit('-Am', 'add bob');
SELECT dolt_pull('origin', 'main');   -- merges alice's commit                
SELECT dolt_push('origin', 'main');   -- pushes the merged history 

No wire protocol. No port. No server. A C library call into a .dylib, .so, .dll, or .wasm you linked into your app. dolt_push to share with everyone else holding a copy.

In the example, Alice and Bob inserted different rows, so the merge was trivial. If they had both updated row two to different names, dolt_pull would do what Git does: drop both versions into a dolt_conflicts_users table and refuse to commit until a human picks. That’s the part CRDTs hide. For data with audit or rollback requirements, you want disagreement surfaced, not silently resolved.

DoltLite is the local-first use case, with Git-style merging on structured data instead of CRDTs.

Try DoltLite#

All DoltLite needs is users. Have a local-first app you’ve been waiting to build because there was no Git-style sync model? Wait no longer. Questions? Bugs? Feature requests? Cut an issue. Otherwise, come by our Discord to discuss. Meet me in the #doltlite🪶 channel.