Upgrading across a storage-format change (export / import)
Omnigraph storage is strict-single-version: a binary reads exactly one
Omnigraph storage is strict-single-version: a binary reads exactly one
internal-schema (storage-format) version. There is no in-place migration. When a
release changes the internal schema, a graph created by an older release is
refused on open with a message that points here, and you move it forward by
rebuilding it: export with the old binary, then init + load with the new one.
This is a deliberate pre-release design choice. The rationale (lower long-term liability than carrying in-place migration code for a format that is still changing) is in docs/dev/versioning.md.
How you know you need this
Opening a graph whose stamp is below the binary's version fails with:
__manifest is stamped at internal schema vN, but this omnigraph reads only vM.
This graph was created by an older omnigraph release; rebuild it: run `omnigraph
export` with the older omnigraph binary that created it, then `omnigraph init` +
`omnigraph load` with this one. (Data, vectors, and blobs are preserved; commit
history and branches are not.)You can also check versions before you hit a refusal:
omnigraph version— the binary's served version (theinternal-schema <N>line).omnigraph snapshot <graph>— the graph's on-diskinternal_schema_version.
If the graph's stamp is higher than the binary's, the binary is too old — upgrade omnigraph rather than rebuilding the graph.
What is preserved (and what is not)
| Preserved | Not preserved |
|---|---|
| All node and edge rows | Commit history (the graph DAG starts fresh) |
| Vector columns (embeddings round-trip verbatim) | Branches (export is a single-branch snapshot) |
| Blob columns | Snapshot/time-travel history of the old graph |
The schema (re-applied at init) |
The rebuilt graph is a faithful copy of the exported branch's current state. If you need history or multiple branches carried forward, there is no supported path today — export each branch you care about separately.
The recipe
Use the old binary for the export steps and the new binary for init/load. Keep them as separate executables (for example a downloaded release archive) so you can run both.
# 1. With the OLD binary — capture the schema and the data.
old-omnigraph schema show s3://bucket/graph.omni > schema.pg
old-omnigraph export s3://bucket/graph.omni > graph.jsonl
# 2. With the NEW binary — create a fresh graph and load the data.
omnigraph init --schema schema.pg s3://bucket/graph-v2.omni
omnigraph load --mode overwrite --data graph.jsonl s3://bucket/graph-v2.omni
# 3. With the NEW binary — verify.
omnigraph snapshot s3://bucket/graph-v2.omni # internal_schema_version is current
omnigraph version # confirms the binary's served versionomnigraph export writes a full JSONL snapshot (one row per node/edge, all
columns including vectors and blobs) of the chosen branch (default main; pass
--branch for another) to stdout. omnigraph load --mode overwrite replaces the
target graph's contents with that snapshot.
Once you have verified the rebuilt graph, retire the old one. If you rebuilt in place (same URI), export to a side location first and only overwrite after the new graph verifies.
Notes
- Upgrade the whole fleet together. A mixed fleet where an old binary still writes a graph a newer binary has stamped is unsupported, as with any internal-schema bump.
- Embeddings are not recomputed. Export carries the stored vectors verbatim, so a load does not re-run the embedding pipeline. If you changed the embedding model, re-embed after loading.
- Server deployments: take the graph out of the serving set, rebuild it offline
with the CLI, then point the cluster at the rebuilt graph (
cluster apply).
Migrating to v0.8.0
v0.8.0 is the first release with a storage-format change since v0.4.0. Any graph created by an earlier release must be rebuilt with the recipe above. Beyond the rebuild, v0.8.0 changes two things to plan for: the on-disk layout, and write-time validation strictness.
What changed on disk (internal schema v4)
- Graph commit lineage now lives in the
__manifesttable. Commits, parents, merge parents, per-branch heads, and the authoring actor are stored asgraph_commit/graph_headrows, written in the same atomic commit as the table-version rows of a graph publish. Previously a crash in a narrow window could leave a published version with no matching history entry; that window no longer exists. - Two internal datasets are retired.
_graph_commits.lanceand_graph_commit_actors.lanceare no longer created, read, or written — a graph created by v0.8.0 has neither. If backup scripts, disk-usage tooling, or monitoring reference those paths inside a graph directory, update them. - The version gate is enforced in both directions, including read-only opens.
A v0.8.0 binary refuses a pre-v0.8.0 graph with the rebuild message above; a
pre-v0.8.0 binary refuses a v0.8.0 graph with an
upgrade omnigraph before opening this grapherror. There is no mixed-version window: upgrade every binary that touches a graph together, then rebuild.
If you have tooling that inspects __manifest directly, note that it now holds
three kinds of rows (table versions, commits, branch heads) rather than one —
filter by row kind instead of assuming every row is a table version.
Stricter validation — pre-flight your pipelines
Independently of the storage change, v0.8.0 unifies constraint validation across all three write surfaces (load, mutation, branch merge). Every change is stricter; none relaxes an existing check. A pipeline that unknowingly relied on one of these gaps will now fail loudly at write time:
- Enum constraints are enforced on branch merge (previously only on load and mutation).
- Cross-version uniqueness: inserting a
@uniquevalue that collides with a different, already-committed row is rejected on load and mutation (previously only merges caught it). Re-upserting the same row — same key — is still an update, not a violation. - Duplicate keys within one input batch are rejected: the same
@keyvalue twice in one load file is an error. The same id across separate batches or statements still coalesces (last write wins). - Overwrite loads validate the new image per table: an edges-only overwrite resolves referential integrity against the retained node tables, and orphan edges are rejected.
Pre-flight recipe: before upgrading a production writer, run your ingest with a
v0.8.0 binary against a branch of a rebuilt copy, using the same --mode
your pipeline uses in production (--mode is always required; overwrite is
the mode whose validation changed most):
omnigraph load --data batch.jsonl --mode merge \
--branch preflight --from main s3://bucket/graph-v2.omniRows violating the stricter checks fail the load with a typed error naming the constraint; fix the data (or the constraint) and re-run. Nothing is partially applied — a failed load publishes no commit.
Verifying versions
The two CLI checks are listed in
How you know you need this (omnigraph version,
omnigraph snapshot). New in v0.8.0, the server's GET /healthz response also
reports internal_schema_version.