cloudflare/vinext

▲ 65 stars today★ 8,977⑂ 420

Vite plugin that reimplements the Next.js API surface — deploy anywhere

About cloudflare/vinext

cloudflare/vinext is an open-source project on GitHub, mainly written in TypeScript. Vite plugin that reimplements the Next.js API surface — deploy anywhere It currently holds 8,977 stars and 420 forks with 557 open issues, and was last pushed on 2026-09-29 (repository created 2026-02-24).

Project Overview

Git Homed tracks it on the Today's Trending board, currently at rank #57 with 65 new stars today.

GitHub Repository Details

Repository cloudflare/vinext · default branch main · size 54399 KB · watchers 41 · source: GitHub REST API and repository README

README

vinext

Run Next.js applications on Vite, with Cloudflare Workers as the primary deployment target.

Website: vinext.dev

Documentation: vinext.dev/docs

Read the announcement: How we rebuilt Next.js with AI in one week
Under active development. vinext supports substantial Next.js applications today, but it is not yet a drop-in replacement for every application or production workload. Expect compatibility gaps, especially in newer App Router features, and evaluate it against your own application before adopting it.

vinext reimplements the Next.js API surface on Vite rather than consuming next build output. It supports both the App Router and Pages Router, React Server Components, Server Actions, middleware, route handlers, ISR, static export, and the most commonly used next/* modules. Cloudflare Workers has the deepest integration; Node.js and other platforms are available with different levels of support.

Project status

What works today

Known gaps we're working on

These are active compatibility areas, not permanent exclusions:

Run vinext check against an existing application before migrating. If a gap is not listed here, check the open issues or file a focused reproduction.

Quick start

Use the official setup commands below. They are the recommended way to create or migrate a vinext project because they configure dependencies, scripts, Vite, and your deployment target for you.

Start a new project with create-vinext-app:

pnpm create vinext-app@latest my-app

Migrate an existing Next.js project with vinext init:

npx vinext init

Optional: migrate with an AI agent

Prefer vinext init for a direct, repeatable migration. If you want an AI agent to investigate compatibility issues and guide the migration, vinext also includes an optional Agent Skill. It works with Claude Code, OpenCode, Cursor, Codex, and dozens of other AI coding tools:

npx skills add cloudflare/vinext

Then open your Next.js project in any supported tool and say:

migrate this project to vinext

The skill handles compatibility checking, dependency installation, config generation, and dev server startup. It knows what vinext supports and will flag anything that needs manual attention.

Or do it manually

npm install vinext
npm install -D vite @vitejs/plugin-react

If you're using the App Router, also install:

npm install react-server-dom-webpack
npm install -D @vitejs/plugin-rsc

Add a Vite config:

import { defineConfig } from "vite";
import vinext from "vinext";

export default defineConfig({ plugins: [vinext()], });

Then use Vite for development and builds:

{
  "scripts": {
    "dev": "vite dev",
    "build": "vite build",
    "start": "vinext start"
  }
}
npx vite dev        # Development server with HMR
npx vite build      # Production build
npx @vinext/cloudflare deploy  # Build and deploy to Cloudflare Workers

With Vite+, use vpx @vinext/cloudflare deploy, or vp exec vinext-cloudflare deploy when running the locally installed bin.

The vinext() plugin auto-detects your app/ or pages/ directory and loads next.config.js.

Your existing pages/, app/, next.config.js, and public/ directories work as-is. Run vinext check first to scan for known compatibility issues, or use vinext init to automate the full migration.

CLI reference

| Command | Description | | ---------------------------------- | ----------------------------------------------------------------------- | | vite dev | Start dev server with HMR | | vite build | Production build (multi-environment for App Router: RSC + SSR + client) | | vinext start | Start local production server for testing | | npx @vinext/cloudflare deploy | Build and deploy to Cloudflare Workers | | vp exec vinext-cloudflare deploy | Build and deploy to Cloudflare Workers with Vite+ | | vinext init | Migrate a Next.js project to run under vinext | | vinext check | Scan your Next.js app for compatibility issues before migrating | | vinext lint | Delegate to eslint or oxlint |

vinext dev and vinext build remain as thin aliases for the project-local Vite commands. They require a Vite config; if one is missing, run vinext init. Vite owns their options, output, and exit behavior. For older configured projects, the aliases still preload dotenv before Vite evaluates the config and add "type": "module" (renaming known CommonJS config files to .cjs) when an unambiguous default Vite config requires the ESM migration. An explicit "type": "commonjs" is never changed. Direct vite dev and vite build do not perform these wrapper compatibility steps.

@vinext/cloudflare deploy options: --preview, --env , --name , --skip-build, --dry-run, --warm-cache, --traffic-aware-warm-cache.

vinext init prompts for a deployment target, defaulting to Cloudflare. Agents must ask the user which target they want, then pass --platform=cloudflare or --platform=node.

Other options: --port (default: 3001), --skip-check, --force.

Cloudflare init uses cf and cloudflare.config.ts by default. Both vinext init and create-vinext-app accept --legacy-wrangler-cloudflare-init to retain the legacy Wrangler setup. Existing Wrangler configs are not automatically migrated.

If your next.config.* sets output: "standalone", vite build emits a self-hosting bundle at dist/standalone/. Start it with:

node dist/standalone/server.js

Environment variables: PORT (default 3000), HOST (default 0.0.0.0).

Note: Next.js standalone uses HOSTNAME for the bind address, but vinext uses HOST to avoid collision with the system-set HOSTNAME variable on Linux. Update your deployment config accordingly.

Starting a new vinext project

Use create-vinext-app for new projects. It creates a TypeScript App Router project with Tailwind CSS and then runs the same vinext init setup used for existing apps:

pnpm create vinext-app@latest my-app

The generated project is Cloudflare Workers-ready by default. Pass --platform=node if you want the Node target instead.

Migrating an existing Next.js project

vinext init automates the migration in one command:

npx vinext init

This will:

1. Run vinext check to scan for compatibility issues 2. Install vinext runtime packages as dependencies and Vite/plugin tooling as devDependencies 3. Rename CJS config files (e.g. postcss.config.js -> .cjs) to avoid ESM conflicts 4. Add "type": "module" to package.json 5. Add dev:vinext, build:vinext, and start:vinext scripts to package.json 6. Prompt for a deployment platform (Cloudflare by default, or Node) 7. Generate the matching vite.config.ts 8. For Cloudflare, generate cloudflare.config.ts for cf and Cloudflare Vite plugin v2

The migration is non-destructive -- your existing Next.js setup continues to work alongside vinext. It does not modify next.config, tsconfig.json, or any source files, and it does not remove Next.js dependencies.

vinext targets Vite 8, which defaults to Rolldown, Oxc, Lightning CSS, and a newer browser baseline. If you bring custom Vite config or plugins from an older setup, prefer oxc, optimizeDeps.rolldownOptions, and build.rolldownOptions over older esbuild and build.rollupOptions knobs, and override build.target if you still need older browsers. If a dependency breaks because of stricter CommonJS default import handling, fix the import or use legacy.inconsistentCjsInterop: true as a temporary escape hatch. See the Vite 8 migration guide.

npm run dev:vinext    # Start the vinext dev server (port 3001)
npm run build:vinext  # Build production output with vinext
npm run start:vinext  # Start vinext production server
npm run dev           # Still runs Next.js as before

Use --platform=cloudflare or --platform=node to skip the platform prompt. Cloudflare init updates an existing JavaScript or TypeScript Vite config using its AST, preserving unrelated settings. Use --force to replace an existing Node-target Vite config, or --skip-check to skip the compatibility report.

Why

Vite has become the default build tool for modern web frameworks — fast HMR, a clean plugin API, native ESM, and a growing ecosystem. With @vitejs/plugin-rsc adding React Server Components support, it's now possible to build a full RSC framework on Vite.

vinext reimplements the Next.js API surface on Vite so existing Next.js applications can run on a different toolchain. The answer, so far, is that substantial applications can.

vinext works everywhere. It natively supports Cloudflare Workers (with npx @vinext/cloudflare deploy or vp exec vinext-cloudflare deploy, bindings, KV caching), and can be deployed to Vercel, Netlify, AWS, Deno Deploy, and more via the Nitro Vite plugin. Native support for additional platforms is planned.

Alternatives worth knowing about:

Design principles

FAQ

What is this? vinext is a Vite plugin that reimplements the public Next.js API — routing, server rendering, next/* module imports, the CLI — so you can run Next.js applications on Vite instead of the Next.js compiler toolchain. It can be deployed anywhere: Cloudflare Workers is the first natively supported target, with other platforms available via Nitro. Native adapters for more platforms are planned.

Is this a fork of Next.js? No. vinext is an alternative implementation of the Next.js API surface built on Vite. The core is written from scratch. The goal is not to create a competing framework or add features beyond what Next.js offers; it is to provide the same well-defined API surface on Vite's toolchain.

Does vinext require Next.js to be installed? No. vinext ships fallback declarations for the supported next and next/* APIs, so applications can run and type-check without the next package. If both packages are installed, vinext keeps using Next.js's authoritative types and adds only its own extensions. Compatibility features that consume Next.js internals, such as styled-jsx, may still require a matching Next.js installation when used.

How is this different from OpenNext? OpenNext adapts the _output_ of a standard next build to run on various platforms. Because it builds on Next.js's own output, it inherits broad API coverage and has been well-tested for much longer. vinext takes a different approach: it reimplements the Next.js APIs on Vite from scratch, which means faster builds and smaller bundles, but less coverage of the long tail of Next.js features. If you need a mature, well-tested way to run Next.js outside Vercel, OpenNext is the safer choice. If you want a lighter Vite-based toolchain and do not need every Next.js API, vinext may be a good fit.

Can I use this in production? You can, with caution. vinext has known compatibility gaps and has not yet been battle-tested across the full range of production Next.js workloads. Evaluate the features and deployment target your application relies on before adopting it.

Can I just self-host Next.js? Yes. Next.js supports self-hosting on Node.js servers, Docker containers, and static exports. If you're happy with the Next.js toolchain and just want to run it somewhere other than Vercel, self-hosting is the simplest path.

How are you verifying this works? The test suite has over 1,700 Vitest tests and 380 Playwright E2E tests. This includes tests ported directly from the Next.js test suite and OpenNext's Cloudflare conformance suite, covering routing, SSR, RSC, server actions, caching, metadata, middleware, streaming, and more. Vercel's App Router Playground also runs on vinext as an integration test. See the Tests section and tests/nextjs-compat/TRACKING.md for details.

Who is reviewing this code? A mix of humans and AI agents. Humans review PRs before they merge, focused on behavior, structure, and long-term direction. We lean heavily on agent-driven code review to catch issues at PR time and across the codebase. The test suite is the primary quality gate. Outside contributions and deeper human code review are very welcome.

Why Vite? Vite is an excellent build tool with a rich plugin ecosystem, first-class ESM support, and fast HMR. The @vitejs/plugin-rsc plugin adds React Server Components support with multi-environment builds. vinext builds the Next.js developer experience on top of that infrastructure.

Does this support the Pages Router, App Router, or both? Both. File-system routing, SSR, client hydration, and deployment to Cloudflare Workers work for both routers.

What version of Next.js does this target? Next.js 16.x. No support for deprecated APIs from older versions.

Can I deploy to AWS/Netlify/other platforms? Yes. Add the Nitro Vite plugin alongside vinext, and you can deploy to Vercel, Netlify, AWS Amplify, Deno Deploy, Azure, and many more. See Other platforms (via Nitro) for setup. For Cloudflare Workers, the native integration (npx @vinext/cloudflare deploy or vp exec vinext-cloudflare deploy) gives you the smoothest experience. Native adapters for more platforms are planned.

What happens when Next.js releases a new feature? We track the public Next.js API surface and add support for new stable features. Experimental or unstable Next.js features are lower priority. The plan is to add commit-level tracking of the Next.js repo so we can stay current as new versions are released.

Deployment

Cloudflare Workers

vinext has native integration with Cloudflare Workers through @cloudflare/vite-plugin, including bindings access via cloudflare:workers, KV caching, image optimization, and the @vinext/cloudflare deploy one-command workflow.

Prerequisites

Before running npx @vinext/cloudflare deploy for the first time, run vinext init --platform=cloudflare to install cf and Cloudflare Vite plugin v2, create or update vite.config.*, and generate cloudflare.config.ts.

Authentication — pick one:

Account ID:

Set accountId at the top level of defineConfig in cloudflare.config.ts, outside worker. Find your account ID in the Cloudflare dashboard URL (dash.cloudflare.com/).

Alternatively, set the CLOUDFLARE_ACCOUNT_ID environment variable instead of hardcoding it in the config file.

@vinext/cloudflare deploy validates the initialized setup, builds the application, and deploys its Cloudflare Build Output with cf without rewriting project configuration.

Cloudflare init can also configure image optimization declaratively in the Vite config with imagesOptimizer() and add the matching Images binding to cloudflare.config.ts. The built-in fetch handlers register that optimizer at runtime; image optimization is not implemented or generated by @vinext/cloudflare deploy.

npx @vinext/cloudflare deploy
vp exec vinext-cloudflare deploy
npx @vinext/cloudflare deploy --env staging
vp exec vinext-cloudflare deploy --env staging

Use --env to select the Vite mode for the build and deployment. --preview is shorthand for --env preview.

In Response Store service-binding mode, both Workers build together, but the cache Worker is deployed explicitly. After creating the R2 bucket named by init, run:

pnpm run build:vinext
pnpm run deploy:response-store
pnpm run deploy:vinext

For create-vinext-app projects, use build and deploy instead of build:vinext and deploy:vinext. Redeploy the Response Store only when its package or config changes; normal application deployments do not deploy auxiliary Workers.

The init command also auto-detects and fixes common migration issues:

Both App Router and Pages Router work on Workers with full client-side hydration.

Cloudflare Bindings (D1, R2, KV, AI, etc.)

Use import { env } from "cloudflare:workers" to access bindings in any server component, route handler, or server action. No custom worker entry or special configuration required.

import { env } from "cloudflare:workers";

export default async function Page() { const result = await env.DB.prepare("SELECT * FROM posts").all(); return

{JSON.stringify(result)}
; }

This works because @cloudflare/vite-plugin runs the RSC environment in workerd, where cloudflare:workers is a native module. In production builds, the import is externalized so workerd resolves it at runtime. All binding types are supported: D1, R2, KV, Durable Objects, AI, Queues, Vectorize, Browser Rendering, etc.

Add bindings to your Worker's env in cloudflare.config.ts:

import { bindings } from "cf/config";

env: { // ...existing bindings DB: bindings.d1({ name: "my-db" }), CACHE: bindings.kv(), },

Binding and runtime types are generated in .cloudflare/types during dev and build. Include that directory in tsconfig.json; run cf workers types before standalone type-checks. Generated types and Build Output stay gitignored.

Note: You do not need getPlatformProxy(), a custom worker entry with fetch(request, env), or any other workaround. cloudflare:workers is the recommended way to access bindings in vinext.

Traffic-aware pre-warming

Traffic-aware warming queries Cloudflare zone analytics at deploy time to select the routes that actually get traffic. Those routes then go through vinext's standard staged CDN pre-warming flow, including route resolution, cacheability checks, and promotion.

npx @vinext/cloudflare deploy --traffic-aware-warm-cache                              # Pre-warm routes covering 90% of traffic
vp exec vinext-cloudflare deploy --traffic-aware-warm-cache                           # Same, with Vite+
npx @vinext/cloudflare deploy --traffic-aware-warm-cache --traffic-aware-coverage 95  # More aggressive coverage
npx @vinext/cloudflare deploy --traffic-aware-warm-cache --traffic-aware-limit 500    # Cap at 500 routes
npx @vinext/cloudflare deploy --traffic-aware-warm-cache --traffic-aware-window 48    # Use 48h of analytics
npx @vinext/cloudflare deploy --traffic-aware-warm-cache --warm-cache-target https://example.com  # Set the production origin manually

Requires a custom domain (zone analytics are unavailable on *.workers.dev) and CLOUDFLARE_API_TOKEN with Zone > Analytics > Read and Zone > Zone > Read permissions for that zone.

For typed config projects, declare the custom domain with domains: ["example.com"] on the Worker in cloudflare.config.ts. The first domain in the generated Build Output is used for both analytics and staged warming. Wrangler projects retain domain selection from their configured routes and deployed triggers. Use --warm-cache-target https://example.com to override the origin. Add --warm-cache-certify t

GitHub Stars & Activity

8,977Stars
420Forks
557Open issues
TypeScriptLanguage

GitHub Popularity

GitHub stars8,977
Forks420
Open issues557
Primary languageTypeScript
LicenseMIT
Stars gained today65
Created2026-02-24
Last pushed2026-09-29

Trending History

Daily boardrank #57 · ▲ 65 stars

Related GitHub Projects

1

openclaw / openclaw

TypeScript★ 390,938⑂ 82,213▲ 136 stars
→
2

firecrawl / firecrawl

TypeScript★ 187,083⑂ 9,993▲ 579 stars
→
3

anthropics / claude-code

TypeScript★ 148,706⑂ 25,110▲ 123 stars
→
4

modelcontextprotocol / servers

TypeScript★ 90,770⑂ 11,721▲ 48 stars
→
5

OpenHands / OpenHands

TypeScript★ 89,634⑂ 11,833▲ 127 stars
→
6

makeplane / plane

TypeScript★ 60,176⑂ 5,924▲ 82 stars
→
7

heygen-com / hyperframes

TypeScript★ 54,617⑂ 4,966▲ 352 stars
→
8

ChromeDevTools / chrome-devtools-mcp

TypeScript★ 52,810⑂ 5,273▲ 66 stars
→

More Trending Repositories