Lix is designed to be used as the foundation for application-specific file formats. Instead of building change control, versioning, and collaboration from scratch, you can build your file format on top of lix and inherit these capabilities automatically.
Let's say you want to build a markdown editor where:
With lix, we could define a new file format .mdoc that stores everything in a single portable file:
document.mdoc # A portable lix file (like a .zip)
├── /doc.md # Markdown content
├── /assets/diagram.png
├── /assets/photo.jpg
└── /config.json # MetadataA lix file is essentially a portable directory with built-in change control. Think of it like a zip file, but every change to every file is tracked, versioned, and can be reviewed.
Building a file format on lix:
newLixFile(), open with openLix()The lix file is portable - share it anywhere. All files inside get automatic change tracking and can sync between devices.
Local first app
Building a web app with lix is reduced to providing a user interface that opens and saves a file.

Auth, permissions, collaboration, change history, and automations come with lix
These features are solved at the file level rather than application level.

Building a file format on lix gives you:
Solving features at the file level enables different apps and personas to work with the same file. A designer, developer, translator, and PM can each use their preferred tool while collaborating on the same underlying data.
Inlang uses this in production: multiple inlang apps (editor, CLI, plugins, IDE extensions) all work with the same .inlang file. Each app provides a different interface for different personas, but they all read and write to the same portable file with shared auth, permissions, and change history.
This interoperability is only possible because features are solved at the file level rather than locked into a specific application.
1. Create a lix file
Use newLixFile() and openLix() to initialize your portable file format.
2. Store your data
Add files (/doc.md, /assets/*) and configuration. Optionally define custom entities.
3. Provide a domain API
Wrap lix operations in methods that feel natural (doc.setContent(), not lix.db.updateTable()).
Let's build a portable markdown document format (.mdoc):
import { newLixFile, openLix } from "@lix-js/sdk";
// Create new .mdoc file
async function newMarkdownDoc() {
const lix = await openLix({ blob: await newLixFile() });
await lix.db
.insertInto("file")
.values({
path: "/doc.md",
data: new TextEncoder().encode("# New Document"),
})
.execute();
return await lix.toBlob();
}
// Load and edit
async function loadMarkdownDoc(blob: Blob) {
const lix = await openLix({ blob });
return {
async getContent() {
const file = await lix.db
.selectFrom("file")
.where("path", "=", "/doc.md")
.select("data")
.executeTakeFirstOrThrow();
return new TextDecoder().decode(file.data);
},
async setContent(markdown: string) {
await lix.db
.updateTable("file")
.where("path", "=", "/doc.md")
.set({ data: new TextEncoder().encode(markdown) })
.execute();
},
// Access lix for versioning/history
lix,
async save() {
return await lix.toBlob();
},
};
}Usage:
const file = await newMarkdownDoc();
const doc = await loadMarkdownDoc(file);
await doc.setContent("# Hello World");
const updatedFile = await doc.save();
// Version management comes free
const version = await createVersion({ lix: doc.lix, name: "draft" });Inlang built a production i18n file format on lix used by thousands of developers:
Why it works:
.inlang filesproject.db.selectFrom("message") feels intuitive for i18n developersThis demonstrates the power of file-level features: different personas (developers, designers, translators) use different apps but collaborate on the same portable file.
See the [Inlang SDK source code](https://github.com/opral/monorepo/tree/main/inlang/packages/sdk/src/project) for implementation details.
1. Store structure as files
/doc.md # Content
/assets/ # Binary assets
/config.json # Configuration2. Define custom schemas for structured data Use lix's schema system for domain entities (messages, tasks, records) instead of storing everything as files.
3. Expose underlying lix
Let advanced users access project.lix for versioning, history, and change proposals.
4. Provide domain-specific operations
Hide lix complexity: doc.addImage() not lix.db.insertInto("file").
5. Make it portable
Implement toBlob() for serialization and accept blob in your load function.