Versions - Enable Parallel Work

Versions enable parallel work, safe experimentation, and clear diffs in Lix. They allow you to create isolated environments for different tasks or experiments, similar to branches in Git.

Versions

Parallel workMultiple AI agents — and human editors — can make different changes at the same time without overwriting each other's progress.
Risk free experimentsLet agents make changes without impacting the users' version—delete instantly if results disappoint.
Clear diffs & reviewsSee exactly what each agent (or human) changed between versions.

Use case examples

Human-AI Agent Collaboration

  1. Agent (or your orchestration layer) creates a version.
  2. Agent writes data; Lix auto-commits each change.
  3. Human (or another agent) asks for a diff vs main.
  4. On approval, merge or discard the version.
// 1. Create and switch to an isolated version for Agent A
const versionA = await createVersion({ lix, name: "agent-a-playground" });
await switchVersion({ lix, to: versionA });

// 2. Agent writes changes (auto-committed under the hood)
await agentA.runTasks(lix);

// 3. Diff against main
const diff = await diffVersion({ lix, from: versionA.id, to: "main" });

// 4. Review / merge or drop
if (await humanApproves(diff)) {
  await mergeVersion({ lix, from: versionA.id, into: "main" });
} else {
  await deleteVersion({ lix, id: versionA.id });
}

A/B Testing

Let different AI agents create competing advertisements autonomously, then automatically promote the one with better conversion rates.

// Create parallel versions for competing agents
const versionA = await createVersion({ lix, name: "agent-a-campaign" });
const versionB = await createVersion({ lix, name: "agent-b-campaign" });

// Let agents work autonomously with their own strategies
(agentA.createAdvertisements(versionA), agentB.createAdvertisements(versionB));

// Compare performance and merge the winner
const winner = await determineWinner(versionA, versionB);

await mergeVersion({ lix, source: winner.id, target: "main" });

// Clean up the losing version
const loser = winner.id === versionA.id ? versionB : versionA;
await deleteVersion({ lix, id: loser.id });

// Winner function compares conversion rates
async function determineWinner(versionA, versionB) {
  const [conversionsA, conversionsB] = await Promise.all([
    getConversionRate(versionA),
    getConversionRate(versionB),
  ]);

  return conversionsA > conversionsB ? versionA : versionB;
}

Key benefits:

  • Safe experimentation: Both agents work in isolation, no risk to production
  • Data-driven decisions: Compare real performance metrics, not just agent confidence
  • Easy rollback: If both experiments fail, main version stays untouched
  • Scalable testing: Run dozens of agent experiments simultaneously

How Versions Work

Versions in Lix are like branches in Git—they are pointers to a specific commit that expresses state at a point in time.

Version A (main) ──► commit (245) ↘ commit (309) ──► commit (38e) ... Version B (feature-x) ──► commit (sh4) ↗
NOTE

Lix uses the term "version" instead of "branch" because it's more intuitive for non-technical users. "Version" mirrors the familiar concept of duplicating a file and adding v2 or final to the file name e.g. something_v2.docx or something_final.docx.

Interactive example

Versions let you work with different states of your data in isolation. Here's a simple example showing how to update product prices in a separate version:

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

const lix = await openLix({
  providePlugins: [jsonPlugin],
});

// Get main version info for later use
const mainVersion = await lix.db
  .selectFrom("version")
  .where("name", "=", "main")
  .select(["id"])
  .executeTakeFirstOrThrow();

// Helper function to log file differences
const logFileDifferences = (allFiles: any[]) => {
  allFiles.forEach((file) => {
    const data = JSON.parse(new TextDecoder().decode(file.data));
    const versionName =
      file.lixcol_version_id === mainVersion.id ? "main" : "price-update";
    const tshirtPrice = data.items.find(
      (item: any) => item.name === "T-Shirt",
    ).price;
    console.log(`T-Shirt price in '${versionName}': $${tshirtPrice}`);
  });
};
// Create a product catalog file in the main version
await lix.db
  .insertInto("file")
  .values({
    path: "/products.json",
    data: new TextEncoder().encode(
      JSON.stringify({
        items: [{ id: 1, name: "T-Shirt", price: 29.99, stock: 100 }],
      }),
    ),
  })
  .execute();

// 1. Create a new version (branches from active version by default)
const priceUpdateVersion = await createVersion({
  lix,
  name: "price-update",
});

// 2. Switch to the new version
await switchVersion({ lix, to: priceUpdateVersion });

// 3. Modify the file - update prices
await lix.db
  .updateTable("file")
  .set({
    data: new TextEncoder().encode(
      JSON.stringify({
        items: [{ id: 1, name: "T-Shirt", price: 34.99, stock: 100 }],
      }),
    ),
  })
  .where("path", "=", "/products.json")
  .execute();

// 4. Query files across all versions to see the differences
const allFiles = await lix.db
  .selectFrom("file_all")
  .where("path", "=", "/products.json")
  .select(["lixcol_version_id", "data"])
  .execute();

logFileDifferences(allFiles);
Function / TypePurposeDocs
createVersion()Create a new version branchAPI
switchVersion()Change active versionAPI
createCheckpoint()Create a labeled commitAPI
LixVersionVersion type definitionAPI