# Migrate to Vercel from Netlify

**Author:** Jason Hoch

---

In this guide, you will go through all the steps needed to migrate your Netlify application to Vercel.

## Project Creation

Before you can start the migration you need to create a project on Vercel. This [Getting Started](https://vercel.com/docs/concepts/get-started/deploy) guide will instruct you on how to add your project to Vercel.

Once the setup is complete, you can start migrating your application settings.

## Custom Domains

To migrate your domains to Vercel, refer to the following documentation:

- [Custom Domains](https://vercel.com/docs/concepts/projects/custom-domains)
  
- [Zero-Downtime Domain Migration with Vercel](https://vercel.com/guides/zero-downtime-migration-for-dns)
  

## Build Settings

Vercel will automatically detect the framework and any necessary build settings. However, you may have custom settings in [Netlify](https://vercel.com/kb/guide/vercel-vs-netlify) that you need to migrate. You need to find the settings which can be found in either the UI or your `netlify.toml` file.

### Gathering Netlify Build Data

#### 1\. Netlify UI Build Settings

Open your project in Netlify and find the `Site Settings`.

Select `Build and Deploy` from the left navigation. The `Build Settings` section includes the information Vercel needs to build and deploy your application.

The three fields that need to be copied to Vercel are:

- Base Directory
  
- Build Command
  
- Publish Directory
  

#### 2. `netlify.toml` File Build Settings

In your `netlify.toml` file, the build settings will be signified by a `[build]` table which lists all the currently configured options for each command. Inside the `netlify.toml` file you can set a custom command to ignore builds signified by the `ignore` key. `[build] base = "project/" publish = "build-output/" command = "echo 'default context'" ignore = "git diff --quiet $CACHED_COMMIT_REF $COMMIT_REF"` ### Setup Build Settings on Vercel Open your Vercel project and locate the `Settings` tab. Locate the section called `Build and Development Settings` and fill in the Build Command and Output Directory sections. There is a section below where you can enter the base directory if you are using a monorepo. If you had an `ignore` key set in the `netlify.toml`, you can add that to your Vercel settings. Select `Git` from the left navigation in Vercel and locate the `Ignored Build Step` section where you can copy the command. ## Environment Variables If you have environment variables configured in Netlify, those will need to be migrated to Vercel. These settings can be found in either the UI or your `netlify.toml` file. ### Gathering Netlify Environment Data #### 1\. Netlify UI Environment Data Open your project in Netlify and find the `Site Settings`. Select `Build and Deploy` from the left navigation and locate the `Environment` section. This includes all the environment variables needed to configure your project, make note of them all to copy to Vercel. #### 2. `netlify.toml` File Environment Data In your `netlify.toml` file, each environment's variables are signified by a `[context.ENVIRONMENT.environment]` table which lists all the currently configured values for the environment. `[context.staging.environment] NOT_PRIVATE_ITEM = "not so secret" [context.prod.environment] NOT_PRIVATE_ITEM = "really not so secret"` ### Setup Environment Variables on Vercel Open your Vercel project and locate the Settings tab. From the left navigation, select `Environment Variables` and paste your environment variables from Netlify. You can choose to configure them to only apply to any [specific environment](https://vercel.com/docs/deployments/environments) or any custom branch.

## Redirects and rewrites

There are two ways currently to configure rewrites and redirects in Netlify:

- A plain text file called 
  
  `_redirects`
  
   without a file extension to the publish directory of your site in Netlify
  
- One or more 
  
  `redirects`
  
   tables in your Netlify configuration file
  
  `netlify.toml`
  

You will need to take note of all the redirects set up in Netlify to properly configure them in Vercel.

### Gathering Netlify Redirects Data

#### 1. `_redirects` File

In a `_redirects` file, each rule must be listed on a separate line, with the original path followed by the new path or URL. The status code is optional and listed at the end. A 200 status code indicates a rewrite.

`/home / /blog/my-post.php /blog/my-post /news /blog /cats /dogs 200`

#### 2. `netlify.toml` File Redirects Data

In a `netlify.toml` file, each rule will be signified by a `[[redirects]]` table which lists all the currently configured options for each redirect. `[[redirects]] from = "/old-path" to = "/new-path" status = 301 [[redirects]] from = "/search" to = "https://api.mysearch.com" status = 200` Once you have collected all the rewrites and redirects in your application you can start configuring them in Vercel. The method will depend on your application framework. ### Setup Redirects on Vercel #### 1\. Next.js (`next.config.js`) Redirects Next.js has a built-in way to configure redirects in your application and that is the preferred way to set them up in your application as they have precedence over platform-level redirects. For each [redirect](https://nextjs.org/docs/api-reference/next.config.js/redirects) and [rewrite](https://nextjs.org/docs/api-reference/next.config.js/rewrites) you can use the `redirects` and `rewrites` keys in the `next.config.js` file in your project.

`module.exports = { async rewrites() { return [{ source: '/about', destination: '/', }, ]; }, async redirects() { return [ { source: '/about', destination: '/', permanent: true, }, ]; }, };` #### 2\. Non-Next.js (`vercel.json`) Redirects When using a framework without a built-in way to configure redirects you can create a `vercel.json` file in your project to set them up. For each [redirect](https://vercel.com/docs/concepts/projects/project-configuration#redirects) and [rewrite](https://vercel.com/docs/concepts/projects/project-configuration#rewrites) you can use the `redirects` and `rewrites` keys in the `vercel.json` file in your project.

`{ "redirects": [{ "source": "/me", "destination": "/profile.html" }, { "source": "/user", "destination": "/api/user", "permanent": false }, { "source": "/view-source", "destination": "https://github.com/vercel/vercel" }, { "source": "/:path((?!uk/).*)", "has": [ { "type": "header", "key": "x-vercel-ip-country", "value": "GB" } ], "destination": "/uk/:path*", "permanent": false } ], "rewrites": [ { "source": "/about", "destination": "/about-our-company.html" }, { "source": "/resize/:width/:height", "destination": "/api/sharp" }, { "source": "/proxy/:match*", "destination": "https://example.com/:match*" }, { "source": "/:path((?!uk/).*)", "has": [ { "type": "header", "key": "x-vercel-ip-country", "value": "GB" } ], "destination": "/uk/:path*" } ] }` ## Custom Headers There are two ways currently to configure custom headers in Netlify: - A plain text file called `_headers` without a file extension to the publish directory of your site in Netlify    - One or more `[[headers]]` tables in your Netlify configuration file `netlify.toml`    You will need to take note of all the headers set up in Netlify to properly configure them in Vercel. ### Gathering Netlify Headers Data #### 1. `_headers` File In a `_headers`file, you can specify one or several URL paths with their additional headers indented below them: `# a path: /templates/index.html # headers for that path: X-Frame-Options: DENY X-XSS-Protection: 1; mode=block # another path: /templates/index2.html # headers for that path: X-Frame-Options: SAMEORIGIN /* X-Frame-Options: DENY X-XSS-Protection: 1; mode=block` #### 2. `netlify.toml` File Headers Data In a `netlify.toml` file, each rule will be signified by a `[[headers]]` table which lists all the currently configured options for each route. `[[headers]] for = "/*" [headers.values] X-Frame-Options = "DENY" X-XSS-Protection = "1; mode=block"` Once you have collected all the custom headers in your application you can start configuring them in Vercel. The method will depend on your application framework. ### Setup Headers on Vercel Next.js has a built-in way to configure custom headers in your application and that is the preferred way to set them up in your application as they have precedence over platform-level configuration. #### 1\. Next.js (`next.config.js`) Headers For each [custom header](https://nextjs.org/docs/api-reference/next.config.js/headers) you can use the `headers` keys in the `next.config.js` file in your project.

`module.exports = { async headers() { return [{ source: '/about', headers: [ { key: 'x-custom-header', value: 'my custom header value', }, { key: 'x-another-custom-header', value: 'my other custom header value', }, ], }, ]; }, };` #### 2\. Non-Next.js (`vercel.json`) Headers When using a framework without a built-in way to configure headers you can create a `vercel.json` file in your project to set them up. For each [header](https://vercel.com/docs/concepts/projects/project-configuration#headers) you can use the `headers` key in the `vercel.json` file in your project.

`{ "headers": [{ "source": "/service-worker.js", "headers": [ { "key": "Cache-Control", "value": "public, max-age=0, must-revalidate" } ] }, { "source": "/(.*)", "headers": [ { "key": "X-Content-Type-Options", "value": "nosniff" }, { "key": "X-Frame-Options", "value": "DENY" }, { "key": "X-XSS-Protection", "value": "1; mode=block" } ] }, { "source": "/:path*", "has": [ { "type": "query", "key": "authorized" } ], "headers": [ { "key": "x-authorized", "value": "true" } ] } ] }` ## Serverless Functions If using serverless functions outside of a framework like Next.js there will be a couple of steps involved to migrate them from Netlify to Vercel. ### 1. `API` Directory Netlify has a similar file-based routing system for their Serverless Functions where they are placed in a folder called `functions/`, as opposed to `api/`. To run them on Vercel, they are expected to be found in a directory called `api/`. ### 2\. Function Signature The function signatures between Netlify and Vercel Functions are also different and will require some modification. Netlify uses an `event` and `context` input that matches AWS Lambda functions. A TypeScript Netlify function will look like this: `import { Handler } from '@netlify/functions'; const handler: Handler = async (event, context) => { return { statusCode: 200, body: JSON.stringify({ message: 'Hello World' }), }; }; export { handler };` Vercel uses a standard `Request` and `Response` API: ``export function GET(request: Request) { return new Response(`Hello from ${process.env.VERCEL_REGION}`); }`` ## Middleware If using middleware outside of a framework like Next.js there will be a couple of steps involved to migrate them from Netlify to Vercel. ### 1\. Middleware Directory Structure Netlify's Middleware structure differs from Vercel's file-based routing system. They are currently placed in a folder called `netlify/edge-functions` and require configuration in the `netlify.toml` file to match specific routes. `[[edge_functions]] path = "/test" function = "hello"` To use [Middleware](https://vercel.com/docs/concepts/functions/edge-middleware) on Vercel, they are expected to be found in a single file called `middleware.ts` at the root of your project.

### 2\. Middleware Function Signature

The function signatures between Netlify and Vercel functions are also different and will require some modification.

Netlify uses a `request` and `context` input which matches the underlying Deno functions. A TypeScript Netlify function will look like this:

`import type { Context } from 'https://edge.netlify.com'; export default async (request: Request, context: Context) => { return context.rewrite('/about-2'); };`

Vercel uses a standard `Request` input object and also requires a config object to match the middleware to specific routes:

`import { rewrite } from '@vercel/edge'; export function middleware(request: Request) { return rewrite(new URL('/about-2', request.url)); } // config with a custom matcher export const config = { matcher: '/test', };`

---

[View full KB sitemap](/kb/sitemap.md)
