Skip to content

Evaluate replacing Next.js/OpenNext stack with cloudflare/vinext #54

@posaune0423

Description

@posaune0423

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:

  1. keep the current Next.js 16 + OpenNext stack as the default,
  2. build a vinext PoC branch in parallel, or
  3. 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:

  1. separate scheduled Worker with its own trigger and service bindings
  2. multi-Worker setup using Cloudflare's newer auxiliary Worker story where appropriate
  3. 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:

  1. run vinext init
  2. add the required Cloudflare App Router Vite config
  3. get the web request path booting under vinext
  4. do not migrate cron yet; split or stub it intentionally
  5. replace getCloudflareContext() usage with cloudflare:workers where needed for the web path

Phase 2: port repo-specific platform concerns

After the web app boots:

  1. port or remove custom webpack behavior
  2. validate bundle behavior for:
    • Three.js
    • Solana wallet deps
    • Metaplex deps
    • MDX
  3. validate next/image behavior against Arweave / permagate usage
  4. validate middleware and OGP routes on Workers

Phase 3: split cron cleanly

Move the scheduled generation path out of the framework entrypoint:

  1. extract cron-specific binding/runtime code into its own Worker boundary
  2. keep D1 / AI / asset fetch dependencies explicit
  3. 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:

Appendix: vinext check result on this repo

Ran on 2026-03-14 with:

bunx vinext@latest check

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions