This guide shows you how to move an application from Vercel to Cloudflare Workers. Workers runs your framework's server code and serves its static assets from a single Worker.
Each framework guide includes a prompt for your coding agent and the equivalent manual steps. Every guide was tested end to end by migrating a real Vercel-hosted application.
| Framework | Guide | What changes |
|---|---|---|
| Astro | Migrate Astro from Vercel | @astrojs/vercel is replaced by @astrojs/cloudflare |
| Next.js | Migrate Next.js from Vercel | vinext runs your Next.js app on Vite and Workers |
| Nuxt | Migrate Nuxt from Vercel | The Nitro vercel preset is replaced by cloudflare_module |
| Remix and React Router | Migrate React Router from Vercel | @vercel/remix is replaced by the Cloudflare Vite plugin |
| SvelteKit | Migrate SvelteKit from Vercel | adapter-vercel is replaced by adapter-cloudflare |
| TanStack Start | Migrate TanStack Start from Vercel | The Nitro Vite plugin is replaced by the Cloudflare Vite plugin |
| Static site or single-page app | Migrate a static site from Vercel | A Wrangler configuration file points to your build output |
For other frameworks, refer to the framework guides and the rest of this page.
These steps apply to every framework:
- Install dependencies before you run any migration tool. Automatic project configuration cannot detect your framework without
node_modules. - If you use pnpm 10 or later, allow the
esbuildandworkerdbuild scripts. Otherwise, installs fail withERR_PNPM_IGNORED_BUILDS. Runpnpm approve-builds --all, or add the packages toallowBuildsinpnpm-workspace.yaml. - Set the Worker
nameexplicitly. Migration tools default to thenamefield inpackage.json, which is often a template name. - Use a compatibility date of
2026-08-04or later, for example today. Node.js compatibility is on by default for these dates, so new configurations do not need thenodejs_compatflag. Existing configurations can keep it. For more information, refer to Node.js compatibility flag. - Add
.wrangler/and.dev.vars*to.gitignore. - If your account has access to more than one Cloudflare account, set the
CLOUDFLARE_ACCOUNT_IDenvironment variable before you deploy.
To migrate a project that does not render pages on the server, refer to Migrate a static site or SPA from Vercel to Cloudflare Workers.
Each Vercel feature has a Cloudflare equivalent:
| Vercel feature | Cloudflare equivalent |
|---|---|
| Analytics and Speed Insights | Web Analytics |
| Blob | R2 |
| Cron Jobs | Cron Triggers with a scheduled() handler |
| Edge Config | Workers KV |
| Environment variables | Environment variables and secrets |
| Functions, Edge Functions, Middleware | One Worker, built by your framework adapter |
| Git integration and preview URLs | Workers Builds and preview URLs |
| Image Optimization | Images binding or image transformations |
ISR and s-maxage caching |
Prerendering, or your framework's Cloudflare cache integration. Refer to Replace ISR and edge caching. |
| KV and Upstash Redis | Workers KV, or keep Upstash and connect over HTTP |
| Postgres | Keep your database and connect with Hyperdrive, or use D1 |
| Queues | Queues |
vercel.json headers and redirects |
Framework configuration, or _headers and _redirects for static assets |
Vercel-specific URLs, such as /_vercel/image and /_vercel/insights, return 404 after you migrate. Update any references to them.
To copy production environment variables from Vercel to your Worker:
-
Pull the production environment variables with the Vercel CLI:
vercel env pull .env.production.local --environment=productionVercel does not return the values of sensitive environment variables. Add those values to the file manually.
-
Upload the variables as Worker secrets:
npx wrangler secret bulk .env.production.localyarn wrangler secret bulk .env.production.localpnpm wrangler secret bulk .env.production.local -
Delete
.env.production.localafter the upload.
Store non-secret values in vars in your Wrangler configuration file. Store local development secrets in a .dev.vars file. Public build-time variables, such as NEXT_PUBLIC_*, VITE_*, and PUBLIC_*, must exist when your project builds. If you use Workers Builds, add them as build variables.
Vercel serves hashed build assets with a one-year immutable cache. Workers serves static assets with max-age=0, must-revalidate by default. To restore long-lived caching, add a _headers file to your static directory. Adjust the path to match your framework's asset directory:
/assets/*
Cache-Control: public, max-age=31536000, immutableSvelteKit and Nuxt generate a _headers file for you. Cloudflare applies every _headers rule that matches a path. To replace a header value from a less specific rule, add ! Header-Name before the new value. For more information, refer to Headers.
On Vercel, a Cache-Control: s-maxage header caches server-rendered responses at the edge. On Workers, turn on Workers Cache to cache your Worker's responses based on the Cache-Control headers they return. Workers Cache requires Wrangler 4.69.0 or later.
{
"cache": {
"enabled": true,
},
}[cache]
enabled = trueWorkers Cache does not serve stale responses that include s-maxage, even if they also set stale-while-revalidate. For more information, refer to Cache-Control semantics.
When caching is on, all requests to your Worker are billed at the standard request rate, including static asset requests. For more information, refer to Workers Cache pricing.
You can also prerender pages that do not change between deploys, use your framework's Cloudflare cache integration, such as Astro route caching or a vinext cache adapter, or use the Cache API from your server code.
Workers Custom Domains only supports domains that are configured as zones on your account. A zone is a domain, such as example.com, that Cloudflare manages for you, including its DNS and traffic.
To move a domain without downtime:
- Deploy your Worker and test it on its
workers.devURL. Keep Vercel serving production. - Lower the time to live (TTL) of your DNS records.
- Add your domain to Cloudflare as a zone. Confirm that the imported DNS records match your Vercel records, then update the nameservers at your registrar.
- Add a custom domain to your Worker. The custom domain replaces the existing Vercel DNS record for that hostname and issues a certificate.
- Confirm that traffic reaches your Worker, then remove the domain from your Vercel project.
To return to a previous version of your Worker, run:
npx wrangler rollbackyarn wrangler rollbackpnpm wrangler rollbackTo shift traffic gradually between versions, refer to Gradual deployments.
After your custom domain sends requests to Cloudflare Workers, you can delete your Vercel application.
- Review the Workers limits. SSR applications usually need the Workers Paid plan, because the Free plan allows 10 ms of CPU time per request.
- Native Node.js modules, such as
sharpandcanvas, do not run on Workers. Runtime writes to the file system also fail. - On a
workers.devURL, Cloudflare serves a managedrobots.txtfile if your application does not provide one. - For more migration steps, refer to the Cloudflare Pages to Workers migration guide.