I am getting below error when deploying my Next.js app+payloadcms on cloudflare workers:
(error) ⨯ Error: [unenv] process.report.getReport is not implemented yet!
The above error is because I am using
@967091941873426493/db-postgres with a PostgreSQL database (Neon), but PostgreSQL doesn't work well in Cloudflare Workers due to Node.js API compatibility issues (like process.report).
So, do I need to switch to D1 SQLite??
Also, I am confused which one is better for my usecase D1 SQLite or postgres??
I have got ecommerce usecase but data in payloadcms would be used only for cms related stuff like faq, about us, product desciption etc.
The real data would come from backend.
Hi! Right now, Cloudflare + Payload supports using D1 or Postgres via Hypedrive as a database. I haven't tried using Hyperdrive with Neon yet, but I got it working with Supabase with no issues.
A quick look at Neon's documentation seems to indicate they work well with Hyperdrive as well:
https://neon.com/docs/guides/cloudflare-hyperdriveYou can also find some recent discussion about this topic in the
#1422639568808841329channel
For your use case, I'd say both D1 and Postgres will work fine
Thanks, let me check.
Also, I am confused which one is better for my usecase??
D1 or postgres??
I'd say whatever you prefer. Either option will be fine. If you already have everything else on Postgres, might as well just keep using it for the rest of the website.
D1 is native to cloudflare so latency would be less compared to the case where it would be connecting to Supabase postgresql.
How much difference in latency would be there is what I am confused about.
Read below blog:
If you use D1 with read replicas, latency will be around 100ms-200ms on most scenarios, considering you get traffic from all over the world. Hyperdrive provides a connection pool and supports caching query results, which also speeds things up quite a bit.
You said you'll be using Payload for storing mostly static data, which means it can be cached for long periods of time. If the data is cached, then the database latency is irrelevant, as most of the requests will be served from cache. Which is why I say probably both solutions will work great in your scenario.
The major difference when choosing between D1 and Postgres, besides the inherent differences between SQLite and Postgres, has to do with load and size. You can find the current limits here:
https://developers.cloudflare.com/d1/platform/limits/. However, in your use case you probably won't hit any of those limits
If you really want to compare the two, I think the easiest way is to build a small test: first with one database and then switch to the other and compare.
As payload supports both, it's just a matter of switching database adapters. The rest of the code will stay the same
Thanks.
Ended up choosing postgres.
thanks for jumping in here with this detailed explanation!
Alright! Let me know if you find any issues when running Payload on Cloudflare and connecting to Postgres
Sure thanks
I would like to add some more resources for those who might be confused:
PayloadCMS with Postgres cannot run at runtime in Cloudflare Workers with multi-tenant plugin and hyperdrive??
PayloadCMS uses
@967091941873426493/db-postgres → which uses the pg library
The pg library requires Node.js modules (fs, path, stream) not available in Workers/Edge runtime
My app calls getPayload() at runtime in fetchTenantByDomain() → which is called from middleware and pages
This fails because Workers don't support these Node.js modules in edge routes
I am consistently getting below logs and I have checked db and there are no issues as it ran perfectly on vercel:
GET
https://kasvi.shopengenie.com/- Ok @ 10/16/2025, 2:08:47 PM
(log) [Hyperdrive] Connection string injected: postgresql://9657384de684468791a3cbea962d6b81:92df...
GET
https://kasvi.shopengenie.com/in- Ok @ 10/16/2025, 2:08:48 PM
(error) Error: Failed query: select count(*) from "tenants" where "tenants"."domain" = $1
params: kasvi.shopengenie.com
Hi! The pg library is fully supported in Workers. The native Node.js modules you mention are also available on workers, as long as you're using the "nodejs_compat" compatibility flag. You can find more information regarding Node.js modules support here:
https://developers.cloudflare.com/workers/runtime-apis/nodejs/What's the problem then??
Below is my wrangler.jsonc:
If you want to take a look at my wrangler.jsonc file, it's below:
{
"$schema": "node_modules/wrangler/config-schema.json",
"main": ".open-next/worker.js",
"name": "my-app-test",
"compatibility_date": "2025-08-15",
"compatibility_flags": [
// Enable Node.js API
// see
https://developers.cloudflare.com/workers/configuration/compatibility-flags/#nodejs-compatibility-flag"nodejs_compat",
// Allow to fetch URLs in your app
// see
https://developers.cloudflare.com/workers/configuration/compatibility-flags/#global-fetch-strictly-public"global_fetch_strictly_public",
],
"assets": {
"directory": ".open-next/assets",
"binding": "ASSETS",
},
"hyperdrive": [
{
"binding": "HYPERDRIVE",
"id": "3dedca04b2494841a41cdee8515e86bc"
}
],
"services": [
// The service should match the "name" of your worker
// {
// "binding": "WORKER_SELF_REFERENCE",
// "service": "my-app"
// },
],
"r2_buckets": [
{
"binding": "R2",
"bucket_name": "my-app",
},
// Create a R2 binding with the binding name "NEXT_INC_CACHE_R2_BUCKET"
// {
// "binding": "NEXT_INC_CACHE_R2_BUCKET",
// "bucket_name": "<BUCKET_NAME>",
// },
],
// Environment variables
// NOTE: For sensitive values, use: wrangler secret put <KEY>
// or set them in Cloudflare Dashboard: Workers > your-worker > Settings > Variables
"vars": {
// IMPORTANT: Replace these placeholder values with your actual values
"MEDUSA_BACKEND_URL": "
https://api.shopengenie.com",
"NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY": "pk_8cf8076441d2cbcf7285bf761344c2f64263eeb69b8db307784f1f6131b6a6d4",
"NEXT_PUBLIC_DEFAULT_REGION": "in",
"NEXT_PUBLIC_SERVER_URL": "
https://kasvi.shopengenie.com",
"NEXT_PUBLIC_BASE_URL": "
https://kasvi.shopengenie.com"
},
}
Does your error message say anything else? The error itself simply says that it failed to run the query, but doesn't have any stacktrace
yeah, when I navigates to /admin route for payloadcms admin panel, I get a different error:
500
Internal Server Error.
It's because of ❌ Missing environment variables which means database url is not present.
Hmm.. but on your log message it says
Connection string injected: postgresql://...so which environment variable is missing?
That's where all of the issue is.
This database_url env variable seems to be not working.
I'm sorry but I'm not really getting what you're trying to describe.
I see in your wrangler.jsonc that you've added the Hyperdrive binding. Hyperdrive itself doesn't use any DATABASE_URL environment variable.
Is the postgres connection string that shows in the log correct? Or wrong?
Are you testing locally or are the logs from the deployed version? If it's local, you need to specify the
localConnectionStringproperty of the Hyperdrive binding configuration and point it to the postgres database you want. More information here:
https://developers.cloudflare.com/hyperdrive/configuration/local-development/I am getting logs using npx wrangler tail command for deployed version by visiting my domain.
It's not on local.
// src/utilities/fetchTenantByDomain.ts
export async function fetchTenantByDomain(domain: string): Promise<Tenant | null> {
const payload = await getPayload({ config: configPromise }) // ❌ This fails
const { docs } = await payload.find({
collection: 'tenants',
where: { domain: { equals: domainClean } },
depth: 1,
limit: 1,
})
return docs[0] || null
}
I am using Hyperdrive with correct Supabase Session pooler - IPv4 compatible
// src/payload.config.ts
export default buildConfig({
db: postgresAdapter({
pool: {
connectionString: process.env.PAYLOAD_DATABASE_URL, // Injected by Hyperdrive
max: 1, min: 0, // Workers-optimized settings
idleTimeoutMillis: 10000,
connectionTimeoutMillis: 10000,
},
}),
})
Okok. So in that case it should be using the connection string you configured for Hyperdrive in the Cloudflare Dashboard.
Is the connection string that shows up in the logs the correct one?
Hmm.. don't think you're using the hyperdrive binding there?
It should be something like this:
db: postgresAdapter({
pool: {
connectionString: cloudflare.env.HYPERDRIVE.connectionString,
maxUses: 1,
}
}),Thanks for the help.
Let me try.
Sorry, I actually had implemented this early but I messed it up in order to fix it.
Now, I am getting below logs when trying to access /admin(payloadcms admin) page:
GET
https://kasvi.shopengenie.com/in/admin- Exception Thrown @ 10/16/2025, 5:21:06 PM
(log) [CountryCodePage] Looking for page: {
originalHost: 'kasvi.shopengenie.com',
tenantDomain: 'kasvi.shopengenie.com',
slug: 'admin',
countryCode: 'in'
}
(log) [queryPageBySlug] Querying with: { tenantDomain: 'kasvi.shopengenie.com', slug: 'admin', draft: false }
✘ [ERROR] Error: The Workers runtime canceled this request because it detected that your Worker's code had hung and would never generate a response. Refer to:
https://developers.cloudflare.com/workers/observability/errors/✘ [ERROR] Error: The Workers runtime canceled this request because it detected that your Worker's code had hung and would never generate a response. Refer to:
https://developers.cloudflare.com/workers/observability/errors/Below is what I am seeing in ui:
Error 1101 Ray ID: 98f93b107d241852 • 2025-10-16 17:21:18 UTC
Worker threw exception
What happened?
You've requested a page on a website (kasvi.shopengenie.com) that is on the Cloudflare network. An unknown error occurred while rendering the page.
What can I do?
If you are the owner of this website:
refer to Workers - Errors and Exceptions and check Workers Logs for kasvi.shopengenie.com.
Cloudflare Ray ID: 98f93b107d241852 • Your IP: Click to reveal • Performance & security by Cloudflare
I am getting below error when trying to navigate to /store:
GET
https://www.shopengenie.com/in/store- Ok @ 10/16/2025, 5:25:21 PM
(error) Error: Failed to communicate with Payload CMS: {}
Hmm this error is trickier to debug, because it simply means that some promise is being awaited for, and possibly it's a promise that is never resolving. It could be anything, from your custom code to maybe the payload multi tenant plugin (I haven't played at all with that plugin so I have no idea whether it is working with D1. Not sure if anyone has played with it already)
At least the database should be connecting now, right?
You can check which queries are being made to the database by adding a logger to the postgres adapter, like:
db: postgresAdapter({
logger: new DefaultLogger({ writer: new ConsoleLogWriter() }),
pool: {
connectionString: cloudflare.env.HYPERDRIVE.connectionString,
maxUses: 1,
}
}),Would you please confirm whether multi-tenant plugin is compatible with cloudflare workers deployment??
Sorry, I messed up some stuff at the backend side.
Everything is working perfectly now(some testing is remaining).
Huge thanks to
@200787202886729728
It wouldn't have been possible without you.
Thanks a lot for the help.
Cool! Does this mean the multi tenant plugin works with D1? If so, that's pretty cool then!
I tested it with hyperdrive only.
where are you importing cloudflare from in
cloudflare.env.HYPERDRIVE.connectionString?
Hi! You can find the declaration of the cloudflare variable in the payload.config.ts file of the official payload template:
https://github.com/payloadcms/payload/blob/main/templates/with-cloudflare-d1/src/payload.config.ts#L18is it okay to commit the hyperdrive id?
There's an error ✘ [ERROR] ERR_METHOD_NOT_IMPLEMENTED [Error]: The process.report.getReport method is not implemented, triggered by the sharp library
I removed configs that require sharp from the Media collection (based on the vercel template) and disabled Image component optimization through next config but I'm still getting the same error.
Would appreciate your support
@200787202886729728Yeah the ID is fine. Just the value for the localConnectionString property could be dangerous to commit, if pointing to a remote database or if it contains a password
Hmm sharp doesn't work inside Cloudflare Workers, so I guess you should search for any references to sharp in your code and remove it
I tried my best to remove all references but it is still leaking somehow.
Is there a way to know where it is leaking from?
getting this in CI with postgres:
05:10:59.248 ▲ Next.js 15.4.4
05:10:59.248
05:11:00.138 unhandledRejection [Error: When developing locally, you should use a local Postgres connection string to emulate Hyperdrive functionality. Please setup Postgres locally and set the value of the 'CLOUDFLARE_HYPERDRIVE_LOCAL_CONNECTION_STRING_HYPERDRIVE' variable or "HYPERDRIVE"'s "localConnectionString" to the Postgres connection string.] {
05:11:00.138 telemetryMessage: 'no local hyperdrive connection string'
05:11:00.138 }
05:11:00.162 ELIFECYCLE Command failed with exit code 1.trying to setup hyperdrive, I left out the localConnectionString field
You can try adding extra logging by overriding Payload's logger in payload.config.ts with something like:
logger: {
debug: (msg: any, ...args: any[]) => console.log(msg, ...args),
error: (msg: any, ...args: any[]) => console.error(msg, ...args),
info: (msg: any, ...args: any[]) => console.log(msg, ...args),
warn: (msg: any, ...args: any[]) => console.log(msg, ...args),
trace: (msg: any, ...args: any[]) => console.trace(msg, ...args),
} as any,I believe that's showing up when running the
payload migratecommand. By default wrangler will use the local bindings, hence why it recommends setting up the local connection string, via wrangler.jsonc or via the environment variable. You can configure the environment variable as a secret for the CI using the Cloudflare Dashboard.
Alternatively, if you use wrangler version 4.42.0 you can enable the experimental remote bindings (in
https://github.com/payloadcms/payload/blob/main/templates/with-cloudflare-d1/src/payload.config.ts#L54) which will force wrangler to use the remote Hyperdrive instance.
(I'm trying to request internally to restore that behavior in the newer versions of wrangler)
Hey! Appreciate you getting back to me on this
But then the connection won’t be made through hyperdrive no?
with the 1st option no, but it will only be used during the migrations step. After deploy, it will use hyperdrive as configured in the Dashboard. With the 2nd option it will always use the remote Hyperdrive instance
I tried setting CLOUDFLARE_HYPERDRIVE_LOCAL_CONNECTION_STRING_HYPERDRIVE in .env.local, and running pnpm dev, but it still throws the same error. Am I missing anything?
It works if I set the localConnectionString in the wrangler config, but I’d rather not commit that
Hmm just tried it myself setting the env variable via .env.local and it worked fine. Is your binding in the wrangler.jsonc called "HYPERDRIVE"?
Yes
Do you have a .dev.vars file?
Are you setting CLOUDFLARE_ENV anywhere?
Nope and nope. During pnpm dev, right after compile finishes for the / route, I see the following logs:
Found a non-empty CLOUDFLARE_HYPERDRIVE_LOCAL_CONNECTION_STRING_HYPERDRIVE variable for binding. Hyperdrive will connect to this database during local development.
Using vars defined in .env.localI had to go out, but I’ll try clearing .next and .opennextjs-cloudflare and trying again when I get back
Alright it works now, cool. Clearing .opennextjs-cloudflare worked
Yo
@200787202886729728does CLOUDFLARE_HYPERDRIVE_LOCAL_CONNECTION_STRING_HYPERDRIVE work if you run pnpm opennextjs-cloudflare preview? Opennextjs build command works correctly, but preview isn’t working in my setup.
Hey
@324065102615674881! Yeah, if I use preview the variable is also not being used. I believe it has to do with the fact that OpenNext configures wrangler to not load the variables from the .env files when running in preview (
https://github.com/opennextjs/opennextjs-cloudflare/blob/main/packages/cloudflare/src/cli/utils/run-wrangler.ts#L84)
As a workaround, I managed to make it use the variable by exporting the variable on my shell before invoking the preview command. To make things a bit simpler, you could update your .env.local to use the format "export VARIABLE=VALUE" and then run
source .env.localbefore starting the preview
Thanks man
Star
Discord
online
Get dedicated engineering support directly from the Payload team.