Omnigraph
Schema

Edges

Edge types define directed relationships between node types, with optional properties and cardinality constraints.

An edge declaration creates a directed relationship between two node types. Each edge type gets its own storage table with three built-in columns — id, src, and dst — plus one column per declared property.

Basic syntax

edge WorksAt: Person -> Company

The identifier after edge is the type name. The source and destination are existing node type names separated by ->.

Edge properties

Edges can carry properties just like nodes. Declare them inside braces:

edge Knows: Person -> Person {
    since:      Date?
    confidence: F64?
}

Property rules are the same as for nodes: each property has a name, a type, and optional annotations. Nullable properties use the ? suffix.

Self-referencing edges

An edge can connect a node type to itself:

edge Knows: Person -> Person
edge DependsOn: Task -> Task

This is how you model recursive structures like social graphs, dependency chains, or org hierarchies.

Cardinality constraints

Use the @card body constraint to limit how many edges of a given type can originate from or point to a single node.

edge ManagedBy: Employee -> Manager {
    @card(1..1)
}

The range syntax:

PatternMeaning
@card(1..1)Exactly one edge per source node.
@card(0..1)At most one edge per source node.
@card(1..)At least one edge per source node.
@card(0..)No constraint (default).

Cardinality is checked when edges are inserted or deleted. A mutation that would violate the constraint is rejected.

Preventing duplicate edges

Use @unique(src, dst) to ensure that at most one edge of a given type exists between any pair of nodes:

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

Without this constraint, multiple WorksAt edges between the same Person and Company are allowed (which may be useful for modeling separate employment periods).

Edge storage

Every edge row contains:

ColumnTypeDescription
idU64Auto-generated unique identifier.
srcU64Row id of the source node.
dstU64Row id of the destination node.

Plus one column per declared property. The src and dst columns are indexed automatically for efficient traversal in both directions.

Full example

A decision-tracking graph with multiple edge types:

node Actor {
    name: String @key
    role: String
}

node Decision {
    slug:   String @key
    title:  String @index
    status: enum(proposed, accepted, rejected, superseded)
}

node Signal {
    slug:     String @key
    title:    String @index
    strength: enum(strong, moderate, weak)
}

edge Authored: Actor -> Decision {
    date: Date
    @description("Records who authored a decision and when.")
}

edge Informed: Signal -> Decision {
    weight: F64?
    @description("Links a signal to the decision it informed.")
}

edge Supersedes: Decision -> Decision {
    @card(0..1)
    @description("A newer decision that replaces an older one.")
}

edge Supports: Signal -> Signal {
    @unique(src, dst)
    @description("One signal corroborating another.")
}

On this page