Skip to content

Edge Middleware APIs

Learn about the Edge Middleware APIs.

Edge Middleware use the Edge Runtime, a runtime that is built on top of V8. The Edge Runtime exposes a subset of Web Standard APIs such as FetchEvent, Response, and Request.

These native Web API objects are extended to give you more control over how you manipulate and configure a response, based on the incoming requests.

The Edge Runtime can execute V8 code, but you don't have access to regular Node.js APIs such as process, path, or fs. This is because they are Node.js specific, and not available in a browser context.

Instead you have access to APIs related to networking, like fetch, request, and response, APIs that are available on the browser:

For a full list of available APIs see the Edge Runtime API documentation.

Note: For information and examples on writing Edge Middleware with Next.js, see the Next.js documentation.

All Middleware should be created in a single middleware.ts or middleware.js file at the root of your project. You can then export a middleware function from the file.

The following example assumes you have a route called /about in your project, and that you want to rewrite to a new route /about-2 whenever someone visits /about:

middleware.js
export default function middleware(request) {
  return Response.redirect(new URL('/about-2', request.url));
}
// config with custom matcher
export const config = {
  matcher: '/about/:path*',
};

Middleware will be invoked for every route in your project. There are two ways to define which paths the middleware should be run on: with a custom matcher config or with conditional statements.

While the config option is the preferred method, as it does not get invoked on every request, you can also use conditional statements to only run the Middleware when it matches specific paths.

To decide which route the Middleware should be run on, you can use a custom matcher config to filter on specific paths. The matcher property can be used to define either a single path, or using an array syntax, multiple paths.

middleware.ts
export const config = {
  matcher: '/about/:path*',
};
middleware.ts
export const config = {
  matcher: ['/about/:path*', '/dashboard/:path*'],
};
middleware.ts
import { rewrite } from '@vercel/edge';

export function middleware(request: Request) {
  const url = new URL(request.url);

  if (url.pathname.startsWith('/about')) {
    return rewrite(new URL('/about-2', request.url));
  }

  if (url.pathname.startsWith('/dashboard')) {
    return rewrite(new URL('/dashboard/user', request.url));
  }
}

In addition to these APIs, Next.js Middleware comes with built in helpers that are based upon the native FetchEvent, Response, and Request objects.

See the next/server documentation for more information.

While Next.js comes with built in helpers, if you are using Edge Middleware outside of Next.js, you can use the @vercel/edge package, which exports the following helpers:

  • rewrite: Returns a response that rewrites the request to a different URL
  • geolocation: Returns the location information for the incoming request
  • ipAddress: Returns the IP address of the request from the headers
  • next

Add the @vercel/edge package to your project with:


npm i @vercel/edge

Installing @vercel/edge using the npm command.

The rewrite helper returns a response that rewrites the request to a different URL. The following example shows how to rewrite a request to a different URL:

middleware.ts
import { rewrite } from '@vercel/edge';

export function middleware(request: Request) {
  return rewrite(new URL('/about-2', request.url));
}

The geolocation helper returns the location information for the incoming request. The function receives a request object and returns the following properties:

  • city: The city that the request originated from
  • country: The country that the request originated from
  • latitude: The latitude of the client
  • longitude: The longitude of the client
  • region: The Vercel Edge Network region that received the request

Each property returns a string, or undefined.

The following example assumes a bare project with index.html, and blocked.html files at the root.

middleware.ts
import { geolocation } from '@vercel/edge';

const BLOCKED_COUNTRY = 'SE';

export const config = {
  // Only run the middleware on the home route
  matcher: '/',
};

export default function middleware(request: Request) {
  const url = new URL(request.url);

  const { country } = geolocation(request);
  // You can also get the country using dot notation on the function
  // const country = geolocation(request).country;

  if (country === BLOCKED_COUNTRY) {
    url.pathname = '/blocked.html';
  } else {
    url.pathname = '/index.html';
  }

  // Return a new redirect response
  return Response.redirect(url);
}

The ipAddress helper returns the IP address of the request from the headers. The function receives a request object, and the returned value is a string with the IP address, or undefined.

The following example adds a custom header based on the IP address of the request:

middleware.ts
import { ipAddress, next } from '@vercel/edge';

export function middleware(request: Request) {
  const ip = ipAddress(request);

  return next({
    headers: { 'x-your-ip-address': ip || 'unknown' },
  });
}

The next helper returns a Response that instructs the function to continue processing the request. The function receives a request object and returns a Response object.

The following example adds a custom header:

middleware.js
import { next } from '@vercel/edge';

export default function middleware() {
  return next({
    headers: { 'x-from-middleware': 'true' },
  });
}

A no-op example. This will return a 200 OK response with no further action:

middleware.js
import { next } from '@vercel/edge';

export default function middleware() {
  return next();
}

The Edge Runtime has some restrictions including:

  • Native Node.js APIs are not supported. For example, you can't read or write to the filesystem
  • Node Modules can be used, as long as they implement ES Modules and do not use any native Node.js APIs. For example, you could use the path-to-regexp package to do path matches
  • You can use ES Modules and split your code into reusable files that will then be bundled together when the application is built
  • Calling require directly is not allowed. If you do use it, it might work when the import path can be statically resolved, but it is not recommended. Use ES Modules instead

The following JavaScript language features are disabled, and will not work:

  • eval: Evaluates JavaScript code represented as a string
  • new Function(evalString): Creates a new function with the code provided as an argument

See Edge Middleware Limitations for more information on these limitations.