Insert
Add new nodes and edges to the graph.
The insert operation adds new nodes and edges to the graph. Inserts are
validated against the schema at commit time: every required property must be
present, types must match, and constraint annotations are enforced.
Inserting nodes
Use insert TypeName { ... } inside a named query to add a node:
query add_person($name: String, $age: I32) {
insert Person { name: $name, age: $age }
}Run it from the CLI:
omnigraph change --uri ./graph.omni \
--query mutations.gq \
--name add_person \
--params '{"name": "Alice", "age": 30}'Or via the HTTP API:
curl -X POST http://localhost:8080/change \
-H "Content-Type: application/json" \
-d '{
"query_source": "query add_person($name: String, $age: I32) { insert Person { name: $name, age: $age } }",
"query_name": "add_person",
"params": {"name": "Alice", "age": 30},
"branch": "main"
}'Nullable properties
Properties marked with ? in the schema can be omitted from the insert.
Omitted nullable properties default to null:
node Person {
name: String @key
age: I32?
bio: String?
}query add_person($name: String) {
insert Person { name: $name }
}This inserts a Person with age and bio set to null.
Inserting edges
Edges connect two existing nodes. You reference the source and destination by
their @key values using the reserved fields from and to:
query add_edge($person: String, $company: String) {
insert WorksAt { from: $person, to: $company }
}omnigraph change --uri ./graph.omni \
--query mutations.gq \
--name add_edge \
--params '{"person": "Alice", "company": "Acme"}'If the edge type has properties, include them in the insert:
query add_knows($a: String, $b: String, $since: Date) {
insert Knows { from: $a, to: $b, since: $since }
}Both the source and destination nodes must already exist. If either is missing, the insert fails with a referential integrity error.
Upsert behavior for keyed node types
When you insert a node whose type has a @key property, and a node with that
key value already exists, Omnigraph performs an upsert: the existing node is
updated with the new property values instead of creating a duplicate.
node Person {
name: String @key
age: I32?
}query upsert_person($name: String, $age: I32) {
insert Person { name: $name, age: $age }
}If a Person with name = "Alice" already exists, this updates her age
rather than inserting a second row.
Constraint validation
Inserts are checked against every constraint declared in the schema:
| Constraint | Behavior on insert |
|---|---|
@key | Upserts if a matching key already exists |
@unique | Rejects the insert if a duplicate value exists |
@range | Rejects the insert if the value is outside the declared range |
@check | Rejects the insert if the check expression evaluates to false |
| Required properties | Rejects the insert if a non-nullable property is missing |
If any constraint fails, the entire transaction is rolled back and no data is written.
Auto-embed columns
When a Vector(N) property carries an @embed(source_prop) annotation, you
can omit it from the insert. The engine generates the embedding from the
source property at commit time. You only need to populate the embedding
explicitly if you want to skip the runtime embedder.
node Document {
title: String @key
body: String
embedding: Vector(1536) @embed(body) @index
}query add_document($title: String, $body: String) {
insert Document { title: $title, body: $body }
}The embedding column is populated automatically from body. Omitting an
@embed-source property when the embedding column is also omitted is rejected
, provide one or the other.
now() inside inserts
now() is valid anywhere a DateTime value is expected, including insert
bodies:
query log_event($kind: String, $message: String) {
insert Event {
kind: $kind,
message: $message,
recorded_at: now(),
}
}Bulk inserts with JSONL
For loading large volumes of data, use the load subcommand with a JSONL file
instead of individual insert mutations:
omnigraph load ./graph.omni --data data.jsonlSee the Quick Start for the JSONL format.
Blob properties
Node types with Blob properties accept two value formats in inserts.
Base64-encoded inline data:
query add_photo($slug: String) {
insert Photo {
slug: $slug,
image: "base64:iVBORw0KGgo...",
}
}URI reference (S3 or local path):
query add_photo_from_s3($slug: String) {
insert Photo {
slug: $slug,
image: "s3://my-bucket/photos/sunset.jpg",
}
}Blob properties appear as null in normal query projections. To read blob
bytes, use the dedicated blob read API rather than a standard return
projection.