Skip to content

Migrate to Vercel from Netlify

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

Before you can start the migration you need to create a project on Vercel. This Getting Started guide will instruct you on how to add your project to Vercel.

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

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

Vercel will automatically detect the framework and any necessary build settings. However, you may have custom settings in 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.

Open your project in Netlify and find the Site Settings.

Netlify Project 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

Netlify 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"

Open your Vercel project and locate the Settings tab.

Vercel Project Settings

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.

Vercel Build Settings

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.

Vercel Ignored Build Step

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.

Open your project in Netlify and find the Site Settings.

Netlify Project 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.

Netlify Environment Settings

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"

Open your Vercel project and locate the Settings tab.

Vercel Project Settings

Select Environment Variables from the left navigation and copy over your environment variables from Netlify. They can be configured to only apply to preview environments, production environments or any custom branch.

Vercel Environment Settings

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.

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

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.

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 and rewrite 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,
      },
    ];
  },
};

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 and rewrite 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*"
    }
  ]
}

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.

In a _headersfile, 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

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.

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.

For each custom header 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',
          },
        ],
      },
    ];
  },
};

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 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"
        }
      ]
    }
  ]
}

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.

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.

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 the underlying 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 input which mirrors an Express API:

import { VercelRequest, VercelResponse } from '@vercel/node';
const handler = async (req: VercelRequest, res: VercelResponse) => {
  res.status(200).json({});
};
export default handler;

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.

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 on Vercel, they are expected to be found in a single file called middleware.ts at the root of your project.

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:

// middleware.ts
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',
};

Couldn't find the guide you need?