vinext
Documentation menu

Documentation

Migrate a Next.js app

Add vinext alongside an existing Next.js setup without rewriting the application.

Migration is non-destructive. vinext init leaves your Next.js scripts and source files in place, then adds parallel *:vinext scripts for evaluation.

Migrate with an AI agent

To have an AI agent investigate compatibility issues and guide the migration, install the optional vinext Agent Skill. It works with Claude Code, OpenCode, Cursor, Codex, and other AI coding tools:

pnpm dlx skills add cloudflare/vinext

Then open your Next.js project in your agent and ask it to migrate this project to vinext. The skill runs the compatibility check, installs dependencies, generates config, and starts the dev server, and flags anything that needs manual attention. When it runs vinext init for Cloudflare, it asks you for the cache and image optimization choices rather than picking them itself.

Migrate manually

vinext init is the direct, repeatable path. Run these steps yourself to migrate without an agent.

1. Check compatibility

pnpm dlx vinext check

The scanner reports known unsupported configuration, imports, and project patterns. Also check the compatibility dashboard and open issues for behavior specific to your application.

2. Initialize vinext

pnpm dlx vinext init

Choose Cloudflare or Node when prompted. The command installs the required packages, adds ESM and Vite configuration, and creates deployment config for the selected platform.

For a non-interactive run, pass the choices explicitly:

pnpm dlx vinext init --platform=cloudflare --cdn-cache=none --data-cache=none --image-optimization=none
pnpm dlx vinext init --platform=node

For Cloudflare, agents and CI must pass all three of --cdn-cache, --data-cache, and --image-optimization. The Cloudflare command above chooses no cache and no image optimization; see Run init without prompts for the other values.

3. Run both toolchains

pnpm dev:vinext
pnpm build:vinext
pnpm dev

Compare the routes and workflows your application depends on. Start with authentication, middleware, mutations, caching, and deployment bindings rather than only checking the home page.

Styling

CSS Modules

If the project contains CSS Modules, init adds vite-css-modules and configures stable class names so PostCSS runs before class scoping. It updates inline Vite config objects automatically. For dynamic configs (factories, spreads, identifier exports, or CommonJS), init stops before changing the project rather than guessing how to rewrite the config. To continue with init, convert the Vite config to an inline object; otherwise finish the migration manually with equivalent CSS settings:

import { createHash } from "node:crypto";
import path from "node:path";
import { patchCssModules } from "vite-css-modules";
import { defineConfig } from "vite";
import vinext from "vinext";

export default defineConfig({
  plugins: [patchCssModules({ exportMode: "default" }), vinext()],
  css: {
    modules: {
      generateScopedName(name: string, filename: string) {
        const relativePath = path
          .relative(import.meta.dirname, filename.replace(/\?.*$/, ""))
          .replaceAll("\\", "/");
        return `_${name}_${createHash("sha256").update(relativePath).digest("hex").slice(0, 7)}`;
      },
    },
  },
});

Keep any other plugins and options in your existing config; place patchCssModules before vinext.