Middleware
Version History
Version | Changes |
---|---|
v12.2.0 | Middleware is stable |
v12.0.9 | Enforce absolute URLs in Edge Runtime (PR) |
v12.0.0 | Middleware (Beta) added |
Middleware allows you to run code before a request is completed, then based on the incoming request, you can modify the response by rewriting, redirecting, adding headers, or setting cookies.
Middleware runs before cached content, so you can personalize static files and pages. Common examples of Middleware would be authentication, A/B testing, localized pages, bot protection, and more. Regarding localized pages, you can start with i18n routing and implement Middleware for more advanced use cases.
Note: If you were using Middleware prior to
12.2
, please see the upgrade guide.
Using Middleware
To begin using Middleware, follow the steps below:
- Install the latest version of Next.js:
npm install next@latest
- Create a
middleware.ts
(or.js
) file at the root or in thesrc
directory (same level as yourpages
) - Export a middleware function from the
middleware.ts
file:
// middleware.ts
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('/about-2', request.url))
}
// See "Matching Paths" below to learn more
export const config = {
matcher: '/about/:path*',
}
Note the
pageExtensions
config affects middleware as well, see related documentation here.
Matching Paths
Middleware will be invoked for every route in your project. The following is the execution order:
headers
fromnext.config.js
redirects
fromnext.config.js
- Middleware (
rewrites
,redirects
, etc.) beforeFiles
(rewrites
) fromnext.config.js
- Filesystem routes (
public/
,_next/static/
, Pages, etc.) afterFiles
(rewrites
) fromnext.config.js
- Dynamic Routes (
/blog/[slug]
) fallback
(rewrites
) fromnext.config.js
There are two ways to define which paths Middleware will run on:
- Custom matcher config
- Conditional statements
Matcher
matcher
allows you to filter Middleware to run on specific paths.
export const config = {
matcher: '/about/:path*',
}
You can match a single path or multiple paths with an array syntax:
export 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:
export const config = {
matcher: [
/*
* Match all request paths except for the ones starting with:
* - api (API routes)
* - static (static files)
* - favicon.ico (favicon file)
*/
'/((?!api|static|favicon.ico).*)',
],
}
Note: 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.
Note: For backward compatibility, Next.js always considers
/public
as/public/index
. Therefore, a matcher of/public/:path
will match.
Conditional Statements
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
if (request.nextUrl.pathname.startsWith('/about')) {
return NextResponse.rewrite(new URL('/about-2', request.url))
}
if (request.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.rewrite(new URL('/dashboard/user', request.url))
}
}
NextResponse
The NextResponse
API allows you to:
redirect
the incoming request to a different URLrewrite
the response by displaying a given URL- Set response cookies
- Set response headers
To produce a response from Middleware, you should rewrite
to a route (Page or Edge API Route) that produces a response.
Using Cookies
The cookies
API extends Map and allows you to get
, set
, and delete
cookies. It also includes methods like entries and values.
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
// Setting cookies on the response
const response = NextResponse.next()
response.cookies.set('vercel', 'fast')
response.cookies.set('vercel', 'fast', { path: '/test' })
// Getting cookies from the request
const cookie = request.cookies.get('vercel')
console.log(cookie) // => 'fast'
const allCookies = request.cookies.entries()
console.log(allCookies) // => [{ key: 'vercel', value: 'fast' }]
const { value, options } = response.cookies.getWithOptions('vercel')
console.log(value) // => 'fast'
console.log(options) // => { Path: '/test' }
// Deleting cookies
response.cookies.delete('vercel')
response.cookies.clear()
return response
}