JSONLT JSONLT

Keyed records that diff cleanly

JSONLT is a format for storing keyed records in append-only files using JSON Lines. Optimized for human readability and version control diffs.

What is JSONLT?

JSONLT (JSON Lines Table) is a data format for storing collections of records. Each line is a standalone JSON object representing one record, and every record has a key field that uniquely identifies it. To update a record, append a new version—the last entry for each key wins.

users.jsonlt
{"id": "alice", "name": "Alice", "role": "admin"}
{"id": "bob", "name": "Bob", "role": "user"}
{"id": "alice", "name": "Alice Chen", "role": "admin"}

Alice updated her name. The original line stays; the new version appends. When read, "alice" resolves to the latest entry.

Keyed

Each record has a unique identifier field

Append-only

Changes add new lines, never modify existing ones

Last wins

The most recent entry for a key is the current value

Why append-only wins

Three real scenarios where JSONLT's append-only design solves version control headaches.

1. Git blame stays accurate

When lines shift in a JSON array, blame points to whoever caused the shift—not the original author.

Traditional JSON Blame breaks
git blame users.json
abc123 (Alice) | {
abc123 (Alice) | "users": [
def456 (Dave)  |   {"id": "alice", "role": "admin"}   <- wrong!
def456 (Dave)  |   {"id": "carol", "role": "user"}
def456 (Dave)  |   {"id": "bob", "role": "user"}      <- wrong!
abc123 (Alice) | ]
abc123 (Alice) | }

Dave added carol. Now blame says Dave authored alice and bob too.

JSONLT Clean history
git blame users.jsonlt
abc123 (Alice) | {"id": "alice", "role": "admin"}
abc123 (Alice) | {"id": "bob", "role": "user"}
def456 (Dave)  | {"id": "carol", "role": "user"}

Dave's addition appends. Alice's records keep their attribution.

2. Merge conflicts disappear

Two developers edit different records. In JSON arrays, this often causes conflicts. In JSONLT, both just append.

Traditional JSON Conflict
settings.json
{
  "settings": [
<<<<<<< HEAD
    {"key": "theme", "val": "dark"},
    {"key": "lang", "val": "en"}
=======
    {"key": "theme", "val": "light"},
    {"key": "lang", "val": "fr"}
>>>>>>> feature
  ]
}

Alice changed theme, Bob changed lang. Manual resolution required.

JSONLT Auto-merges
settings.jsonlt (after merge)
{"key": "theme", "val": "light"}
{"key": "lang", "val": "en"}
{"key": "theme", "val": "dark"}    <- Alice
{"key": "lang", "val": "fr"}       <- Bob

Both changes append to different lines. Git merges automatically.

3. Minimal diff noise

Adding a record to a JSON array changes multiple lines. JSONLT diffs show only what you added.

Traditional JSON Noisy diff
products.json
 {
   "products": [
     {"sku": "A001", "price": 29.99},
-    {"sku": "B002", "price": 49.99}
+    {"sku": "B002", "price": 49.99},
+    {"sku": "C003", "price": 19.99}
   ]
 }

Adding C003 required changing the previous line's trailing comma.

JSONLT Minimal diff
products.jsonlt
 {"sku": "A001", "price": 29.99}
 {"sku": "B002", "price": 49.99}
+{"sku": "C003", "price": 19.99}

One line added, one line in the diff. Every time.

Why JSONLT?

Clean version control diffs

Modifications append new lines rather than rewriting existing content. You can see exactly what changed and when in your git history.

Human-readable format

Plain text JSON you can read, edit, and grep. No special tools required—works with any text editor and standard Unix utilities.

No infrastructure required

Just files. No database servers to manage, no services to configure. Your data lives alongside your code in version control.

Formally specified

A complete specification with conformance profiles, test suites, and reference implementations ensures interoperability across languages.

Simple to use

JSONLT implementations provide a familiar key-value interface. Here's how it looks in Python:

example.py
from jsonlt import Table

# Open or create a table
users = Table("users.jsonlt", key="id")

# Insert or update records
users.put({"id": "alice", "name": "Alice", "role": "admin"})
users.put({"id": "bob", "name": "Bob", "role": "user"})

# Retrieve a record
alice = users.get("alice")
print(alice["role"])  # "admin"

# Delete a record
users.delete("bob")

Implementations

The JSONLT project maintains reference implementations that demonstrate spec-conformant behavior and serve as test beds for the conformance suite.

Python
In development

Reference implementation

View on GitHub
Go
Planned
JavaScript
Planned
Ruby
Planned
Rust
Planned

Interested in contributing?

Join the discussion →