Neo4j Driver API

Neo4j Drivers export a uniform API. This allows driver concepts and naming to be shared across ecosystems, making transition between languages and multi-language support easier and more consistent.

Driver objects

  • Driver

  • Session

  • Transaction

  • DriverConfig

    • uri::String

    • auth::Dictionary

    • user_agent::String

    • encrypted::Boolean

    • trust::String

  • SessionConfig

    • default_access_mode::String

    • database::String

    • fetch_size::Integer

    • bookmarks::List<String>

    • imp_user::String

  • TransactionConfig

    • metadata::Dictionary

    • timeout::Integer

  • AuthToken

  • TransactionManager

  • Connection pool

  • Routing

  • Bolt Protocol

  • PackStream

  • Neo4jExceptions

  • DriverExceptions

URI schemes

No TLS enabled:

  • bolt: connect to a single Neo4j instance.

  • neo4j: connect to a Neo4j instance and use the routing table information for further connections.

Enable TLS and allow self-signed certificate authority:

  • bolt+ssc

  • neo4j+ssc

Enable TLS and only allow system enabled certificate authority and verify hostname:

  • bolt+s

  • neo4j+s

Client-side routing

Neo4j supports clustered setups and uses The Raft Consensus Algorithm.

Each Neo4j primary server in a cluster supports routing and reading. Only one cluster primary can be selected as leader, who is in charge of write operations. This selection can rotate over time. The driver should support a routing table. Secondary servers are not involved in the Raft Consensus Algorithm, but secondaries do return a routing table that only contain the secondary itself.

See Operations Manual → Clustering for more information.

Fetching routing tables

The procedure call to fetch the routing table has changed considerably throughout the various versions of Neo4j.

Table 1. Route message (4.3+)
Neo4j Bolt Bolt message

4.3

4.3

ROUTE {$context} [$bookmarks] $db

4.4

4.4

ROUTE {$context} [$bookmarks] {"db": $db, "imp_user": $imp_user}

Table 2. How to fetch the routing table for database foo
Neo4j Bolt Bolt message

4.3

4.3

ROUTE {"address": "example.org:7687"} ["neo4j-bookmark-transaction:1", "neo4j-bookmark-transaction:2"] "foo"

4.4

4.4

ROUTE {"address": "example.org:7687"} ["neo4j-bookmark-transaction:1", "neo4j-bookmark-transaction:2"] {"db": "foo"}

Example
C: 60 60 B0 17
C: 00 00 04 04 00 00 00 00 00 00 00 00 00 00 00 00
S: 00 00 04 04
C: HELLO {"scheme": "basic", "principal": "user", "credentials": "password", "user_agent": "Example/4.4.0", "routing": {"address": "localhost:9001", "policy": "example_policy", "region": "example_region"}}
S: SUCCESS {"server": "Neo4j/4.4.0", "connection_id": "bolt-123456789"}
C: ROUTE {"address": "localhost:9001", "policy": "example_policy", "region": "example_region"} ["neo4j-bookmark-transaction:1", "neo4j-bookmark-transaction:2"], {}
S: SUCCESS {"rt": {"ttl": 300, "db": "foo", "servers": [{"addresses": ["127.0.0.1:9001"], "role": "WRITE"}, {"addresses": ["127.0.0.1:9002"], "role": "READ"}, {"addresses": ["127.0.0.1:9001", "127.0.0.1:9002"], "role": "ROUTE"}]}}
C: GOODBYE

Procedure call <4.2

Neo4j Bolt Neo4j Procedure call

3.5

3

dbms.cluster.routing.getRoutingTable($context)

4.0

4.0

dbms.routing.getRoutingTable($context, $database)

4.1

4.1

dbms.routing.getRoutingTable($context, $database)

4.2

4.2

dbms.routing.getRoutingTable($context, $database)

Table 3. How to fetch the routing table for database foo
Neo4j Bolt Bolt message

3.5

3

RUN "CALL dbms.cluster.routing.getRoutingTable($context)" {"context": {}} {"mode": "r"}

4.0

4.0

RUN "CALL dbms.routing.getRoutingTable($context, $database)" {"context": {}, "database": "foo"} {"db": "system", "mode": "r"}

4.1

4.1

RUN "CALL dbms.routing.getRoutingTable($context, $database)" {"context": {}, "database": "foo"} {"db": "system", "mode": "r"}

4.2

4.2

RUN "CALL dbms.routing.getRoutingTable($context, $database)" {"context": {}, "database": "foo"} {"db": "system", "mode": "r"}

Example
C: 60 60 B0 17
C: 00 00 01 04 00 00 00 00 00 00 00 00 00 00 00 00
S: 00 00 01 04
C: HELLO {"scheme": "basic", "principal": "user", "credentials": "password", "user_agent": "Example/4.1.0", "routing": {"address": "localhost:9001", "policy": "example_policy", "region": "example_region"}}
S: SUCCESS {"server": "Neo4j/4.1.0", "connection_id": "bolt-123456789"}
C: RUN "CALL dbms.routing.getRoutingTable($context)" {"context": {"address": "localhost:9001", "policy": "example_policy", "region": "example_region"}} {"mode": "r", "db": "system"}
C: PULL {"n": -1}
S: SUCCESS {"fields": ["ttl", "servers"]}
S: RECORD [300, [{"addresses": ["127.0.0.1:9001"], "role": "WRITE"}, {"addresses": ["127.0.0.1:9002"], "role": "READ"}, {"addresses": ["127.0.0.1:9001", "127.0.0.1:9002"], "role": "ROUTE"}]]
S: SUCCESS {"bookmark": "example-bookmark:1", "type": "r", "t_last": 5, "db": "system"}
C: GOODBYE

Clusters and multiple databases

System database

  • The name of the system database is fixed and named system.

  • The system database cannot be changed for a single instance or a cluster.

  • The system database exists on each instance.

Cluster member

A cluster contains primary members and secondary members.

  • Only one primary at any time can be the leader (accept writes).

  • Each database in a cluster has its own raft group and each database has its own routing table. In other words, the leader/primary/secondary for each database in a cluster can be different.

  • Any primary member in a cluster can provide a routing table for any database inside this cluster. Given a seed URL pointing to a primary member, this can be used to find any databases in a cluster by fetching the routing table from a primary member.

Moreover, in Neo4j 4.x:

  • Each cluster member hosts the exact same databases. If cluster member A has databases foo and system, then all other cluster members should also have and only have foo and system.

  • There is a default database for a single instance and/or a cluster.

These do not apply in Neo4j 5.x.

Driver routing table

The Driver should prevent the routing table from growing infinitely. The routing table for a specific database should be removed from the routing table if there is a failed to attempt to obtain routing information. The routing table for a specific database should be removed from the routing table if it is invalid. An invalid routing table could either be a:

  • routing table that has timed out where the TTL (Time To Live) key for that routing table have ended.

  • routing table that is pointing to a database that no longer exists.

This is the workflow the driver should follow when fetching a routing table for database named foo.

  1. Find the routing table for database foo.

  2. If the database does not exist in the routing table, then create an empty routing table with seed URL as initial router.

  3. If the routing table is stale, then refresh the routing table with a query to a cluster member that.

  4. If any error happens, remove the key foo from routing table map.

The only errors possible are:

  • SECURITY_ERROR

  • ROUTING_ERROR

  • SERVICE_UNAVAILABLE_ERROR, happens when the driver failed to get routing table for all existing routers.

Client-side logging

  • Logging levels

  • Logging syntax

Session

  • Connections

  • Connection pool

Transaction

  • Atomic unit of work

  • Transaction manager

  • Transaction functions

Causal chaining

  • Bookmark