Docs
View as markdown

Schema clauses

The exact grammar relate accepts for CREATE INDEX, CREATE CONSTRAINT, DROP, SHOW INDEXES, SHOW CONSTRAINTS and graph types, with defaults, naming and errors.

cypher

Schema statements manage the indexes, constraint A rule the store enforces on every write, such as a unique property, a required property, a property type or a node key; a violating write fails. Read more in the glossary and graph type A schema for a whole graph, declared in Cypher, that lists node and relationship types with their properties; writes that break it fail. Read more in the glossary of a store A relate database: a directory, a single .rl file, or :memory:, opened with --database. Read more in the glossary. An index speeds up lookups and searches; a constraint is a rule every write must satisfy; a graph type declares the node and relationship types of the whole graph and turns each declaration into constraints. Each statement takes effect when it commits. On success, CREATE and DROP return no rows, and the CLI prints nothing; SHOW INDEXES and SHOW CONSTRAINTS are how to see what changed.

Synopsis

CREATE [RANGE] INDEX [<name>] [IF NOT EXISTS]
  FOR (<v>:<Label>) ON (<v>.<property> [, <v>.<property> …]) [OPTIONS {…}]
CREATE [RANGE] INDEX [<name>] [IF NOT EXISTS]
  FOR ()-[<v>:<TYPE>]-() ON (<v>.<property> [, <v>.<property> …]) [OPTIONS {…}]
CREATE TEXT INDEX [<name>] [IF NOT EXISTS]
  FOR (<v>:<Label>) | ()-[<v>:<TYPE>]-() ON (<v>.<property>) [OPTIONS {…}]
CREATE POINT INDEX [<name>] [IF NOT EXISTS]
  FOR (<v>:<Label>) | ()-[<v>:<TYPE>]-() ON (<v>.<property>) [OPTIONS {…}]
CREATE LOOKUP INDEX [<name>] [IF NOT EXISTS] FOR (<v>) ON EACH labels(<v>) [OPTIONS {…}]
CREATE LOOKUP INDEX [<name>] [IF NOT EXISTS] FOR ()-[<v>]-() ON EACH type(<v>) [OPTIONS {…}]
CREATE VECTOR INDEX …      (see the search reference)
CREATE FULLTEXT INDEX …    (see the search reference)
DROP INDEX <name> [IF EXISTS]
SHOW [ALL | RANGE | TEXT | POINT | LOOKUP | VECTOR | FULLTEXT] INDEXES
  [YIELD <column> [, …] | YIELD *] [WHERE <predicate>] [RETURN …]

CREATE CONSTRAINT [<name>] [IF NOT EXISTS]
  FOR (<v>:<Label>) | ()-[<v>:<TYPE>]-()
  REQUIRE <property list> IS [NODE | RELATIONSHIP] UNIQUE
        | <property list> IS NOT NULL
        | <property list> IS [NODE | RELATIONSHIP] KEY
        | <v>.<property> IS :: <type> | IS TYPED <type>
  <property list> = <v>.<property> | (<v>.<property>, <v>.<property> …)
DROP CONSTRAINT <name> [IF EXISTS]
SHOW [<filter>] CONSTRAINTS [YIELD <column> [, …] | YIELD *] [WHERE <predicate>] [RETURN …]
  <filter> = ALL | [NODE | REL | RELATIONSHIP] [[PROPERTY] UNIQUE | UNIQUENESS | EXIST | EXISTENCE | TYPE | KEY]

CREATE GRAPH TYPE <name> [AS] { <element type or constraint> [, …] }
ALTER CURRENT GRAPH TYPE SET { … } | SET GRAPH TYPE <name> | ADD { … } | ALTER { … } | DROP { … }
SHOW CURRENT GRAPH TYPE [YIELD specification RETURN …]
SHOW CURRENT GRAPH TYPE AS GRAPH [SINGLE | SEPARATE]

Indexes

KindStatementEntityPropertiesSHOW INDEXES type
RangeCREATE INDEX or CREATE RANGE INDEXNode label or relationship typeOne or moreRANGE
TextCREATE TEXT INDEXNode label or relationship typeExactly oneTEXT
PointCREATE POINT INDEXNode label or relationship typeExactly one, holding pointsPOINT
LookupCREATE LOOKUP INDEX … ON EACH labels(n) or … ON EACH type(r)Every node, or every relationshipNoneLOOKUP
VectorCREATE VECTOR INDEX (search)Node label or relationship typeOne, holding vectors, plus WITH [...] filter propertiesVECTOR
Full-textCREATE FULLTEXT INDEX (search)Node label or relationship typeOne or more strings, in ON EACH [...]FULLTEXT

A new store has no indexes. A point index An index over a property holding point values that narrows bounding-box and radius predicates to nearby nodes through an R-tree. Read more in the glossary narrows distance and bounding-box predicates on point values (geospatial).

RuleBehavior
No namerelate generates one; SHOW INDEXES reports it
IF NOT EXISTSNo error and no change when an index of that name exists, even with another definition
A name another index usessemantic error: IndexAlreadyExists
A name a constraint usessemantic error: There already exists a constraint called '<name>'.
The same kind, entity and properties under another name, or a constraint already owning that indexsemantic error: EquivalentSchemaRuleAlreadyExists
More than one property on a text or point indexsyntax error: InvalidArguments: this index type requires one property
OPTIONS {…}One key is accepted, indexConfig, whose settings depend on the index kind; any other key, indexProvider included, fails with syntax error: InvalidIndexOption
CREATE BTREE INDEXsyntax error: parse error: UnsupportedIndexType: BTREE indexes were removed; use RANGE, POINT, TEXT, FULLTEXT, LOOKUP, or VECTOR
DROP INDEX on a missing namesemantic error: NoSuchIndex: `<name>` ; with IF EXISTS, nothing happens and no error is raised
DROP INDEX on an index a constraint ownsUnable to drop '<name>': the index belongs to a constraint. (CLI exit code 1)
State after CREATESHOW INDEXES reports state ONLINE and populationPercent 100.0

SHOW INDEXES columns

ColumnHolds
id0 for every index; name identifies an index
nameThe index name
stateONLINE
populationPercent100.0
typeRANGE, TEXT, POINT, LOOKUP, VECTOR or FULLTEXT
entityTypeNODE or RELATIONSHIP
labelsOrTypesThe label or type, null for a lookup index
propertiesThe properties, null for a lookup index
indexProviderThe provider name, such as range-1.0
owningConstraintThe constraint that owns the index, or null
lastRead, readCountRead tracking
options, createStatement, failureMessage, trackedSinceOnly with YIELD * or by name

Constraints

ConstraintREQUIRE formEntitySHOW CONSTRAINTS typeOwns an index
UniquenessIS UNIQUE, IS NODE UNIQUE, IS RELATIONSHIP UNIQUENode or relationship; one property or a listNODE_PROPERTY_UNIQUENESS, RELATIONSHIP_PROPERTY_UNIQUENESSYes
ExistenceIS NOT NULLNode or relationship; one property or a listNODE_PROPERTY_EXISTENCE, RELATIONSHIP_PROPERTY_EXISTENCENo
KeyIS KEY, IS NODE KEY, IS RELATIONSHIP KEYNode or relationship; one property or a listNODE_KEY, RELATIONSHIP_KEYYes
Property typeIS :: <type>, IS TYPED <type>; a union such as STRING | INTEGERNode or relationship; one propertyNODE_PROPERTY_TYPE, RELATIONSHIP_PROPERTY_TYPENo
RuleBehavior
No namerelate generates one, such as constraint_unique_Person_name
IF NOT EXISTSNo error and no change when a constraint of that name exists
A name another constraint usessemantic error: ConstraintAlreadyExists
A name an index usessemantic error: DuplicatedIndexName
The same rule under another namesemantic error: EquivalentSchemaRuleAlreadyExists
A uniqueness or key constraint on the label and properties of an existing range indexsemantic error: AlreadyExists: there already exists an index (:<Label> {<property>, …}). A constraint cannot be created until the index has been dropped. A text index on the same property does not block it
More than one property in IS :: or IS TYPEDsyntax error: InvalidConstraintSyntax: only single property IS TYPED constraints are supported
Existing data breaks the ruleThe CREATE CONSTRAINT fails with the violation message and creates nothing
A uniqueness constraint and a missing propertyAllowed: uniqueness applies to entities that have the property
DROP CONSTRAINTRemoves the constraint and the index it owns
DROP CONSTRAINT on a missing namesemantic error: ConstraintNotFound; with IF EXISTS, nothing happens and no error is raised
DROP CONSTRAINT on a constraint a graph type createdDependentConstraintManagedIndividually: dependent constraints cannot be dropped (CLI exit code 1)

Constraint violations

A write that breaks a constraint fails, and the statement changes nothing. The message names the constraint and the rule:

Rule brokenMessage
Uniqueness, or a key's uniquenesssemantic error: ConstraintValidationFailed: `<name>` uniqueness
Existence, or a key property missingsemantic error: ConstraintValidationFailed: `<name>` requires properties
Property typesemantic error: ConstraintValidationFailed: `<name>` property type
A graph type's implied labelConstraintValidationFailed: node with label <label> must also have label <label>

Under the CLI the first three exit with code 6, the implied-label violation with code 1.

SHOW CONSTRAINTS filters and columns

The <filter> in the synopsis has an entity part and a kind part, both optional. NODE limits the list to node constraints, REL or RELATIONSHIP to relationship constraints; PROPERTY before UNIQUE, UNIQUENESS, EXIST, EXISTENCE or TYPE changes nothing in the result.

Kind partLists
None, or ALLEvery constraint, or every constraint of the entity part
UNIQUE, UNIQUENESSUniqueness constraints; key constraints are not included
EXIST, EXISTENCEExistence constraints
KEYKey constraints
TYPEProperty type constraints
PROPERTY KEYsyntax error: parse error: InvalidConstraintTypeFilter: PROPERTY cannot combine with the KEY filter
PROPERTY alonesyntax error: parse error: InvalidConstraintTypeFilter: PROPERTY must be followed by UNIQUE[NESS], EXIST[ENCE], or TYPE

The columns are id (0 for every constraint), name, type, entityType, labelsOrTypes, properties, ownedIndex, propertyType and enforcedLabel; YIELD * adds options, createStatement and classification.

Graph types

A graph type lists node element types, (:<Label> => {<property> :: <type> [NOT NULL], …}), and relationship element types, (:<Label> =>)-[:<TYPE> => {…}]->(:<Label> =>). The => (or IMPLIES) after a label is required before a property block. A property declaration can end in IS KEY or IS UNIQUE, and a CONSTRAINT … REQUIRE … entry can sit in the list. A graph type is open: nodes with labels it does not declare are accepted.

StatementEffect
CREATE GRAPH TYPE <name> { … }Registers a named type. It does not apply it. A second CREATE with the same name replaces it without an error
ALTER CURRENT GRAPH TYPE SET GRAPH TYPE <name>Makes the named type current; an unknown name fails with semantic error: GraphTypeNotFound
ALTER CURRENT GRAPH TYPE SET { … }Replaces the current type
ALTER CURRENT GRAPH TYPE ADD { … }Adds element types
ALTER CURRENT GRAPH TYPE ALTER { … }Redefines element types that exist
ALTER CURRENT GRAPH TYPE DROP { (:<Label> =>) }Removes element types and their constraints
SHOW CURRENT GRAPH TYPEOne row, specification: the current type as text, {} when none is set
SHOW CURRENT GRAPH TYPE AS GRAPHOne row with nodes and relationships lists

Setting a type creates the constraints it implies, which SHOW CONSTRAINTS lists under generated names, including RELATIONSHIP_SOURCE_LABEL and RELATIONSHIP_TARGET_LABEL for a relationship's endpoints. Data that breaks the new type makes the ALTER fail with the violation message. Constraints created with CREATE CONSTRAINT while a type is current appear in its specification. Optional properties, default values and inheritance between element types are preview features (Cypher overview).

Schema procedures

ProcedureYieldsNotes
db.schema.nodeTypeProperties()nodeType, nodeLabels, propertyName, propertyTypes, mandatoryInferred from the stored nodes: one row per label set and property
db.schema.relTypeProperties()relType, propertyName, propertyTypes, mandatoryThe same for relationships
db.schema.visualization([<boolean or map>])nodes, relationshipsThe argument defaults to true. One virtual node per label and one virtual relationship per label-type-label combination; false limits it to combinations in the data
db.labels()labelThe labels in use
db.relationshipTypes()relationshipTypeThe relationship types in use
db.propertyKeys()propertyKeyThe property keys in use
db.awaitIndexes([<seconds>])NothingReturns when every index is online; the timeout defaults to 300 seconds

The procedures page lists the rest.

Examples

The cells run in page order on one in-memory store, starting from 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

One index of three kinds, then the list:

Cypher
CREATE INDEX works_on_since IF NOT EXISTS FOR ()-[w:WORKS_ON]-() ON (w.since);
CREATE TEXT INDEX person_role IF NOT EXISTS FOR (p:Person) ON (p.role);
CREATE LOOKUP INDEX node_labels IF NOT EXISTS FOR (n) ON EACH labels(n)
Recorded result
(no rows) · indexes added: 3
Cypher
SHOW INDEXES YIELD name, type, entityType, labelsOrTypes, properties
RETURN name, type, entityType, labelsOrTypes, properties
ORDER BY name
Recorded result
nametypeentityTypelabelsOrTypesproperties
"node_labels""LOOKUP""NODE"nullnull
"person_role""TEXT""NODE"["Person"]["role"]
"works_on_since""RANGE""RELATIONSHIP"["WORKS_ON"]["since"]

3 rows

A uniqueness constraint owns an index, so the index cannot be dropped on its own:

Cypher
CREATE CONSTRAINT person_name IF NOT EXISTS FOR (p:Person) REQUIRE p.name IS UNIQUE
Recorded result
(no rows) · constraints added: 1
Cypher
DROP INDEX person_name
Expected error
error: Unable to drop 'person_name': the index belongs to a constraint.

A second Ada breaks the constraint, and the write fails:

Cypher
CREATE (:Person {name: 'Ada', role: 'designer'})
Expected error
error: semantic error: ConstraintValidationFailed: `person_name` uniqueness

A constraint that existing data breaks is not created: two people share the role engineer:

Cypher
CREATE CONSTRAINT person_role_unique FOR (p:Person) REQUIRE p.role IS UNIQUE
Expected error
error: semantic error: ConstraintValidationFailed: `person_role_unique` uniqueness

Constraints listed by filter:

Cypher
SHOW UNIQUE CONSTRAINTS YIELD name, type, labelsOrTypes, properties, ownedIndex
RETURN name, type, labelsOrTypes, properties, ownedIndex
Recorded result
nametypelabelsOrTypespropertiesownedIndex
"person_name""NODE_PROPERTY_UNIQUENESS"["Person"]["name"]"person_name"

1 row

DROP CONSTRAINT removes the constraint and its index; a missing name with IF EXISTS is no error:

Cypher
DROP CONSTRAINT person_name;
DROP CONSTRAINT person_name IF EXISTS;
SHOW INDEXES YIELD name RETURN collect(name) AS indexes
Recorded result
indexes
["node_labels", "person_role", "works_on_since"]

1 row · constraints removed: 1

A graph type for the example graph, registered and then made current:

Cypher
CREATE GRAPH TYPE team {
  (p:Person => {name :: STRING NOT NULL, role :: STRING}),
  (r:Project => {name :: STRING NOT NULL, language :: STRING}),
  (p)-[:WORKS_ON => {since :: INTEGER}]->(r)
};
ALTER CURRENT GRAPH TYPE SET GRAPH TYPE team;
SHOW CURRENT GRAPH TYPE YIELD specification RETURN specification
Recorded result
specification
"{\n (:`Person` => {`name` :: STRING NOT NULL, `role` :: STRING}),\n (:`Project` => {`language` :: STRING, `name` :: STRING NOT NULL}),\n (:`Person` =>)-[:`WORKS_ON` => {`since` :: INTEGER}]->(:`Project` =>)\n}"

1 row · constraints added: 9

A person without a name now fails:

Cypher
CREATE (:Person {role: 'engineer'})
Expected error
error: semantic error: ConstraintValidationFailed: `constraint_238af3a3` requires properties

The inferred node schema:

Cypher
CALL db.schema.nodeTypeProperties() YIELD nodeType, propertyName, propertyTypes, mandatory
RETURN nodeType, propertyName, propertyTypes, mandatory
ORDER BY nodeType, propertyName
Recorded result
nodeTypepropertyNamepropertyTypesmandatory
":Person""name"["STRING NOT NULL"]true
":Person""role"["STRING NOT NULL"]true
":Project""language"["STRING NOT NULL"]true
":Project""name"["STRING NOT NULL"]true

4 rows

See also