astro-webflow-to-vercel
$
npx mdskill add vercel-labs/vercel-kb-skills/astro-webflow-to-vercelMigrate an Astro app from Webflow Cloud to Vercel
- Solves the task of moving an Astro app off Webflow Cloud onto Vercel
- Uses the Vercel CLI, Git, and Astro framework tools
- Detects Webflow Cloud-specific files and configurations in the project
- Updates dependencies, removes Cloudflare-specific code, and deploys to Vercel
SKILL.md
.github/skills/astro-webflow-to-vercelView on GitHub ↗
---
name: astro-webflow-to-vercel
description: "Migrate an Astro application from Webflow Cloud to Vercel. Use this skill when a user wants to move, migrate, or port an Astro app off Webflow Cloud onto Vercel. This covers swapping the @astrojs/cloudflare adapter for @astrojs/vercel, removing Wrangler and the Webflow Cloud config files (webflow.json, wrangler.json, worker-configuration.d.ts), dropping the base path the app mounted under on a Webflow site, removing the Edge runtime directive from API routes, repointing Cloudflare storage bindings read through locals.runtime.env (Object Storage/R2, Key Value Store/Workers KV, SQLite/D1) to Vercel storage, recreating environment variables, and deploying. Triggers include phrases like 'migrate to Vercel', 'move off Webflow Cloud', 'Astro Webflow Cloud to Vercel', or the presence of webflow.json, wrangler.json, @astrojs/cloudflare, or locals.runtime.env in an Astro project. Do not use for non-Astro frameworks or for migrations in the opposite direction (Vercel to Webflow Cloud)."
license: Apache-2.0
compatibility: Requires git or the Vercel CLI, and access to the internet
allowed-tools: Bash(git:*) Bash(vercel:*) Read
metadata:
author: vercel
version: "1.0.0"
one-liner: "Migrate an Astro app from Webflow Cloud to Vercel"
guide: "https://vercel.com/kb/guide/migrate-an-astro-app-from-webflow-cloud-to-vercel"
---
# Migrate Astro from Webflow Cloud to Vercel
## What this skill does
Moving an Astro app from Webflow Cloud to Vercel mostly means swapping the adapter, not rewriting the app. On Webflow Cloud the app runs as a Cloudflare Worker through the `@astrojs/cloudflare` adapter, served from a mount path inside a Webflow site. On Vercel the same app runs on Vercel Functions with Fluid compute on by default, in a full Node.js runtime, served from the root, so it scales with traffic on its own and supports Astro's full on-demand rendering feature set.
The app code (pages, components, Server Endpoints) mostly stays the same. The work sits in a few places: the Astro adapter and config, the Webflow Cloud and Wrangler config files that get deleted, the base path the app mounted under, the Edge runtime directive on API routes, and any server code that read storage bindings through `locals.runtime.env`.
## The Vercel Plugin
The user will have installed the [Vercel Plugin](https://vercel.com/docs/agent-resources/vercel-plugin.md) already, which among other things includes a number of helpful skills that can assist you and the user with this migration. Prefer those skills for current, detailed product guidance, and let this skill drive the order of work. The ones that line up with these steps:
- `vercel-storage` and `marketplace`: step 5 (Blob, Edge Config, Neon, Upstash, and Marketplace provisioning).
- `env-vars`: steps 5 and 6 (`vercel env`, `.env` files, OIDC tokens).
- `vercel-cli` and `deployments-cicd`: steps 6 and 7 (env vars and deploy).
- `vercel-functions`: step 5 (Server Endpoints on Vercel Functions) and the Best practices section (`maxDuration`, regions, ISR).
There are other skills included that may assist with the migration.
## Steps the user completes manually
You handle most of the migration directly by editing files and running commands. A few actions need the Vercel dashboard, a Vercel account, or secret values, so the user has to do those:
- Creating the Vercel account (see Before you start).
- Creating and connecting the backing stores in step 5.
- Adding environment variables in step 6.
- Deploying in step 7.
Guide the user through each of these. Give clear, specific instructions, then wait for them to confirm before moving on. Do not report any of them as done while the user still has to do it.
If you are unsure about a dashboard flow or whether a detail is still current, use an applicable Vercel skill when one is available (see "The Vercel Plugin" above), and check the latest with a web search scoped to the vercel.com domain (for example, `site:vercel.com vercel blob oidc token`).
## Service mapping (quick reference)
| Webflow Cloud | Vercel |
| --- | --- |
| Cloudflare Workers runtime (`workerd`) | [Vercel Functions](https://vercel.com/docs/functions) (Fluid compute) |
| `@astrojs/cloudflare` adapter | `@astrojs/vercel` adapter |
| `platformProxy` (adapter option for local dev) | Not needed |
| `react-dom/server.edge` Vite alias | Not needed (full Node.js runtime) |
| `webflow.json` | Not needed, Astro is auto-detected |
| `wrangler.json` | `vercel.json` (optional) |
| `worker-configuration.d.ts` | Not needed |
| `base` and `build.assetsPrefix` (mount path) | Served from the root; remove unless you want a base path |
| `locals.runtime.env` / `Astro.locals.runtime.env` | `process.env` |
| `dev.vars` (local runtime variables) | `.env` via `vercel env pull` |
| `webflow cloud deploy` or GitHub push | Git push or the `vercel` CLI |
| Object Storage (R2 binding) | [Vercel Blob](https://vercel.com/storage/blob) |
| Key Value Store (Workers KV binding) | [Redis on the Vercel Marketplace](https://vercel.com/marketplace?search=Redis), or [Edge Config](https://vercel.com/storage/edge-config) for read-heavy config |
| SQLite (D1 binding) | [Postgres on the Vercel Marketplace](https://vercel.com/marketplace?search=postgres) |
| `export const config = { runtime: 'edge' }` on routes | Remove it to run on Node.js (recommended) |
| Edge runtime API routes | Astro Server Endpoints on Vercel Functions |
| Astro middleware on the Edge runtime | Astro middleware on Vercel Functions, or at the Edge with `middlewareMode: 'edge'` |
| No scheduled jobs, queues, or workflows | New on Vercel: [Cron Jobs](https://vercel.com/docs/cron-jobs), [Queues](https://vercel.com/docs/queues), and [Workflows](https://vercel.com/workflows) |
## Before you start
Check the repo for these, and ask the user to confirm anything the repo cannot show:
- A working Astro app deployed on Webflow Cloud. Look for `astro` in `package.json` and the `@astrojs/cloudflare` adapter in `astro.config.mjs` to confirm the framework and platform before changing anything.
- Node.js 20 or later.
- A Vercel account (the user confirms this; you cannot create one).
- The Vercel CLI, for the env and deploy steps: `npm i -g vercel`.
Do not use this skill for a different framework, a brand-new app (set it up for Vercel directly instead), or a move in the other direction (Vercel to Webflow Cloud).
## Steps
Work through these in order. Step 0 tells you which of steps 3 and 5 apply, so you can skip what the app does not use.
### Step 0: Audit the current Webflow Cloud setup
Run the audit script from the project root:
```bash
bash scripts/audit.sh /path/to/project
```
It reports the Webflow Cloud and Wrangler config files, the `@astrojs/cloudflare` adapter and its `platformProxy` option, the `react-dom/server.edge` Vite alias, the base path (`base` and `build.assetsPrefix`) and its manual prefixing, any `runtime: 'edge'` directives on routes, every `locals.runtime.env` / `Astro.locals.runtime.env` access, and which storage bindings are declared in `wrangler.json` (Object Storage, Key Value Store, SQLite). Use the output to pick which later steps apply, then show the user a short checklist. Skipping this leads to missed bindings and runtime errors.
### Step 1: Replace the Cloudflare adapter with the Vercel adapter
Astro needs an adapter to server-render on each platform, so the core setup change is swapping one adapter for the other. Uninstall the Cloudflare adapter and Wrangler, then install the Vercel adapter:
```bash
npm uninstall @astrojs/cloudflare wrangler
npm install @astrojs/vercel
```
Update `astro.config.mjs` to import and use the Vercel adapter. Keep `output: "server"` to render every route on demand as a Vercel function, which matches how the app ran on Webflow Cloud:
```js
import { defineConfig } from "astro/config";
import vercel from "@astrojs/vercel";
import react from "@astrojs/react";
export default defineConfig({
output: "server",
adapter: vercel(),
integrations: [react()],
});
```
The `react()` integration above is only an example; keep whatever integrations the app already declares and just swap the adapter.
If most pages are static and only a few are dynamic, set `output: "static"` instead and add `export const prerender = false` to the components that need server rendering.
Two Cloudflare-specific options can go at the same time. Remove the `platformProxy` setting, which only configured the Workers runtime for local development, and remove the `react-dom/server.edge` Vite alias, a Workers workaround the Node.js runtime doesn't need.
### Step 2: Remove the Webflow Cloud configuration files
Delete the Cloudflare- and Webflow-specific files that no longer apply on Vercel:
- `webflow.json`, which told Webflow Cloud your framework. Vercel detects Astro automatically.
- `wrangler.json`, including its `compatibility_date`, `nodejs_compat` flag, `assets` binding, and storage bindings. Vercel Functions run on Node.js, so the compatibility flags have no equivalent.
- `worker-configuration.d.ts`, the generated binding types.
Your storage bindings live in `wrangler.json`. Before deleting the file, note which bindings the app uses (Object Storage, Key Value Store, or SQLite) so you can recreate them on Vercel in step 5.
### Step 3: Remove the base path and Edge runtime settings
On Webflow Cloud the app is served from a mount path such as `/app`, so `base` and `build.assetsPrefix` are set in `astro.config.mjs` to match. On Vercel the app is served from the root, so remove both options unless you intend to keep serving the app under a subpath:
```js
import { defineConfig } from "astro/config";
import vercel from "@astrojs/vercel";
export default defineConfig({
// Remove base and build.assetsPrefix when serving from the root
// base: "/app",
// build: { assetsPrefix: "/app" },
output: "server",
adapter: vercel(),
});
```
Because the base path is gone, remove the manual prefixing Webflow Cloud required in client-side `fetch` calls and asset references. Change `fetch(${import.meta.env.BASE_URL}/api/users)` back to `fetch("/api/users")`, and drop `import.meta.env.ASSETS_PREFIX` from plain `<img>` tags and from the favicon link in your layout.
Webflow Cloud also runs API routes on the Edge runtime. Remove the `export const config = { runtime: 'edge' }` directive from your Server Endpoints so they run on the default Node.js runtime. Migrating from the Edge runtime to Node.js is recommended for performance and reliability, both runtimes run on [Fluid compute](https://vercel.com/fluid) with [Active CPU pricing](https://vercel.com/docs/functions/usage-and-pricing#active-cpu), and Node.js gives your routes the full Node.js API surface and access to npm packages that depend on Node.js built-ins.
### Step 4: Update your build scripts
Replace the Webflow Cloud preview script in `package.json` with the standard Astro commands. Vercel runs the build for you, so you no longer need Wrangler to preview the Workers build:
```json
{
"scripts": {
"dev": "astro dev",
"build": "astro build",
"preview": "astro preview"
}
}
```
Vercel auto-detects Astro on import and sets the build command and output directory, so these scripts mainly support local development.
### Step 5: Replace Webflow Cloud bindings with Vercel storage
This is the main code change. On Webflow Cloud you read storage through bindings on the Cloudflare runtime, accessed in a Server Endpoint through the `locals` object (`locals.runtime.env`) and in components through `Astro.locals.runtime.env`. On Vercel you read connection details from `process.env` and talk to each store through its SDK. Remove every `locals.runtime.env` and `Astro.locals.runtime.env` access, and replace the binding operations. Read `references/service-mapping.md` for the before and after code for each binding, then install the SDK you need, for example:
```bash
npm i @vercel/blob
```
Have the user create and connect the backing stores. This is what adds the env vars the code reads, so it has to be done before the app will run:
- Object Storage to Blob: create a Blob store on the [Storage page](https://vercel.com/d?to=%2F%5Bteam%5D%2F%7E%2Fstores), then connect it to the project from the store's Projects tab. Vercel adds the store's environment variables, including a short-lived `VERCEL_OIDC_TOKEN` that it rotates, and the SDK uses them automatically, so `put()` needs no token in code. This [OIDC approach](https://vercel.com/docs/vercel-blob/using-blob-sdk#oidc-tokens-recommended) is recommended over the long-lived `BLOB_READ_WRITE_TOKEN`, which is only for code that runs outside Vercel.
- Key Value Store to Redis: add a Redis integration such as [Upstash Redis](https://vercel.com/marketplace/upstash) for caching and session data, or use [Edge Config](https://vercel.com/storage/edge-config) for small, read-heavy config.
- SQLite to Postgres: add a Postgres database such as [Neon](https://vercel.com/marketplace/neon). If you used Drizzle ORM with SQLite, Drizzle supports Postgres too, so you keep your schema-first workflow.
Provisioning a store from the Marketplace adds its connection string and credentials as env vars, which the code reads from `process.env`.
### Step 6: Move environment variables and secrets
Recreate your Webflow Cloud environment variables as Vercel environment variables. Webflow Cloud stores these per environment in your app's settings and injects them at runtime only. Vercel stores them per environment (production, preview, and development) in project settings and makes them available at both build time and runtime.
> **Never handle the user's secrets.** Do not ask the user for secret values, and do not accept secrets pasted into the chat. Do not offer to save, enter, or store environment variables or secrets for the user, and refuse if asked to do so. Setting the actual values is the user's job, done in the dashboard or in their own terminal. Your part is to prepare the list of variable names and the exact commands.
You can list every variable and secret to recreate and write out the exact commands, but you cannot supply secret values or sign the CLI in, and you must not make up values.
The user adds each variable, either on the [project's Environment Variables page](https://vercel.com/d?to=%2F%5Bteam%5D%2F%5Bproject%5D%2Fsettings%2Fenvironment-variables) or with the CLI after `vercel login`:
```bash
vercel env add DATABASE_URL production
```
Once the user has signed in, you can link the project and pull the values into a local `.env`:
```bash
vercel link
vercel env pull
```
You can delete the `dev.vars` file Webflow Cloud used for local runtime variables, since Astro loads `.env` automatically. A variable added to production is not available in preview or development unless it is added there too.
The way you read variables changes, too. On Webflow Cloud, custom server variables came from `Astro.locals.runtime.env` in components and `locals.runtime.env` in Server Endpoints. On Vercel's Node.js runtime, read them from `process.env` (for example, `process.env.DATABASE_URL`). For variables you want exposed to client-side code, use Astro's `PUBLIC_` prefix and `import.meta.env`. Because Vercel exposes environment variables during the build, you can re-enable any build-time validation you had to disable on Webflow Cloud, where variables aren't available at build time.
### Step 7: Deploy
You cannot import a project, confirm the framework preset, sign in, or select Deploy, so walk the user through one of these paths. Both run the app on Vercel Functions.
Deploy with Git (recommended):
1. Push the project to GitHub, GitLab, or Bitbucket.
2. In the [Vercel dashboard](https://vercel.com), select Add New > Project, then import the repo.
3. Vercel detects Astro and sets the build command and output directory. Confirm the framework preset, add the environment variables from step 6, and select Deploy.
After the first import, every push to the production branch creates a production deploy, and every pull request gets its own preview URL.
Deploy with the CLI: after `vercel login`, run `vercel` for a preview or `vercel --prod` for production.
If the `vercel-deploy` skill is available, you can use it to create a preview deploy and a claim URL without the user signing in first, which is a good way to check the build before wiring up a connected project.
## After the move: check these
You can grep for the code issues; ask the user to check anything in the dashboard. See `references/troubleshooting.md` for fixes.
- No `@astrojs/cloudflare` import or `platformProxy` option remains in `astro.config.mjs`.
- No `locals.runtime.env` or `Astro.locals.runtime.env` access remains anywhere in server code.
- No leftover base path: `base` and `build.assetsPrefix` are gone, and client-side `fetch` calls, `<img>` tags, and the layout's favicon link no longer prefix `import.meta.env.BASE_URL` or `ASSETS_PREFIX`.
- No `export const config = { runtime: 'edge' }` remains on Server Endpoints.
- Each env var exists in the right environment, not only production.
## Tune after migrating (optional)
- Set function resources in the adapter, such as `adapter: vercel({ maxDuration: 60 })` for routes that need more time, or configure memory and regions in `vercel.json`.
- Put functions near the data: set the function region close to the Marketplace database to cut latency.
- Take advantage of features that were limited on Webflow Cloud: Incremental Static Regeneration (`adapter: vercel({ isr: true })`), Image Optimization with Astro's `Image` component, Web Analytics, and Speed Insights all work with minimal configuration. For scheduled and background work Webflow Cloud didn't offer, look at [Cron Jobs](https://vercel.com/docs/cron-jobs), [Queues](https://vercel.com/docs/queues), and [Workflows](https://vercel.com/workflows).
## References
- [service-mapping](references/service-mapping.md): Before and after code for replacing each Webflow Cloud binding (Object Storage to Blob, Key Value Store to Redis or Edge Config, SQLite to Postgres), plus the store setup notes. Read before step 5.
- [troubleshooting](references/troubleshooting.md): The common errors after the move and how to fix them.
More from vercel-labs/vercel-kb-skills
- nextjs-webflow-to-vercelMigrate a Next.js application from Webflow Cloud to Vercel. Use this skill when a user wants to move, migrate, or port a Next.js app off Webflow Cloud onto Vercel. This covers removing the OpenNext Cloudflare adapter (@opennextjs/cloudflare) and the initOpenNextCloudflareForDev dev hook, uninstalling Wrangler, deleting the Webflow Cloud config files (webflow.json, wrangler.json, open-next.config.ts, cloudflare-env.d.ts), dropping the base path the app mounted under on a Webflow site (basePath and assetPrefix in next.config.ts), removing the Edge runtime directive (export const runtime = 'edge') from Route Handlers and middleware, repointing Cloudflare storage bindings read through getCloudflareContext().env (Object Storage/R2, Key Value Store/Workers KV, SQLite/D1) to Vercel storage, recreating environment variables, and deploying. Next.js runs natively on Vercel, so no adapter replaces OpenNext. Triggers include phrases like 'migrate to Vercel', 'move off Webflow Cloud', 'Next.js Webflow Cloud to Vercel', or the presence of webflow.json, wrangler.json, @opennextjs/cloudflare, open-next.config.ts, or getCloudflareContext in a Next.js project. Do not use for non-Next.js frameworks or for migrations in the opposite direction (Vercel to Webflow Cloud).
- tanstack-start-cloudflare-to-vercelMigrate a TanStack Start application from Cloudflare Workers to Vercel. Use this skill when a user wants to move, migrate, or port a TanStack Start (or TanStack) app off Cloudflare Workers or Wrangler onto Vercel. This covers swapping the @cloudflare/vite-plugin for Nitro, removing Wrangler config, repointing Cloudflare bindings (R2, Workers KV, D1, Durable Objects, Workers AI) to Vercel storage, and moving Cron Triggers and Queues to their Vercel equivalents, then deploying. Triggers include phrases like 'migrate to Vercel', 'move off Cloudflare', 'TanStack Start Cloudflare to Vercel', or the presence of wrangler.jsonc, wrangler.toml, or cloudflare:workers imports in a TanStack project. Do not use for non-TanStack frameworks or for migrations in the opposite direction (Vercel to Cloudflare).
- tanstack-start-netlify-to-vercelMigrate a TanStack Start application from Netlify to Vercel. Use this skill when a user wants to move, migrate, or port a TanStack Start (or TanStack) app off Netlify onto Vercel. This covers swapping @netlify/vite-plugin-tanstack-start for Nitro, removing netlify.toml, repointing Netlify Blobs and Netlify DB to Vercel storage (Vercel Blob, Redis, Edge Config, Postgres), and moving Scheduled Functions and Background Functions to their Vercel equivalents (Cron Jobs and Queues), then deploying. Triggers include phrases like 'migrate to Vercel', 'move off Netlify', 'TanStack Start Netlify to Vercel', or the presence of netlify.toml, @netlify/vite-plugin-tanstack-start, or @netlify/blobs imports in a TanStack project. Do not use for non-TanStack frameworks or for migrations in the opposite direction (Vercel to Netlify).