Limitations

Neo4j’s role-based access control (RBAC) has limitations that can lead to unexpected results if not carefully considered during security model design and when writing Cypher queries. Depending on the restrictions applied to the roles a user are assigned to, query results may differ in the following ways:

  • Access control and indexes: Indexes are used to speed up queries, but what they return to the user depends on the security model. If a user has restrictions on certain labels, relationship types, or properties, the system will not return any results that contain those elements, regardless of the indexes used. Also, full-text and vector indexes may return fewer results than expected because Lucene prevents Neo4j from checking security rules for each returned index entry. As a result, Neo4j only returns results it can guarantee do not violate security rules and excludes results that might violate security rules, even if they do not.

  • Fail-open DENY behavior: A DENY rule fails open when its criteria are not met, so Neo4j does not apply the restriction, and it grants access by default if a broader GRANT exists. This can lead to unintended data exposure if the DENY rule is not carefully crafted.

  • Access control and labels: Query results differ when nodes have multiple labels, and the user has access to traverse on some of those labels but not others. This is because the user can see all labels attached to a node they have access to, even if they do not have access to traverse on all of those labels.

  • Access control and performance: Complex security rules and large graphs with restrictive access can lead to significant performance degradation, especially for queries that would otherwise be efficient.

Access control and indexes

Neo4j uses indexes to speed up Cypher queries. See the Cypher Manual → Indexes for more details on the different types of indexes available in Neo4j.

However, Neo4j’s security model still controls what results you see, regardless of whether or not you use indexes.

Search-performance indexes (range, text, point, and token lookup)

Search-performance indexes are automatically used by the Cypher planner when they are relevant to a query. The results returned by these indexes are filtered by the security model, so that users only see results they have access to. If the security model causes fewer results to be returned due to restricted read access in graph and sub-graph access control, the index will also return the same fewer results.

Semantic indexes (full-text and vector)

Full-text and vector indexes differ from search-performance indexes because they are built on Lucene and are not automatically used by the Cypher planner.

Lucene implications

Lucene prevents Neo4j from checking the security rules for each specific entry returned from the index. As a result, Neo4j needs to take a more conservative approach to ensure that it does not return results that violate the security rules. If a result might violate the security rules, Neo4j treats it as if it does violate the security rules and excludes it from the results returned by the index. This means it either returns zero results (if all results from the index are potentially affected) or a partial result (if some rows can be guaranteed not to be affected).

Usage implications

Cypher does not automatically use full-text or vector indexes. You must explicitly state the index you want to use when calling procedures for full-text indexes, such as db.index.fulltext.queryNodes and db.index.fulltext.queryRelationships, or for vector indexes: db.index.vector.queryNodes, db.index.vector.queryRelationships, or via the Cypher /docs/cypher-manual/current/clauses/search/[SEARCH] clause (introduced in Neo4j 2026.01). This avoids a situation in which the same Cypher query returns different results because of an underlying index. The problem is that if you do not know this behavior, you might expect the full-text or vector index to return the same results that a different but semantically similar Cypher query does.

The following examples illustrate the implications of using full-text indexes with different security rules, compared to using search-performance indexes. The full-text index examples also apply to the vector indexes. Vector indexes with multiple labels, multiple relationship types, or additional properties are introduced in Neo4j 2026.01. In previous versions, they could only be on a single property and a single label or relationship type.

Example 1: Denied labels and index on multiple properties

The example assumes that the database contains nodes with the labels :User and :Person, and the properties name and surname.

  1. Create a single property range index on name, a composite range index on name and surname, and a full-text index on both properties:

    CREATE INDEX singleProp FOR (n:User) ON (n.name);
    CREATE INDEX composite  FOR (n:User) ON (n.name, n.surname);
    CREATE FULLTEXT INDEX userNames FOR (n:User|Person) ON EACH [n.name, n.surname];

    Full-text indexes support multiple labels. See Cypher Manual → Indexes for full-text search for more details on creating and using full-text indexes.

    After creating these indexes, it may appear that the latter two indexes accomplish the same thing. However, this is not completely accurate.
    The composite and full-text indexes behave differently and are focused on different use cases. A key difference is that full-text indexes are backed by Lucene and use the Lucene syntax for querying. This has consequences for users restricted to the labels or properties involved in the indexes. Ideally, if the labels and properties in the index are denied, they can correctly return zero results from both native indexes and full-text indexes. However, there are borderline cases where this is not as simple as it seems.

  2. Let’s add the following nodes to the database:

    CREATE (:User {name: 'Sandy'});
    CREATE (:User {name: 'Mark', surname: 'Andy'});
    CREATE (:User {name: 'Andy', surname: 'Anderson'});
    CREATE (:User:Person {name: 'Mandy', surname: 'Smith'});
    CREATE (:User:Person {name: 'Joe', surname: 'Andy'});
  3. Deny the label :Person:

    DENY TRAVERSE ON GRAPH * NODES Person TO users;
  4. Now run a query that uses one of the indexes:

    Run a query that uses the single property range index on name:

    MATCH (n:User)
    WHERE n.name CONTAINS 'ndy'
    RETURN n.name

    This query performs several checks:

    • Scans the index to create a stream of results of nodes with the name property, which leads to five results.

    • Filters the results to include only nodes where n.name CONTAINS 'ndy', filtering out Mark and Joe, which leads to three results.

    • Filters the results to exclude nodes that also have the denied label :Person, filtering out Mandy, leaving two results.

    Finally, the query returns two results, but only one has the surname property.

    Run a query that uses the composite range index on name and surname. To use the composite range index on name and surname, the query needs to include a predicate on the surname property as well:

    MATCH (n:User)
    WHERE n.name CONTAINS 'ndy' AND n.surname IS NOT NULL
    RETURN n.name

    This query performs several checks, which are almost identical to the single property index query:

    • Scans the index to create a stream of results of nodes with the name and surname property, which leads to four results.

    • Filters the results to include only nodes where n.name CONTAINS 'ndy', filtering out Mark and Joe, which leads to two results.

    • Filters the results to exclude nodes that also have the denied label :Person, filtering out Mandy, leaving only one result.

    However, in the end, it returns only one result.

    Run the same query as for the composite index, but using the full-text index instead:

    CALL db.index.fulltext.queryNodes("userNames", "ndy") YIELD node, score
    RETURN node.name

    The problem now is that it is not clear whether the results provided by the index are achieved due to a match to the name or the surname property.

    The query performs the following steps:

    • Run a Lucene query on the full-text index to return results containing ndy in either property, leading to five results.

    • Filter the results to exclude nodes that also have the label :Person, filtering out Mandy and Joe, leading to three results.

    This difference in results is caused by the OR relationship between the two properties in the index creation.

Denied properties on all labels

The example uses the same database as in Example 1: Denied labels and index on multiple properties, but instead of denying the :Person label, it denies the surname property for all labels.

  1. Deny the surname property for all labels:

    DENY READ {surname} ON GRAPH * TO users;
  2. Run the same queries as in the previous example using one of the indexes:

    Run a query that uses the single property range index on name:

    MATCH (n:User)
    WHERE n.name CONTAINS 'ndy'
    RETURN n.name

    This query operates exactly as before, except for the check on the :Person label, because nothing in it relates to the denied property:

    • Scans the index to create a stream of results of nodes with the name property, which leads to five results.

    • Filters the results to include only nodes where n.name CONTAINS 'ndy', filtering out Mark and Joe, which leads to three results.

    Finally, the query returns three results, only one of which has the surname property.

    Run a query that uses the composite range index on name and surname:

    MATCH (n:User)
    WHERE n.name CONTAINS 'ndy' AND n.surname IS NOT NULL
    RETURN n.name

    Since the surname property is denied, it always appears to be null and the composite index to be empty. Therefore, the query returns no result.

    Run the same query as for the composite index, but using the full-text index instead:

    CALL db.index.fulltext.queryNodes("userNames", "ndy") YIELD node, score
    RETURN node.name

    The problem now is that it is not clear whether the results provided by the index are achieved due to a match to the name or the surname property. Results from the surname property now need to be excluded by the security rules, because they require the user not to be able to see any surname properties. However, the security model cannot introspect the Lucene query to determine what it will actually do, whether it works only on the allowed name property or also on the disallowed surname property. Therefore, to prevent the index from returning results that the user should not see, the index treats all properties as denied rather than just the surname property. The query performs the following steps:

    • Run a Lucene query on the full-text index to return results containing ndy in either property, leading to five results.

    • Filter the results to exclude all nodes, filtering out everyone, leading to no result.

    In the end, the query returns zero results rather than the expected results Andy, Mandy, and Sandy.

Denied properties on a specific label

Instead of denying the surname property for all labels, like the example in Denied properties on all labels, consider denying reading it only for nodes with the :Person label.

  1. Deny read access to the surname property for nodes with the :Person label:

    DENY READ {surname} ON GRAPH * NODES Person TO users;
  2. Run the same queries as in the previous examples using one of the indexes:

    Run a query that uses the single property range index on name:

    MATCH (n:User)
    WHERE n.name CONTAINS 'ndy'
    RETURN n.name

    The query operates exactly as in Denied properties on all labels, returning the same three results, because nothing in it relates to the denied property.

    Run a query that uses the composite range index on name and surname:

    MATCH (n:User)
    WHERE n.name CONTAINS 'ndy' AND n.surname IS NOT NULL
    RETURN n.name

    Since the surname property is denied only for nodes with the label :Person, it appears to be null only for those nodes, and the composite index does not contain them. The composite index still contains the remaining :User nodes that have both properties. Therefore, the query returns only one result.

    Run a query that uses the full-text index on name and surname:

    CALL db.index.fulltext.queryNodes("userNames", "ndy") YIELD node, score
    RETURN node.name

    The problem now is that it is not clear whether the results provided by the index are achieved due to a match to the name or the surname property. However, the impact is lessened, as only nodes with the label :Person need to exclude the results from the surname property. Nodes without the :Person label can read the surname property and do not need to be excluded.

    However, the security model cannot introspect the Lucene query to determine what it will actually do, whether it works only on the allowed name property or also on the disallowed surname property. Therefore, to prevent the index from returning results that the user should not see, the index treats all properties of nodes with the label :Person as denied, rather than just the surname property. Since the surname property is denied only for nodes with the label :Person, the index can safely return any nodes that do not have that label.

    The query performs the following steps:

    • Run a Lucene query on the full-text index to return results containing ndy in either property, leading to five results.

    • Filter the results to exclude nodes that also have the label :Person, filtering out Mandy and Joe, leading to three results.

    In the end, the query returns three results rather than zero, as in Denied properties on all labels, because the security model can still allow results from nodes that do not have the :Person label, even if they match on the denied surname property.

Fail-open DENY behavior

A DENY rule fails open when its criteria are not met, so Neo4j does not apply the restriction, and it grants access by default if a broader GRANT exists. This can lead to unintended data exposure if the DENY rule is not carefully crafted. To avoid this, apply the principle of least privilege and grant access only to the specific data the user needs to see.

For example, consider the following scenarios:

An unmet DENY failing open with property-based RBAC

You grant a user access to a property and try to restrict it with a DENY rule. However, if the DENY rule does not match any data, for example, if the property is null or misspelled, the DENY rule will not apply, and the user can still access the property.

Let’s take a few examples:

Example 1. Grant read access to the salary property on all nodes with the Employee label, but deny it for employees whose position is 'CEO':
GRANT READ {salary} ON GRAPH * NODES Employee TO myRole;
DENY READ {salary} ON GRAPH * FOR (e:Employee) WHERE e.position = 'CEO' TO myRole;

In this case, if the e.position property is null or misspelled, the DENY rule will not apply, and myRole will see the salary property.

A better way is to apply the principle of least privilege and only grant access to the salary property for employees whose position is not 'CEO':

Example 2. Grant read access to the salary property on all nodes with the Employee label, whose position is not 'CEO':
GRANT READ {salary} ON GRAPH * FOR (e:Employee) WHERE e.position <> 'CEO' TO myRole;

In this way, if e.position is null or misspelled, the user will not see the salary property, and the DENY will not be needed.

Or, if for some reason using DENY is unavoidable, the problem can be mitigated by adding an additional DENY to cover the case where e.position is null:

Example 3. Deny read access to the salary property for employees whose position is null:
DENY READ {salary} ON GRAPH * FOR (e:Employee) WHERE e.position IS NULL TO myRole;

This way, if e.position is null, the user will not see the salary property, and the DENY will not apply.

Alternatively, you can add a constraint to ensure that the e.position property cannot be null, so the DENY condition is always checkable:

Example 4. Add a constraint to ensure that the position property cannot be null:
CREATE CONSTRAINT FOR (e:Employee) REQUIRE e.position IS NOT NULL;

This way, the DENY will never apply due to null values, and the user will not see the salary property for employees whose position is 'CEO'.

An unmet DENY failing open with label-based RBAC

A DENY rule does not apply when it is too broad and does not match the data.

For example, if you grant read access to the salary property on all nodes and then try to restrict it with a DENY rule for nodes with a specific label, if the nodes with that label are not present in the graph, the DENY rule will not apply, and the user can still access the salary property on all nodes.

Example 5. Grant read access to the salary property on all nodes:
GRANT READ {salary} ON GRAPH * NODES * TO myRole;

This grants read access to the salary property on all nodes, including those that should not be accessible.

Then, you try to restrict it with a DENY rule to prevent access to the salary property on nodes labeled Management:

Example 6. Deny read access to the salary property for nodes with the Management label:
DENY READ {salary} ON GRAPH * NODES Management TO myRole;

In this case, if the Management label is not present on a node that has the salary property, the DENY rule does not apply, and myRole can still see the salary property on that node.

A better way is to apply the principle of least privilege and only grant access to the salary property for nodes that have a specific label, such as IndividualContributor:

Example 7. Grant read access to the salary property only for nodes with the IndividualContributor label:
GRANT READ {salary} ON GRAPH * NODES IndividualContributor TO myRole;

This way, the user only sees the salary property on nodes with the IndividualContributor label, not on any other nodes.

Access control and labels

In Neo4j, nodes can have multiple labels, but relationships only have one type. This is important when it comes to controlling who can see what.

The following scenarios only focus on nodes because they can have multiple labels. The same general rules apply to relationships, but they are simpler.

For details on the general influence of access control privileges on graph traversal, see Graph and sub-graph access control.

Traversing multi-labeled nodes with partial access to labels

To get information about labels attached to a node by calling the built-in labels() function, a user needs to have the privilege to traverse on one or multiple labels attached to that node using GRANT TRAVERSE or GRANT MATCH. In the case of nodes with multiple labels, the user will be able to see all labels attached to the node, even if they were not granted access to traverse on some of those labels.

For example, let’s assume that a graph contains three nodes: one labeled :A, another labeled :B, and one with both labels :A and :B.

  1. Grant traversal access to nodes with the label :A to the custom role:

    GRANT TRAVERSE ON GRAPH * NODES A TO custom;
  2. Then, run one of the following queries and see the results:

    Run a query to get all labels of nodes with the :A label:

    MATCH (n:A)
    RETURN n, labels(n)

    The query returns a result with two nodes: the node with label :A and the node with labels :A :B.

    In contrast, if you run a query to get the labels of nodes with the :B label:

    MATCH (n:B)
    RETURN n, labels(n)

    The query returns only the node that has both labels: :A and :B. Even though :B does not have access to traversals, there is one node with that label accessible in the dataset due to the allow-listed label :A that is attached to the same node.

Traversing multi-labeled nodes with denied access to some of the labels

If a user is denied access to a label, they will never get results from any node with that label. Thus, the label name will never appear to them.

For example, let’s assume that a graph contains three nodes: one labeled :A, another labeled :B, and one with both labels :A and :B and that the user has access to traverse on label :A but not on label :B.

  1. Grant traversal access to nodes with the label :A to the custom role, but deny traversal access to nodes with the label :B:

    GRANT TRAVERSE ON GRAPH * NODES A TO custom;
    DENY TRAVERSE ON GRAPH * NODES B TO custom;
  2. Then, run one of the following queries and see the results:

    Run a query to get all labels of nodes with the :A label:

    MATCH (n:A)
    RETURN n, labels(n)

    The query returns the node that only has the :A label. It does not return the node with both labels :A and :B, because the user does not have access to traverse on it because of :B, even though it also has the label :A that is allow-listed.

    Run a query to get the labels of nodes with the :B label:

    MATCH (n:B)
    RETURN n, labels(n)

    The query returns no nodes.

The db.labels() procedure

In contrast to the normal graph traversal described in the previous section, the built-in db.labels() procedure does not process the data graph itself, but the security rules defined on the system graph. That means:

  • If a label is explicitly whitelisted (granted), it will be returned by this procedure.

  • If a label is denied or is not explicitly allowed, it will not be returned by this procedure.

For example, let’s assume that a graph contains three nodes: one labeled :A, another labeled :B, and one with both labels :A and :B.

  1. Grant traversal access to nodes with the label :A to the custom role:

    GRANT TRAVERSE ON GRAPH * NODES A TO custom;
  2. Then, run the following query:

    CALL db.labels()

    The query returns only label :A, because the user does not have access to traverse on label :B.

Privileges for nonexistent labels, relationship types, and property names

Privileges for nonexistent labels, relationship types, and property names take effect only after they are created. In other words, when authorizing a user, only privileges for existing labels, relationship types, and property names are applied. This is because the graph elements must be resolved internally to check against privileges when users later try to use them. If a label, relationship type, or property name does not yet exist, it will not resolve, and therefore, the privileges will not apply.

A workaround is to create the label, relationship type, or property name using the db.createLabel(), db.createRelationshipType(), and db.createProperty() procedures in the relevant database when creating the privileges.

Labels, relationship types, and property names are considered nonexistent in a database if:

  • There has never been a node with that label, a relationship with that relationship type, or a property with that name. Nor any index or constraint on them.

  • There has been no attempt to add a node with that label, a relationship with that relationship type, or a property with that name. An attempted creation adds the label, relationship type, or property name to the known labels, relationship types, and property names, even if the operation ultimately fails, unless it fails due to missing or denied privileges to create new labels, relationship types, or property names.

  • There has been no attempt to create an index or constraint using that label, relationship type, or property name. Although many index or constraint errors are detected before the label, relationship type, or property name is created, it may still be created in some cases (for example, if a property existence constraint fails because existing data violates it).

  • They have not been created using any of the db.createLabel(), db.createRelationshipType(), or db.createProperty() procedures.

There is currently no way to remove a label, relationship type, or property name from the database. Once existent in the database, they cannot return to nonexistent.

For example, let’s assume you have a new, empty database called testing.

The example focuses only on nodes and their labels, though the same principle applies to relationships and their relationship type, and properties (on both nodes and relationships) and their names.

  1. Define some privileges to the custom role that include a nonexistent label :A:

    GRANT MATCH {*} ON GRAPH testing NODES * TO custom;
    GRANT CREATE ON GRAPH testing NODES A TO custom;
    GRANT SET LABEL A ON GRAPH testing TO custom;
    GRANT CREATE NEW NODE LABEL ON DATABASE testing TO custom;
  2. Then, connect as a user with the custom role, for example, Alice, and run the following query to create a node with the nonexistent label :A:

    CREATE (:A)

    You get the following exception even though you are allowed to create new labels:

    Create node with labels 'A' on database 'testing' is not allowed for user 'Alice' with roles [PUBLIC, custom].

However, rerunning the same query creates the node. This is because the failed creation still creates the label, making it no longer nonexistent when the query is run a second time.

To ensure success on the first attempt, when setting up the privileges for the custom role, the administrator should run the db.createLabel() procedure on the affected databases for all nonexistent labels that get assigned privileges. In this example, when creating the custom role, connect to testing and run CALL db.createLabel('A') to ensure you create the node successfully on your first attempt.

Access control and performance

Neo4j’s role-based access control can have performance implications, especially when security rules are complex or when querying large graphs with restrictive access. For example, count store operations, which are usually fast lookups, may experience significant performance differences because the database must check each node or relationship against the security rules rather than simply retrieving counts from the count store.

Access control and performance of database operations

When security rules that restrict access to certain nodes, relationships, or properties are in place, Neo4j must perform additional checks to ensure that the user only sees what they are allowed to see.

For example, consider a graph with nodes labeled :Person and :Customer, where some nodes have both labels.

  1. Define two roles with different privileges:

    • restricted — with some restrictions on traversals.

    • unrestricted — with no restrictions on traversals.

      GRANT TRAVERSE ON GRAPH * NODES Person TO restricted;
      DENY TRAVERSE ON GRAPH * NODES Customer TO restricted;
      GRANT TRAVERSE ON GRAPH * ELEMENTS * TO unrestricted;

      The restricted role allows traversing nodes with the label :Person, but denies traversing nodes with the label :Customer, while the unrestricted role allows traversing all nodes and relationships.

  2. When you run the following query, the execution plan looks the same regardless of the role:

    Cypher query to count nodes with the :Person label
    MATCH (n:Person)
    RETURN count(n)
    Execution plan for both users
    +--------------------------+
    | Operator                 |
    +--------------------------+
    | +ProduceResults          |
    | |                        +
    | +NodeCountFromCountStore |
    +--------------------------+

    However, the underlying operations can differ significantly due to the security rules applied to each role:

User with unrestricted role User with restricted role

The database accesses the count store to retrieve the total number of nodes with the label :Person, without needing to check each node against any security rules. This is a very quick operation.

The database cannot access the count store because it must make sure that only traversable nodes with the desired label :Person are counted. It needs to check each node with the :Person label to see whether it also has the :Customer label, and deny access to it if it does. Therefore, due to the additional data access required by the security checks, this operation is slower compared to executing the query as an unrestricted user.

Access control and performance of property rules

Extra node or relationship-level security checks are necessary when adding security rules based on property rules, and these can have a significant performance impact.

The following example shows how the database behaves when adding security rules for nodes to roles restricted and unrestricted. The same limitations apply to relationships.

  1. Define two roles with different privileges:

    GRANT TRAVERSE ON GRAPH * FOR (n:Customer) WHERE n.secret <> true TO restricted;
    GRANT TRAVERSE ON GRAPH * ELEMENTS * TO unrestricted;
  2. When you run the following query, the execution plan looks the same regardless of the role:

    Cypher query to get all nodes with the :Customer label
    MATCH (n:Customer)
    RETURN n
    Execution plan for users with either role
    +--------------------------+
    | Operator                 |
    +--------------------------+
    | +ProduceResults          |
    | |                        +
    | +AllNodesScan             |
    +--------------------------+

    However, the underlying operations can differ significantly due to the security rules applied to each role:

User with unrestricted role User with restricted role

The database scans all nodes and quickly identifies accessible nodes based solely on the presence of the :Customer label. This is a relatively quick operation.

The database scans all nodes, identifies potentially accessible nodes based on the presence of the specified label, then accesses the properties of those nodes and inspects their values to ensure the property rule criteria are met (i.e., that secret is not set to true in this case). Due to the additional data access required by the security checks, this operation is slower than executing the query as an unrestricted user.

Glossary

allocator

A component in the cluster that allocates databases to servers according to the topology constraints specified and an allocation strategy.

asynchronous replication

Asynchronous replication is used by secondary copies to poll for new transactions, which means they cannot be guaranteed to have received the most recent transactions. This enables efficient scale-out of read-performance.

Aura instance

A fully-managed DBMS represented by a single instance ID, that is running in the Neo4j Aura cloud.

auto-commit transaction

An automatically committed transaction that contains a single query.

Bolt protocol

Bolt is a protocol used for interaction between Neo4j instances and drivers.

bookmark

A marker the client can request from the cluster to ensure that it is able to read its own writes so that the application’s state is consistent and only databases that have a copy of the bookmark are permitted to respond.

category (Bloom)

A category is based on a node label and is defined in a Perspective as a way of visually distinguishing nodes with the same label(s).

causal consistency

All servers in a cluster agree on the order in which transactions take place. The position of a server on the causal chain can be guaranteed using a bookmark.

cluster

A Neo4j DBMS that spans multiple servers working together to increase fault tolerance and/or read scalability. Databases on a cluster may be configured to replicate across servers in the cluster thus achieving read scalability or high availability.

client application

Software that interacts with a Neo4j server.

commit

A commit is the successful completion of a transaction, which ensures durability of any changes made. For more details, visit Operations Manual → Transaction management.

composite database

Composite databases are the means to access partitioned graph data with a single Cypher query.

constraint

Constraints are sets of data modeling rules that ensure the data is consistent and reliable.

Cypher®

Neo4j’s graph query language.

data model

A data model defines how information is organized in a database. A good data model will make querying and understanding your data easier. In Neo4j, the data models have a graph structure.

database

A database is a container used by the DBMS to manage and store graph data. The physical structure of data is controlled by the database.

database vs graph

Databases are the physical containers of graph data. Graphs are the logical structure of data in Neo4j.

Database Management System

Database Management System, or DBMS, capable of managing multiple databases. A DBMS may run on a single server, or span several servers configured as a cluster.

database schema

The prescribed property existence and datatypes for nodes and relationships.

deallocate

An act of removing a database from a server or a server from a cluster without loss of data or reduced fault tolerance.

degree (of a node)

The number of relationships of a specific node; loops are counted twice.

disaster recovery

A manual intervention to restore availability of a cluster, or databases within a cluster.

driver

A software library that provides access to Neo4j from a particular programming language.

election

In the event that the Raft leader becomes unresponsive, followers automatically trigger an election and vote for a new leader.

entity

A node or a relationship.

expression (Cypher)

A component of a Cypher query which produces values. It may be used in projections, as a predicate, or when setting properties on graph elements.

fabric

Fabric is the architectural design of a unified system that provides a single access point to local or distributed graph data.

fault tolerance

A guarantee that a cluster can maintain a database’s persistence and availability in the event of one or more servers failing.

follower

A primary copy of a database acting as a follower, receives and acknowledges synchronous writes from the leader.

Generative AI (GenAI)

A type of artificial intelligence (AI) system that generates text, images, or other media in response to prompts.

graph

A logical representation of a set of nodes where some pairs are connected by relationships.

index

Data structure that improves read performance of a database.

knowledge graph

A specific type of graph that has an organizing principle so that a user (or a computer system) can reason about the underlying data. The organizing principle provides an additional layer of structure that adds context to support knowledge discovery.

label

Marks a node as a member of a named and indexed subset. A node may be assigned zero or more labels.

leader

A single primary copy of a database is designated as the leader. It receives all write transactions from clients and replicates writes synchronously to followers and asynchronously to secondary copies of the database.

main database

In terms of Neo4j Enterprise Studio, the database(s) containing the user’s data. Can exist in the same Neo4j deployment as the tool asset database.

motif

A description of a specific pattern within a graph.

node

A node represents an entity or discrete object in your graph data model. Nodes can be connected by relationships, hold data in properties, and are classified by labels.

operator

A symbol representing a mathematical or logical operation.

parameter

Named value provided when running a Cypher statement.

path

A sequence of nodes and the relationships connecting them, that does not contain duplicate relationships. Several paths can match a pattern.

pattern

A specific arrangement of nodes and relationships that can be matched in a graph. A pattern follows a motif.

perspective (Bloom)

A Perspective defines a certain business view or domain that can be found in the target Neo4j graph. A single Neo4j graph can be viewed through different Perspectives, each tailored for a different business purpose.

primary

A copy of the database that is able to process write transactions and is eligible to be elected as a leader. It participates in fault tolerant writes as it is part of the majority required to acknowledge and commit write transactions.

primary vs secondary

In a cluster, databases can operate in either primary or secondary mode. Primary databases are able to process write and read transactions, ensuring fault tolerance. Secondary databases are replicated asynchronously from primaries, and their main purpose is to provide read scaling within the cluster.

project (Aura)

An isolated environment in the unified Aura console that contains its own database instances, configurations, and resources. Preceded by tenant in the classic Aura console.

property

Properties are key-value pairs that are used for storing data on nodes and relationships.

query (Cypher)

A statement that retrieves or writes information to a database.

Raft group

A group of servers that are participating in hosting a particular database in primary mode.

Raft group member

A server that is participating in a Raft group. A server can be a member of one or more groups.

Raft log

A shared log between all Raft group members that is guaranteed to be consistently updated and viewed by those members. The log contains both database data and operational state of the Raft group.

Raft protocol

The networking mechanism that enables a database to replicate its data across multiple servers to give high availability for accessing the data and high durability to the data stored.

read scaling

Distributing query load by creating additional database copies hosted in secondary mode (read-only).

relationship

A relationship represents a connection between nodes in your graph data model. Relationships connect a source node to a target node, hold data in properties, and are classified by type.

secondary

An asynchronously replicated copy of the database that provides read scaling within the cluster.

seed

A seed is a database dump or a full backup used to create a database on a cluster. This is sometimes called seeding.

server

A physical machine, a virtual machine, or a container running an instance of Neo4j. Servers can be standalone or part of a cluster.

session

A causally linked sequence of transactions.

session consistency

An alternative name for Neo4j’s causal consistency.

standalone

A single server running Neo4j and not part of a cluster.

synchronous replication

Synchronous replication requires the leader primary to replicate a transaction and block the commit until a quorum of the follower primaries acknowledges that the transaction is successfully replicated. Once the transaction is replicated, the commit is allowed to proceed. This ensures data durability and consistency within the cluster.

system database

A database used by Neo4j to store system information.

tenant (Aura)

An isolated environment in the classic Aura console that contains its own database instances, configurations, and resources. Replaced by project in the unified Aura console.

tool asset database

In terms of Neo4j Enterprise Studio, the database where tools' assets are stored. This can be in the same Neo4j deployment as the main database(s) or in a separate deployment.

topology

A configuration that describes how the copies of a database should be spread across the servers in a cluster, see primary mode and secondary mode.

transaction

A transaction comprises a unit of work performed against a database. It is treated in a coherent and reliable way, independent of other transactions. Transactions comply with the ACID consistency model (atomic, consistent, isolated, and durable).