Skip to content

GQL

GQL

SurrealDB supports ISO/IEC 39075 GQL for graph pattern matching and data modification over your existing tables and RELATE edges. The surface syntax is closer to Cypher-style MATCH … RETURN than to SurrealQL SELECT, but it runs on the same storage model: node labels map to tables, edge types map to relation tables, and properties map to record fields.

Note

From 3.3.0, ISO GQL is enabled by default on POST /gql, the gql RPC method, and MCP - no experimental capability is required. On 3.2.x, enable it with --allow-experimental gql (or SURREAL_CAPS_ALLOW_EXPERIMENTAL=gql). The surface includes read queries (MATCH … RETURN) and data-modifying statements (INSERT, SET, REMOVE, DELETE) - see GQL mutations.

SurrealDB exposes two different graph query languages on separate endpoints. Do not abbreviate GraphQL to gql in product identifiers - the short name gql refers to ISO GQL only.

GQL (this guide)GraphQL
StandardISO/IEC 39075 GQLGraphQL
SyntaxMATCH (a)-[:knows]->(b) RETURN …query { persons { name } }
HTTPPOST /gqlPOST /graphql
WebSocket RPCmethod: "gql"method: "graphql"
SetupOn by default from 3.3.0 (experimental gql on 3.2.x)DEFINE CONFIG GRAPHQL
SchemaTables and RELATE edges you already haveAuto-generated GraphQL schema from your database
  • You already think in graph patterns such as (a)-[:knows]->(b), SHORTEST, and ALL SHORTEST, and have yet to learn how to query such paths in SurrealQL.

  • You are migrating from Neo4j and want to move Cypher queries to a standard language. GQL does not accept openCypher syntax, but most MATCH … RETURN queries carry over with the changes in Notable syntax differences from openCypher.

  • You want a stable graph query surface aligned with the ISO GQL standard.

For general-purpose schema changes, bulk load, and full SurrealQL expressiveness, keep using SurrealQL and the /sql endpoint. For ISO graph-pattern writes (INSERT, SET, REMOVE, DELETE), see GQL mutations.

SurfaceHow to call
HTTPPOST /gql - raw GQL query in the request body
WebSocket RPC{ "method": "gql", "params": ["<query>", { "var": value }] } - use for typed $variables
Postgres wireSET dialect = 'gql' (or options=-c dialect=gql at connect) on a Postgres client connection
MySQL wireSET dialect = 'gql' on a MySQL client connection, from SurrealDB 4.0
MCPgql tool (when the server exposes MCP)
SurrealQLeval::gql - nested GQL in the caller's transaction (capability-gated)

Session headers match /sql: Surreal-NS, Surreal-DB, and authentication. Responses use the same JSON envelope as /sql (status, result, time).

To experiment in the REPL without curl or POST /gql, wrap a GQL string in eval::gql. The function runs the same engine as the HTTP endpoint and participates in the caller's transaction (including mutations).

eval::gql needs the eval capability that --allow-all does not enable: --allow-eval-query (denied for every subject by default). From 3.3.0 you do not also need --allow-experimental gql (that flag is still required on 3.2.x).

Embedded REPL (surreal db sql against memory or a file path - no separate surreal db start):

echo 'eval::gql("MATCH (n:person) RETURN n.name AS name ORDER BY name");' | surreal db sql --user root --pass secret --allow-eval-query --pretty --hide-welcome

To explore interactively instead, open the same REPL without piping:

surreal db sql --user root --pass secret --allow-eval-query

Remote server (surreal db start + surreal db sql -e ws://…): pass --allow-eval-query on surreal db start only. The client REPL does not enable eval at runtime.

surreal db start --user root --pass secret --allow-eval-query

Optional bindings use an object as the second argument: eval::gql("… WHERE n.age > $min …", { min: 18 }). Full setup, seed data, and more examples can be found on the Eval functions page.

GQLSurrealDB
(:person)Records in table person
-[k:knows]->Records in relation table knows (in / out record IDs)
n.nameField name on the bound record
$minParameter - bind via RPC params object (typed JSON values)

GQL is not lowered to SurrealQL text - it compiles to an internal match plan and runs on the streaming engine. The sample queries page shows SurrealQL that returns the same shape where a close equivalent exists; some patterns (optional match blocks, path selectors) are much more concise in GQL.

SurrealDB implements a subset of ISO GQL. A statement outside the subset fails with an error, and changes no data.

SupportedNot supported yet
MATCH with several patterns, and several MATCH clausesCREATE and MERGE (use INSERT)
OPTIONAL MATCH, including the block formWITH, UNWIND, YIELD, LET, FOR, FILTER and CALL
Inline WHERE in a pattern, and WHERE clausesCASE, CAST and EXISTS
RETURN with DISTINCT, ORDER BY, SKIP / OFFSET and LIMITScalar functions, such as upper()
Edges in both directions (-> and <-)Undirected edges
Variable-length edges with a postfix quantifier: {1,3}, *, +, ?UNION, EXCEPT and INTERSECT
Path variables, and the ANY SHORTEST and ALL SHORTEST selectorsXOR, IN, CONTAINS, STARTS WITH and ENDS WITH
count, sum, avg, min, max and collect, with GROUP BYDISTINCT inside an aggregate, and NULLS FIRST / NULLS LAST
INSERT, SET, REMOVE, and DELETE with DETACH or NODETACH
  • -- starts a line comment, not an undirected edge.

  • Inequality is <>, not !=.

  • Label conjunction uses & (:person&employee), not :person:employee.

  • Variable-length quantifiers are postfix on the edge: -[e:knows]->{1,3}(b), not *1..3 inside the brackets.

  • No IN list membership operator in this subset.

Design notes, the supported subset, and mutation semantics are documented in the SurrealDB source tree under doc/gql/ (REFERENCE.md, LOWERING.md). The parser grammar is vendored from the upstream opengql/grammar project; that name refers to the grammar repository, not the ISO standard SurrealDB implements.

Was this page helpful?