The Neo4j JavaScript driver, sessions, retries and a slower release cadence
Neo4j Bolt driver for JavaScript
At a glance
- What is it?
- The neo4j-javascript-driver is the official Bolt driver for JavaScript, with standard and reactive sessions, managed transaction functions that retry transient failures, and a browser build that talks WebSockets. From version 6.0 it ships on a deliberate, infrequent cadence instead of monthly releases.
- Who is it for?
- neo4j-javascript-driver suits application teams writing Cypher from Node.js or from a browser, who want the official driver with managed transactions and session semantics rather than hand-written protocol code. It does not suit a project that depends on a new driver version every month, because from 6.0 the release cadence has deliberately slowed.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
One driver per database per application
The neo4j-javascript-driver repository is the official Neo4j driver for JavaScript, and it speaks the Bolt protocol. The usage guidance in the README is short and worth memorising: it should be enough to have a single driver per database per application. That is the object you construct once and keep, and it owns the connection pool.
Constructing it takes a URI and an authentication helper:
var driver = neo4j.driver(
'neo4j://localhost',
neo4j.auth.basic('neo4j', 'password')
)The URI scheme is not cosmetic. The README distinguishes the single instance case, the bolt URI scheme, from the Causal Cluster case, the neo4j URI scheme, and the driver behaves differently between them: reads written as transaction functions benefit from automatic retries and, in a cluster deployment, automatic load balancing.
The other rule about the driver is about shutdown. Driver instance should be closed when the Node.js application exits, and driver.close() returns a Promise, so it can be awaited. The reason given is practical rather than stylistic: otherwise application shutdown might hang or it might exit with a non-zero exit code.
In Node.js the driver is installed from npm:
npm install neo4j-driverThe node version of the driver requires Node.js 18 or later. There is also a pre-release channel, npm install neo4j-driver@next, and the README is careful to note that @next only points to pre-releases that are not suitable for production use. For the latest stable release you omit the @next part or use @latest instead.
Sessions carry the access mode, the database and the bookmarks
Work happens in sessions, and the session configuration is where the semantics of your application are decided.
A regular session is created with driver.session(), and the README insists on one thing: always make sure to close sessions when you are done using them. A session has a default access mode, and it can be set explicitly, for example driver.session({ defaultAccessMode: neo4j.session.READ }) for read work or neo4j.session.WRITE for writes. You can also target a specific database with the database option, which matters in a multi-database deployment.
Bookmarks are the fourth option, and they are the mechanism for causal consistency across sessions. A session can be created with a list of bookmarks taken from a previous session, so that the new session starts from a point in the transaction log that is at or after everything the previous session observed. In practice this is how you make a read that follows a write see that write, without asking the reader to understand the cluster's internals.
The reactive variant is the same shape. driver.rxSession() creates a reactive session, and it accepts the same defaultAccessMode, bookmarks and database options. The difference is the return types: the reactive API hands back streams and observables rather than promises, for applications that already have a reactive stack and want to compose Cypher results into it.
Because both variants take the same options, a codebase can move between them without restructuring its session configuration, which is a small piece of design coherence worth having.
Transaction functions buy retries for the transient failures
The managed transaction functions are the part of the driver that changes how an application behaves under failure, and they are worth understanding rather than copying blindly.
executeRead and executeWrite wrap a function that receives a transaction object. The transaction is committed automatically if the function returns, so there is no explicit commit or rollback to write, and the driver can retry the whole function when it fails for a reason it expects, such as a network fluctuation or a transient error. That is the difference between a managed transaction and a hand-rolled one, where a failed attempt leaves you to decide whether the work is safe to repeat.
The retry budget is configured at the driver level, not on the transaction, and the default maximum retry time is 30 seconds:
neo4j.driver('neo4j://localhost', neo4j.auth.basic('neo4j', 'password'), {
maxTransactionRetryTime: 30000
})That setting applies to both standard and reactive sessions. A transaction function is a good fit for a read whose result you want to be consistent, and a write whose body is idempotent or at least safe to repeat, because the driver will re-run it. It is a poor fit for a transaction that must not run twice, for example one that increments a counter based on a value read inside the transaction without a uniqueness constraint behind it.
The returned value is a Promise, so the result can be consumed with then and catch, and the session closed afterwards.
The browser build connects over WebSockets
The driver also ships a special browser version, which supports connecting to Neo4j over WebSockets, and it is loaded into a page with a script tag pointing at lib/browser/neo4j-web.min.js, either as a direct reference or from a CDN such as unpkg or jsDelivr. That build makes a global neo4j object available, and you create a driver instance from it with neo4j.driver.
From version 5.4.0 the browser build is also exported as an ECMAScript module, so it can be imported from a module using the ESM builds of the same file, again directly or from a CDN. The README is precise that the ESM imports need a version of at least 5.4.0.
Shutdown behaves differently in the browser, and the difference is reasoned rather than accidental. It is not required to explicitly close the driver on a web page, because the web browser should gracefully close all open WebSockets when the page is unloaded. However, the driver instance should be explicitly closed when its lifetime is not the same as the lifetime of the web page, which is the case for a single-page application that swaps views or signs a user out, and again driver.close() returns a Promise.
One thing to plan for is that a browser connecting over WebSockets needs a server that accepts it, and the README does not document the server-side configuration for that. The driver side is documented; the deployment side is a question for your Neo4j setup.
Version 6.0 changed the release policy on purpose
The most consequential thing in the README is not an API, it is a policy. Starting with 6.0, the Neo4j drivers are no longer on a monthly release cadence. Minor version releases happen when there are sufficient new features or improvements to warrant them, and the stated reason is to reduce the required work of users updating their driver.
The second half of the policy is about patch versions. As a policy, patch versions will not be released except on rare occasions. Bug fixes and updates go into the latest minor version, and users should upgrade to that.
The third is the guarantee that makes the policy workable. Driver upgrades within a major version will never contain breaking API changes. So a 6.1 to 6.2 move is safe by policy, and only crossing a major boundary can break you.
In practice that means a slower stream. The release list shows 6.2.0 on 2026-06-30, 6.1.0 on 2026-06-05, and 5.28.3 in January 2026, with the default branch being 6.x and the last push to the repository on 2026-10-19. The licence field on the repository says Apache-2.0, and the supported versions policy is documented on Neo4j's developer knowledge base.
For an application team this is a good trade. A driver that changes monthly forces a dependency bump review every month, and every bump is a chance to pick up a regression in the driver rather than in your code. A driver that changes when there is something worth changing moves that cost to a rarer, more deliberate occasion.
A monorepo with a shared test kit and a browser test suite
The repository is a monorepo built with pnpm and lerna, with the packages under packages/. The lint-staged configuration in the root package.json shows the shape of it: core, bolt-connection, neo4j-driver, neo4j-driver-lite and a Deno variant are linted separately, and the testkit-backend package has its own deno fmt and deno lint rules. The root scripts run the workspace tasks, with separate targets for unit, deno, integration, browser and stress tests, and there are start-neo4j and stop-neo4j scripts for bringing a local database up and down for those runs.
The testkit/ and benchkit/ directories at the top level are the parts worth noting. A shared test kit is how a driver stays compatible with a database implementation rather than only with itself, since the same suite can be run against different clients. The benchkit directory is the benchmarking side.
For a JavaScript team this matters for one more reason. The driver is written in TypeScript in the source, and the packages are linted with standard and ts-standard, but it is published as a JavaScript package that Node.js and browsers can consume. The type declarations are shipped alongside it, which is what makes a typed session configuration and a typed result usable from TypeScript without the runtime being TypeScript.
Editorial conclusion
neo4j-javascript-driver suits application teams writing Cypher from Node.js or from a browser, who want the official driver with managed transactions and session semantics rather than hand-written protocol code. It does not suit a project that depends on a new driver version every month, because from 6.0 the release cadence has deliberately slowed. Before you upgrade, read the 6.x changelog, keep to one major version at a time since upgrades inside a major version never carry breaking API changes, and confirm your Node.js version meets the requirement of Node 18 or later.
Frequently asked questions
How do I install and use the Neo4j JavaScript driver in Node.js?
Install it with npm install neo4j-driver, which requires Node.js 18 or later, then create a driver with neo4j.driver and a URI such as neo4j://localhost, and close it with driver.close() when the application exits so shutdown does not hang or exit with a non-zero code.
What is the difference between a regular session and a reactive session?
Both are created from the same driver and take the same options, including defaultAccessMode, bookmarks and database. The regular session returns promises and the reactive session returns streams and observables, so the reactive variant is the one to use in an application that already has a reactive stack.
How do managed transaction functions handle transient errors?
executeRead and executeWrite commit automatically and are retried by the driver on network fluctuations and transient errors. The retry window is set on the driver with maxTransactionRetryTime, which defaults to 30 seconds, and applies to both standard and reactive sessions.
Can I use the Neo4j driver in a web browser?
Yes, a special browser build supports connecting over WebSockets and is loaded from lib/browser/neo4j-web.min.js, directly or from a CDN, and since version 5.4.0 it is also exported as an ECMAScript module. Closing the driver explicitly is only required when its lifetime is longer than the page's.
How often are new versions of the Neo4j JavaScript driver released?
Starting with 6.0 the drivers are no longer on a monthly cadence. Minor releases happen when there are sufficient new features, patch versions are rare, bug fixes go into the latest minor version, and upgrades within a major version never contain breaking API changes.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/neo4j-neo4j-javascript-driver)Was this useful?