# Void, vinext, or React Router for a Cloudflare app?

> Choose a Cloudflare full-stack setup by following a request, a database change, and a deployment through Void, vinext, and React Router.

Author: [Flavio Copes](https://flaviocopes.com/about/) | Published: 2026-10-31 | Topics: [Cloudflare](https://flaviocopes.com/tags/cloudflare/) | Canonical: https://flaviocopes.com/cloudflare-full-stack-frameworks/

You want to build a full-stack app on Cloudflare. Void, vinext, and React Router can all be relevant, but they bring different assumptions about the application you already have.

An existing Next.js app gives me a reason to investigate vinext before rewriting its routes. React Router fits a new React app organized around server loaders and form actions. I would evaluate Void when a Vite app needs a coordinated backend and resource provisioning.

There's also overlap. Void can manage resources and deployment around a React Router app while React Router keeps ownership of routing and rendering.

Let's compare them using a reading-list app. A signed-in user saves a URL, sees their articles, and marks one as read. This is a proposed design comparison based on the official documentation checked in October 2026. I haven't built three equivalent apps or measured their performance.

## Begin with the code you want to keep

An existing application's framework is part of its cost. Rewriting a working router means revisiting forms, errors, authentication, and deployment behavior.

Before choosing a replacement, list the conventions your app relies on. Next.js code may rely on Server Components or Server Actions. In React Router, loaders and nested layouts may already organize the application. A plain Vite frontend may have none of those conventions.

For a new project, decide where the first request runs. Does the server need to authenticate the user and fetch articles before rendering HTML? Is a static frontend calling a JSON API sufficient?

Those questions narrow the choice more usefully than a generic claim that one framework is smaller or faster.

## Native Void: one Vite app with a backend

[Void's app types documentation](https://void.cloud/guide/app-types) describes a native application with API routes and optional server-rendered pages. It can also wrap a frontend that talks to those routes.

For the reading list, a native Void request can follow this path:

```text
Browser submits a URL
  → Worker middleware identifies the user
  → Void server handler validates the URL
  → Database write records the article's owner
  → Response updates the reading list
```

The existing [Void tutorial](https://flaviocopes.com/void/) walks through a reading list in detail, including its Hono-based handlers and database setup.

Void's deployment workflow can infer resources from code and provision them. Its [quickstart](https://void.cloud/guide/quickstart) supports deploying directly to a Cloudflare account; a team hosting platform is another option.

That coordinated workflow is the reason I would evaluate it. When adding a database-backed feature, I want to understand how its resource declaration, schema change, and application deployment fit together.

It also means reviewing what a deployment will change. Automatically creating infrastructure is convenient, but you still need to know which account receives it, where production data lives, and how a migration affects the previous application version.

## React Router: routes own loading and mutation

React Router's framework mode gives routes [server loaders for data](https://reactrouter.com/start/framework/data-loading). A route can load the signed-in user's saved articles before rendering its component. A form action can validate and save a new article, then return validation feedback or redirect.

For our reading list, the route boundary becomes the natural place to trace the request. Check which loader reads the articles and which action creates them. Shared layout routes can supply surrounding UI while the child route handles its own data.

Cloudflare's [React Router guide](https://developers.cloudflare.com/workers/framework-guides/web-apps/react-router/) describes a Workers setup with the Cloudflare Vite plugin and bindings available to server code. Start with that supported scaffold rather than assembling configuration from an old tutorial.

The guide currently notes restrictions around SPA mode and prerendering with the Cloudflare Vite plugin. If either is central to your app, verify support before adopting that particular setup. React Router used as a browser routing library is a different arrangement from this server-rendered framework integration.

For a new React application, I would choose this path when I want to organize data loading and forms around routes. The appeal is the programming model I intend to use throughout the app.

## vinext: investigate an existing Next.js app

[Cloudflare's Next.js guide](https://developers.cloudflare.com/workers/framework-guides/web-apps/nextjs/) recommends vinext for running Next.js applications on Workers. vinext is a Vite-based reimplementation of the Next.js API surface.

For an existing reading-list app, that means investigating whether its routes and rendering conventions can continue working. Start with the documented compatibility check, then test the specific features the app uses.

Keeping a familiar API surface doesn't establish complete compatibility with every package or behavior. Follow vinext's [compatibility documentation](https://vinext.dev/compatibility) for the supported features, and check libraries that assume a particular Node runtime or deployment platform.

I would make the first trial small. Run the existing list page, submit the save form, and test the authentication boundary. Inspect the rendered response and confirm that the database write happens in the expected account and environment.

For a brand-new app, I would choose vinext when I specifically want the Next.js programming model on Workers. I wouldn't introduce that compatibility surface solely because the name is familiar.

## Follow the same feature through each option

| Decision | Native Void | React Router on Workers | vinext on Workers |
| --- | --- | --- | --- |
| Incoming request | Void routing and Hono-based middleware | Framework route and its server loader or action | The supported Next.js-style route or server entry |
| Database access | Void resource APIs can coordinate schema and bindings | Server code uses the configured database binding or client | Server code uses supported runtime APIs and configured bindings |
| Save form | Handler or pages action in the native app | Route action with route-level data flow | Supported Server Action or route handler |
| Deployment work | Void's resource and deployment workflow | Workers project and its generated build configuration | vinext build and its Workers deployment integration |
| Strong starting reason | You want a Vite backend with managed resources | You want React route loaders and actions | You want to retain or adopt the Next.js API model |

The database is still a separate decision. A framework can make D1 convenient, but the choice also depends on your queries, data model, and operational needs. Confirm that a proposed database fits before letting a starter template settle it for you.

## Void can wrap another framework

The supported app types guide explains that a framework integration keeps its own routing and server rendering. Void can add resource inference and its deployment workflow around that framework.

That makes “Void or React Router?” an incomplete question. You can use React Router's application model and separately decide whether Void's infrastructure workflow helps.

Check the [framework integration guide](https://void.cloud/integrations/frameworks/overview) before assuming native Void features carry across. For example, the app types documentation says Void-managed authentication isn't supported in framework mode. Follow the framework's supported auth integration instead.

Choose one documented owner for each concern. If two tools both generate a deployment file or provision a database, understand which one is authoritative. Avoid layering tools just to collect features you haven't needed yet.

## Test an authenticated write before committing

A useful trial reaches past the homepage. For the reading list, I would check these cases with test accounts:

- A signed-out visitor can't retrieve private articles.
- One account can't read or update another account's article by changing an ID.
- An invalid URL returns a useful form error without creating a row.
- A failed save leaves the page usable for another attempt.

Then build the production artifact and verify it in the intended runtime. A development server can hide a dependency on local Node behavior, filesystem access, or credentials that won't exist in the Worker.

Finally, trace one schema change through a preview and deployment. Verify the preview uses separate data, inspect its migrations, and make sure deploying it won't alter production resources by accident.

Use that trial to choose the workflow you want to maintain. A compatible route, a verified write, and an understandable deployment process give you a firmer basis than a comparison of homepage benchmarks.
