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.
Warning
Linear programs
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
MATCHorOPTIONALafter a mutation re-scans live (post-write) state in the same transaction — a clause afterSETorDELETEsees updated or removed records; a clause afterINSERTsees created records and may bind variables theINSERTintroduced.RETURNis optional when the query mutates. Read-only queries must still end withRETURN.A mutation-only query (no
RETURN) returns an empty result.
The examples below assume that the following seed data has been first uploaded.
Via eval::gql
The same mutation strings work in the REPL when both gql and eval are allowed — see Try without HTTP:
SET
Update properties on a bound node or edge.
SET a.p = v— set one property.SET a = { … }— replace all user properties (aCONTENT-style replace). Properties absent from the map are dropped. The recordid, and an edge'sin/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.
REMOVE
Unset a property without deleting the record.
REMOVE a:Label is rejected for the same one-table-per-record rule as SET label mutations.
DELETE
Delete a matched node or edge.
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 becomenullin a trailingRETURN.
A deleted binding becomes null in post-mutation projections.
INSERT
Create nodes and edges. Each new node requires a label (table name).
Leading insert (no preceding MATCH) — runs once:
After MATCH — runs once per binding row. Relate existing endpoints or create new nodes:
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).
Read after write
Mutations and reads can interleave in one query:
The second MATCH sees the updated age on C and returns both B and C (both age 20).
RETURN after mutations
When present, RETURN projects the post-mutation binding table:
SET/INSERTrebind 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).
DELETEnulls deleted bindings;DETACH DELETEalso nulls cascaded edge bindings.
Rejected forms
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
INSERTgraph patterns (e.g. undirected edges, anonymous nodes without labels where required)
Parse and semantic errors return the same error envelope as read queries.
SurrealQL vs GQL for writes
| Task | Prefer |
|---|---|
Schema changes, bulk load, RELATE with arbitrary SurrealQL | SurrealQL on POST /sql |
| Graph-pattern read + write in one ISO GQL program | GQL mutations on POST /gql |
| Nested GQL inside an open SurrealQL transaction | eval::gql |
Next steps
GQL overview — capabilities, wire surfaces, and syntax differences from openCypher
Sample queries — read-only pattern examples
POST /gql— HTTP headers and response envelope