Cypher is a language that is constantly evolving. New features are added to the language continuously, and occasionally, some features become deprecated and are subsequently removed. All changes to Cypher are introduced in Neo4j versions.
This section lists all of the features that have been removed, deprecated, added, or extended in different versions of Neo4j. Replacement syntax for deprecated and removed features are also indicated.
|
Important
|
Neo4j 2026.02+ databases explicitly set Cypher 25 as their query language.
Cypher 25 was introduced in Neo4j 2025.06 and can only be used on Neo4j 2025.06+ databases.
Features removed in Cypher 25 are still available on Neo4j 2025.06+ databases either by prepending a query with CYPHER 5 or by having Cypher 5 as the default language for the database.
For more information, see queries/select-version.adoc.
|
| Feature | Details |
|---|---|
label:functionality[] label:updated[] New databases now explicitly set Cyper 25 as their query language. |
New self-managed installations and new Aura instances now explicitly set Cyper 25 as their query language.
New self-managed deployments have the setting + In Aura, Cypher 25 is the default for newly created organisations. The default query language attached to created databases is determined by the organisation setting "Default Cypher Version" and can be manually changed. |
label:functionality[] label:updated[] SHOW CONSTRAINTS YIELD name, enforcedLabel, classification |
Introduced two new columns returned by
For more information, see Constraints → Result columns for listing constraints and Graph types → Graph type elements in |
label:functionality[] label:updated[] SHOW [NODE] EXIST[ENCE] CONSTRAINTS |
The |
label:functionality[] label:updated[] SHOW CONSTRAINTS |
The |
| Feature | Details |
|---|---|
label:functionality[] label:new[] Added the performance-improving operator |
|
label:functionality[] label:new[] label:preview[] ALTER CURRENT GRAPH TYPE SET {
(:Person => :Resident {name :: STRING NOT NULL}),
(:Pet => :Resident&Animal {healthCertificate :: STRING, name :: STRING}),
(:City => {name :: STRING NOT NULL, population :: INTEGER}),
(:Resident)-[:LIVES_IN => {since :: DATE NOT NULL}]->(:City)
} |
Introduced the ability to set a graph type for a database using the |
label:functionality[] label:new[] label:preview[] ALTER CURRENT GRAPH TYPE ADD {
(p:Person => :Resident {name :: STRING, ssn :: INTEGER, nationality :: STRING})
REQUIRE (p.name, p.ssn) IS KEY,
CONSTRAINT pet_address FOR (pet:Pet) REQUIRE pet.address IS NOT NULL,
(:Animal => {type :: STRING NOT NULL})
} |
Introduced the ability to extend graph types using the |
label:functionality[] label:new[] label:preview[] ALTER CURRENT GRAPH TYPE ALTER {
(:Robot => :Resident&Machine {application :: STRING NOT NULL, id :: INTEGER NOT NULL}),
(:Resident)-[:LIVES_IN => {since :: ANY NOT NULL}]->(:City)
} |
Introduced the ability to alter element types in a graph type using the |
label:functionality[] label:new[] label:preview[] SHOW CURRENT GRAPH TYPE |
Introduced the ability to show graph types using the |
label:functionality[] label:new[] label:preview[] ALTER CURRENT GRAPH DROP {
(:Pet =>),
CONSTRAINT pet_address
} |
Introduced the ability to drop element types and constraints from graph types using the |
label:functionality[] label:new[] GQL naming aliases for functions RETURN ceiling(1.2) AS c, ln(2.0) AS natural_log,
char_length("Hello") AS len, lower("Neo4j") AS lower, upper("Neo4j") AS upper;RETURN local_time() AS t, local_datetime() AS ldt,
zoned_time() AS zt, zoned_datetime() AS zdt;RETURN duration_between(date("2020-01-01"), date("2020-02-01")) AS d;MATCH p = (a)-[r]->(b)
RETURN path_length(p) AS path_len;UNWIND [1, 2, 3] AS n
RETURN collect_list(n) AS list,
percentile_cont(n, 0.5) AS p50,
percentile_disc(n, 0.5) AS p50_disc,
stdev_samp(n) AS sd_samp,
stdev_pop(n) AS sd_pop; |
Cypher now provides GQL naming aliases so that queries written for other GQL implementations can run with minimal changes.
Aliases added: |
| Feature | Details |
|---|---|
label:functionality[] label:new[] CREATE VECTOR INDEX multiLabel
FOR (n:Label1|Label2)
ON n.embeddingCREATE VECTOR INDEX multiRelType
FOR ()-[r:REL_TYPE1|REL_TYPE2]-()
ON r.embeddingCREATE VECTOR INDEX additionalProperties
FOR (n:Label)
ON n.embedding
WITH [n.propety1, n.property2] |
Vector indexes can now have multiple labels, relationship types or include additional properties for filtering. |
| Feature | Details |
|---|---|
label:functionality[] label:new[] MATCH (n)
SEARCH n IN (
VECTOR INDEX nodeVectorIndex
FOR $vectorEmbedding
WHERE n.prop > 10
LIMIT 5
)
RETURN nMATCH ()-[r]->()
SEARCH r IN (
VECTOR INDEX relVectorIndex
FOR $vectorEmbedding
LIMIT 5
)
RETURN r |
A new SEARCH subclause for |
label:functionality[] label:new[] Introduced a query size limit. |
Introduced a query size limit for a query to be considered for query caching. This limit is used to prevent large generated query text strings from occupying memory in the query cache. |
| Feature | Details |
|---|---|
label:functionality[] label:updated[] label,name
Actor,Henry CavillCREATE RANGE INDEX actor_has_name FOR (a:Actor) ON (a.name);
LOAD CSV WITH HEADERS FROM 'people.csv' AS row
MERGE (:$(row.label) { name: row.name }) |
Cypher can now leverage indexes on property values, improving the performance of
|
| Feature | Details |
|---|---|
label:functionality[] label:new[] RETURN coll.distinct([true, false, false, true, true, false])
RETURN coll.flatten([1, [2]]), coll.flatten([false, ['a']], 2);
RETURN coll.indexOf(['A', 'new', 'function'], 'new');
RETURN coll.insert([1, 2, 4], 2, 3);
RETURN coll.max([1.5, 2, 5.4, 0, 4]);
RETURN coll.min([1.5, 2, 5.4, 0, 4]);
RETURN coll.remove(['a', 'a', 'b', 'c', 'd'], 2);
RETURN coll.sort([3, 1, 4, 2, 'a', 'c', 'b']); |
Introduction of eight new collection-based Cypher functions. For more information, see Functions → List functions. |
label:functionality[] label:new[] Added the performance-improving operators |
|
| Feature | Details |
|---|---|
label:functionality[] label:updated[] RETURN toFloatList(Vector([1, 2, 3], 3, INTEGER64)),
toIntegerList(Vector([1, 2, 3], 3, INTEGER8)),
vector.similarity.cosine(vector([3, 5, 7], 3, INT), vector([-1, -2, -3], 3, INT)),
vector.similarity.euclidean(vector([3, 5, 7], 3, INT), vector([-1, -2, -3], 3, INT)) |
The |
label:functionality[] label:updated[] RETURN datetime('11/18/1986', "MM/dd/yyyy") AS dt |
The following constructors of temporal types have been extended with the optional argument |
| Feature | Details |
|---|---|
label:functionality[] label:new[] VECTOR([1.05, 0.123, 5], 3, FLOAT32 NOT NULL) |
Introduced a |
label:functionality[] label:new[] WITH vector([1, 2, 3], 3, INTEGER) AS vector
RETURN vector, valueType(vector) AS vectorType |
|
label:functionality[] label:new[] RETURN vector_dimension_count(vector([1, 2, 3], 3, INTEGER)) AS size |
New |
label:functionality[] label:new[] RETURN vector_distance(vector([1, 2, 3], 3, INT), vector([1, 2, 4], 3, INT), COSINE) AS distance |
New |
label:functionality[] label:new[] RETURN vector_norm(vector([1.0, 5.0, 3.0, 6.7], 4, FLOAT), EUCLIDEAN) AS norm |
New |
label:functionality[] label:new[] CREATE CONSTRAINT node_vector_constraint
FOR (n:Movie) REQUIRE n.embedding IS :: VECTOR<INT32>(42)CREATE CONSTRAINT rel_vector_constraint
FOR ()-[r:CONTAINS]->() REQUIRE r.embedding IS :: VECTOR<FLOAT32>(1536) |
Introduced |
| Feature | Details |
|---|---|
label:functionality[] label:new[] WITH datetime('1986-11-18T6:04:45.123456789+01:00[Europe/Berlin]') AS dt
RETURN format(dt, "MM/dd/yyyy") AS US, format(dt, "dd/MM/yyyy") AS EU |
Cypher’s new |
label:functionality[] label:new[] New operator: |
Introduced |
| Feature | Details |
|---|---|
label:functionality[] label:updated[] MATCH (p:Product) WHERE p.name <> "Coffee"
CALL (p) {
MATCH (p)<-[:BUYS]-(c:Customer)-[:BUYS]->(otherProduct)
RETURN c, otherProduct
NEXT
RETURN count(DISTINCT c) AS customers, 0 AS customersAlsoBuyingCoffee
UNION
FILTER otherProduct.name = "Coffee"
RETURN 0 as customers, count(DISTINCT c) AS customersAlsoBuyingCoffee
NEXT
RETURN max(customers) AS customers, max(customersAlsoBuyingCoffee) AS customersAlsoBuyingCoffee
}
RETURN p.name AS product,
round(toFloat(customersAlsoBuyingCoffee) * 100 / customers, 1) AS percentageOfCustomersAlsoBuyingCoffee
ORDER BY product |
|
label:functionality[] label:updated[] PROFILE
WITH "Person" AS label
MATCH (people:$(label))
RETURN people.name |
Cypher can now leverage token lookup indexes when planning queries with dynamic labels and relationship types.
This is enabled by the introduction of three new query plan operators: |
| Feature | Details |
|---|---|
label:functionality[] label:new[] MATCH (()-->(n))+
WHERE allReduce(acc = 0, node IN n | acc + node.x, 6 < acc < 30)
RETURN [i IN n | i.x] AS sequence
ORDER BY head(n).x, size(n) |
New |
| Feature | Details |
|---|---|
label:functionality[] label:updated[] MATCH (n)-[r]->()
WHERE n:$(<expr1>)
WITH n, r:$(<expr2>) AS hasType
RETURN n:$(<expr3>) |
Added the ability to dynamically reference node labels and relationship types in places where label expressions are allowed. |
| Feature | Details |
|---|---|
label:functionality[] label:removed[] CREATE DATABASE db OPTIONS { seedCredentials: ... } |
The option |
label:functionality[] label:removed[] CREATE DATABASE db OPTIONS { existingDataSeedInstance: ... } |
The option |
label:functionality[] label:removed[] CREATE ALIAS composite.`1` FOR DATABASE neo4jUSE composite.`1` |
Graph references with separately backticked name parts have been removed. Use parameters or backtick the entire name, e.g. |
label:functionality[] label:removed[] RETURN 1 as my\u0085identifier |
The Unicode character |
label:functionality[] label:removed[] RETURN 1 as my$Identifier |
The character with the Unicode representation The following Unicode Characters are removed in identifiers:
|
label:functionality[] label:removed[] MATCH (n)-[r:REL]->(m) SET n = r;
MATCH (n)-[r:REL]->(m) SET n += r;
MATCH (n)-[r:REL]->(m) SET r = n;
MATCH (n)-[r:REL]->(m) SET r += n; |
Using a MATCH (n)-[r:REL]->(m) SET n = properties(r) |
label:functionality[] label:removed[] REVOKE READ {*} ON GRAPH * NODES A FROM missingUser
REVOKE ROLE missingRole FROM bob |
Errors have replaced notifications for impossible |
label:functionality[] label:removed[] MERGE (a {foo:1})-[:T]->(b {foo:a.foo}) |
It is no longer possible to specify a property of one entity (node or relationship) by referring to another entity’s property within the same |
label:functionality[] label:removed[] CREATE ... INDEX ... OPTIONS { indexProvider: ... }
CREATE ... CONSTRAINTS ... OPTIONS { indexProvider: ... } |
Specifying an index provider in the |
label:functionality[] label:removed[] db.create.setVectorProperty()
db.index.vector.createNodeIndex()
dbms.cluster.readReplicaToggle()
dbms.cluster.uncordonServer()
dbms.quarantineDatabase()
dbms.upgrade()
dbms.upgradeStatus() |
These procedures have been removed from Cypher 25. For more information, see the Operations Manual → Procedures. |
| Feature | Details |
|---|---|
label:functionality[] label:deprecated[] CREATE DATABASE db OPTIONS { existingData: ... } |
The option |
| Feature | Details |
|---|---|
label:functionality[] label:updated[] WITH 1 AS g
RETURN COLLECT {
UNWIND [1,2,3] AS x
WITH * WHERE x < 0
WITH count(*) AS agg
RETURN agg + g
} AS x |
Imported variables are now correctly handled as constants inside |
label:functionality[] label:updated[] RETURN $0hello |
Parameters can start with extended identifier characters (such as numbers), in line with the GQL standard. For more information, see syntax/parameters.adoc. |
label:functionality[] label:updated[] MATCH SHORTEST $param (:A)-[:R]->{0,10}(:B)MATCH p = ANY $param (:A)-[:R]->{0,10}(:B)MATCH SHORTEST $param GROUPS (:A)-[:R]->{0,10}(:B) |
Parameters can now be used in |
label:functionality[] label:updated[] CALL db.schema.nodeTypeProperties() YIELD propertyTypes RETURN propertyTypes;
CALL db.schema.relTypeProperties() YIELD propertyTypes RETURN propertyTypes; |
The column |
label:syntax[] label:updated[] SHOW NODE PROPERTY UNIQUENESS CONSTRAINTS
SHOW RELATIONSHIP PROPERTY UNIQUENESS CONSTRAINTS
SHOW PROPERTY UNIQUENESS CONSTRAINTS |
The constraint type keyword filtering for |
label:functionality[] label:updated[] SHOW TRANSACTIONS YIELD startTime, clientAddress, outerTransactionId, currentQuery, currentQueryId, parameters, planner, runtime, indexes, currentQueryStartTime, currentQueryElapsedTime, currentQueryCpuTime, currentQueryIdleTime, currentQueryStatus |
Several
|
label:functionality[] label:updated[] USE graph.byName('composite.with.dot.constituent')
USE graph.propertiesByName('composite.with.dot.constituent') |
Graph references in the arguments of the functions In Cypher 5, if a composite database or constituent name contains dots, those name parts have to be wrapped in quotes to resolve the name correctly, e.g., |
label:functionality[] label:updated[] CREATE (:Person)
MATCH (p:Person)
RETURN count(p) AS count |
Queries no longer require |
label:functionality[] label:updated[] RETURN replace("hello world", "l", "", 1) |
The |
| Feature | Details |
|---|---|
label:functionality[] label:new[] CREATE [COMPOSITE] DATABASE actors SET DEFAULT LANGUAGE CYPHER 25 |
Set the default Cypher version for a standard or composite database when creating it.
The available versions are |
label:functionality[] label:new[] CREATE ALIAS `remote-with-default-language`
FOR DATABASE `northwind-graph-2020`
AT "neo4j+s://location:7687"
USER alice
PASSWORD 'example_secret'
DEFAULT LANGUAGE CYPHER 25 |
Set the default Cypher version for a remote database alias when creating it.
The available versions are |
label:functionality[] label:new[] ALTER DATABASE movies SET DEFAULT LANGUAGE CYPHER 25 |
Alter the default Cypher version of an existing standard or composite database.
The available versions are |
label:functionality[] label:new[] ALTER ALIAS `remote-with-default-language` SET DATABASE DEFAULT LANGUAGE CYPHER 25 |
Alter the default Cypher version of a remote database alias.
The available versions are |
label:functionality[] label:new[] SHOW DATABASES YIELD name, defaultLanguage |
The new return column |
label:functionality[] label:new[] SHOW ALIAS `remote-with-default-language` FOR DATABASE YIELD name, defaultLanguage |
The new return column |
label:functionality[] label:new[] CYPHER 25
MATCH (n:Person)
FILTER n.age < 35
RETURN n.name AS name |
New query option: |
label:functionality[] label:new[] RETURN 1 AS a
NEXT
RETURN 1 AS b |
New |
label:functionality[] label:new[] MATCH (s:Supplier)-[:SUPPLIES]->(p:Product)
LET supplier = s.name
RETURN supplier, p.name AS product |
New |
label:functionality[] label:new[] UNWIND [1, 2, 3, 4, 5, 6] AS x
FILTER x > 2
RETURN xLOAD CSV WITH HEADERS FROM 'file:///companies.csv' AS row
FILTER row.Id IS NOT NULL
MERGE (c:Company {id: row.Id}) |
|
label:functionality[] label:new[] WHEN false THEN RETURN 1 AS x
WHEN true THEN RETURN 2 AS x
ELSE RETURN 3 AS x MATCH (n:Person)
OPTIONAL MATCH (n)-[:KNOWS]->(m)
CALL (*) {
WHEN m IS NULL THEN {
CREATE (f: Person {name: 'Peter', age: n.age}),
(n)-[:KNOWS]->(f)
RETURN f, n.name AS newConnection
}
}
RETURN f.name AS newNode,
collect(newConnection) AS newConnections |
Introduction of |
label:functionality[] label:new[] {
MATCH (n:Actor)
RETURN n.name AS name
UNION
MATCH (n:Director)
RETURN n.name AS name
}
UNION ALL
MATCH (n:Movie)
RETURN n.title AS name |
|
label:functionality[] label:new[] CREATE DATABASE db OPTIONS { seedRestoreUntil: ... } |
The option |
label:functionality[] label:new[] CREATE DATABASE db OPTIONS { seedSourceDatabase: ... } |
You can specify the name of a source database if the |
label:functionality[] label:new[] RETURN cosh(0.5), coth(0.5), sinh(0.5), tanh(0.5) |
Introduction of four new hyperbolic trigonometric Cypher functions. For more information, see Mathematical functions - trigonometric. |
label:functionality[] label:new[] MATCH (n)
RETURN ALL n.prop AS prop |
The keyword |
label:functionality[] label:new[] MATCH (n)
WITH ALL n.prop AS prop
RETURN prop |
The keyword |
label:functionality[] label:new[] MATCH REPEATABLE ELEMENTS p = (:B)-->{,5}()
RETURN [n IN nodes(p) | n.q] AS nodes |
New match mode, |
label:functionality[] label:new[] MATCH DIFFERENT RELATIONSHIPS p = (:B)-->{,5}()
RETURN [n IN nodes(p) | n.q] AS nodes |
New keyword, |