Lix provides a filesystem with files and directories. Files contain binary data that plugins process to detect changes.
await lix.db
.insertInto("file")
.values({
path: "/config.json",
data: new TextEncoder().encode(JSON.stringify({ theme: "dark" })),
})
.execute();Automatic directory creation: Ancestor directories are created automatically if they don't exist. You don't need to create /configs/ before adding /configs/app.json.
Path collision detection: Inserting a file will fail if a directory already exists at that path.
// Get a specific file
const file = await lix.db
.selectFrom("file")
.where("path", "=", "/config.json")
.selectFirst();
// Get all files
const allFiles = await lix.db.selectFrom("file").selectAll().execute();Query a file at a specific version:
const file = await lix.db
.selectFrom("file_by_version")
.where("path", "=", "/config.json")
.where(
"lixcol_root_commit_id",
"=",
lix.db
.selectFrom("version")
.where("name", "=", "feature-branch")
.select("commit_id"),
)
.selectFirst();Query file history across commits:
const history = await lix.db
.selectFrom("file_history")
.where("path", "=", "/config.json")
.where("lixcol_root_commit_id", "=", currentCommit)
.orderBy("lixcol_depth", "asc")
.execute();See History for more details.
await lix.db
.updateTable("file")
.where("path", "=", "/config.json")
.set({
data: new TextEncoder().encode(JSON.stringify({ theme: "light" })),
})
.execute();When you update a file, plugins automatically detect changes and create entity records.
await lix.db.deleteFrom("file").where("path", "=", "/config.json").execute();Add application-specific data using metadata:
await lix.db
.insertInto("file")
.values({
path: "/import.csv",
data: csvData,
metadata: {
imported_from: "external-system",
import_date: new Date().toISOString(),
},
})
.execute();Directories organize files in a hierarchical structure. The root directory is represented by /.
Each directory has:
Directories enforce uniqueness by (name, parent_id), preventing duplicate names in the same parent.
await lix.db
.insertInto("directory")
.values({
path: "/configs/",
hidden: false,
})
.execute();// List all files in a directory
const files = await lix.db
.selectFrom("file")
.where("path", "like", "/configs/%")
.selectAll()
.execute();
// List immediate subdirectories
const subdirs = await lix.db
.selectFrom("directory")
.where("path", "like", "/configs/%/")
.where("path", "not like", "/configs/%/%/")
.selectAll()
.execute();await lix.db.deleteFrom("directory").where("path", "=", "/configs/").execute();Cascade delete: Deleting a directory automatically removes all files and subdirectories within it.
Files in Lix are composed of two parts:
A tracked entity containing structural information:
/)config for config.json)json), null if no extensionThe file path is derived from the directory hierarchy + name + extension. This structure enables efficient path-based queries and directory operations.
The file.data column is not stored directly. It's materialized from plugin change records:
detectChangesGlob matches the file pathapplyChanges function to reconstruct the binary datalix_unknown_file_fallback_plugin stores the raw bytesThis design enables schema-aware change tracking while still providing direct file access.
Paths must be normalized before use:
/config.json). or ..)/dir/file.json)/dir/)Use the exported helpers to normalize paths:
import {
normalizeFilePath,
normalizeDirectoryPath,
normalizePathSegment,
} from "@lix-js/sdk";
const filePath = normalizeFilePath("/config.json");
const dirPath = normalizeDirectoryPath("/configs/");
const segment = normalizePathSegment("my-file");