CREATE

Introduction

The CREATE clause allows you to create nodes and relationships. To define these entities, CREATE uses a syntax similar to that of MATCH. However, while patterns only need to evaluate to either true or false, the syntax for CREATE needs to specify exactly what nodes and relationships to create.

Syntax for nodes

The CREATE clause allows you to create one or more nodes. Each node can be assigned labels and properties. You can bind each node to a variable that you can refer to later in the query. Multiple labels are separated by colons.

Query
CREATE (charlie:Person:Actor {name: 'Charlie Sheen'}), (oliver:Person:Director {name: 'Oliver Stone'})

As of Neo4j 5.18, multiple labels can also be separated by an ampersand &, in the same manner as it is used in label expressions. Separation by colon : and ampersand & cannot be mixed in the same clause.

Query
CREATE (charlie:Person&Actor {name: 'Charlie Sheen'}), (oliver:Person&Director {name: 'Oliver Stone'})

Both of the above queries create two nodes, bound to the variables charlie and oliver, each with a Person label and a name property. The node representing Charlie Sheen also has the label Actor while the node representing Oliver Stone is assigned the label Director.

Syntax for relationships

Relationships can also be created using the CREATE clause. Unlike nodes, relationships always need exactly one relationship type and a direction. Similar to nodes, relationships can be assigned properties and relationship types and be bound to variables.

Query
CREATE (charlie:Person:Actor {name: 'Charlie Sheen'})-[:ACTED_IN {role: 'Bud Fox'}]->(wallStreet:Movie {title: 'Wall Street'})<-[:DIRECTED]-(oliver:Person:Director {name: 'Oliver Stone'})

This query creates the Person nodes for Charlie Sheen and Oliver Stone and the Movie node for Wall Street. It also created the relationships of the types ACTED_IN and DIRECTED between them.

Reusing variables

The previous example created a path between the specified nodes. Note, that these newly created nodes and relationships are not connected to what was previously in the graph. To connect them to already existing data, bind the desired nodes and relationships to variables. These variables can then be passed along to subsequent clauses in a query that target pre-existing elements in the graph.

Query
MATCH (charlie:Person {name: 'Charlie Sheen'}), (oliver:Person {name: 'Oliver Stone'})
CREATE (charlie)-[:ACTED_IN {role: 'Bud Fox'}]->(wallStreet:Movie {title: 'Wall Street'})<-[:DIRECTED]-(oliver)

In this example, the MATCH clause finds the nodes Charlie Sheen and Oliver Stone and binds them to the charlie and oliver variables respectively. These variables are then passed along to the subsequent CREATE clause, which creates new relationships from the bound nodes.

You can also reuse variables from the same CREATE, both in the same or a later clause. This way, you can, for example, define constructs that are more complex than just a linear path.

Query
CREATE p = (charlie:Person:Actor {name: 'Charlie Sheen'})-[:ACTED_IN {role: 'Bud Fox'}]->(wallStreet:Movie {title: 'Wall Street'})<-[:DIRECTED]-(oliver:Person:Director {name: 'Oliver Stone'}), (wallStreet)<-[:ACTED_IN {role: 'Gordon Gekko'}]-(michael:Person:Actor {name: 'Michael Douglas'})
RETURN length(p)

Creates all three nodes for Charlie Sheen, Oliver Stone and Michael Douglas and connects them all to the node representing the Wall Street movie. It then returns the length of the path from Charlie Sheen to Oliver Stone.

Note that when repeating a node’s variable, you may not add labels or properties to the repetition.

Query
MATCH (charlie:Person {name: 'Charlie Sheen'})
CREATE (charlie:Actor)

This query will fail because the variable charlie has already been bound to a pre-existing node, and therefore it cannot be reused to create a new node. If you intend to add a label, use the SET clause instead.

Reusing variables in properties

The value that can be assigned to a node’s or a relationship’s property can be defined by an expression.

Query
MATCH (person:Person)
  WHERE person.name IS NOT NULL
CREATE (anotherPerson:Person {name: person.name, age: $age})

This example created a Person node with the same name as another person and the age from a parameter called age.

Such an expression may not contain a reference to a variable that is defined in the same CREATE statement. This is to ensure that the value of a property is always clear.

Query
CREATE (charlie {score: oliver.score + 1}), (oliver {score: charlie.score + 1})

This query tries to create nodes such that Charlie’s score is higher than Oliver’s and vice versa, which is a contradiction. The query therefore fails.

Use parameters with CREATE

Create node with a parameter for the properties

You can also create a graph entity from a map. All the key/value pairs in the map will be set as properties on the created relationship or node. In this case we add a Person label to the node as well.

Parameters
{
  "props": {
    "name": "Andy",
    "position": "Developer"
  }
}
Query
CREATE (n:Person $props)
RETURN n
Table 1. Result
n

Node[2]{name:"Andy",position:"Developer"}

Rows: 1
Nodes created: 1
Properties set: 2
Labels added: 1

Create multiple nodes with a parameter for their properties

By providing Cypher® an array of maps, it will create a node for each map.

Parameters
{
  "props": [ {
    "name": "Andy",
    "position": "Developer"
  }, {
    "name": "Michael",
    "position": "Developer"
  } ]
}
Query
UNWIND $props AS map
CREATE (n)
SET n = map
Table 2. Result

(empty result)

Rows: 0
Nodes created: 2
Properties set: 4

CREATE using dynamic node labels and relationship types

Node labels and relationship types can be referenced dynamically in expressions, parameters, and variables when creating nodes and relationships. This allows for more flexible queries and mitigates the risk of Cypher injection. (For more information about Cypher injection, see Neo4j Knowledge Base → Protecting against Cypher injection).

Syntax for creating nodes and relationships dynamically
CREATE (n:$(<expr>))
CREATE ()-[r:$(<expr>)]->()

The expression must evaluate to a STRING NOT NULL | LIST<STRING NOT NULL> NOT NULL value. Using a LIST<STRING> with more than one item when creating a relationship using dynamic relationship types will fail. This is because a relationship can only have exactly one type.

Parameters
{
  "nodeLabels": ["Person", "Director"],
  "relType": "DIRECTED",
  "movies": ["Ladybird", "Little Women", "Barbie"]
}
Create nodes and relationships using dynamic node labels and relationship types
CREATE (greta:$($nodeLabels) {name: 'Greta Gerwig'})
WITH greta
UNWIND $movies AS movieTitle
CREATE (greta)-[rel:$($relType)]->(m:Movie {title: movieTitle})
RETURN greta.name AS name, labels(greta) AS labels, type(rel) AS relType, collect(m.title) AS movies
Table 3. Result
name labels relType movies

"Greta Gerwig"

["Person", "Director"]

"DIRECTED"

["Ladybird", "Little Women", "Barbie"]

Rows: 1

INSERT as a synonym of CREATE

INSERT can be used as a synonym to CREATE for creating nodes and relationships, and was introduced as part of Cypher’s GQL conformance. However, INSERT requires that multiple labels are separated by an ampersand & and not by colon :.

Query
INSERT (tom:Person&Actor&Director {name: 'Tom Hanks'})

Creates a node, bound to the variable tom, with the labels Person, Actor, and Director and a name property.