Schemas
A schema declares a table: columns, types, primary key, constraints. Register one and Lix gives you a typed SQL surface for it, with the same branches, history, and diffs as every other row.
Lix Schema v1 is a strict JSON representation of the PostgreSQL table subset
supported by Lix. Its public identifier is https://lix.dev/schema-v1.json.
Schemas are JSON, so plugins can ship them
A schema is data, not code. That is deliberate.
Plugins run as sandboxed WASM components and may be written in any language, so they cannot hand Lix a Rust struct or a TypeScript type. They ship JSON files instead. A plugin manifest lists them by path inside its archive:
{
"key": "plugin_csv",
"file_match": { "path_glob": "*.{csv,tsv}", "content": "text" },
"entry": "plugin.wasm",
"schemas": ["schema/csv_table.json", "schema/csv_row.json"]
}
Each listed file is a Schema v1 document. Installing the plugin is a normal
tracked write: its schemas become lix_registered_schema rows. From then on the
plugin's rows behave like any other rows — same SQL surfaces, same history, same
diffs. A manifest may declare between 1 and 64 schemas.
The CSV plugin defines what a CSV record is. The Markdown plugin defines what a block is. Your application defines its own tables the same way. Lix has no per-format code path.
Discover registered schemas
Query lix_registered_schema to list every registered schema. schema_key
holds the key. The JSONB value column holds the Schema v1 document:
SELECT schema_key, value
FROM lix_registered_schema
ORDER BY schema_key;
Register a schema
INSERT INTO lix_registered_schema (schema_key, value)
VALUES ('acme_section', '{
"$schema": "https://lix.dev/schema-v1.json",
"key": "acme_section",
"columns": [
{ "name": "id", "type": "uuid", "nullable": false,
"default_expression": "uuidv7()" },
{ "name": "title", "type": "text", "nullable": false },
{ "name": "body", "type": "text", "nullable": false },
{ "name": "metadata", "type": "jsonb", "nullable": true }
],
"primary_key": ["id"],
"unique": [["title"]]
}'::jsonb);
schema_key must equal value.key. After registration, acme_section and
lix_history('acme_section') expose the typed current row and its revision
history.
Contract
Schema v1 supports:
- PostgreSQL type names
text,uuid,int8,float8,boolean,jsonb, andtimestamptz; - ordered columns, a required non-empty
primary_key, unique constraints, and foreign keys; nullable,default_value, and theuuidv7()andCURRENT_TIMESTAMPdefault expressions; anddescription,examples, anddeprecatedannotations.
Identifiers must be lowercase snake_case and no longer than PostgreSQL's
63-byte identifier limit. Primary-key columns must be non-null text, uuid,
or int8. Composite keys preserve their declared order:
"primary_key": ["order_id", "line_number"],
"unique": [["order_id", "sku"]]
Foreign keys name local and referenced columns directly:
"foreign_keys": [{
"columns": ["author_id"],
"references": {
"schema_key": "acme_author",
"columns": ["id"]
}
}]
Omitted options use PostgreSQL defaults: MATCH SIMPLE, ON DELETE NO ACTION, ON UPDATE NO ACTION, and NOT DEFERRABLE.
jsonb accepts any JSON value but does not validate nested structure. It
discards whitespace, object-key order, duplicate keys, and numeric spelling.
Use text when lexical preservation matters.
Amendments
Re-registering the same key is an amendment. Lix permits documentation-only changes and appending a nullable column or a column with a compatible default. Lix rejects everything else: key changes, removing or renaming or reordering or retyping a column, changing a column's nullability or default, and changing a primary key, unique constraint, or foreign key. Use a new schema key for an incompatible model until an explicit migration API exists.
Naming
Use an owner prefix such as acme_task or xlsx_cell. The lix and lix_*
names are reserved for Lix. A schema key identifies the durable schema and its
SQL surface, so treat it like a stable package name. Each row has its own
primary-key identity within that schema.
The machine-readable meta-schema and its PostgreSQL mapping live in the
lix-schema crate, at schema/schema-v1.json and schema/schema-v1.md.