---
description: Migrate a Next.js application from Vercel to Cloudflare Workers with vinext, which runs Next.js on Vite. Includes a prompt for your coding agent.
title: Migrate Next.js from Vercel to Cloudflare Workers with vinext
image: https://developers.cloudflare.com/workers/static-assets/migration-guides/vercel-to-workers/nextjs/og.png?v=16f36763ef781121
---

[Skip to content](#main-content)

> Documentation Index  
> Fetch the complete documentation index at: https://developers.cloudflare.com/workers/llms.txt  
> Use this file to discover all available pages before exploring further.

# Migrate Next.js from Vercel to Cloudflare Workers with vinext

Last updated Nov 5, 2026|Copy as Markdown| [View as Markdown](https://developers.cloudflare.com/workers/static-assets/migration-guides/vercel-to-workers/nextjs/index.md)| [Agent setup](https://developers.cloudflare.com/agent-setup/)

This guide moves a Next.js application from Vercel to Cloudflare Workers with [vinext ↗︎](https://github.com/cloudflare/vinext). vinext reimplements the Next.js API on Vite and deploys to Workers.

Your `app/`, `pages/`, `next.config.*`, and `public/` directories stay the same. `next dev` and `next build` keep working after the migration.

## Before you begin

- vinext aims to support Next.js 14 and later. Partial Prerendering support is in progress. To check your application's compatibility with vinext, run `npx vinext check`.
- vinext uses `cloudflare.config.ts` instead of a Wrangler configuration file, and deploys with the `cf` CLI. The Worker name is the `worker.name` value in that file.
- Run `vinext init` directly instead of `wrangler setup`. [Automatic project configuration](https://developers.cloudflare.com/workers/framework-guides/automatic-configuration/#nextjs-configuration) with Wrangler configures OpenNext, not vinext.
- Review the steps in [Before you begin](https://developers.cloudflare.com/workers/static-assets/migration-guides/vercel-to-workers/#before-you-begin) that apply to every framework.

## Migrate with a coding agent

Copy this prompt into your coding agent. The agent stops before it deploys.

```txt
Migrate this Next.js app from Vercel to Cloudflare Workers using vinext (https://github.com/cloudflare/vinext).

1. Check the installed "next" version in package.json and the lockfile. Do not use `npx wrangler setup`, because it configures OpenNext.
2. Run `npx vinext check` and summarize the report. Stop and ask me if there are critical incompatibilities.
3. Choose the init flags. `vinext init` fails without a terminal unless you pass all of them:
   - --name <repository name>. Without it, the Worker uses the package.json "name".
   - Caching: if the app has no ISR (export const revalidate, fetch next.revalidate), no revalidatePath or revalidateTag, and no "use cache", use --cdn-cache=none --data-cache=none. Otherwise, use --cdn-cache=response-store --response-store-mode=self-contained --data-cache=none. Workers Response Store caches both responses and data, so do not add --data-cache=kv.
   - Images: use --image-optimization=cloudflare-images only if next/image renders raster (PNG, JPEG, WebP, AVIF) or remote images. Otherwise, use --image-optimization=none.
   Then run: npx vinext init --platform=cloudflare --name <name> --cdn-cache=<value> --data-cache=<value> --image-optimization=<value>
   Read every file that init creates or changes. Add ".cloudflare/types" to tsconfig.json "include". Add ".cloudflare/**", ".vinext/**", and "dist/**" to the ESLint ignores. Do not add "nodejs_compat" to compatibilityFlags. A compatibility date of 2026-08-04 or later already enables it. Do not register @vitejs/plugin-rsc manually. Do not add a wrangler.jsonc file.
4. Do not modify app/ or pages/ beyond the replacements in step 5. Do not rewrite next/* imports. Do not delete next.config.*.
5. Replace Vercel features:
   - Move vercel.json redirects, rewrites, and headers into next.config redirects(), rewrites(), and headers(). List any crons and ask me how to handle them.
   - Replace @vercel/kv with Workers KV, @vercel/blob with R2, @vercel/postgres with Hyperdrive or D1 (ask me), and @vercel/edge-config with KV. Declare bindings in cloudflare.config.ts and read them with `import { env } from "cloudflare:workers"`. Run `npx cf workers types` after you change bindings.
   - Remove @vercel/analytics and @vercel/speed-insights, or ask me about Cloudflare Web Analytics.
   - Replace native modules such as sharp, @resvg/resvg-js, and @napi-rs/canvas.
6. Verify:
   - Run `<pm> run dev:vinext -- --port <free port>` and check the main routes.
   - Run `<pm> run build:vinext`, then `<pm> run start:vinext -- --port <free port>`, and check the routes again. This runs the built Worker locally.
   - Confirm that lint, type checking, and `next dev` still work.

Rules: work on a new git branch; use the repository's package manager; never print secret values; do not deploy, log in, or change DNS.
When you finish, list the files you changed, the Vercel features that were replaced or are unsupported, and the secrets I must set. Give me the deploy commands: `npx cf auth login`, then `npx @vinext/cloudflare deploy --dry-run`, then `npx @vinext/cloudflare deploy`. Remind me that NEXT_PUBLIC_* values must exist at build time.
```

vinext also provides a `migrate-to-vinext` agent skill. To install it, run `npx skills add cloudflare/vinext`.

## Migrate manually

1. Check that your application is compatible with vinext:npmyarnpnpm

   ```
   npx vinext check
   ```

   ```
   yarn dlx vinext check
   ```

   ```
   pnpx vinext check
   ```

2. Initialize vinext with the cache and image options your application needs. All three options are required when you run `vinext init` without an interactive terminal.npmyarnpnpm

   ```
   npx vinext init --platform=cloudflare --name <YOUR_WORKER_NAME> --cdn-cache=none --data-cache=none --image-optimization=none
   ```

   ```
   yarn dlx vinext init --platform=cloudflare --name <YOUR_WORKER_NAME> --cdn-cache=none --data-cache=none --image-optimization=none
   ```

   ```
   pnpx vinext init --platform=cloudflare --name <YOUR_WORKER_NAME> --cdn-cache=none --data-cache=none --image-optimization=none
   ```

   Change the options if your application needs them:

   | Your application uses | Option |
   | --- | --- |
   | ISR, `revalidatePath`, `revalidateTag`, or `"use cache"` | `--cdn-cache=response-store --response-store-mode=self-contained` |
   | `next/image` with raster or remote images | `--image-optimization=cloudflare-images` |

   Workers Response Store caches both rendered responses and data, so keep `--data-cache=none` when you use it. In self-contained mode, your application Worker owns the R2 bucket and Durable Object that the cache uses. To run the cache in a separate Worker, use `--response-store-mode=service-binding` instead, and deploy the cache Worker with the `deploy:response-store` script before you deploy your application. For more information, refer to [Caching in vinext ↗︎](https://vinext.dev/docs/guides/caching).

   `vinext init` adds dependencies, `vite.config.ts`, `cloudflare.config.ts`, and the `dev:vinext`, `build:vinext`, `start:vinext`, and `deploy:vinext` scripts. It can also upgrade `react` and `react-dom`.

   You do not need `nodejs_compat` in `compatibilityFlags`. A compatibility date of `2026-08-04` or later enables Node.js compatibility by default.
3. Add `.cloudflare/types` to the `include` array in `tsconfig.json`. Add `.cloudflare/**`, `.vinext/**`, and `dist/**` to your ESLint ignores.
4. Replace Vercel-specific packages. Declare bindings in `cloudflare.config.ts`, and read them in Server Components, Route Handlers, and Server Actions:

   ```ts
   import { env } from "cloudflare:workers";
   ```

5. Start the vinext development server:npmyarnpnpm

   ```
   npm run dev:vinext
   ```

   ```
   yarn run dev:vinext
   ```

   ```
   pnpm run dev:vinext
   ```

6. Build your application and run the built Worker locally:npmyarnpnpm

   ```
   npm run build:vinext
   ```

   ```
   yarn run build:vinext
   ```

   ```
   pnpm run build:vinext
   ```

   npmyarnpnpm

   ```
   npm run start:vinext
   ```

   ```
   yarn run start:vinext
   ```

   ```
   pnpm run start:vinext
   ```

7. Log in with the Cloudflare CLI and deploy your application:npmyarnpnpm

   ```
   npx cf auth login
   ```

   ```
   yarn dlx cf auth login
   ```

   ```
   pnpx cf auth login
   ```

   npmyarnpnpm

   ```
   npx @vinext/cloudflare deploy
   ```

   ```
   yarn dlx @vinext/cloudflare deploy
   ```

   ```
   pnpx @vinext/cloudflare deploy
   ```

## Map Next.js features on vinext

These Vercel and Next.js features behave differently on vinext:

| Feature | Behavior on vinext |
| --- | --- |
| ISR, `revalidatePath`, and `revalidateTag` | Supported. Choose a persistent cache when you run `vinext init`. The default cache is in memory. |
| `next/font/google` | Supported. Fonts are downloaded at build time and served from your Worker. |
| `next/image` | Without an optimizer, `/_next/image` redirects to the original file. |
| `runtime` and `preferredRegion` route options | Ignored. Every route runs on Workers. |
| `vercel.json` | Not read. Move its rules into `next.config`. |
| `@vercel/kv`, `@vercel/blob`, `@vercel/postgres` | Not supported. Use [Workers KV](https://developers.cloudflare.com/kv/), [R2](https://developers.cloudflare.com/r2/), and [Hyperdrive](https://developers.cloudflare.com/hyperdrive/) or [D1](https://developers.cloudflare.com/d1/). |

## Known issues

- **`vinext init` exits with `vinext init needs Cloudflare cache and image choices`.** Coding agents run without an interactive terminal. Pass `--cdn-cache`, `--data-cache`, and `--image-optimization`.
- **The Worker uses the wrong name.** Pass `--name` to `vinext init`, or edit `worker.name` in `cloudflare.config.ts`. The `--name` option of `@vinext/cloudflare deploy` does not apply to `cloudflare.config.ts` projects.
- **ESLint reports thousands of problems after the first build.** ESLint lints the `.cloudflare/` build output. Add the build directories to your ESLint ignores.
- **Deploy prompts for an account.** Set the `CLOUDFLARE_ACCOUNT_ID` environment variable, or add `accountId` to `cloudflare.config.ts`.

## Related resources

- [Next.js framework guide](https://developers.cloudflare.com/workers/framework-guides/web-apps/nextjs/)
- [vinext compatibility ↗︎](https://vinext.dev/compatibility)
- [Caching in vinext ↗︎](https://vinext.dev/docs/guides/caching)
- [Migrate from Vercel to Workers](https://developers.cloudflare.com/workers/static-assets/migration-guides/vercel-to-workers/)

Was this helpful?

YesNo

## On this page

[![](https://developers.cloudflare.com/_astro/logo.te5VL_aD.svg)Docs](https://developers.cloudflare.com/)

```json
{"@context":"https://schema.org","@type":"TechArticle","@id":"https://developers.cloudflare.com/workers/static-assets/migration-guides/vercel-to-workers/nextjs/#page","headline":"Migrate Next.js from Vercel to Cloudflare Workers with vinext","description":"Migrate a Next.js application from Vercel to Cloudflare Workers with vinext, which runs Next.js on Vite. Includes a prompt for your coding agent.","url":"https://developers.cloudflare.com/workers/static-assets/migration-guides/vercel-to-workers/nextjs/","inLanguage":"en","image":"https://developers.cloudflare.com/workers/static-assets/migration-guides/vercel-to-workers/nextjs/og.png?v=16f36763ef781121","dateModified":"2026-11-05","publisher":{"@type":"Organization","name":"Cloudflare","description":"One platform for your apps, agents, and workforce. Build, secure, and scale without managing infrastructure","url":"https://www.cloudflare.com/","sameAs":["https://github.com/cloudflare","https://www.linkedin.com/company/cloudflare","https://x.com/cloudflare"],"logo":{"@type":"ImageObject","url":"https://developers.cloudflare.com/logo.svg"},"address":{"@type":"PostalAddress","streetAddress":"101 Townsend St","addressLocality":"San Francisco","addressRegion":"CA","postalCode":"94107","addressCountry":"US"},"contactPoint":[{"@type":"ContactPoint","contactType":"Customer Support","url":"https://support.cloudflare.com/","availableLanguage":["English"]},{"@type":"ContactPoint","contactType":"Sales","url":"https://www.cloudflare.com/contact/","availableLanguage":["English"]}]},"isPartOf":{"@type":"WebSite","@id":"https://developers.cloudflare.com/#website","name":"Cloudflare Docs","url":"https://developers.cloudflare.com/"}}
```
