logo
  • Docs
  • Plugins
  • API Reference
    Introduction
    What is Lix?
    Getting Started
    Comparison to Git
    Lix for AI Agents
    Release Notes
    Essentials
    Filesystem
    SQL Interface
    Schemas
    Plugins
    Persistence
    Guides
    Versions (Branching)
    History
    Diffs
    Attribution (Blame)
    Change Proposals
    Validation Rules
    Undo/Redo
    Restore
    Conversations
    Labels
    Key-Value Store
    Environment API
    Testing
    React Integration
    Logging & Debugging
    Deterministic Mode
    Metadata
    Writer Key
    Architecture
    Lix as File Format
    Previous pageWhat is Lix?Next pageComparison to Git

    #Getting Started

    #Install

    npm
    yarn
    pnpm
    bun
    deno
    npm install @lix-js/sdk @lix-js/plugin-json
    yarn add @lix-js/sdk @lix-js/plugin-json
    pnpm add @lix-js/sdk @lix-js/plugin-json
    bun add @lix-js/sdk @lix-js/plugin-json
    deno add npm:@lix-js/sdk npm:@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 { InMemoryEnvironment, openLix  } from "@lix-js/sdk";
    import { plugin as jsonPlugin } from "@lix-js/plugin-json";
    
    const lix = await openLix({
      environment: new InMemoryEnvironment(),
      providePlugins: [jsonPlugin],
    });

    #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.

    import { InMemoryEnvironment, openLix  } from "@lix-js/sdk";
    import { plugin as jsonPlugin } from "@lix-js/plugin-json";
    
    const lix = await openLix({
      environment: new InMemoryEnvironment(),
      providePlugins: [jsonPlugin],
    });
    const config = {
      theme: "light",
      notifications: true,
      language: "en",
    };
    
    await lix.db
      .insertInto("file")
      .values({
        path: "/config.json",
        data: new TextEncoder().encode(JSON.stringify(config, null, 2)),
      })
      .execute();

    #3. Update the file

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

    import { InMemoryEnvironment, openLix  } from "@lix-js/sdk";
    import { plugin as jsonPlugin } from "@lix-js/plugin-json";
    
    const lix = await openLix({
      environment: new InMemoryEnvironment(),
      providePlugins: [jsonPlugin],
    });
    
    const config = {
      theme: "light",
      notifications: true,
      language: "en",
    };
    
    await lix.db
      .insertInto("file")
      .values({
        path: "/config.json",
        data: new TextEncoder().encode(JSON.stringify(config, null, 2)),
      })
      .execute();
    // Update the config: change theme to dark
    await lix.db
      .updateTable("file")
      .where("path", "=", "/config.json")
      .set({
        data: new TextEncoder().encode(
          JSON.stringify(
            { theme: "dark", notifications: true, language: "en" },
            null,
            2,
          ),
        ),
      })
      .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.):

    import { InMemoryEnvironment, openLix  } from "@lix-js/sdk";
    import { plugin as jsonPlugin } from "@lix-js/plugin-json";
    
    const lix = await openLix({
      environment: new InMemoryEnvironment(),
      providePlugins: [jsonPlugin],
    });
    
    const config = {
      theme: "light",
      notifications: true,
      language: "en",
    };
    
    await lix.db
      .insertInto("file")
      .values({
        path: "/config.json",
        data: new TextEncoder().encode(JSON.stringify(config, null, 2)),
      })
      .execute();
    
    // Update the config: change theme to dark
    await lix.db
      .updateTable("file")
      .where("path", "=", "/config.json")
      .set({
        data: new TextEncoder().encode(
          JSON.stringify(
            { theme: "dark", notifications: true, language: "en" },
            null,
            2,
          ),
        ),
      })
      .execute();
    // Get the active version's commit_id
    const activeVersionCommitId = lix.db
      .selectFrom("active_version")
      .innerJoin("version", "active_version.version_id", "version.id")
      .select("version.commit_id");
    
    // Query file history from the active version
    const history = await lix.db
      .selectFrom("file_history")
      .where("path", "=", "/config.json")
      .where("lixcol_root_commit_id", "=", activeVersionCommitId)
      .select(["path", "data", "lixcol_depth"])
      .orderBy("lixcol_depth", "asc")
      .execute();
    
    for (const row of history) {
      console.log(`Depth ${row.lixcol_depth}:`, {
        path: row.path,
        data: JSON.parse(new TextDecoder().decode(row.data)),
      });
    }
    // 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