Omnigraph
Queries search

Query Language (`.gq`)

A .gq file contains named, typed queries. Read queries match graph patterns

A .gq file contains named, typed queries. Read queries match graph patterns and return columns; mutation queries use the same declaration form and are covered in Mutations.

query engineers($title: String) @description("People with a title") {
  match {
    $p: Person { title: $title }
    $p worksAt $c
  }
  return { $p.name, $c.name as company }
  order { company asc, $p.name asc }
  limit 50
}

Run an ad-hoc query with:

omnigraph query engineers --query queries.gq \
  --params '{"title":"Engineer"}' --store graph.omni

Declarations and parameters

query <name>($required: String, $optional: I32?) { ... }

Parameter types use the schema scalar types. A trailing ? accepts null or an omitted value. @description("...") and @instruction("...") attach metadata for clients that expose stored queries as tools.

Match patterns

Inside match { ... }:

PatternMeaning
$p: Person { name: $name }Bind nodes and filter properties.
$person worksAt $companyFollow a directed edge.
$a knows{1,3} $bFollow a path from one to three hops.
$a <related> $bMatch the edge in either direction. The edge must connect the same node type at both ends.
$a $rel:related $bBind a single-hop edge instance so its properties can be used.
$p.age >= 18Apply a filter expression.
not { $p Blocked $other }Keep rows for which the inner pattern has no match.

An unbound traversal has set semantics for endpoint pairs. Binding the edge returns one result per matching edge, so parallel edges remain distinct. Edge bindings are available only for a single hop.

Traversal spelling begins with a lowercase letter (worksAt for the declared edge WorksAt); edge lookup itself is case-insensitive.

Comparison operators are =, !=, <, <=, >, and >=.

Strings and lists

  • $x.tags contains "rust" tests membership when tags is a list.
  • $x.title contains "graph" tests exact, case-sensitive substring containment when title is a String.
  • $x.title starts_with "Omni" tests an exact, case-sensitive prefix.

NULL never matches these predicates. % and _ are ordinary characters, not wildcards. The predicates remain correct without an index; do not assume a free-text String index accelerates exact prefix or substring filters.

Use full-text search for tokenization, fuzzy matching, and relevance ranking.

Return, order, and limit

return { $person.name, count($company) as companies }
order { companies desc, $person.name asc }
limit 20

Return expressions include variables, properties, literals, now(), earlier projection aliases, and the aggregates count, sum, avg, min, and max. Search expressions are documented in Search.

An explicit order is total and deterministic: OmniGraph adds entity ids as a final tie-breaker when user keys are equal. Ascending order places nulls first; descending order places them last. nearest(...) ordering requires a limit.

Blobs

Blob properties are not ordinary read-query values. They cannot be projected, filtered, ordered, or passed to an aggregate. Read one logical Blob cell with the CLI or HTTP Blob endpoint described in Blobs. Blob parameters remain valid for mutation assignment.

Branches and historical reads

Reads default to main. Select another branch or an immutable commit with --branch or --snapshot:

omnigraph query engineers --query queries.gq --branch review \
  --params '{"title":"Engineer"}' --store graph.omni

When the snapshot has an effective graph head, omnigraph query --json includes its graph_commit_id, pinned with the returned rows. Use that same-snapshot id with a later mutation's --if-commit option when implementing read-modify-write. On a newly created, unmodified branch, it is the head inherited from the source branch and is valid for the branch's first conditional mutation.

See Branches, Commits, and History.

Linting

Validate queries without running them:

omnigraph lint --query queries.gq --schema schema.pg --json

Q000 identifies parse errors. L201 warns when a nullable property is never set by any update query in the inspected set. Type errors report the affected query and source location. The command exits nonzero when the overall status is an error.

For every query that compiles successfully, JSON output includes an operation descriptor:

  • result lists projected fields in return order. Each field has name, kind, and nullable; list fields also have item_kind, and vectors have vector_dim.
  • reads conservatively lists every node or edge type the query may inspect.
  • writes lists every node or edge type the query may change and is empty for a read query.

Read and write entries are sorted, deduplicated objects with kind (node or edge) and the case-sensitive type_name. Result kinds use the spellings string, bool, int, bigint, float, date, datetime, blob, vector, list, and object. A parse or type error has no operation descriptor.

A mutation target appears in both reads and writes. An edge insert also reads its endpoint node types, and a node delete includes incident edge types that its cascade may remove.

On this page