Docs
View as markdown

Differences from Neo4j

Where relate's Cypher differs from what Neo4j habits suggest, with the exact error each habit produces in relate and the form to write instead.

cypherclipython

relate speaks Neo4j's Cypher The declarative graph query language relate runs, written as ASCII-art patterns such as (a)-[:KNOWS]->(b); relate follows Neo4j's Cypher 25 by default. Read more in the glossary, including much of Cypher 25, inside your process. It runs embedded, with no procedure libraries such as APOC and no user accounts, and serves a network surface only when relate serve starts one, so a statement or a connection string written from Neo4j habits can fail in relate. The table lists those habits with the error relate returns, character for character, and the form that works. Everything not in the table behaves as the Cypher overview describes.

Synopsis

Each row is one habit. The relate column quotes the message relate returns: the CLI prints it on stderr and, under --mode json, jsonl or envelope, in the error object's message on stdout; a client raises it. The examples run each one.

The Neo4j column gives the habit's origin in Neo4j as of 2026-11-07, for current releases under Cypher 25 unless a row names a release. It summarizes Neo4j's behavior and was not checked against a Neo4j server; the relate and Write instead columns were checked against relate.

Differences

FeatureNeo4jrelateWrite instead
APOC functionsThe APOC library adds apoc.* functionsNo APOC. syntax error: UnknownFunction: unknown function apoc.text.join()A built-in function, such as string.join(list, ', '); SHOW FUNCTIONS lists them all
APOC proceduresThe APOC library adds apoc.* proceduressyntax error: ProcedureNotFound: apoc.meta.schemaCALL db.schema.nodeTypeProperties(), CALL db.schema.relTypeProperties() or CALL db.schema.visualization() for the schema; SHOW PROCEDURES lists the rest
Graph Data Science proceduresThe GDS library adds gds.* proceduressyntax error: ProcedureNotFound: gds.pageRank.streamCypher patterns and aggregation, or an algorithm in your own code over a query result
Index proceduresNeo4j 5 releases created vector indexes with the procedure db.index.vector.createNodeIndexsyntax error: ProcedureNotFound: db.index.vector.createNodeIndexCREATE VECTOR INDEX <name> FOR (n:<Label>) ON (n.<property>) OPTIONS {indexConfig: {…}}, or CREATE FULLTEXT INDEX
db.index.vector.queryNodesA procedure for top-k vector queriesRuns, and is deprecated: EXPLAIN reports The procedure `db.index.vector.queryNodes` is deprecated. with the remedy Use the `SEARCH` clause instead. The three other search procedures report the sameMATCH (n:<Label>) SEARCH n IN (VECTOR INDEX <name> FOR $vector LIMIT <k>) SCORE AS score
The SEARCH scoreThe SEARCH clauseLIMIT is required, and the score exists only through SCORE AS: syntax error: UndefinedVariable: variable 'score' not definedSEARCH n IN (… LIMIT <k>) SCORE AS score; the search reference has every rule
Cosine similarity rangevector.similarity.cosine returns 0 to 1The same range: 1.0 same direction, 0.5 orthogonal, 0.0 opposite. A threshold taken from a raw cosine (−1 to 1) is on another scaleConvert a raw-cosine threshold t to (1 + t) / 2; vector_distance(a, b, COSINE) returns the raw cosine distance
Drivers and bolt://A server; drivers connect to bolt:// or neo4j://Embedded: no server unless one is started. Failed to open Relate: storage error: unsupported URI scheme bolt:// (engine URIs are :memory:, a filesystem path, or file://) (exit code 1); the Python client raises OperationalError with the message that follows Failed to open Relate: Open the store in your process with a client, relate.connect("./graph.rl"), or serve it to a Neo4j driver with relate serve --bolt <port> --database ./graph.rl --read-only
Several databasesCREATE DATABASE, then USE <name>Three fixed namespaces: neo4j, system, system_ontologies. semantic error: DatabaseNotFound: Graph not found: movies; semantic error: UnsupportedAdministrationCommand: Unsupported administration command: CREATE DATABASE moviesOne store per graph: --database ./movies.rl; Namespaces explains the three names
Users, roles, and privilegesCREATE USER, roles, GRANTNo user management. CREATE USER bob SET PASSWORD 'secret' fails with syntax error: parse error: expected a patternFile permissions on the store, --read-only, and relate serve --auth <user>:<password> on a served store
Many writers on one databaseThe server takes writes from many clientsOne writing process per store. A second opener fails with Failed to open Relate: storage locked: <path> (exit code 5)One process owns the store. Beside that writer, a directory store opens with --read-only; a .rl file opens read-only only after the writer exits. Otherwise go through relate serve
DROP INDEX, DROP CONSTRAINTThe result summary counts what was removedThe CLI prints nothing on success. A missing name fails: semantic error: NoSuchIndex: `<name>` , semantic error: ConstraintNotFoundSHOW INDEXES or SHOW CONSTRAINTS before and after; IF EXISTS for a drop that may find nothing
LOAD CSV sourcesFiles from the server's import directory, and http and https URLsLocal files under the --load-csv-dir directory only, denied by default. Anything else: LOAD CSV file unavailable (exit code 1)Download the file first, then --load-csv-dir <dir>; see import a CSV
Long explicit path boundsNo fixed ceiling on *1..NMore than 500 hops: syntax error: TraversalDepthExceeded: This query allows paths up to <n> hops. This is a safety limit protecting against excessive traversal (not a database limit) — lower the path bound, or raise it with --max-traversal-depth (up to 2000)., where <n> is the statement's own bound, not the limitA lower bound, or --max-traversal-depth <n> up to 2000
Browser and shell commands:param, :use and other colon commands in Neo4j Browser and cypher-shellNot Cypher: syntax error: parse error: unexpected token ":"--param <name>=<value> on the CLI, a parameters map in a client
id()DeprecatedRuns, and is deprecated: EXPLAIN reports The function `id()` is deprecated. with the remedy Use `elementId` instead.elementId(n)
CALL { … } IN CONCURRENT TRANSACTIONSBatches run in parallelAccepted; the batches run one after another in the embedded engineNo change needed
Default Cypher versionSet by the server's version and configurationCYPHER 25 for every namespace, as SHOW DATABASES reports in defaultLanguageA CYPHER 5 prefix on a statement that needs Cypher 5 behavior

Examples

The examples run in page order on one in-memory store A relate database: a directory, a single .rl file, or :memory:, opened with --database. Read more in the glossary with the shared example graph:

Cypher
CREATE (ada:Person {name: 'Ada', role: 'engineer'}),
       (grace:Person {name: 'Grace', role: 'engineer'}),
       (noor:Person {name: 'Noor', role: 'maintainer'}),
       (relate:Project {name: 'relate', language: 'Rust'}),
       (tck:Project {name: 'opencypher-tck', language: 'Gherkin'}),
       (ada)-[:WORKS_ON {since: 2024}]->(relate),
       (grace)-[:WORKS_ON {since: 2023}]->(relate),
       (grace)-[:WORKS_ON {since: 2022}]->(tck),
       (noor)-[:MAINTAINS]->(relate),
       (ada)-[:KNOWS]->(grace)
Recorded result
(no rows) · nodes created: 5, relationships created: 5, properties set: 13, labels added: 5

An APOC function fails, and the built-in returns the same string:

Cypher
MATCH (p:Person) RETURN apoc.text.join(collect(p.name), ', ') AS names
Expected error
error: syntax error: UnknownFunction: unknown function apoc.text.join()
Cypher
MATCH (p:Person) WITH p ORDER BY p.name RETURN string.join(collect(p.name), ', ') AS names
Recorded result
names
"Ada, Grace, Noor"

1 row

An APOC schema procedure fails; the db.schema procedures describe the same graph:

Cypher
CALL apoc.meta.schema() YIELD value RETURN value
Expected error
error: syntax error: ProcedureNotFound: apoc.meta.schema
Cypher
CALL db.schema.nodeTypeProperties() YIELD nodeType, propertyName, propertyTypes
RETURN nodeType, propertyName, propertyTypes
ORDER BY nodeType, propertyName
Recorded result
nodeTypepropertyNamepropertyTypes
":Person""name"["STRING NOT NULL"]
":Person""role"["STRING NOT NULL"]
":Project""language"["STRING NOT NULL"]
":Project""name"["STRING NOT NULL"]

4 rows

An index procedure fails; CREATE VECTOR INDEX is the statement:

Cypher
CALL db.index.vector.createNodeIndex('person_focus', 'Person', 'focus', 3, 'cosine')
Expected error
error: syntax error: ProcedureNotFound: db.index.vector.createNodeIndex

A database name other than the three namespaces fails, and so does creating one:

Cypher
USE movies MATCH (n) RETURN count(n) AS n
Expected error
error: semantic error: DatabaseNotFound: Graph not found: movies
Cypher
CREATE DATABASE movies
Expected error
error: semantic error: UnsupportedAdministrationCommand: Unsupported administration command: CREATE DATABASE movies
Cypher
SHOW DATABASES YIELD name, defaultLanguage RETURN name, defaultLanguage
Recorded result
namedefaultLanguage
"neo4j""CYPHER 25"
"system""CYPHER 25"
"system_ontologies""CYPHER 25"

3 rows

A path bound beyond the default limit of 500 hops fails before the statement runs:

Cypher
MATCH (a:Person)-[:KNOWS*1..1000]->(b:Person) RETURN count(*) AS n
Expected error
error: syntax error: TraversalDepthExceeded: This query allows paths up to 1,000 hops. This is a safety limit protecting against excessive traversal (not a database limit) — lower the path bound, or raise it with --max-traversal-depth (up to 2000).

The cosine scale, and the raw cosine distance next to it:

Cypher
RETURN vector.similarity.cosine([1, 0], [0, 1]) AS orthogonal,
       vector.similarity.cosine([1, 0], [-1, 0]) AS opposite,
       vector_distance(vector([1, 0], 2, FLOAT32), vector([0, 1], 2, FLOAT32), COSINE) AS rawDistance
Recorded result
orthogonaloppositerawDistance
0.50.01.0

1 row

A bolt:// address is not a store, on the CLI:

relate --database bolt://localhost:7687 --mode envelope "RETURN 1 AS ok"

The first line is stderr, the second the error object on stdout:

Failed to open Relate: storage error: unsupported URI scheme bolt:// (engine URIs are :memory:, a filesystem path, or file://)
{"error":{"code":"fatal_error","exit_code":1,"kind":"storage","message":"storage error: unsupported URI scheme bolt:// (engine URIs are :memory:, a filesystem path, or file://)","retryable":false}}

LOAD CSV does not fetch a URL, even with a directory allowed:

mkdir import
relate --load-csv-dir ./import --mode envelope "LOAD CSV FROM 'https://example.com/people.csv' AS row RETURN row"
LOAD CSV file unavailable
{"error":{"code":"fatal_error","exit_code":1,"kind":"execution","message":"LOAD CSV file unavailable","retryable":false}}

See also

  • Cypher overview: what the dialect covers, and the preview features.
  • Search: the SEARCH clause and the vector functions.
  • Limitations: the scope choices behind several rows.
  • Errors: every message with its exit code The number a relate run returns to the shell; each nonzero value names a class of failure, such as 2 for usage, 5 for conflict, 6 for a rejected statement. Read more in the glossary and remedy.
  • The Cypher dialect: why the dialect differs where it does.
  • Migrate from Neo4j: the features beyond the dialect, such as APOC, GDS and clustering, with what to use instead.