Skip to content

Commit 5a6f361

Browse files
authored
feat(db-*): adds support for readReplicas in D1 adapter config (#14040)
This PR adds support for read replicas in D1 adapter, you can enable it by adding this into your DB adapter ```ts readReplicas: 'first-primary' ```
1 parent c135bf0 commit 5a6f361

File tree

7 files changed

+63
-3
lines changed

7 files changed

+63
-3
lines changed

.github/workflows/pr-title.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ jobs:
4040
db-postgres
4141
db-vercel-postgres
4242
db-sqlite
43+
db-d1-sqlite
4344
drizzle
4445
email-\*
4546
email-nodemailer

docs/database/sqlite.mdx

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,3 +310,29 @@ export default buildConfig({
310310
It inherits the options from the SQLite adapter above with the exception of the connection options in favour of the `binding`.
311311

312312
You can see our [Cloudflare D1 template](https://github.com/payloadcms/payload/tree/main/templates/with-cloudflare-d1) for a full example of how to set this up.
313+
314+
### D1 Read Replicas
315+
316+
You can enable read replicas support with the `first-primary` strategy. This is experimental.
317+
318+
You must also enable it on your D1 database in the Cloudflare dashboard. Read more about it in the [Cloudflare documentation](https://developers.cloudflare.com/d1/best-practices/read-replication/).
319+
320+
<Banner type="info">
321+
All write queries are still forwarded to the primary database instance. Read
322+
replication only improves the response time for read query requests.
323+
</Banner>
324+
325+
```ts
326+
import { sqliteD1Adapter } from '@payloadcms/db-d1-sqlite'
327+
328+
export default buildConfig({
329+
collections: [],
330+
db: sqliteD1Adapter({
331+
binding: cloudflare.env.D1,
332+
// You can also enable read replicas support with the `first-primary` strategy.
333+
readReplicas: 'first-primary',
334+
}),
335+
})
336+
```
337+
338+
You can then verify that they're being used by checking the logs in your Cloudflare dashboard. You should see logs indicating whether a read or write operation was performed, and on which database instance.

packages/db-d1-sqlite/src/connect.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,20 @@ export const connect: Connect = async function connect(
2121

2222
try {
2323
const logger = this.logger || false
24+
const readReplicas = this.readReplicas
25+
26+
let binding = this.binding
27+
28+
if (readReplicas && readReplicas === 'first-primary') {
29+
// @ts-expect-error - need to have types that support withSession binding from D1
30+
binding = this.binding.withSession('first-primary')
31+
}
32+
33+
this.drizzle = drizzle(binding, {
34+
logger,
35+
schema: this.schema,
36+
})
2437

25-
this.drizzle = drizzle(this.binding, { logger, schema: this.schema })
2638
this.client = this.drizzle.$client as any
2739

2840
if (!hotReload) {

packages/db-d1-sqlite/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ export function sqliteD1Adapter(args: Args): DatabaseAdapterObj<SQLiteD1Adapter>
117117
push: args.push,
118118
rawRelations: {},
119119
rawTables: {},
120+
readReplicas: args.readReplicas,
120121
relations: {},
121122
relationshipsSuffix: args.relationshipsSuffix || '_rels',
122123
schema: {},

packages/db-d1-sqlite/src/types.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,15 @@ export type SQLiteSchemaHook = (args: SQLiteSchemaHookArgs) => Promise<SQLiteSch
2727

2828
export type Args = {
2929
binding: AnyD1Database
30+
/**
31+
* Experimental. Enables read replicas support with the `first-primary` strategy.
32+
*
33+
* @experimental
34+
* @example
35+
*
36+
* ```readReplicas: 'first-primary'```
37+
*/
38+
readReplicas?: 'first-primary'
3039
} & BaseSQLiteArgs
3140

3241
export type GenericColumns = {
@@ -99,6 +108,14 @@ export type SQLiteD1Adapter = {
99108
binding: Args['binding']
100109
client: AnyD1Database
101110
drizzle: Drizzle
111+
/**
112+
* Experimental. Enables read replicas support with the `first-primary` strategy.
113+
*
114+
* @example
115+
*
116+
* ```readReplicas: 'first-primary'```
117+
*/
118+
readReplicas?: 'first-primary'
102119
} & BaseSQLiteAdapter &
103120
SQLiteDrizzleAdapter
104121

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
PAYLOAD_SECRET=THISISYOURSECRET
1+
# A generated secret for Payload
2+
PAYLOAD_SECRET=

templates/with-cloudflare-d1/README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
[![Deploy to Cloudflare](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=https://github.com/payloadcms/payload/tree/main/templates/with-cloudflare-d1)
44

5-
This template comes configured with the bare minimum to get started on anything you need.
5+
**This can only be deployed on Paid Workers right now due to size limits.** This template comes configured with the bare minimum to get started on anything you need.
66

77
## Quick start
88

@@ -48,6 +48,8 @@ Images will be served from an R2 bucket which you can then further configure to
4848

4949
The Worker will have direct access to a D1 SQLite database which Wrangler can connect locally to, just note that you won't have a connection string as you would typically with other providers.
5050

51+
You can enable read replicas by adding `readReplicas: 'first-primary'` in the DB adapter and then enabling it on your D1 Cloudflare dashboard. Read more about this feature on [our docs](https://payloadcms.com/docs/database/sqlite#d1-read-replicas).
52+
5153
## Working with Cloudflare
5254

5355
Firstly, after installing dependencies locally you need to authenticate with Wrangler by running:

0 commit comments

Comments
 (0)