Deterministic Mode

Who is this for? If you're testing, debugging, or simulating distributed systems with Lix and need predictable, reproducible behavior across runs, deterministic mode is for you.

Use deterministic mode for:

  • Testing - Unit and integration tests that produce identical results every run
  • Debugging - Reproduce exact sequences of events from bug reports
  • Simulations - Run deterministic simulations across multiple environments

Quick Example

Normal mode (default) - different results each run:

import { openLix, timestamp, random } from "@lix-js/sdk";

const lix = await openLix({ blob });

timestamp({ lix }); // "2024-03-15T10:32:45.123Z" (current time)
timestamp({ lix }); // "2024-03-15T10:32:45.124Z" (real time passes)
random({ lix }); // 0.7234... (unpredictable)
random({ lix }); // 0.1823... (unpredictable)

Deterministic mode - same results every run:

const lix = await openLix({
  blob,
  keyValues: [
    {
      key: "lix_deterministic_mode",
      value: {
        enabled: true,
      },
      lixcol_version_id: "global",
    },
  ],
});

timestamp({ lix }); // "1970-01-01T00:00:00.000Z" (always epoch)
timestamp({ lix }); // "1970-01-01T00:00:00.001Z" (always +1ms)
random({ lix }); // 0.318... (always this sequence)
random({ lix }); // 0.937... (always this sequence)

Configuration

Basic Setup

Enable deterministic mode when opening a Lix:

const lix = await openLix({
  blob,
  keyValues: [
    {
      key: "lix_deterministic_mode",
      value: {
        enabled: true,
      },
      lixcol_version_id: "global",
    },
  ],
});

Or enable it after opening:

await lix.db
  .updateTable("key_value_all")
  .set({ value: { enabled: true } })
  .where("key", "=", "lix_deterministic_mode")
  .where("lixcol_version_id", "=", "global")
  .execute();

Configuration Options

The deterministic mode is configured through a single key-value object:

KeyTypeDescription
lix_deterministic_modeobjectConfiguration object for deterministic mode

The configuration object has the following properties:

PropertyTypeDefaultDescription
enabledbooleanrequiredEnable/disable deterministic mode
randomLixIdbooleanfalseUse random lix_id for distributed testing
timestampbooleantrueUse deterministic timestamps
random_seedstring"lix-deterministic-seed"Seed for the random number generator
nano_idbooleantrueUse deterministic nano ID generation
uuid_v7booleantrueUse deterministic UUID v7 generation

Advanced Usage

Distributed Testing with Random Lix IDs

For distributed testing scenarios where you need multiple Lix instances with different IDs:

// Creates Lix instances with random IDs for distributed testing
const lix1 = await openLix({
  keyValues: [
    {
      key: "lix_deterministic_mode",
      value: {
        enabled: true,
        randomLixId: true, // Each instance gets a random lix_id
      },
      lixcol_version_id: "global",
    },
  ],
});

const lix2 = await openLix({
  keyValues: [
    {
      key: "lix_deterministic_mode",
      value: {
        enabled: true,
        randomLixId: true, // Different from lix1
      },
      lixcol_version_id: "global",
    },
  ],
});
NOTE
  • Use default deterministic mode (enabled: true) for reproducibility testing (e.g., unit tests, regression tests)
  • Use randomLixId mode (enabled: true, randomLixId: true) for distributed testing scenarios (e.g., simulating multiple Lix instances syncing)

Different RNG Seeds

To make multiple Lix instances behave differently in deterministic mode:

// Set seed when opening
const lix1 = await openLix({
  blob,
  keyValues: [
    {
      key: "lix_deterministic_mode",
      value: {
        enabled: true,
        random_seed: "instance-1",
      },
      lixcol_version_id: "global",
    },
  ],
});

// Or update seed after opening using SQLite's json_set function
import { sql } from "@lix-js/sdk";

await lix.db
  .updateTable("key_value_all")
  .set({
    value: sql`json_set(value, '$.random_seed', 'instance-2')`,
  })
  .where("key", "=", "lix_deterministic_mode")
  .where("lixcol_version_id", "=", "global")
  .execute();

State Persistence

Deterministic state is automatically persisted:

EventState Flushed?
Successful mutating transaction
lix.toBlob() / lix.close()
Read-only transaction
Transaction rollback/error

All state is stored in internal_state_all_untracked with version_id = "global".

The following functions provide deterministic behavior when lix_deterministic_mode is enabled:

FunctionPurposeDocs
timestamp({ lix })Logical clock timestampsAPI docs
random({ lix })Reproducible random numbersAPI docs
uuidV7({ lix })Deterministic UUID v7 generationAPI docs
nanoId({ lix })Deterministic nano ID generationAPI docs
nextDeterministicSequenceNumber({ lix })Monotonic counter (advanced)API docs