Cypher styleguide

The purpose of the Cypher® styleguide is to make queries as easy to read as possible.

For rules and recommendations for naming of labels, relationship types and properties, please see the Naming rules and recommendations.

The best way to make sure your queries follow the styling rules is to use cypherfmt, the official Cypher formatter. It is available as part of the Neo4j VS Code Extension, and as a command line tool through the Neo4j Cypher Language Support npm package.

General recommendations

  • When using Cypher language constructs in prose, use a monospaced font and follow the styling rules.

  • When referring to labels and relationship types, the colon should be included as follows: :Label, :REL_TYPE.

  • When referring to functions, use lower camel case and parentheses. For example: toString().

  • If you are storing Cypher statements in a separate file, use the file extension .cypher.

Indentation and line breaks

  • Start a new clause on a new line.

Bad
MATCH (n) WHERE n.name CONTAINS 's' RETURN n.name
Good
MATCH (n)
WHERE n.name CONTAINS 's'
RETURN n.name
  • Indent ON CREATE and ON MATCH with two spaces. Put ON CREATE before ON MATCH if both are present.

Bad
MERGE (n) ON CREATE SET n.prop = 0
MERGE (a:A)-[:T]->(b:B)
ON MATCH SET b.name = 'you'
ON CREATE SET a.name = 'me'
RETURN a.prop
Good
MERGE (n)
  ON CREATE SET n.prop = 0
MERGE (a:A)-[:T]->(b:B)
  ON CREATE SET a.name = 'me'
  ON MATCH SET b.name = 'you'
RETURN a.prop
  • Start a subquery on a new line after the opening brace, indented with two (additional) spaces. Leave the closing brace on its own line.

Bad
MATCH (a:A)
WHERE
  EXISTS { MATCH (a)-->(b:B) WHERE b.prop = 'yellow' }
RETURN a.foo
Also bad
MATCH (a:A)
WHERE EXISTS
{MATCH (a)-->(b:B)
WHERE b.prop = 'yellow'}
RETURN a.foo
Good
MATCH (a:A)
WHERE EXISTS {
  MATCH (a)-->(b:B)
  WHERE b.prop = 'yellow'
}
RETURN a.foo
  • Do not break the line if the simplified subquery form is used.

Bad
MATCH (a:A)
WHERE EXISTS {
  (a)-->(b:B)
}
RETURN a.prop
Good
MATCH (a:A)
WHERE EXISTS { (a)-->(b:B) }
RETURN a.prop
  • Limit line length to 80 characters if possible. Line breaks should be applied starting from the outermost group, with each nested group breaking until either the line fits or no more line breaks can be inserted. Add two spaces of indentation for each nested broken group.

Bad
MATCH (n)
WHERE n.prop <> 'a' AND n.prop <> 'b' AND n.prop <> 'c' AND n.prop <> 'd' AND n.prop <> 'e'
RETURN n
Good
MATCH (n)
WHERE
  n.prop <> 'a' AND
  n.prop <> 'b' AND
  n.prop <> 'c' AND
  n.prop <> 'd' AND
  n.prop <> 'e'
RETURN n
  • Start ORDER BY and LIMIT clauses on new lines.

Bad
MATCH (n)
RETURN 5 ORDER BY n.prop LIMIT 10
Good
MATCH (n)
RETURN 5
ORDER BY n.prop
LIMIT 10
  • A group containing a CASE expression should always break, and each WHEN, ELSE, and END should be put on a new line. Additionally, WHEN and ELSE should add two spaces of indentation.

Bad
MATCH (n:Person {name: 'Alice'})
RETURN CASE WHEN n.age >= 18 THEN 'Adult' ELSE 'Minor' END AS ageGroup
Good
MATCH (n:Person {name: 'Alice'})
RETURN
  CASE
    WHEN n.age >= 18 THEN 'Adult'
    ELSE 'Minor'
  END AS ageGroup
  • When a line ends with a list or map literal that does not fit within the maximum line width, place the opening bracket or brace on the same line as the clause that introduces it. Start each element of the literal on a new line, indented two spaces further than the line containing the opening bracket or brace. Close the literal at the original indentation level.

Bad
RETURN
  [
    "Alice",
    "Bob",
    "Charlie",
    "David",
    "Eve",
    "Frank",
    "Grace",
    "Heidi",
    "Ivan",
    "Judy"
  ]
Good
RETURN [
  "Alice",
  "Bob",
  "Charlie",
  "David",
  "Eve",
  "Frank",
  "Grace",
  "Heidi",
  "Ivan",
  "Judy"
]
  • A single blank line may be used to separate clauses, queries or comments.

Good
MATCH (n)-[r]->(m)
RETURN n, r, m
Also good
MATCH (n)-[r]->(m)

RETURN n, r, m

Casing

  • Write keywords in upper case.

Bad
match (p:Person)
where p.name starts with 'Ma'
return p.name
Good
MATCH (p:Person)
WHERE p.name STARTS WITH 'Ma'
RETURN p.name
  • Write the value null in lower case.

Bad
WITH NULL AS n1, Null AS n2
RETURN n1 IS NULL AND n2 IS NOT NULL
Good
WITH null AS n1, null AS n2
RETURN n1 IS NULL AND n2 IS NOT NULL
  • Write BOOLEAN literals (true and false) in lower case.

Bad
WITH TRUE AS b1, False AS b2
RETURN b1 AND b2
Good
WITH true AS b1, false AS b2
RETURN b1 AND b2
  • Use camel case, starting with a lower-case character, for:

    • functions

    • properties

    • variables

    • parameters

Bad
CREATE (N:Label {Prop: 0})
WITH N, RAND() AS Rand, $pArAm AS MAP
RETURN Rand, MAP.property_key, count(N)
Good
CREATE (n:Label {prop: 0})
WITH n, rand() AS rand, $param AS map
RETURN rand, map.propertyKey, count(n)

Spacing

  • For literal maps:

    • No space between the opening brace and the first key

    • No space between key and colon

    • One space between colon and value

    • No space between value and comma

    • One space between comma and next key

    • No space between the last value and the closing brace

Bad
WITH { key1 :'value' ,key2  :  42 } AS map
RETURN map
Good
WITH {key1: 'value', key2: 42} AS map
RETURN map
  • One space between label/type predicates and property predicates in patterns.

Bad
MATCH (p:Person{property: -1})-[:KNOWS   {since: 2016}]->()
RETURN p.name
Good
MATCH (p:Person {property: -1})-[:KNOWS {since: 2016}]->()
RETURN p.name
  • No space in patterns.

Bad
MATCH (:Person) --> (:Vehicle)
RETURN count(*)
Good
MATCH (:Person)-->(:Vehicle)
RETURN count(*)
  • Use a wrapping space around operators.

Bad
MATCH p=(s)-->(e)
WHERE s.name<>e.name
RETURN length(p)
Good
MATCH p = (s)-->(e)
WHERE s.name <> e.name
RETURN length(p)
  • No space in label predicates.

Bad
MATCH (person    : Person  :  Owner  )
RETURN person.name
Good
MATCH (person:Person:Owner)
RETURN person.name
  • Use a space after each comma in lists and enumerations.

Bad
MATCH (),()
WITH ['a','b',3.14] AS list
RETURN list,2,3,4
Good
MATCH (), ()
WITH ['a', 'b', 3.14] AS list
RETURN list, 2, 3, 4
  • No padding space within function call parentheses.

Bad
RETURN split( 'original', 'i' )
Good
RETURN split('original', 'i')
  • Use padding space within simple subquery expressions.

Bad
MATCH (a:A)
WHERE EXISTS {(a)-->(b:B)}
RETURN a.prop
Good
MATCH (a:A)
WHERE EXISTS { (a)-->(b:B) }
RETURN a.prop

Patterns

  • When patterns wrap lines, break after arrows, not before.

Bad
MATCH (:Person)-->(vehicle:Car)-->(:Company)
      <--(:Country)
RETURN count(vehicle)
Good
MATCH (:Person)-->(vehicle:Car)-->(:Company)<--
      (:Country)
RETURN count(vehicle)
  • Use anonymous nodes and relationships when the variable would not be used.

Bad
MATCH (kate:Person {name: 'Kate'})-[r:LIKES]-(c:Car)
RETURN c.type
Good
MATCH (:Person {name: 'Kate'})-[:LIKES]-(c:Car)
RETURN c.type
  • Chain patterns together to avoid repeating variables.

Bad
MATCH (:Person)-->(vehicle:Car), (vehicle:Car)-->(:Company)
RETURN count(vehicle)
Good
MATCH (:Person)-->(vehicle:Car)-->(:Company)
RETURN count(vehicle)
  • Put named nodes before anonymous nodes.

Bad
MATCH ()-->(vehicle:Car)-->(manufacturer:Company)
WHERE manufacturer.foundedYear < 2000
RETURN vehicle.mileage
Good
MATCH (manufacturer:Company)<--(vehicle:Car)<--()
WHERE manufacturer.foundedYear < 2000
RETURN vehicle.mileage
  • Keep anchor nodes at the beginning of the MATCH clause.

Bad
MATCH (:Person)-->(vehicle:Car)-->(manufacturer:Company)
WHERE manufacturer.foundedYear < 2000
RETURN vehicle.mileage
Good
MATCH (manufacturer:Company)<--(vehicle:Car)<--(:Person)
WHERE manufacturer.foundedYear < 2000
RETURN vehicle.mileage
  • Prefer outgoing (left to right) pattern relationships to incoming pattern relationships.

Bad
MATCH (:Country)-->(:Company)<--(vehicle:Car)<--(:Person)
RETURN vehicle.mileage
Good
MATCH (:Person)-->(vehicle:Car)-->(:Company)<--(:Country)
RETURN vehicle.mileage

Meta-characters

  • Use single quotes, ', for literal STRING values.

Bad
RETURN "Cypher"
Good
RETURN 'Cypher'
  • Disregard this rule for literal STRING values that contain a single quote character. If the STRING has both, use the form that creates the fewest escapes. In the case of a tie, prefer single quotes.

Bad
RETURN 'Cypher\'s a nice language', "Mats' quote: \"statement\""
Good
RETURN "Cypher's a nice language", 'Mats\' quote: "statement"'
  • Avoid using characters and keywords that require the input to be quoted with backticks.

Bad
MATCH (`odd-ch@racter$`:`Spaced Label` {`&property`: 42})
RETURN labels(`odd-ch@racter$`)
Good
MATCH (node:NonSpacedLabel {property: 42})
RETURN labels(node)
  • Do not use a semicolon at the end of the statement.

Bad
RETURN 1;
Good
RETURN 1