All skills
cloudflare avatar

/migrate-to-vinext

@115771d
by cloudflarecloudflare/vinext9.1k stars
427

Migrates Next.js projects to vinext (Vite-based Next.js reimplementation). Load when asked to migrate, convert, or switch from Next.js to vinext. Handles compatibility scanning, package replacement, Vite config generation, ESM conversion, and deployment setup (Cloudflare Workers natively, other platforms via Nitro).

Use this Skill: https://skilld.dev/gh/cloudflare/vinext/migrate-to-vinext

This session only. Nothing lands on disk.

referencesconfig-examples.md

≈1.5k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Vite Config Examples

These examples stay minimal on purpose. If you add custom build tuning on Vite 8, prefer oxc, optimizeDeps.rolldownOptions, and build.rolldownOptions / worker.rolldownOptions over older esbuild and build.rollupOptions settings.

Pages Router — Local Development

No Cloudflare, no deployment. Simplest possible config.

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

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

App Router — Local Development

vinext auto-registers @vitejs/plugin-rsc when an app/ directory is detected and the rsc option is not false. No extra config needed.

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

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

To disable auto-registration (e.g., Pages Router only project with an unused app/ dir):

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

Pages Router — Cloudflare Workers

import vinext from "vinext";
import { cloudflare } from "@cloudflare/vite-plugin";
import { defineConfig } from "vite";

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

App Router — Cloudflare Workers

Cloudflare multi-environment setup. RSC plugin registration stays automatic — do not add an explicit rsc() call, or the build fails with [vinext] Duplicate @vitejs/plugin-rsc detected.

import { defineConfig } from "vite";
import vinext from "vinext";
import { cloudflare } from "@cloudflare/vite-plugin";

export default defineConfig({
  plugins: [
    vinext(),
    cloudflare({
      viteEnvironment: { name: "rsc", childEnvironments: ["ssr"] },
    }),
  ],
});

@vitejs/plugin-rsc is an optional peer dependency: it must be installed in the project, but vinext registers it for you. Only register it yourself after passing rsc: false to vinext().

In most cases npx @vinext/cloudflare deploy generates this automatically. Only use manual config when customizing the worker entry or adding bindings.

wrangler.jsonc — Cloudflare Workers

Minimal config for deployment:

{
  "$schema": "node_modules/wrangler/config-schema.json",
  "name": "my-app",
  "compatibility_date": "2026-02-12",
  "compatibility_flags": ["nodejs_compat"],
  "main": "vinext/server/app-router-entry",
  "assets": {
    "not_found_handling": "none",
  },
}

For custom worker entries (e.g., adding KV cache, image optimization bindings):

{
  "$schema": "node_modules/wrangler/config-schema.json",
  "name": "my-app",
  "compatibility_date": "2026-02-12",
  "compatibility_flags": ["nodejs_compat"],
  "main": "./worker/index.ts",
  "assets": {
    "not_found_handling": "none",
    "binding": "ASSETS",
  },
  "images": { "binding": "IMAGES" },
}

Accessing Cloudflare Bindings

Use import { env } from "cloudflare:workers" in server components, route handlers, and server actions. No custom worker entry needed.

// app/page.tsx (server component)
import { env } from "cloudflare:workers";

export default async function Page() {
  const result = await env.DB.prepare("SELECT * FROM posts").all();
  return <div>{JSON.stringify(result)}</div>;
}
// app/api/data/route.ts (route handler)
import { env } from "cloudflare:workers";

export async function GET() {
  const value = await env.CACHE.get("key");
  return Response.json({ value });
}

Define bindings in wrangler.jsonc:

{
  "name": "my-app",
  "compatibility_date": "2026-02-12",
  "compatibility_flags": ["nodejs_compat"],
  "main": "vinext/server/app-router-entry",
  "d1_databases": [{ "binding": "DB", "database_name": "my-db", "database_id": "..." }],
  "kv_namespaces": [{ "binding": "CACHE", "id": "..." }],
  "r2_buckets": [{ "binding": "BUCKET", "bucket_name": "my-bucket" }],
  "ai": { "binding": "AI" },
}

Run wrangler types to generate TypeScript types for the env object.

Do NOT use getPlatformProxy(), getRequestContext(), or custom worker entries with fetch(request, env). These are older patterns. cloudflare:workers is the recommended approach.

App Router — Other Platforms (via Nitro)

For deploying to Vercel, Netlify, AWS, Deno Deploy, or any other Nitro-supported platform:

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

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

Build with a preset:

NITRO_PRESET=vercel npx vite build
NITRO_PRESET=netlify npx vite build
NITRO_PRESET=deno_deploy npx vite build
NITRO_PRESET=node npx vite build

Nitro auto-detects the platform in most CI/CD environments, so the NITRO_PRESET is often unnecessary.

For Cloudflare Workers, Nitro works but the native integration (npx @vinext/cloudflare deploy / vp exec vinext-cloudflare deploy / @cloudflare/vite-plugin) is recommended for the best experience with cloudflare:workers bindings, KV caching, and one-command deploys.

VinextOptions

Option Type Default Description
appDir string project root Custom base directory for app/ and pages/
rsc boolean true Auto-register @vitejs/plugin-rsc for App Router

@vinext/cloudflare deploy flags

Flag Description
--preview Deploy to preview environment
--name <name> Override worker name
--skip-build Skip build step (deploy existing output)
--dry-run Generate config without deploying
--warm-cache Warm discovered routes before promotion
--traffic-aware-warm-cache Enable traffic-aware cache warming

Source: SKILL.md on GitHub

No alerts3d5 checks · Risk SAFE
  • Gen Agent Trust Hub3d

    This skill provides a guided process for migrating web projects to a new build system and framework. It utilizes standard developer workflows, including automated package management and command execution for building and deploying applications. These operations are appropriate for the skill's stated purpose of project migration.

  • Socket3d

    No alerts

  • Snyk3d

    Risk: LOW · No issues

  • Runlayer6mo

    4 files scanned · No issues

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at 115771d. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 hours ago.

Activeupdated 3 days ago
  • Next.js
  • vite
  • vinext
  • migration
  • cloudflare
  • workers
  • esm
  • app-router
  • pages-router
  • nitro

README badge

README badge for cloudflare/vinext

Migrates Next.js projects to vinext, a Vite-based reimplementation of Next.js that runs existing app/ and pages/ directories without code changes. Handles compatibility scanning, package replacement, Vite config generation, ESM conversion, and deployment to Cloudflare Workers or other platforms via Nitro.

Generated from the current SKILL.md.

Do I need to rewrite my app/ or pages/ directory?
No. vinext reimplements the Next.js API surface on Vite, so existing `app/`, `pages/`, and `next.config.js` work as-is without code changes.
What package managers does this support?
The skill detects and works with npm, pnpm, yarn, and bun based on the lockfile present in the project.
Can I deploy to platforms other than Cloudflare?
Yes. For Vercel, Netlify, AWS, Deno Deploy, and other platforms, add the Nitro Vite plugin and set the appropriate NITRO_PRESET during build. For Cloudflare Workers specifically, the native `vinext deploy` integration is recommended.
How do I access Cloudflare bindings like D1, R2, or KV?
Use `import { env } from "cloudflare:workers"` in server components or route handlers. Bindings must be defined in `wrangler.jsonc`, and this approach works out of the box with vinext and `@cloudflare/vite-plugin`.
What happens if vinext init fails?
The skill provides a manual migration path (Phase 3) that covers package replacement, script updates, ESM conversion, and Vite config generation as a fallback.

Generated from the current SKILL.md. These answers refresh after source changes.