• Start

GQL

Mutations

ISO GQL data-modifying statements — INSERT, SET, REMOVE, and DELETE — on the /gql endpoint.

Available since: v3.2.0

ISO GQL on SurrealDB supports the four data-modifying statements from the standard — INSERT, SET, REMOVE, and DELETE — in addition to read-only MATCH … RETURN queries. Mutations run on the same POST /gql endpoint and through eval::gql when the gql capability is enabled.

A GQL query is a linear program: an ordered sequence of MATCH / OPTIONAL read clauses and data-modifying statements, in any interleaving, optionally ending in RETURN.

  • The binding table threads through every step in textual order.

  • A MATCH or OPTIONAL after a mutation re-scans live (post-write) state in the same transaction — a clause after SET or DELETE sees updated or removed records; a clause after INSERT sees created records and may bind variables the INSERT introduced.

  • RETURN is optional when the query mutates. Read-only queries must still end with RETURN.

  • A mutation-only query (no RETURN) returns an empty result.

The examples below assume that the following seed data has been first uploaded.

The same mutation strings work in the REPL when both gql and eval are allowed — see Try without HTTP:

eval::gql("MATCH (n:person WHERE n.name = 'A') SET n.age = 99 RETURN n.age AS age");
-- { age: 99 }

Update properties on a bound node or edge.

MATCH (n:person WHERE n.name = 'A') SET n.age = 99 RETURN n.age AS age
  • SET a.p = v — set one property.

  • SET a = { … } — replace all user properties (a CONTENT-style replace). Properties absent from the map are dropped. The record id, and an edge's in / out, are preserved.

Setting reserved keys id, in, or out is rejected on both the per-property form (SET a.id = …) and the object form.

SET a:Label is rejected — a SurrealDB record belongs to exactly one table; labels are immutable.

Unset a property without deleting the record.

MATCH (n:person WHERE n.name = 'A') REMOVE n.age RETURN n.name AS name

REMOVE a:Label is rejected for the same one-table-per-record rule as SET label mutations.

Delete a matched node or edge.

MATCH (n:person WHERE n.name = 'A') DETACH DELETE n
  • NODETACH DELETE (ISO default) — errors if the node still has connected edges.

  • DETACH DELETE — deletes the node and cascades connected edges. Bound edge variables for cascaded edges become null in a trailing RETURN.

A deleted binding becomes null in post-mutation projections.

Create nodes and edges. Each new node requires a label (table name).

Leading insert (no preceding MATCH) — runs once:

INSERT (p:person {name: 'Z', age: 1}) RETURN p.name AS name

After MATCH — runs once per binding row. Relate existing endpoints or create new nodes:

MATCH (a:person WHERE a.name = 'A')
MATCH (b:person WHERE b.name = 'C')
INSERT (a)-[:likes]->(b)
RETURN a.name AS src, b.name AS dst

Graph-pattern form: INSERT (a:Label {…})-[:Edge {…}]->(b:Label {…}). A node with no label and no properties references a variable already bound by a preceding MATCH (an existing endpoint).

Mutations and reads can interleave in one query:

MATCH (n:person WHERE n.name = 'C') SET n.age = 20
MATCH (m:person WHERE m.age = 20)
RETURN m.name AS name ORDER BY name

The second MATCH sees the updated age on C and returns both B and C (both age 20).

When present, RETURN projects the post-mutation binding table:

  • SET / INSERT rebind the mutated or created record (the after image).

  • Fan-out that binds the same record more than once applies writes per row, in order (last-write-wins for row-dependent values).

  • DELETE nulls deleted bindings; DETACH DELETE also nulls cascaded edge bindings.

The lowering layer rejects several ISO forms that do not map cleanly to SurrealDB's one-table-per-record model, including:

  • Label mutations (SET a:Label, REMOVE a:Label)

  • Mutations on unbound variables, groups, or path patterns

  • Reserved property keys on SET (id, in, out)

  • Malformed INSERT graph patterns (e.g. undirected edges, anonymous nodes without labels where required)

Parse and semantic errors return the same error envelope as read queries.

TaskPrefer
Schema changes, bulk load, RELATE with arbitrary SurrealQLSurrealQL on POST /sql
Graph-pattern read + write in one ISO GQL programGQL mutations on POST /gql
Nested GQL inside an open SurrealQL transactioneval::gql
  • GQL overview — capabilities, wire surfaces, and syntax differences from openCypher

  • Sample queries — read-only pattern examples

  • POST /gql — HTTP headers and response envelope

Was this page helpful?