Using the Neo4j Driver in Spring Boot

By choice, I’d normally steer clear of Java if I wanted to write a lightweight application, and instead write something with Node. But since joining Neo4j last summer, I’ve become exposed to Java on a daily basis, writing User Defined Functions & Procedures in Neo4j.

However, since being introduced to Spring, I’ve been impressed by how quickly you can get a REST API up and running.  Starting with Spring Intializr, and after a few @Annotations, you can have a production grade application with security up in minutes.  Spring also has an ecosystem of projects around it including Spring Data, a consistent approach to CRUD operations.

Dependency Injection

One of the features of the Spring Framework that I find most useful is Dependency Injection, the ability to inject decoupled implementations of an Interface without the application worrying about the specifics.  In Spring terms, these are called Beans.  Any Plain-Old-Java-Object can be used as a Spring Bean and “wired” into a class or service.

This is the simplest way that we can interact with Neo4j in a Spring application.

Creating a Neo4j Driver @Bean

To create a Spring Boot application with Neo4j, first we’ll need to add the neo4j-java-driver and spring boot dependencies.

dependencies {

Once the dependencies are there, all we need to do is create a method that returns an instance of org.neo4j.driver.v1.Driver in the main application class and annotate it with the @Bean annotation.
public class NeobeansApplication {
    public static void main(String[] args) {, args);
    public Driver neo4jDriver() {
        return GraphDatabase.driver("bolt://localhost:7687", AuthTokens.basic( "neo4j", "p455w0rd" ));

In this example, I am using a Basic auth token but Neo4j also supports Kerberos tokens and custom authentication schemes.

Once the bean has been defined, we can “wire” this into any class, controller or component using the @Autowired annotation.

public class PersonController {
    Driver driver;

    public List<Map<String, Object>> getIndex(
            @RequestParam(defaultValue = "1") int page,
            @RequestParam(defaultValue = "10") int limit
    ) {
        try ( Session session = driver.session() ) {
            Number skip = (page - 1) * limit;

            String query = "MATCH (p:Person) RETURN p ORDER BY SKIP {skip} LIMIT {limit}";

            Map<String, Object> params = new HashMap<String, Object>() {{
                put("limit", limit);
                put("skip", skip);

            return session.readTransaction(tx -> {
               return, params)
                       .list( row -> row.get("p").asMap() );

The @RestController annotation will identify this class as a REST controller.

As you can see, I have used the @Autowired annotation to inject an instance of the driver into the class. This is then used to create a session, run a read query and return a paginated list of results.


Adding Dynamic Configuration

In the example above, the Neo4j credentials are hardcoded into the application. This would never be a good idea for production grade code.

We can use a @Configuration annotated class to pull properties from a configuration file. First off, we’ll need to configure gradle to read the values from src/main/resources/

processResources {

We can then add the properties that we would like to load into the application to the file.

To avoid clashes, I have prefixed each setting with neo4j.. For forward compatibility, I have also split out the auth details – this way we can build support for custom schemes and kerberos authentication into the application.

Next, we can create a @Configuration annotated class.
public class Neo4jConfiguration {
    // ...

In order to pull the properties into the application, we can annotate properties with @Value. The annotation will take the full key of the property, prefixed with a $ and wrapped in braces.

private String scheme;

In this example, I’ve provided a default value of bolt. If you do not provide a default value and the setting, an exception will be thrown on start up.

Next, we can use the value in neo4j.auth.type to create the appropriate token.

 * Use the neo4j.auth.type property to create an appropriate Auth Token
 * @return AuthToken
public AuthToken getAuthToken() {
    switch ( authType ) {
        case "basic":
            return AuthTokens.basic(username, password);
        case "kerberos":
            return AuthTokens.kerberos(ticket);
            return AuthTokens.none();

Then combine the scheme, host, port and routing policy to create a valid URI.

 * Get the URI for the Neo4j Server
 * @return String
public String getUri() {
    // Get the base URI (ie bolt://localhost:7474)
    String uri = String.format("%s://%s:%s", scheme, host, port);
    // If there is a CC routing policy, append it to the end of the string
    if ( scheme == "bolt+routing" && routingPolicy != null ) {
        uri += "?policy="+ routingPolicy;
    return uri;

Finally, we can move our driver @Bean into the configuration file and use the methods to create a URI and Auth Token.

 * Create a new Driver instance
 * @return Driver
public Driver neo4jDriver() {
    String uri = getUri();
    AuthToken token = getAuthToken();
    return GraphDatabase.driver(uri, token);

Although the Bean definition has been moved, Spring is smart enough to pick up this change so we don’t have to modify the rest controller.


Hopefully this post has given you an introduction to interacting with Neo4j inside a Spring application. Spring has a vast ecosystem and this post only scratches the surface. For more information on Spring or the frameworks, head over to Spring Data is an interesting project that is well worth reading up on, and even features an extension that allows you to map plain old Java objects to Nodes in the graph using Spring Data Neo4j.

The code to go with this blog post is available on Github, feel free to clone, fork or create a pull request if you spot anything untoward.