Simplify your stack and build anything. Or everything.
Build tomorrow’s web with a modern solution you truly own.
Code-based nature means you can build on top of it to power anything.
It’s time to take back your content infrastructure.

Postgres causing problem on cloudflare workers for deployment

default discord avatar
chetan18057 months ago
38

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.

  • default discord avatar
    rjgtav7 months ago

    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-hyperdrive

    You can also find some recent discussion about this topic in the

    #1422639568808841329

    channel



    For your use case, I'd say both D1 and Postgres will work fine

  • default discord avatar
    chetan18057 months ago

    Thanks, let me check.



    Also, I am confused which one is better for my usecase??


    D1 or postgres??

  • default discord avatar
    rjgtav7 months ago

    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.

  • default discord avatar
    chetan18057 months ago

    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:


    https://blog.cloudflare.com/payload-cms-workers/
  • default discord avatar
    rjgtav7 months ago

    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

  • default discord avatar
    chetan18057 months ago

    Thanks.


    Ended up choosing postgres.

  • discord user avatar
    seanzubrickas
    7 months ago

    thanks for jumping in here with this detailed explanation!

  • default discord avatar
    rjgtav7 months ago

    Alright! Let me know if you find any issues when running Payload on Cloudflare and connecting to Postgres

  • default discord avatar
    chetan18057 months ago

    Sure thanks



    I would like to add some more resources for those who might be confused:


    https://developers.cloudflare.com/hyperdrive/configuration/how-hyperdrive-works/
    https://blog.cloudflare.com/hyperdrive-making-regional-databases-feel-distributed/
    https://blog.cloudflare.com/how-hyperdrive-speeds-up-database-access/

    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

  • default discord avatar
    rjgtav7 months ago

    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/
  • default discord avatar
    chetan18057 months ago

    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

    "


    },




    }

  • default discord avatar
    rjgtav7 months ago

    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

  • default discord avatar
    chetan18057 months ago

    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.

  • default discord avatar
    rjgtav7 months ago

    Hmm.. but on your log message it says

    Connection string injected: postgresql://...

    so which environment variable is missing?

  • default discord avatar
    chetan18057 months ago

    That's where all of the issue is.


    This database_url env variable seems to be not working.

  • default discord avatar
    rjgtav7 months ago

    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

    localConnectionString

    property 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/
  • default discord avatar
    chetan18057 months ago

    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,


    },


    }),


    })

  • default discord avatar
    rjgtav7 months ago

    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,
      }
    }),
  • default discord avatar
    chetan18057 months ago

    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: {}

  • default discord avatar
    rjgtav7 months ago

    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,
        }
      }),
  • default discord avatar
    chetan18057 months ago
    @281120856527077378

    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.

  • default discord avatar
    rjgtav7 months ago

    Cool! Does this mean the multi tenant plugin works with D1? If so, that's pretty cool then!

  • default discord avatar
    chetan18057 months ago

    I tested it with hyperdrive only.

  • default discord avatar
    omar.ou7 months ago

    where are you importing cloudflare from in

    cloudflare.env.HYPERDRIVE.connectionString

    ?

  • default discord avatar
    rjgtav7 months ago

    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#L18
  • default discord avatar
    omar.ou7 months ago

    is 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

    @200787202886729728
  • default discord avatar
    rjgtav7 months ago

    Yeah 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

  • default discord avatar
    omar.ou7 months ago

    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

  • default discord avatar
    rjgtav7 months ago

    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 migrate

    command. 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)

  • default discord avatar
    omar.ou7 months ago

    Hey! Appreciate you getting back to me on this



    But then the connection won’t be made through hyperdrive no?

  • default discord avatar
    rjgtav7 months ago
    @324065102615674881

    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

  • default discord avatar
    omar.ou7 months ago

    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

  • default discord avatar
    rjgtav7 months ago

    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"?

  • default discord avatar
    omar.ou7 months ago

    Yes



    Do you have a .dev.vars file?



    Are you setting CLOUDFLARE_ENV anywhere?

  • default discord avatar
    rjgtav7 months ago
    @324065102615674881

    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.local
  • default discord avatar
    omar.ou7 months ago

    I 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

    @200787202886729728

    does 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.

  • default discord avatar
    rjgtav7 months ago

    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.local

    before starting the preview

  • default discord avatar
    omar.ou7 months ago

    Thanks man

Star on GitHub

Star

Chat on Discord

Discord

online

Can't find what you're looking for?

Get dedicated engineering support directly from the Payload team.