Omnigraph

Schema Language (`.pg`)

A schema declares the node and edge types a graph accepts. OmniGraph validates

A schema declares the node and edge types a graph accepts. OmniGraph validates the same schema and constraints for mutation queries, loads, and branch merges. Actor attribution on a commit does not create a graph node. Applications may declare their own Actor, OmniActor, or other provenance types; these are ordinary customer-owned types with no automatic rows or permission grants.

node Person {
  email: String @key
  display_name: String
  age: I32?
  @range(age, 0..150)
}

node Company {
  slug: String @key
  name: String
}

edge WorksAt: Person -> Company @card(0..) {
  role: String?
  @unique(@src, @dst)
}

Comments use // ... or /* ... */.

Declarations

interface <Name> { <properties> }
node <Name> [implements <Interface>, ...] { <properties and constraints> }
edge <Name>: <FromNode> -> <ToNode> [@card(...)] { <properties and constraints> }

Interfaces provide reusable properties. An edge's endpoint node types must already be declared. Query traversals spell an edge with a lowercase first letter (worksAt for WorksAt); lookup is otherwise case-insensitive.

Property types

TypeValues
StringUTF-8 text
Booltrue or false
I32, I64Signed integers
U32, U64Unsigned integers
F32, F64Floating-point numbers
DateCalendar date
DateTimeTimestamp
Vector(N)N 32-bit floating-point values
BlobManaged bytes or an external reference; see Blobs
enum(a, b, ...)One of the declared strings
[T]A list of scalar T values
T?A nullable value

Property names starting with _ are reserved for system columns and are rejected when a schema is admitted. The reserved namespace covers Lance's virtual system columns (_rowid, _rowaddr, _rowoffset, _row_created_at_version, _row_last_updated_at_version) and OmniGraph's own implicit stored columns, spelled __id on nodes and edges and __src/__dst on edges for newly created graphs. Supported existing graphs without the system-columns feature keep the earlier spellings id, src, and dst for their implicit columns. They reserve id on nodes and edges, and src/dst on edges. On current graphs all three names are ordinary property names. Query meta-fields use @id, @src, and @dst; projected node objects use @id, and JSONL exports use a top-level id. The schema endpoint (GET /schema) reports the physical spellings in system_columns. _distance and _score are also reserved for new declarations: search-ordered queries rank results by those columns. A graph whose schema already declared either name before this reservation keeps opening; only new schemas are refused.

On edge types the names from and to are also reserved: they are the insert parameters that name the endpoints.

Constraints

Constraints can be written in the type body. @key, @unique, and @index also have a single-property shorthand.

ConstraintApplies toMeaning
@key(p, ...)node or edgeThe property tuple identifies the entity; its id is derived from it. Key properties must be non-null scalar values. An edge key must include both @src and @dst, and a key may be declared only when the type is created.
@unique(p, ...)node or edgeNo two entities may share the property tuple. Edge constraints may include @src and @dst.
@index(p, ...)node or edgeDeclares index intent. Indexes affect performance, not correctness.
@range(p, min..max)nodeRestricts a numeric property; either bound may be omitted.
@check(p, "regex")nodeRequires a String property to match the expression.
@card(min..max)edgeRestricts the number of edges; omit max for an unbounded range, as in @card(1..). The default is unbounded from zero.

Blob, list, and vector properties cannot be keys. Blob properties also cannot be unique or indexed.

Current automatic property indexes are created for single-property node declarations: orderable scalars and enums receive a scalar index, free-text Strings receive a full-text index, and vectors receive a vector index. Composite declarations and edge-property declarations are accepted as schema intent but do not currently create a property index. Edge endpoints are indexed independently for traversal. See Search.

IDs

Every node and edge has a String id. On the wire it rides at the top level of the load or export envelope, under the fixed key id, beside type (nodes) or edge; data holds user properties. Legacy-vintage graphs also accept data.id as identity when the top-level id is absent; providing both is refused. In queries the id is the meta-field $p.@id and an edge's endpoints are $e.@src and $e.@dst (system fields); a bare id in a query is always a user property of that name.

  • A node with @key derives its id from the complete typed key tuple. Renaming a key property with @rename_from does not change existing ids.
  • A node without a key receives a generated id unless input supplies one.
  • An edge with @key derives its id the same way, in the catalog's key order: @src, then @dst, then any scalar members. A composite id encodes as a JSON array of the member values, for example ["Alice","Bob"].
  • An edge without a key uses generated or supplied ids. Edges store their endpoints as the graph's endpoint columns, __src and __dst on graphs created by this binary.

For hand-authored load data, omit a keyed node's or keyed edge's top-level id and let OmniGraph derive it; a supplied id on a keyed edge must equal the derived id exactly. Export includes ids so a graph can be rebuilt without losing edge references.

Annotations

  • @rename_from("OldName") on a node, edge, or property declares a rename during schema migration. Use the current name everywhere after applying it.
  • @description("...") adds human-readable metadata to types and properties.
  • @instruction("...") adds usage guidance to node and edge types.
  • @embed("source_property", model="model-id") associates a vector with its source String property. The model is optional; see Embeddings.

Property-level @key, @unique, and @index are shorthands for their single-property constraints. Unknown annotations are retained as metadata but have no built-in behavior.

Schema changes

Always preview a direct schema change before applying it:

omnigraph schema plan --schema next.pg graph.omni
omnigraph schema apply --schema next.pg graph.omni

Supported changes include adding types, adding nullable properties, renaming nodes, edges, or properties with @rename_from, adding index declarations, widening an enum with new values, updating descriptions or instructions, and soft-dropping node, edge, or property declarations.

Changes such as adding a required property to existing entities, changing a property type (except enum widening), changing edge endpoints or cardinality, changing a node's implemented interfaces, and adding or removing most constraints are rejected. The plan reports the exact unsupported step before anything changes.

A normal drop removes the declaration from the current schema while older commits remain readable until destructive cleanup removes their storage. schema apply --allow-data-loss makes drops immediately destructive. Review its plan carefully; it cannot be undone.

Cluster-managed graphs change schema through omnigraph cluster apply. Direct schema apply and the server schema-apply endpoint refuse cluster-managed graphs.

Diagnostic codes

Migration rejections may include a stable OG-... code. Match automation on the code rather than the message text.

CodeMeaning
OG-DS-102Drop a node type that contains entities.
OG-DS-103Drop an edge type that contains entities.
OG-DS-104Drop a populated property.
OG-MF-103Add a required property to a populated type.
OG-MF-106Change a property's type, including enum narrowing or renaming.

omnigraph schema plan includes these codes in human and JSON output.

On this page