We're excited to share the @prisma/extension-read-replicas
Prisma Client extension! This extension enables you to distribute workloads across database replicas for high-traffic workloads using Prisma Client. Try it out.
What are database replicas, and why would you use them?
A database replica, also known as a replica, is a copy of the primary database instance in the same or different region from your primary database.
One of the primary usages of database replication is to create read replicas. Read replicas can distribute read requests from your application, reserving the primary database for write operations.
Read operation query flow from the server to the read replica databaseWrite operation query flow from the server to the primary database and data propagation to the read replica databaseReplicas can be distributed globally, bringing the data closer to your application users. This can reduce the latency when responding to your application's requests.
Another valuable advantage of replicas is that they improve the resiliency and reliability of your database. This prevents your primary database from becoming a single point of failure. In the event of database failure, data corruption, or loss of data of the primary instance, a replica can be promoted to a primary instance.
Most database providers support read replicas. Here are a few example providers that offer read replica support:
Using read replicas with Prisma Client
There are multiple ways to integrate read replicas in an application. One way you can connect to read replicas from your app is by setting up a DNS service, such as Amazon Route 53, which exposes a single connection string. The DNS service then balances the load between the replicas based on the volume of incoming requests.
Another way to integrate read replicas in your app is via the data layer, for example the database driver, query builder or Object Relational Mapper (ORM). In this case, you could provide multiple connection strings to your data layer, your primary instance and replicas. The data layer then orchestrates request distribution by directing queries to a suitable replica.
In the Node.js ecosystem, Prisma is one of the most popular libraries for implementing the application data layer. Support for read replicas in Prisma Client is one of the most requested features.
We're excited to share the @prisma/extension-read-replicas
extension, which achieves this with a Prisma Client extension!
import { PrismaClient } from '@prisma/client'import { readReplicas } from '@prisma/extension-read-replicas'
const prisma = new PrismaClient() .$extends( readReplicas({ url: 'postgres://johndoe:<password>@jeffery-bezos.us-east-2.aws.com:5432/mydb', }), )
Under the hood, the extension creates and manages Prisma Client instances for each database replica. The extension, by default, will route each read request to a random configured replica.
Connect to read replicas using @prisma/extension-read-replicas
To take advantage of @prisma/extension-read-replicas
, ensure that read replication is set up in your database provider. Once that's done, you can configure the extension with your read replicas.
For the example in this article, we'll use Neon to create and connect to a read replica. If you already have replicas set up, you can skip to Connect your read replicas using Prisma Client.
Create and connect to Neon read replicas
Neon is different from traditional PostgreSQL providers because they separate storage from compute.
Recently they launched same-region read replicas, which uses these compute instances for read replicas to scale a replica up, down or to zero. This means Neon is much faster in setting up read replicas of your primary database than other providers - it uses the same data storage under the hood.
A compute instance is a service that provides your project's virtualized computing resources, e.g. CPU, memory and storage. If you would like to learn more about how Neon's read replicas work, we recommend reading this blog post.
The rest of this article will use Neon for the read replica setup. You can choose a different provider for your read replica setup.
To create a read replica, navigate to the Neon dashboard and sign in:
- If you don't have a project, create one by clicking the New Project button.
- Fill out the details of your project: the project's name, PostgreSQL version, and the region. Once project creation is complete, you will be redirected to the project's dashboard.
- Select Branches on the sidebar in the project dashboard.
- Select the branch where your database resides.
- Select Add compute. A Create Compute Endpoint dialog should appear.
- On the dialog, select Read-Only as the compute and configure the compute size for your workload.
- Click Create once you're done configuring the compute endpoint.
Next, retrieve the connection string for the read replica you just created:
- Navigate to your project Dashboard.
- Under Connection Details, select the branch, database, and role you would like to connect to your database with.
- Under the Compute drop-down menu, select the "Read-only" compute type endpoint you created.
- Copy the connection string from the code example. You will use this connection string to connect to your read replica.
In your application, create a new environment variable for the database replica and paste the value from the Neon dashboard you just copied:
#.envDATABASE_REPLICA_URL="postgres://daniel:<password>@ep-damp-cell-18160816.us-east-2.aws.neon.tech/neondb"Copy
Connect to your read replicas using @prisma/extension-read-replicas
To start using read replicas in your application, install the extension in your project:
npm install @prisma/extension-read-replicasCopy
Next, initialize the extension by extending your existing Prisma Client instance and pointing it to a database replica:
import { PrismaClient } from '@prisma/client'import { readReplicas } from '@prisma/extension-read-replicas'const prisma = new PrismaClient().$extends(readReplicas({url: process.env.DATABASE_REPLICA_URL,}),)Copy
If you wish to set up multiple replicas, you can repeat the steps above to create additional replicas. Then, update the readReplicas
configuration in your application as follows:
// lib/prisma.tsconst prisma = new PrismaClient().$extends(readReplicas({url: [process.env.DATABASE_REPLICA_URL_1,process.env.DATABASE_REPLICA_URL_2,],}),)Copy
And that's it!
When you run your app, the extension will send all read operations, such as findMany
, to a database replica. A replica will be selected randomly if you have multiple replicas defined.
Any write queries (e.g., create
, update
, ...) as well as $transaction
queries are forwarded to the primary instance of your database, which would consequently propagate the resulting changes to the existing database replicas.
If you would like to read from the primary database and bypass read replicas, the extension provides the $primary()
method on your extended Prisma Client instance:
const feed = await prisma.$primary().post.findMany()
This Prisma Client query will always be routed to your primary database to ensure up-to-date data.
Why did we build read replica support as a Prisma Client extension?
A significant advantage of having the extension as a separate package rather than part of the ORM for now is that it allows us to ship improvements to the extension independently from ORM releases. Therefore, we'll be able to refine the API as much as we need to ensure that the extension solves our community's needs.
A side-effect of shipping it as a separate package/repository is that the codebase will remain relatively small and manageable. This will allow our community members to contribute by creating pull requests to improve the extension.
While Prisma Client extensions have been Generally Available since Prisma 4.16.0, we also used the experience from building an extension ourselves as an opportunity to make further improvements to the Prisma Client extension API. For example, in 5.2.0, as preparation for this extension, we removed the datasource name in Prisma Client's constructor configuration, to simplify programmatic connection string overrides, which the extension uses. We also created a few more GitHub issues for future improvements to Client Extensions. Please leave an upvote or comment if you're interested in any of these improvements.
Try it out yourself
We encourage you to try out the @prisma/extension-read-replicas
extension and are looking forward to hearing your feedback! 🎉
Check out this example app to learn how to get up and running with read replicas using the @prisma/extension-read-replicas
extension.
Be sure also to try out Prisma Client extensions and share with us what you build on Twitter or Discord. 🙌