Driver API Specification

This Document is still in a draft state and the content can change at any time.

This document describes the overview of a Driver and how different scenarios like update the routing table for a clustered Neo4j setup, available URI schemes and TLS settings, etc.

Driver Objects

URI Schemes

No TLS enabled.

Enable TLS and allow self signed certificate authority.

Enable TLS and only allow system enabled certificate authorty and verify hostname.

Client Side Routing

Neo4j supports a clustered setup and uses The Raft Consensus Algorithm.


Each Neo4j Core instance in a cluster supports routing and reading.

Only one Neo4j Core in a cluster can be selected to support writing operations. This selection can rotate over time.

The driver should support a routing table.

Read Replicas are not involved in the Raft Consensus Algorithm, but a Read Replica do return a routing table that only contain the Read Replica itself.

Routing Table Procedure Call

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

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 ?

The table shows how to fetch the routing table for database "foo", (Neo4j 3.5 does not support multi-database)

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 ?


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": [""], "role": "WRITE"}, {"addresses": [""], "role": "READ"}, {"addresses": ["", ""], "role": "ROUTE"}]]
S: SUCCESS {"bookmark": "example-bookmark:1", "type": "r", "t_last": 5, "db": "system"}

Neo4j 4.0 Cluster and Multi-database

System Database

Cluster Member

A cluster contains Core members and Read Replica members.

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:

Here 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:

Client Side Logging



Causal Chaining