Evaluate replacing the current Next.js + OpenNext for Cloudflare stack with cloudflare/vinext
Summary
cloudflare/vinext is now credible enough to evaluate seriously for this repo, but it is not yet a safe drop-in replacement for our current production path.
As of 2026-03-14:
- Cloudflare officially backs
vinext and positions it as a Vite-based reimplementation of the Next.js API surface for Cloudflare Workers and other targets.
vinext is still explicitly marked as experimental / under heavy development.
vinext itself says OpenNext is the more mature and safer option today for serious Next.js-on-Cloudflare deployments.
This issue tracks whether we should:
- keep the current
Next.js 16 + OpenNext stack as the default,
- build a
vinext PoC branch in parallel, or
- fully replace the current stack later if the migration risk becomes acceptable.
Why evaluate this now
- Vite continues to gain framework gravity, and Cloudflare is investing heavily in the Workers + Vite path.
vinext gives a Vite-first path for existing Next.js apps instead of adapting next build output after the fact.
- Cloudflare's Vite plugin runs app code in
workerd during local development and preview, which is materially different from the current OpenNext model where day-to-day dev stays on next dev and Cloudflare behavior is validated later.
- Vite 8 is now the current supported Vite major, so the broader ecosystem is clearly moving in this direction.
Current repo assumptions that matter
This repo is not just "a Next app":
Next.js 16 App Router
next-rspack
@opennextjs/cloudflare
- custom
src/worker.ts that combines:
- web fetch handling via
.open-next/worker.js
scheduled() cron handling via src/cron.ts
- Cloudflare bindings used across the app:
D1
KV
Workers AI
Images
R2
- service bindings / assets fetcher
next/image
- dynamic OGP route
- Next middleware
- a server action (
src/lib/actions/report-error.ts)
- tRPC route handlers and server components that currently resolve bindings via
getCloudflareContext()
- custom
webpack logic in next.config.ts
- OpenNext-specific build patches/scripts/config:
open-next.config.ts
scripts/patch-opennext-webpack-runtime.ts
scripts/patch-opennext-setimmediate.ts
build:cf, preview, upload, deploy
So this is not a bundler swap. It is a framework-runtime migration.
What vinext improves
1. Worker-native dev/build/runtime path
vinext uses @cloudflare/vite-plugin, and Cloudflare documents that this path runs code directly in the Workers runtime during local dev.
That is the main architectural attraction here:
- better local fidelity to
workerd
- less OpenNext adapter indirection
- native
cloudflare:workers bindings access
2. Vite-first toolchain
vinext replaces the Next compiler/bundler path with Vite and @vitejs/plugin-rsc.
That gives us:
- access to the Vite ecosystem directly
- a more standard plugin model than our current
next-rspack + OpenNext pipeline
- a clearer future path if the Vite/Workers ecosystem keeps consolidating
3. Simpler Cloudflare binding access model
vinext recommends import { env } from "cloudflare:workers" rather than getCloudflareContext() or a custom fetch(request, env) worker entry for routine binding access.
That likely simplifies a lot of the current binding plumbing in:
src/server/trpc/context.ts
src/server/db/index.ts
src/app/archive/page.tsx
src/app/opengraph-image.tsx
src/lib/workers-ai-client.ts
What vinext does not solve for us yet
1. It is still explicitly experimental
The vinext README is unusually direct:
- under heavy development
- use at your own risk
- not battle-tested at meaningful scale
That is not a footnote. It should directly affect migration timing.
2. OpenNext is still the safer production answer for Next.js on Cloudflare
This is stated both by:
- Cloudflare's official Next.js guide, which still points to OpenNext for Next.js on Workers
- the
vinext README itself, which says OpenNext is more mature and safer
3. Our current webpack / next-rspack customizations do not carry over
next.config.ts currently contains custom webpack logic for:
- alias stubbing during Cloudflare builds
- vendor chunking
- wallet / 3D / Metaplex bundle handling
vinext check flags this directly:
webpack config is unsupported and needs migration to Vite equivalents
This means we must either:
- re-express the intent in Vite config/plugins/manual chunking, or
- delete those optimizations and verify that the resulting bundle/runtime still behaves correctly
4. Our current cron model is a real migration problem
Today we rely on:
src/worker.ts for fetch
src/worker.ts for scheduled
vinext's Cloudflare story is optimized around the app request pipeline, not around our current "single worker handles both web and cron" structure.
The likely migration outcome is:
- the web app moves to
vinext
- the scheduled generation pipeline moves to a separate Worker, or another Cloudflare-managed entrypoint
That split is probably the right architecture anyway, but it is still a migration cost.
5. next/image behavior changes
vinext marks next/image as partial support:
- remote images are handled via
@unpic/react
- local build-time optimization is not there yet
images config is parsed but not used for optimization
This matters here because we currently rely on:
next/image
images.remotePatterns
- Cloudflare image handling around our archive / OGP / Arweave gateway usage
We should assume image behavior changes unless we test it directly.
6. A few repo-specific features are only partial / caveated
vinext check on this repo reported:
- 77% compatible
- unsupported:
webpack
experimental.typedRoutes
- missing
"type": "module"
- one unrecognized
next/dist/server/next-server.js import path that needs source confirmation
- partial:
next/font/google
images
ViewTransition
The ViewTransition finding is specifically relevant because this repo currently sets experimental.viewTransition in next.config.ts.
Repo-specific migration surface
These are the concrete places we would need to touch for a real vinext migration.
A. Build and deployment layer
package.json
next.config.ts
open-next.config.ts
wrangler.toml
src/worker.ts
scripts/patch-opennext-webpack-runtime.ts
scripts/patch-opennext-setimmediate.ts
Expected changes:
- add
"type": "module"
- replace
next / opennextjs-cloudflare scripts with vinext / Vite equivalents
- introduce
vite.config.ts
- remove OpenNext patch scripts/config if no longer needed
- decide where cron lives after the split
B. Cloudflare bindings access
Current access is heavily tied to @opennextjs/cloudflare.
Likely migration direction:
- replace
getCloudflareContext() access with cloudflare:workers
- make sure no top-level I/O happens before bindings are safe to read
Affected areas include:
- DB creation
- tRPC context
- archive page data loading
- OGP route
- Workers AI client
C. Worker entrypoint shape
Current state:
- one Worker for both fetch and scheduled
Likely vinext state:
- app request worker handled by
vinext
- scheduled generation moved elsewhere
Possible directions:
- separate scheduled Worker with its own trigger and service bindings
- multi-Worker setup using Cloudflare's newer auxiliary Worker story where appropriate
- validate whether a custom
vinext Cloudflare entrypoint can still host scheduled() cleanly
At the moment, option 1 looks like the lowest-risk migration shape.
D. Next-specific features that must be regression-tested
- App Router pages/layouts
- route handlers (
src/app/api/trpc/...)
- Next middleware (
src/middleware.ts)
- dynamic OGP (
src/app/opengraph-image.tsx)
- server action (
src/lib/actions/report-error.ts)
next/image
- metadata generation
- MDX setup
Recommended migration approach
Recommendation now
Do not replace the mainline production stack immediately.
The evidence today supports:
- keep
Next.js + OpenNext as the default production path
- build a focused
vinext evaluation branch / spike
- revisit replacement only after repo-specific gates are proven
Phase 1: low-risk evaluation branch
Create a vinext spike branch that does the minimum needed to answer the real questions:
- run
vinext init
- add the required Cloudflare App Router Vite config
- get the web request path booting under
vinext
- do not migrate cron yet; split or stub it intentionally
- replace
getCloudflareContext() usage with cloudflare:workers where needed for the web path
Phase 2: port repo-specific platform concerns
After the web app boots:
- port or remove custom
webpack behavior
- validate bundle behavior for:
- Three.js
- Solana wallet deps
- Metaplex deps
- MDX
- validate
next/image behavior against Arweave / permagate usage
- validate middleware and OGP routes on Workers
Phase 3: split cron cleanly
Move the scheduled generation path out of the framework entrypoint:
- extract cron-specific binding/runtime code into its own Worker boundary
- keep D1 / AI / asset fetch dependencies explicit
- validate local/dev/prod behavior separately from the web app
This split should probably happen even if we ultimately stay on OpenNext.
Success criteria for saying "vinext is viable here"
vinext dev works for the web app
- Cloudflare preview/deploy works for the web app
- archive page works with D1 on Workers
- tRPC route handlers work
- middleware works as expected
- dynamic OGP works
next/image behavior is acceptable for current archive/gallery usage
- no unacceptable regressions in bundle size or boot/runtime stability
- cron pipeline has a clean post-OpenNext story
Decision criteria for full replacement
We should only replace the current stack if the spike proves all of the following:
- developer experience is materially better, not just different
- Worker-runtime fidelity meaningfully reduces bugs or complexity
- we can remove more complexity than we add
- cron has a clean architecture after the split
- image / metadata / middleware behavior stays acceptable
- the remaining
vinext maturity risk is acceptable for production
If those are not true, we should keep OpenNext and revisit later.
Source notes
Primary sources checked on 2026-03-14:
- Cloudflare launch post for
vinext (2026-02-24)
cloudflare/vinext README and current repo
- latest
vinext release visible during review: v0.0.30 (2026-03-13)
vinext issue about currently Cloudflare-specific deployment adapters
- Cloudflare Workers Vite plugin docs
- Cloudflare
cloudflare:workers env docs
- Cloudflare changelog for auxiliary Workers in Vite-backed full-stack setups (2026-01-15)
- Cloudflare Next.js on Workers guide
- OpenNext Cloudflare get-started docs
- Vite releases / migration direction / SSR docs
Appendix: vinext check result on this repo
Ran on 2026-03-14 with:
Key output:
- overall:
77% compatible
- issues:
webpack
experimental.typedRoutes
- missing
"type": "module"
- unrecognized
next/dist/server/next-server.js
- partial support:
next/font/google
images
ViewTransition
Evaluate replacing the current
Next.js + OpenNext for Cloudflarestack withcloudflare/vinextSummary
cloudflare/vinextis now credible enough to evaluate seriously for this repo, but it is not yet a safe drop-in replacement for our current production path.As of 2026-03-14:
vinextand positions it as a Vite-based reimplementation of the Next.js API surface for Cloudflare Workers and other targets.vinextis still explicitly marked as experimental / under heavy development.vinextitself says OpenNext is the more mature and safer option today for serious Next.js-on-Cloudflare deployments.This issue tracks whether we should:
Next.js 16 + OpenNextstack as the default,vinextPoC branch in parallel, orWhy evaluate this now
vinextgives a Vite-first path for existing Next.js apps instead of adaptingnext buildoutput after the fact.workerdduring local development and preview, which is materially different from the current OpenNext model where day-to-day dev stays onnext devand Cloudflare behavior is validated later.Current repo assumptions that matter
This repo is not just "a Next app":
Next.js 16App Routernext-rspack@opennextjs/cloudflaresrc/worker.tsthat combines:.open-next/worker.jsscheduled()cron handling viasrc/cron.tsD1KVWorkers AIImagesR2next/imagesrc/lib/actions/report-error.ts)getCloudflareContext()webpacklogic innext.config.tsopen-next.config.tsscripts/patch-opennext-webpack-runtime.tsscripts/patch-opennext-setimmediate.tsbuild:cf,preview,upload,deploySo this is not a bundler swap. It is a framework-runtime migration.
What
vinextimproves1. Worker-native dev/build/runtime path
vinextuses@cloudflare/vite-plugin, and Cloudflare documents that this path runs code directly in the Workers runtime during local dev.That is the main architectural attraction here:
workerdcloudflare:workersbindings access2. Vite-first toolchain
vinextreplaces the Next compiler/bundler path with Vite and@vitejs/plugin-rsc.That gives us:
next-rspack + OpenNextpipeline3. Simpler Cloudflare binding access model
vinextrecommendsimport { env } from "cloudflare:workers"rather thangetCloudflareContext()or a customfetch(request, env)worker entry for routine binding access.That likely simplifies a lot of the current binding plumbing in:
src/server/trpc/context.tssrc/server/db/index.tssrc/app/archive/page.tsxsrc/app/opengraph-image.tsxsrc/lib/workers-ai-client.tsWhat
vinextdoes not solve for us yet1. It is still explicitly experimental
The
vinextREADME is unusually direct:That is not a footnote. It should directly affect migration timing.
2. OpenNext is still the safer production answer for Next.js on Cloudflare
This is stated both by:
vinextREADME itself, which says OpenNext is more mature and safer3. Our current
webpack/next-rspackcustomizations do not carry overnext.config.tscurrently contains customwebpacklogic for:vinext checkflags this directly:webpackconfig is unsupported and needs migration to Vite equivalentsThis means we must either:
4. Our current cron model is a real migration problem
Today we rely on:
src/worker.tsforfetchsrc/worker.tsforscheduledvinext's Cloudflare story is optimized around the app request pipeline, not around our current "single worker handles both web and cron" structure.The likely migration outcome is:
vinextThat split is probably the right architecture anyway, but it is still a migration cost.
5.
next/imagebehavior changesvinextmarksnext/imageas partial support:@unpic/reactimagesconfig is parsed but not used for optimizationThis matters here because we currently rely on:
next/imageimages.remotePatternsWe should assume image behavior changes unless we test it directly.
6. A few repo-specific features are only partial / caveated
vinext checkon this repo reported:webpackexperimental.typedRoutes"type": "module"next/dist/server/next-server.jsimport path that needs source confirmationnext/font/googleimagesViewTransitionThe
ViewTransitionfinding is specifically relevant because this repo currently setsexperimental.viewTransitioninnext.config.ts.Repo-specific migration surface
These are the concrete places we would need to touch for a real
vinextmigration.A. Build and deployment layer
package.jsonnext.config.tsopen-next.config.tswrangler.tomlsrc/worker.tsscripts/patch-opennext-webpack-runtime.tsscripts/patch-opennext-setimmediate.tsExpected changes:
"type": "module"next/opennextjs-cloudflarescripts withvinext/ Vite equivalentsvite.config.tsB. Cloudflare bindings access
Current access is heavily tied to
@opennextjs/cloudflare.Likely migration direction:
getCloudflareContext()access withcloudflare:workersAffected areas include:
C. Worker entrypoint shape
Current state:
Likely
vinextstate:vinextPossible directions:
vinextCloudflare entrypoint can still hostscheduled()cleanlyAt the moment, option 1 looks like the lowest-risk migration shape.
D. Next-specific features that must be regression-tested
src/app/api/trpc/...)src/middleware.ts)src/app/opengraph-image.tsx)src/lib/actions/report-error.ts)next/imageRecommended migration approach
Recommendation now
Do not replace the mainline production stack immediately.
The evidence today supports:
Next.js + OpenNextas the default production pathvinextevaluation branch / spikePhase 1: low-risk evaluation branch
Create a
vinextspike branch that does the minimum needed to answer the real questions:vinext initvinextgetCloudflareContext()usage withcloudflare:workerswhere needed for the web pathPhase 2: port repo-specific platform concerns
After the web app boots:
webpackbehaviornext/imagebehavior against Arweave / permagate usagePhase 3: split cron cleanly
Move the scheduled generation path out of the framework entrypoint:
This split should probably happen even if we ultimately stay on OpenNext.
Success criteria for saying "vinext is viable here"
vinext devworks for the web appnext/imagebehavior is acceptable for current archive/gallery usageDecision criteria for full replacement
We should only replace the current stack if the spike proves all of the following:
vinextmaturity risk is acceptable for productionIf those are not true, we should keep OpenNext and revisit later.
Source notes
Primary sources checked on 2026-03-14:
vinext(2026-02-24)cloudflare/vinextREADME and current repovinextrelease visible during review:v0.0.30(2026-03-13)vinextissue about currently Cloudflare-specific deployment adapterscloudflare:workersenv docsAppendix:
vinext checkresult on this repoRan on 2026-03-14 with:
Key output:
77% compatiblewebpackexperimental.typedRoutes"type": "module"next/dist/server/next-server.jsnext/font/googleimagesViewTransition