Migrate to Netlify from Vercel

A step-by-step guide to moving a site from Vercel to Netlify, covering build settings, environment variables, redirects, headers, functions, and DNS cutover with zero downtime.

Migration

Most of a Vercel project maps onto Netlify with small, mechanical changes: build settings move to netlify.toml, vercel.json redirects become _redirects rules, and functions keep the same Web Request/Response handler you already wrote. This guide walks through each piece in the order you should tackle it, gathering the config from Vercel first and setting it up on Netlify second.

There is no one-click importer. You can translate the configuration by hand, or ask an AI coding agent to do it for you. For a typical site that takes a couple of hours; for a large app with custom middleware and dozens of functions, plan a day and test on a preview URL before you move DNS.

Work through the sections in this order:

  1. Create the Netlify site
  2. Build settings
  3. Environment variables
  4. Redirects and rewrites
  5. Custom headers
  6. Functions
  7. Middleware and edge functions
  8. Next.js specifics
  9. Custom domains and DNS cutover

1. Create the Netlify site

Connect your Git repository first, before you touch any configuration. In Netlify, choose Add new site, then Import an existing project, and pick your repo. Netlify connects to GitHub, GitLab, Bitbucket, and Azure DevOps (Git workflows).

Netlify detects most frameworks and pre-fills the build command and publish directory. You will confirm those in the next step. Every push now builds a deploy, and every pull request gets its own Deploy Preview, the same way Vercel’s preview deployments work.

2. Build settings

Gather from Vercel. In your Vercel project settings, note the Build Command, Output Directory, and Root Directory. If you keep a vercel.json, check it for a buildCommand and outputDirectory.

Set up on Netlify. Put the equivalent in a netlify.toml file at the repository root (file-based configuration):

[build]
base = "" # Root Directory, if your app lives in a subfolder
command = "npm run build"
publish = "dist" # Vercel's Output Directory

Vercel’s Output Directory maps to Netlify’s publish. For a monorepo, set base to the app’s subfolder.

3. Environment variables

Gather from Vercel. Export your variables from the Vercel project’s Environment Variables page. Note which values are scoped to Production, Preview, or Development.

Set up on Netlify. Add them in the UI under Site configuration, then Environment variables, or import a .env file with the CLI:

netlify env:import .env

Netlify scopes variables by deploy context: production, deploy previews, and branch deploys (including wildcards like release/*). Map Vercel’s Preview scope to Netlify’s deploy-preview context. Set secrets and runtime values in the UI or CLI, where you can scope them by context; netlify.toml values apply at build time, so keep non-secret build defaults there.

4. Redirects and rewrites

Gather from Vercel. Collect the redirects and rewrites arrays from vercel.json (or the redirects()/rewrites() functions in next.config.js). Each entry has a source, a destination, and, for redirects, a permanent flag.

Set up on Netlify. Netlify uses one mechanism for both. A rule with status 301 redirects; a rule with status 200 rewrites, keeping the URL in the bar while serving different content (redirects overview). Add them to netlify.toml:

[[redirects]]
from = "/old-path"
to = "/new-path"
status = 301 # permanent redirect (Vercel's permanent: true)
[[redirects]]
from = "/api/*"
to = "/.netlify/functions/:splat"
status = 200 # rewrite (Vercel's rewrites)

Wildcards (*) and named parameters (:slug) work the way splats and dynamic segments do on Vercel. Netlify processes a _redirects file before netlify.toml, and the first matching rule wins.

5. Custom headers

Gather from Vercel. Copy the headers array from vercel.json (or next.config.js), including any source path matching.

Set up on Netlify. Use [[headers]] tables in netlify.toml or a _headers file (headers docs):

[[headers]]
for = "/*"
[headers.values]
X-Frame-Options = "DENY"
Cache-Control = "public, max-age=0, must-revalidate"

6. Functions

Your handler code ports with little change. Both platforms now use standard Web Request and Response objects.

Gather from Vercel. Vercel functions live in an api/ directory. Note the runtime each one targets.

Set up on Netlify. Move them to netlify/functions/ (Functions overview). A modern Netlify function looks like this:

import type { Config, Context } from '@netlify/functions';
export default async (req: Request, context: Context) => {
return new Response('Hello from Netlify');
};
export const config: Config = {
path: '/api/hello',
};

The handler body is the same Web-standard code you would write on Vercel. The config export with a path replaces Vercel’s file-path routing and lets you serve the function at a clean URL. Netlify Functions run JavaScript/TypeScript and Go; Edge Functions (next section) run on Deno.

7. Middleware and edge functions

Gather from Vercel. Vercel puts middleware in a single middleware.ts at the project root, with an exported config.matcher.

Set up on Netlify. Netlify edge functions serve the same role: they intercept and transform requests at the edge on a Deno runtime (Edge Functions overview). Place them in netlify/edge-functions/:

import type { Config, Context } from '@netlify/edge-functions';
export default async (request: Request, context: Context) => {
// rewrite, redirect, or add headers at the edge
return context.next();
};
export const config: Config = { path: '/*' };

The path in config replaces Vercel’s matcher.

8. Next.js specifics

Netlify runs Next.js on the OpenNext adapter, an open-source runtime that Netlify co-maintains (Next.js on Netlify). Because the adapter is open source, your Next.js app does not depend on a single vendor’s proprietary runtime to deploy and run.

What carries over:

  • App Router and Pages Router both work, no config needed. Netlify supports Next.js 13.5 and up on the OpenNext adapter and detects it automatically; older versions fall back to the legacy runtime.
  • Incremental Static Regeneration is supported, including on-demand, time-based, tag-based, and path-based revalidation.
  • next/image optimization runs through the Netlify Image CDN by default.
  • Middleware runs as an edge function.

A few honest limitations to check before you cut over: rewrites cannot target files in public/, Node middleware does not expose C++ addons or the filesystem API, and Netlify Forms needs extra wiring with Next.js. Vercel remains the reference implementation for the newest Next.js edge features, so test any bleeding-edge feature on a Netlify preview first.

9. Custom domains and DNS cutover

Do this last, once the site builds and works on its netlify.app URL and a Deploy Preview. This keeps downtime near zero.

  1. In Netlify, add your custom domain under domain management.
  2. Keep your DNS where it is and point records at Netlify (external DNS):
    • Apex domain: an ALIAS, ANAME, or flattened CNAME to apex-loadbalancer.netlify.com, or an A record to 75.2.60.5.
    • Subdomain (like www): a CNAME to your-site.netlify.app.
  3. Netlify provisions a free Let’s Encrypt TLS certificate automatically once DNS validates. HTTPS needs no manual setup.

DNS propagation can take up to 48 hours, though most records update within an hour. Because Vercel still serves the old records until propagation completes, visitors reach one platform or the other throughout, never an error page. Once traffic has shifted and you have watched it for a day, remove the domain from Vercel.

What you gain, and what to weigh

Netlify’s genuine advantages after a move:

  • No framework lock-in. Next.js runs on the open-source OpenNext adapter, and functions use Web-standard handlers, so your code stays portable.
  • Deploy Previews on four Git providers, not just GitHub.
  • Commercial use allowed on the free plan, where Vercel’s Hobby tier is personal, non-commercial use only.

Weigh these fairly against the tradeoffs. Netlify moved to credit-based pricing (the Free plan includes 300 credits per month), which some teams find harder to forecast than flat tiers, and Vercel ships the newest Next.js edge features first. Test your specific app on a preview before you commit.

Resources