import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
// This function can be marked `async` if using `await` inside
export function middleware(request: NextRequest) {
return NextResponse.redirect(new URL('/home', request.url))
// See "Matching Paths" below to learn more
export const config = {
matcher: '/about/:path*',
Matching PathsMiddleware will be invoked for every route in your project. The following is the execution order:
headers
from next.config.js
redirects
from next.config.js
Middleware (rewrites
, redirects
, etc.)
beforeFiles
(rewrites
) from next.config.js
Filesystem routes (public/
, _next/static/
, pages/
, app/
, etc.)
afterFiles
(rewrites
) from next.config.js
Dynamic Routes (/blog/[slug]
)
fallback
(rewrites
) from next.config.js
There are two ways to define which paths Middleware will run on:
Custom matcher config
Conditional statements
Matchermatcher
allows you to filter Middleware to run on specific paths.
middleware.jsexport const config = {
matcher: '/about/:path*',
You can match a single path or multiple paths with an array syntax:
middleware.jsexport const config = {
matcher: ['/about/:path*', '/dashboard/:path*'],
The matcher
config allows full regex so matching like negative lookaheads or character matching is supported. An example of a negative lookahead to match all except specific paths can be seen here:
middleware.jsexport const config = {
matcher: [
* Match all request paths except for the ones starting with:
* - api (API routes)
* - _next/static (static files)
* - _next/image (image optimization files)
* - favicon.ico (favicon file)
'/((?!api|_next/static|_next/image|favicon.ico).*)',
You can also ignore prefetches (from next/link
) that don't need to go through the Middleware using the missing
array:
middleware.jsexport const config = {
matcher: [
* Match all request paths except for the ones starting with:
* - api (API routes)
* - _next/static (static files)
* - _next/image (image optimization files)
* - favicon.ico (favicon file)
source: '/((?!api|_next/static|_next/image|favicon.ico).*)',
missing: [
{ type: 'header', key: 'next-router-prefetch' },
{ type: 'header', key: 'purpose', value: 'prefetch' },
Good to know: The matcher
values need to be constants so they can be statically analyzed at build-time. Dynamic values such as variables will be ignored.
Configured matchers:
MUST start with /
Can include named parameters: /about/:path
matches /about/a
and /about/b
but not /about/a/c
Can have modifiers on named parameters (starting with :
): /about/:path*
matches /about/a/b/c
because *
is zero or more. ?
is zero or one and +
one or more
Can use regular expression enclosed in parenthesis: /about/(.*)
is the same as /about/:path*
Read more details on path-to-regexp documentation.
Good to know: For backward compatibility, Next.js always considers /public
as /public/index
. Therefore, a matcher of /public/:path
will match.
Conditional Statementsmiddleware.tsimport { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
// Assume a "Cookie:nextjs=fast" header to be present on the incoming request
// Getting cookies from the request using the `RequestCookies` API
let cookie = request.cookies.get('nextjs')
console.log(cookie) // => { name: 'nextjs', value: 'fast', Path: '/' }
const allCookies = request.cookies.getAll()
console.log(allCookies) // => [{ name: 'nextjs', value: 'fast' }]
request.cookies.has('nextjs') // => true
request.cookies.delete('nextjs')
request.cookies.has('nextjs') // => false
// Setting cookies on the response using the `ResponseCookies` API
const response = NextResponse.next()
response.cookies.set('vercel', 'fast')
response.cookies.set({
name: 'vercel',
value: 'fast',
path: '/',
cookie = response.cookies.get('vercel')
console.log(cookie) // => { name: 'vercel', value: 'fast', Path: '/' }
// The outgoing response will have a `Set-Cookie:vercel=fast;path=/` header.
return response
Setting HeadersYou can set request and response headers using the NextResponse
API (setting request headers is available since Next.js v13.0.0).
middleware.tsimport { NextRequest, NextResponse } from 'next/server'
const allowedOrigins = ['https://acme.com', 'https://my-app.org']
const corsOptions = {
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
export function middleware(request: NextRequest) {
// Check the origin from the request
const origin = request.headers.get('origin') ?? ''
const isAllowedOrigin = allowedOrigins.includes(origin)
// Handle preflighted requests
const isPreflight = request.method === 'OPTIONS'
if (isPreflight) {
const preflightHeaders = {
...(isAllowedOrigin && { 'Access-Control-Allow-Origin': origin }),
...corsOptions,
return NextResponse.json({}, { headers: preflightHeaders })
// Handle simple requests
const response = NextResponse.next()
if (isAllowedOrigin) {
response.headers.set('Access-Control-Allow-Origin', origin)
Object.entries(corsOptions).forEach(([key, value]) => {
response.headers.set(key, value)
return response
export const config = {
matcher: '/api/:path*',
Good to know: You can configure CORS headers for individual routes in Route Handlers.
Producing a Response
You can respond from Middleware directly by returning a Response
or NextResponse
instance. (This is available since Next.js v13.1.0)
middleware.ts