[WIP] Use Workers binding for R2 cache population#1121
Conversation
For large deployments with 500+ prerendered pages, the R2 cache upload now uses the worker's R2 binding directly instead of wrangler's r2 bulk put command. This bypasses the Cloudflare API rate limit. New deploy flow for large R2 caches: 1. Deploy worker with a temporary cache populate token 2. Send cache entries directly to /_open-next/cache/populate endpoint 3. Worker writes to R2 using its binding (no API rate limits) 4. Redeploy without the token to secure the endpoint Features: - Automatic threshold: binding approach for caches with 500+ entries - Batched uploads with configurable batch size (default: 100) - Retry logic with exponential backoff - Secure: Temporary token removed after cache population Closes #1088 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add tests for generateCachePopulateToken - Add comprehensive tests for handleCachePopulate handler: - Request method validation - Token authentication - Invalid JSON handling - Successful writes - Partial failures - Empty entries Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Users can now explicitly choose the cache population method: - auto: Use binding for 500+ entries, wrangler CLI otherwise (default) - wrangler: Always use wrangler CLI (original behavior) - binding: Always use worker binding (bypasses API rate limits) This provides full backward compatibility while giving users control over the cache population strategy. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
… remote binding Reworks the R2 cache upload approach per reviewer feedback. Instead of deploying the worker with a token, populating, then redeploying, we now use a local wrangler dev worker with a remote R2 binding. Key changes: - Replace deploy/populate/redeploy cycle with local wrangler dev approach - Remove --cacheMethod flag and dual code paths - Remove token auth system (local worker needs no auth) - Remove esbuild compilation step (wrangler accepts TS natively) - Revert deploy.ts, worker.ts, cloudflare-context.ts, build.ts, run-wrangler.ts to main - Delete compile-cache-populate-handler.ts The new flow derives a temp wrangler config with the R2 binding set to remote: true, starts wrangler dev locally, sends batched cache entries to the worker, then stops it. Single code path for all cache sizes. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ndler to workers/ - Replace manual spawn + stdout parsing with wrangler's unstable_startWorker API - Pass R2 bindings programmatically, eliminating temp config files - Move handler from templates/ to workers/r2-cache-populate-handler.ts - Separate fetch routing from populateCache logic for testability - Reduce default batch size from 100 to 5 (local server, lower memory) - Update compatibility_date to 2026-01-01 - Simplify remote binding config Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
🦋 Changeset detectedLatest commit: f25e9c0 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
commit: |
|
@vicb FYI while consuming this PR on my project with same setup as the one on which rclone deployment succeeds, pipeline fails on: |
Thanks for trying. Could you please let me know how many files you have an the total size? |
Oops it was missing my last change here. |
ff208d4 to
9c69f84
Compare
|
Hi @vicb I gave a try to your newest branch and it fails as well. This time it generates regression on the fact that we use https://opennext.js.org/cloudflare/howtos/custom-worker. |
Any chance you can share you code privately to move forward? |
|
Hi @vicb,
During build time for tenant that I use for tests, we build a cache with 13.3k elements of total size 2.7 GB (it is our biggest tenant, however it doesn't mean this is the biggest set of data on which code needs to work ;) ).
The only proposal I have is I can work on the reproduction repository which will be my project agnostic and will let you ensure your code passes, however I will manage to do it by the end of the week. |
That would be great and no rush. I guess you can use the rclone pre-release for the time being? It looks like we are close to landing this PR, if it turns out to be longer, we can revisit landing rclone. SGTY? |
|
Sounds good, I will update you once I will have reproduction repository. |
|
Hi @vicb, In this repository you will be able to consume prepared by you version of opennextjs-cloudflare with your approach for R2 population, by default on main branch right now package from #1116 is consumed to make the deployment pass. Have fun / ping me in case of problems / doubts. P.S. I've left routes size on 1k, but in the end feel free to have it "challenging" and support bigger values (5-10 k) in opennextjs-cloudflare. |
|
Hi @vicb ,
Unfortunately that's not an option, we need to have a stable release consumed on our project for internal reasons.
Will you be able to look into this PR and to make it work on reproduction repository, or should we revisit landing rclone? |
|
I'm out this week but I'll move this forward next week |
|
Great, thanks |
Looking today |
Sorry, got diverted but looking at this right now. Could you add instructions on how to reproduce, what is the expected behavior and observed behavior? Do I need to deploy the API, can/should I run it locally? What error do you see, ... Happy to have a chat/VC if it helps |
|
We're having the same original issue as @grabmateusz as we're attempting to migrate our large site from Pages to Workers. The vast majority of the OpenNext builds fail on cache population - so I was hoping this branch could help. I won't be able to provide a reproduction repository, but please let me know if there are any details I can provide to help narrow down the issue. I would also be happy to get on a chat or a call any time. In the meantime, here is the error we're seeing and the configs we have: Original error on @opennext/cloudflare v1.16.5After installing the build from the pkg-pr-new bot in this thread, I am seeing this: The bucket it references definitely exists. We've had a few successful builds on v1.16.5, and the bucket has 15 GB of data. Configs: wrangler.jsonc{
"$schema": "../../node_modules/wrangler/config-schema.json",
"main": ".open-next/worker.js",
"name": "chroma-cboe-com",
"compatibility_date": "2025-03-25",
"compatibility_flags": [
"nodejs_compat",
"global_fetch_strictly_public"
],
"build": {
"watch_dir": "sites/chroma-cboe-com/*",
"cwd": "sites/chroma-cboe-com/"
},
"assets": {
"directory": ".open-next/assets",
"binding": "ASSETS"
},
"vars": {
"NODE_VERSION": "24.11.1"
},
"services": [
{
"binding": "WORKER_SELF_REFERENCE",
"service": "chroma-cboe-com"
}
],
"r2_buckets": [
{
"binding": "NEXT_INC_CACHE_R2_BUCKET",
"bucket_name": "chroma-cboe-com-cache"
}
],
"durable_objects": {
"bindings": [
{
"name": "NEXT_CACHE_DO_QUEUE",
"class_name": "DOQueueHandler"
}
]
},
"migrations": [
{
"tag": "v1",
"new_sqlite_classes": ["DOQueueHandler"]
}
]
}open-next.config.tsimport { defineCloudflareConfig } from '@opennextjs/cloudflare';
import r2IncrementalCache from '@opennextjs/cloudflare/overrides/incremental-cache/r2-incremental-cache';
import { withRegionalCache } from '@opennextjs/cloudflare/overrides/incremental-cache/regional-cache';
import doQueue from '@opennextjs/cloudflare/overrides/queue/do-queue';
// Note that this config mainly supports time-based revalidation for ISR and fetch
// We do not need On-Demand revalidation at this time
export default defineCloudflareConfig({
incrementalCache: withRegionalCache(r2IncrementalCache, {
mode: 'long-lived',
}),
queue: doQueue,
}); |
|
@mgallagher you might want to check #1116 |


Based on #1099
Fixes #1110, #1088
Key differences:
populateCachecommand)TODO
OpenClaude/Opus helped me write that code