Lix is an embeddable version control system that can be imported as a library. Use lix, for example, to enable human-in-the-loop workflows for AI agents like diffs and reviews.
- It's just a library — Lix is a library you import. Get branching, diff, rollback in your existing stack
- Tracks semantic changes — diffs, blame, and history are queryable via SQL
- Approval workflows for agents — agents propose changes in isolated versions, humans review and merge

Tip
Lix does not replace Git. Read how Lix compares to Git →
Semantic change tracking
Lix doesn't track line-by-line text changes. It tracks semantic changes at the entity level via plugins.
A plugin parses a format (or a piece of app state) into structured entities. Then Lix stores what changed — not just which bytes differ.
Before:
{"theme":"light","notifications":true,"language":"en"}
After:
{"theme":"dark","notifications":true,"language":"en"}
Git tracks:
-{"theme":"light","notifications":true,"language":"en"}
+{"theme":"dark","notifications":true,"language":"en"}
Lix tracks:
property theme:
- light
+ dark
Excel file example
With an XLSX plugin (not shipped yet), Lix can show a cell-level diff like: This is exactly the kind of semantic surface plugins define: cells vs formulas vs styling.
Before:
| order_id | product | status |
|---|---|---|
| 1001 | Widget A | shipped |
| 1002 | Widget B | pending |
After:
| order_id | product | status |
|---|---|---|
| 1001 | Widget A | shipped |
| 1002 | Widget B | shipped |
Git tracks:
-Binary files differ
Lix tracks:
order_id 1002 status:
- pending
+ shipped
The same approach extends to any other format your product cares about — as long as there’s a plugin that can interpret it.
How does Lix work?
Lix is change-first: it stores semantic changes as queryable data, not snapshots.
That means audit trails, rollbacks, and “blame” become simple queries:
SELECT *
FROM state_history
WHERE entity_pk = 'settings.theme'
ORDER BY depth ASC;
Lix uses existing SQL databases as both query engine and persistence layer.
Plugins parse files (including binary formats) into "meaningful changes" e.g. cells, properties, whitespace, etc. Lix stores those changes as rows in virtual tables like file, file_history, and state_history.
Why this matters:
- Doesn't reinvent databases — durability, ACID, and recovery come from proven SQL engines.
- SQL API for changes — query diffs, history, and audit trails directly.
- Portable — runs on SQLite, Postgres, or other SQL databases.
┌─────────────────────────────────────────────────┐
│ Lix │
│ │
│ ┌────────────┐ ┌──────────┐ ┌─────────┐ ┌─────┐ │
│ │ Filesystem │ │ Branches │ │ History │ │ ... │ │
│ └────────────┘ └──────────┘ └─────────┘ └─────┘ │
└────────────────────────┬────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ SQL database │
│ (SQLite, Postgres, etc.) │
└─────────────────────────────────────────────────┘
This means: no separate infrastructure to manage, and no “special” datastore just for version control.
Plugins (format support)
Lix’s format support depends on plugins. Here’s the current status:
| Format | Plugin | Status |
|---|---|---|
| JSON | @lix-js/plugin-json | Stable |
| CSV | @lix-js/plugin-csv | Stable |
| Markdown | @lix-js/plugin-md | Beta |
| ProseMirror | @lix-js/plugin-prosemirror | Stable |
Building your own plugin: take an off-the-shelf parser for your format, map it to Lix’s entity/change schema, and you get semantic diffs + history for that format. Plugin documentation →
Why did we build Lix?
Lix was developed alongside inlang, open-source localization infrastructure.
We needed version control as a library, not as an external tool. Git's architecture didn't fit: we needed database semantics (transactions, ACID), queryable history, and semantic diffing. Read more →
The result is Lix, now at over 90k weekly downloads on NPM.

Getting started
JavaScript ·
Python ·
Rust ·
Go
npm install @lix-js/sdk
import { openLix, selectWorkingDiff } from "@lix-js/sdk";
const lix = await openLix({
environment: new InMemorySQLite()
});
await lix.db.insertInto("file").values({ path: "/hello.txt", data: ... }).execute();
const diff = await selectWorkingDiff({ lix }).selectAll().execute();
What's next
The next version of Lix will be a refactor to be purely "preprocessor" based. This makes Lix easier to embed anywhere and enables:
- Fast writes (RFC 001)
- Any SQL database (SQLite, Postgres, Turso, MySQL)
- SDKs for Python, Rust, Go (RFC 002)
┌────────────────┐
SELECT * FROM ... │ Lix Engine │ SELECT * FROM ...
───────────────────▶ │ (Rust) │ ───────────────────▶ Database
└────────────────┘