Getting Started

Install

npm install @lix-js/sdk @lix-js/plugin-json

[!NOTE] Lix is currently JavaScript/TypeScript only. Upvote Python, Rust, or Go to prioritize other languages.

Step 1: Open a Lix with plugins

Plugins (.json, .xlsx, etc.) make Lix file-format aware. The environment can be swapped for persistence.

import { openLix, selectWorkingDiff, InMemoryEnvironment } from "@lix-js/sdk";
import { plugin as json } from "@lix-js/plugin-json";

const lix = await openLix({
  environment: new InMemoryEnvironment(),
  providePlugins: [json],
});

Step 2: Write a file

Lix is powered by SQL under the hood. Writing a file, querying diffs, etc. happens all via SQL.

await lix.db
  .insertInto("file")
  .values({
    path: "/config.json",
    data: new TextEncoder().encode(JSON.stringify({ theme: "light" })),
  })
  .execute();

Step 3: Query changes

Lix tracks changes on the entity level. You can query the history of a specific entity, or the diff between two versions.

const diff = await selectWorkingDiff({ lix }).execute();
console.log(diff);

JSON file example

A more detailed example showing Lix tracking property-level changes in a JSON config file.

The config file

We'll track changes in this config file:

{
  "theme": "light",
  "notifications": true,
  "language": "en"
}

When the config changes, Lix detects exactly which property changed:

  {
-   "theme": "light",
+   "theme": "dark",
    "notifications": true,
    "language": "en"
  }

1. Create a Lix

Open a Lix with the JSON plugin. Plugins teach Lix what a "meaningful change" is for each file format.

import { openLix, InMemoryEnvironment } from "@lix-js/sdk";
import { plugin as json } from "@lix-js/plugin-json";

const lix = await openLix({
  environment: new InMemoryEnvironment(),
  providePlugins: [json],
});

2. Write the config file

The JavaScript SDK uses Kysely for type-safe query building. Insert the config file into the file table. Files are stored as binary (Uint8Array), making Lix format-agnostic.

await lix.db
  .insertInto("file")
  .values({
    path: "/config.json",
    data: new TextEncoder().encode(
      JSON.stringify({
        theme: "light",
        notifications: true,
        language: "en",
      }),
    ),
  })
  .execute();

3. Update the file

Update the config by changing theme from "light" to "dark":

await lix.db
  .updateTable("file")
  .set({
    data: new TextEncoder().encode(
      JSON.stringify({
        theme: "dark",
        notifications: true,
        language: "en",
      }),
    ),
  })
  .where("path", "=", "/config.json")
  .execute();

Lix detects that theme changed, not just "the file changed":

  {
-   "theme": "light",
+   "theme": "dark",
    "notifications": true,
    "language": "en"
  }

4. Query history

Query the file's history using the file_history view. The lixcol_root_commit_id specifies the starting point. Here we use the active version's commit to get history from the current state. The lixcol_depth indicates how far back (0 = current, 1 = previous, etc.):

const activeVersion = await lix.db
  .selectFrom("version")
  .where("is_active", "=", true)
  .select("commit_id")
  .executeTakeFirstOrThrow();

const history = await lix.db
  .selectFrom("file_history")
  .where("path", "=", "/config.json")
  .where("lixcol_root_commit_id", "=", activeVersion.commit_id)
  .orderBy("lixcol_depth", "asc")
  .select(["lixcol_depth", "data"])
  .execute();

for (const entry of history) {
  const content = JSON.parse(new TextDecoder().decode(entry.data));
  console.log(`Depth ${entry.lixcol_depth}:`, content);
}
// Output:
// Depth 0: { path: '/config.json', data: { theme: 'dark', notifications: true, language: 'en' } }
// Depth 1: { path: '/config.json', data: { theme: 'light', notifications: true, language: 'en' } }

Next steps

  • Versions – Create isolated versions (branches) for parallel work
  • Diffs – Query exactly what changed between any two points
  • Change Proposals – Review changes before merging
  • Plugins – Track CSV, Markdown, or create your own