Blog
/
Editorial

We ran vinext (Next.js on Vite) inside a Gadget app

Published
March 9, 2026
Last updated
March 9, 2026
Use vinext in Gadget to get a drop-in replacement for your Next apps on Gadget's infrastructure.

Cloudflare dropped something pretty fun the other week: they rebuilt a drop-in replacement for Next.js on top of Vite. It took them about a week and only cost $1100 in tokens.

The project is called vinext. It keeps the Next.js API but swaps the underlying toolchain for Vite, which means dramatically faster builds and smaller client bundles. The announcement blog post is worth a read if you care about those numbers.

My immediate reaction was: can we use this to power a Gadget frontend?

Gadget already uses Vite for its frontend tooling. If vinext also runs on Vite, we should be able to get it running. So I spent some time experimenting to get a Next-style frontend running inside a Gadget project.

As it turns out you can get something working pretty quickly!

So I figured I’d share the steps I took to set things up. This isn’t meant to be a strict tutorial, it’s more of a “here are the steps I took and how I used agents to do this ” guide.

Also, this is very experimental on both the vinext and Gadget side of things.

You can also check out the video:

The idea

A normal Gadget app contains everything you need to power a modern full-stack web app.

You get a managed Postgres database, a Node backend, authentication and multi-tenancy, and a generated API client. The frontend is a Vite + React Router project that is already wired up to that backend, and has built-in auth and session management.

The experiment was simple: keep all of that exactly the same, but replace the default frontend runtime with vinext.

Conceptually, the architecture becomes:

Gadget app architecture, simplifed

The backend still behaves like a normal Gadget app. The frontend just adopts the Next programming model running on Vite.

Starting with a normal Gadget app

I began by creating a new Gadget web app and pulled it down locally using the <inline-code>ggt<inline-code> CLI. Relevant for the vinext migration, all new apps have a <inline-code>package.json<inline-code> file, a <inline-code>vite.config.mts<inline-code>, and a <inline-code>web<inline-code> directory containing the frontend (in addition to everything needed to power and configure the database and backend).

The <inline-code>web<inline-code> directory is where everything interesting happens.

Normally, Gadget frontends use React Router. In this experiment that router disappears and the frontend becomes a vinext app instead.

Once that swap happens, the project suddenly feels a lot like a Next app. Instead of client-side routing handled by React Router, the project now uses vinext’s Next-style page routing. Page components, layouts, and routing conventions look exactly like what you’d expect from a new NextJS app.

What’s nice is that all the Gadget primitives still work exactly the same way. For example, grabbing the authenticated user in a component still looks like this:

const user = useUser();

That hook comes from Gadget and continues to work normally as long as the <inline-code>GadgetProvider<inline-code> is setup properly. vinext is just responsible for routing and rendering.

Making Vite happy

The only part of the integration that required a bit of experimentation was the Vite configuration.

The project needs both the Gadget Vite plugin and the vinext plugin so the frontend can run the vinext runtime while still talking to the Gadget backend. (The Tailwind plugin was used too. It didn’t need to be touched.)

It seems like authentication needed a small passthrough configuration so auth-related requests resolve correctly during development. This was the major hangup I ran into during the migration experiment, and Codex helped me resolve it. It’s definitely possible (probable, even) that there’s a more “Next-native” way to handle this.

vite.config.mts

Once those pieces are in place, vinext spins up and I can build like I would any other NextJS app, but using my Gadget API client to call my app APIs.

Letting an agent do the migration

Rather than doing everything by hand, I let an agent (Codex) handle most of the conversion.

I started with a fresh NextJS app and used the <inline-code>cloudflare/vinext<inline-code> agent skill to convert it to vinext. If you have an existing app, you could convert it instead. The skill one-shot the transformation. I tested locally and used the converted project as a reference for migrating my Gadget app. 

From there, it was mostly a matter of copying the frontend structure into the Gadget project and adapting it so it used the Gadget API client and authentication hooks. The agent took care of all of it for me. There was a bit of back and forth around using the Vite Tailwind plugin (my reference app used PostCSS instead). And the only other hangup was the auth passthrough.

Look ma, no Next!

Once everything is wired together, you can build a NextJS-style app on Gadget. But, you know, without actually using NextJS.

You still get access to Gadget’s infra-less setup: define data models, Gadget generates the API client, and call those APIs directly from vinext pages. Authentication flows through Gadget. Multi-tenancy still works. The hosted development environment’s backend and database are unchanged.

The frontend just happens to speak the Next API.

vinext is still very early, but the idea behind it is compelling. If the Next programming model can run comfortably on top of Vite, it opens up a lot of flexibility in how those applications can be built and hosted.

Gadget happens to fit that model well. Because the platform already exposes backend services through a generated client, the frontend runtime becomes relatively interchangeable (so long as it uses Vite!). vinext just restructures how you build the UI layer.

This experiment worked better than expected. But let's be real: I migrated a fresh NextJS app and a fresh Gadget app. I didn’t have a bunch of existing, complex logic. I wasn’t exactly pushing the boundaries of vinext here.

But as a proof of concept, running vinext inside a Gadget project is very possible. 

Want to chat more or have questions? I’m usually hanging out in our dev Discord.

Riley Draward
Author
Reviewer
Try Gadget
See the difference a full-stack development platform can make.
Create app
No items found.

We ran vinext (Next.js on Vite) inside a Gadget app

Use vinext in Gadget to get a drop-in replacement for your Next apps on Gadget's infrastructure.
Problem
Solution
Result

Cloudflare dropped something pretty fun the other week: they rebuilt a drop-in replacement for Next.js on top of Vite. It took them about a week and only cost $1100 in tokens.

The project is called vinext. It keeps the Next.js API but swaps the underlying toolchain for Vite, which means dramatically faster builds and smaller client bundles. The announcement blog post is worth a read if you care about those numbers.

My immediate reaction was: can we use this to power a Gadget frontend?

Gadget already uses Vite for its frontend tooling. If vinext also runs on Vite, we should be able to get it running. So I spent some time experimenting to get a Next-style frontend running inside a Gadget project.

As it turns out you can get something working pretty quickly!

So I figured I’d share the steps I took to set things up. This isn’t meant to be a strict tutorial, it’s more of a “here are the steps I took and how I used agents to do this ” guide.

Also, this is very experimental on both the vinext and Gadget side of things.

You can also check out the video:

The idea

A normal Gadget app contains everything you need to power a modern full-stack web app.

You get a managed Postgres database, a Node backend, authentication and multi-tenancy, and a generated API client. The frontend is a Vite + React Router project that is already wired up to that backend, and has built-in auth and session management.

The experiment was simple: keep all of that exactly the same, but replace the default frontend runtime with vinext.

Conceptually, the architecture becomes:

Gadget app architecture, simplifed

The backend still behaves like a normal Gadget app. The frontend just adopts the Next programming model running on Vite.

Starting with a normal Gadget app

I began by creating a new Gadget web app and pulled it down locally using the <inline-code>ggt<inline-code> CLI. Relevant for the vinext migration, all new apps have a <inline-code>package.json<inline-code> file, a <inline-code>vite.config.mts<inline-code>, and a <inline-code>web<inline-code> directory containing the frontend (in addition to everything needed to power and configure the database and backend).

The <inline-code>web<inline-code> directory is where everything interesting happens.

Normally, Gadget frontends use React Router. In this experiment that router disappears and the frontend becomes a vinext app instead.

Once that swap happens, the project suddenly feels a lot like a Next app. Instead of client-side routing handled by React Router, the project now uses vinext’s Next-style page routing. Page components, layouts, and routing conventions look exactly like what you’d expect from a new NextJS app.

What’s nice is that all the Gadget primitives still work exactly the same way. For example, grabbing the authenticated user in a component still looks like this:

const user = useUser();

That hook comes from Gadget and continues to work normally as long as the <inline-code>GadgetProvider<inline-code> is setup properly. vinext is just responsible for routing and rendering.

Making Vite happy

The only part of the integration that required a bit of experimentation was the Vite configuration.

The project needs both the Gadget Vite plugin and the vinext plugin so the frontend can run the vinext runtime while still talking to the Gadget backend. (The Tailwind plugin was used too. It didn’t need to be touched.)

It seems like authentication needed a small passthrough configuration so auth-related requests resolve correctly during development. This was the major hangup I ran into during the migration experiment, and Codex helped me resolve it. It’s definitely possible (probable, even) that there’s a more “Next-native” way to handle this.

vite.config.mts

Once those pieces are in place, vinext spins up and I can build like I would any other NextJS app, but using my Gadget API client to call my app APIs.

Letting an agent do the migration

Rather than doing everything by hand, I let an agent (Codex) handle most of the conversion.

I started with a fresh NextJS app and used the <inline-code>cloudflare/vinext<inline-code> agent skill to convert it to vinext. If you have an existing app, you could convert it instead. The skill one-shot the transformation. I tested locally and used the converted project as a reference for migrating my Gadget app. 

From there, it was mostly a matter of copying the frontend structure into the Gadget project and adapting it so it used the Gadget API client and authentication hooks. The agent took care of all of it for me. There was a bit of back and forth around using the Vite Tailwind plugin (my reference app used PostCSS instead). And the only other hangup was the auth passthrough.

Look ma, no Next!

Once everything is wired together, you can build a NextJS-style app on Gadget. But, you know, without actually using NextJS.

You still get access to Gadget’s infra-less setup: define data models, Gadget generates the API client, and call those APIs directly from vinext pages. Authentication flows through Gadget. Multi-tenancy still works. The hosted development environment’s backend and database are unchanged.

The frontend just happens to speak the Next API.

vinext is still very early, but the idea behind it is compelling. If the Next programming model can run comfortably on top of Vite, it opens up a lot of flexibility in how those applications can be built and hosted.

Gadget happens to fit that model well. Because the platform already exposes backend services through a generated client, the frontend runtime becomes relatively interchangeable (so long as it uses Vite!). vinext just restructures how you build the UI layer.

This experiment worked better than expected. But let's be real: I migrated a fresh NextJS app and a fresh Gadget app. I didn’t have a bunch of existing, complex logic. I wasn’t exactly pushing the boundaries of vinext here.

But as a proof of concept, running vinext inside a Gadget project is very possible. 

Want to chat more or have questions? I’m usually hanging out in our dev Discord.

Interested in learning more about Gadget?

Join leading agencies making the switch to Gadget and experience the difference a full-stack platform can make.