2021-10-26 17:07:32 +02:00
---
2022-06-28 17:22:48 +02:00
description: Learn how to use Middleware to run code before a request is completed.
2021-10-26 17:07:32 +02:00
---
2022-06-28 17:22:48 +02:00
# Middleware
2021-10-26 17:07:32 +02:00
2022-02-13 23:46:30 +01:00
< details open >
2022-06-28 17:22:48 +02:00
< summary > < b > Version History< / b > < / summary >
2022-02-13 23:46:30 +01:00
2022-06-28 17:22:48 +02:00
| Version | Changes |
| --------- | ------------------------------------------------------------------------------------------ |
2022-11-07 20:19:17 +01:00
| `v13.0.0` | Middleware can modify request headers, response headers, and send responses |
2022-06-28 17:22:48 +02:00
| `v12.2.0` | Middleware is stable |
| `v12.0.9` | Enforce absolute URLs in Edge Runtime ([PR](https://github.com/vercel/next.js/pull/33410)) |
| `v12.0.0` | Middleware (Beta) added |
2022-02-13 23:46:30 +01:00
< / details >
2022-11-07 20:19:17 +01:00
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, modifying the request or response headers, or responding directly.
2021-10-26 17:07:32 +02:00
2022-06-28 17:22:48 +02:00
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 ](/docs/advanced-features/i18n-routing ) and implement Middleware for more advanced use cases.
2021-10-26 17:07:32 +02:00
2022-06-28 17:22:48 +02:00
> **Note:** If you were using Middleware prior to `12.2`, please see the [upgrade guide](https://nextjs.org/docs/messages/middleware-upgrade-guide).
2021-10-26 17:07:32 +02:00
2022-06-28 17:22:48 +02:00
## Using Middleware
To begin using Middleware, follow the steps below:
2021-10-26 17:07:32 +02:00
2022-06-28 17:22:48 +02:00
1. Install the latest version of Next.js:
2021-10-26 17:07:32 +02:00
2022-06-28 17:22:48 +02:00
```bash
npm install next@latest
```
2021-10-26 17:07:32 +02:00
2022-09-08 23:27:17 +02:00
2. Create a `middleware.ts` (or `.js` ) file at the root or in the `src` directory (same level as your `pages` )
2022-06-28 17:22:48 +02:00
3. Export a middleware function from the `middleware.ts` file:
```typescript
2022-05-19 17:46:21 +02:00
// middleware.ts
2022-06-28 17:22:48 +02:00
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
2021-10-26 17:07:32 +02:00
2022-06-28 17:22:48 +02:00
// This function can be marked `async` if using `await` inside
export function middleware(request: NextRequest) {
return NextResponse.redirect(new URL('/about-2', request.url))
}
feat(middleware)!: forbids middleware response body (#36835)
_Hello Next.js team! First PR here, I hope I've followed the right practices._
### What's in there?
It has been decided to only support the following uses cases in Next.js' middleware:
- rewrite the URL (`x-middleware-rewrite` response header)
- redirect to another URL (`Location` response header)
- pass on to the next piece in the request pipeline (`x-middleware-next` response header)
1. during development, a warning on console tells developers when they are returning a response (either with `Response` or `NextResponse`).
2. at build time, this warning becomes an error.
3. at run time, returning a response body will trigger a 500 HTTP error with a JSON payload containing the detailed error.
All returned/thrown errors contain a link to the documentation.
This is a breaking feature compared to the _beta_ middleware implementation, and also removes `NextResponse.json()` which makes no sense any more.
### How to try it?
- runtime behavior: `HEADLESS=true yarn jest test/integration/middleware/core`
- build behavior : `yarn jest test/integration/middleware/build-errors`
- development behavior: `HEADLESS=true yarn jest test/development/middleware-warnings`
### Notes to reviewers
The limitation happens in next's web adapter. ~The initial implementation was to check `response.body` existence, but it turns out [`Response.redirect()`](https://github.com/vercel/next.js/blob/canary/packages/next/server/web/spec-compliant/response.ts#L42-L53) may set the response body (https://github.com/vercel/next.js/pull/31886). Hence why the proposed implementation specifically looks at response headers.~
`Response.redirect()` and `NextResponse.redirect()` do not need to include the final location in their body: it is handled by next server https://github.com/vercel/next.js/blob/canary/packages/next/server/next-server.ts#L1142
Because this is a breaking change, I had to adjust several tests cases, previously returning JSON/stream/text bodies. When relevant, these middlewares are returning data using response headers.
About DevEx: relying on AST analysis to detect forbidden use cases is not as good as running the code.
Such cases are easy to detect:
```js
new Response('a text value')
new Response(JSON.stringify({ /* whatever */ })
```
But these are false-positive cases:
```js
function returnNull() { return null }
new Response(returnNull())
function doesNothing() {}
new Response(doesNothing())
```
However, I see no good reasons to let users ship middleware such as the one above, hence why the build will fail, even if _technically speaking_, they are not setting the response body.
## Feature
- [x] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [ ] Related issues linked using `fixes #number`
- [x] Integration tests added
- [x] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.
- [x] Errors have helpful link attached, see `contributing.md`
## Documentation / Examples
- [x] Make sure the linting passes by running `yarn lint`
2022-05-20 00:02:20 +02:00
2022-06-28 17:22:48 +02:00
// See "Matching Paths" below to learn more
export const config = {
matcher: '/about/:path*',
2021-10-26 17:07:32 +02:00
}
```
2022-06-28 17:22:48 +02:00
## Matching Paths
2021-10-26 17:07:32 +02:00
2022-06-28 17:22:48 +02:00
Middleware will be invoked for **every route in your project** . The following is the execution order:
2022-02-06 03:01:18 +01:00
2022-06-28 17:22:48 +02:00
1. `headers` from `next.config.js`
2. `redirects` from `next.config.js`
3. Middleware (`rewrites`, `redirects` , etc.)
4. `beforeFiles` (`rewrites`) from `next.config.js`
5. Filesystem routes (`public/`, `_next/static/` , Pages, etc.)
6. `afterFiles` (`rewrites`) from `next.config.js`
7. Dynamic Routes (`/blog/[slug]`)
8. `fallback` (`rewrites`) from `next.config.js`
2022-02-06 03:01:18 +01:00
2022-06-28 17:22:48 +02:00
There are two ways to define which paths Middleware will run on:
2022-02-06 03:01:18 +01:00
2022-06-28 17:22:48 +02:00
1. Custom matcher config
2. Conditional statements
2022-02-06 03:01:18 +01:00
2022-06-28 17:22:48 +02:00
### Matcher
2022-02-06 03:01:18 +01:00
2022-06-28 17:22:48 +02:00
`matcher` allows you to filter Middleware to run on specific paths.
```js
export const config = {
matcher: '/about/:path*',
}
2022-02-06 03:01:18 +01:00
```
2022-06-28 17:22:48 +02:00
You can match a single path or multiple paths with an array syntax:
```js
export const config = {
matcher: ['/about/:path*', '/dashboard/:path*'],
}
```
2022-09-13 03:26:40 +02:00
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:
```js
export const config = {
matcher: [
/*
* Match all request paths except for the ones starting with:
* - api (API routes)
2022-11-02 19:58:13 +01:00
* - _next/static (static files)
2022-09-13 03:26:40 +02:00
* - favicon.ico (favicon file)
*/
2022-11-02 19:58:13 +01:00
'/((?!api|_next/static|favicon.ico).*)',
2022-09-13 03:26:40 +02:00
],
}
```
2022-07-13 16:36:10 +02:00
> **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.
docs: documents middleware matcher (#40180)
### 📖 What's in there?
Middleware matchers are powerful, but very few people realized it, because they are not really documented.
This PR tries to bring more clarity, and includes a more advanced example.
The example shows how to exclude several pages (no `/static`, no `/public`), but also allow specific page in excluded paths (`/public/disclaimer`)
### 🧪 How to test?
Run the example: `pnpm next dev examples/middleware-matcher`, then browse to http://localhost:3000
The first 3 links should not match, the last 3 ones should.
Don't forget to clear your localhost cookies if you change the middleware code.
### 🆙 Note to reviewers
Using session cookies to pass information from middleware to the rendered page is not great, because `document.cookie` is not available during SSR, and because cookies persist when refreshing the page (making it hard to try different matchers)
However, I couldn't find a simpler way to convey the information from the middleware to the page, and I meant to have something visual. The other option is to use response headers and curl commands, but...
2022-09-05 15:36:09 +02:00
Configured matchers:
1. MUST start with `/`
2022-09-07 02:08:00 +02:00
2. Can include named parameters: `/about/:path` matches `/about/a` and `/about/b` but not `/about/a/c`
3. 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_
4. Can use regular expression enclosed in parenthesis: `/about/(.*)` is the same as `/about/:path*`
docs: documents middleware matcher (#40180)
### 📖 What's in there?
Middleware matchers are powerful, but very few people realized it, because they are not really documented.
This PR tries to bring more clarity, and includes a more advanced example.
The example shows how to exclude several pages (no `/static`, no `/public`), but also allow specific page in excluded paths (`/public/disclaimer`)
### 🧪 How to test?
Run the example: `pnpm next dev examples/middleware-matcher`, then browse to http://localhost:3000
The first 3 links should not match, the last 3 ones should.
Don't forget to clear your localhost cookies if you change the middleware code.
### 🆙 Note to reviewers
Using session cookies to pass information from middleware to the rendered page is not great, because `document.cookie` is not available during SSR, and because cookies persist when refreshing the page (making it hard to try different matchers)
However, I couldn't find a simpler way to convey the information from the middleware to the page, and I meant to have something visual. The other option is to use response headers and curl commands, but...
2022-09-05 15:36:09 +02:00
Read more details on [path-to-regexp ](https://github.com/pillarjs/path-to-regexp#path-to-regexp-1 ) documentation.
> **Note:** For backward compatibility, Next.js always considers `/public` as `/public/index`. Therefore, a matcher of `/public/:path` will match.
2022-06-28 17:22:48 +02:00
### Conditional Statements
```typescript
// 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))
}
}
```
2022-02-06 03:01:18 +01:00
2022-06-28 17:22:48 +02:00
## NextResponse
2022-02-06 03:01:18 +01:00
2022-06-28 17:22:48 +02:00
The [`NextResponse` ](#nextresponse ) API allows you to:
2021-10-26 17:07:32 +02:00
2022-06-28 17:22:48 +02:00
- `redirect` the incoming request to a different URL
- `rewrite` the response by displaying a given URL
2022-10-19 15:46:03 +02:00
- Set request headers for API Routes, `getServerSideProps` , and `rewrite` destinations
2022-06-28 17:22:48 +02:00
- Set response cookies
- Set response headers
2021-10-26 17:07:32 +02:00
2022-06-28 17:22:48 +02:00
To produce a response from Middleware, you should `rewrite` to a route ([Page](/docs/basic-features/pages.md) or [Edge API Route ](/docs/api-routes/edge-api-routes.md )) that produces a response.
2021-10-26 17:07:32 +02:00
2022-06-28 17:22:48 +02:00
## Using Cookies
2021-10-26 17:07:32 +02:00
2022-10-27 09:20:39 +02:00
Cookies are regular headers. On a `Request` , they are stored in the `Cookie` header. On a `Response` they are in the `Set-Cookie` header. Next.js provides a convenient way to access and manipulate these cookies through the `cookies` extension on `NextRequest` and `NextResponse` .
1. For incoming requests, `cookies` comes with the following methods: `get` , `getAll` , `set` , and `delete` cookies. You can check for the existence of a cookie with `has` or remove all cookies with `clear` .
2. For outgoing responses, `cookies` have the following methods `get` , `getAll` , `set` , and `delete` .
2021-10-26 17:07:32 +02:00
2022-06-28 17:22:48 +02:00
```typescript
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
2021-10-26 17:07:32 +02:00
2022-06-28 17:22:48 +02:00
export function middleware(request: NextRequest) {
2022-11-03 03:09:49 +01:00
// Assume a "Cookie:nextjs=fast" header to be present on the incoming request
2022-10-27 09:20:39 +02:00
// Getting cookies from the request using the `RequestCookies` API
const cookie = request.cookies.get('nextjs')?.value
console.log(cookie) // => 'fast'
const allCookies = request.cookies.getAll()
2022-11-12 01:47:39 +01:00
console.log(allCookies) // => [{ name: 'nextjs', value: 'fast' }]
2022-10-27 09:20:39 +02:00
2022-10-30 20:02:56 +01:00
request.cookies.has('nextjs') // => true
request.cookies.delete('nextjs')
request.cookies.has('nextjs') // => false
2022-10-27 09:20:39 +02:00
// Setting cookies on the response using the `ResponseCookies` API
2022-06-28 17:22:48 +02:00
const response = NextResponse.next()
response.cookies.set('vercel', 'fast')
2022-10-27 09:20:39 +02:00
response.cookies.set({
name: 'vercel',
value: 'fast',
path: '/test',
})
const cookie = response.cookies.get('vercel')
console.log(cookie) // => { name: 'vercel', value: 'fast', Path: '/test' }
// The outgoing response will have a `Set-Cookie:vercel=fast;path=/test` header.
2022-06-28 17:22:48 +02:00
return response
}
```
2021-10-26 17:07:32 +02:00
2022-10-19 15:46:03 +02:00
## Setting Headers
2022-10-27 21:31:52 +02:00
You can set request and response headers using the `NextResponse` API (setting _request_ headers is available since Next.js v13.0.0).
2022-10-19 15:46:03 +02:00
```ts
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
// Clone the request headers and set a new header `x-hello-from-middleware1`
const requestHeaders = new Headers(request.headers)
requestHeaders.set('x-hello-from-middleware1', 'hello')
// You can also set request headers in NextResponse.rewrite
const response = NextResponse.next({
request: {
// New request headers
headers: requestHeaders,
},
})
// Set a new response header `x-hello-from-middleware2`
response.headers.set('x-hello-from-middleware2', 'hello')
return response
}
```
> **Note:** Avoid setting large headers as it might cause [431 Request Header Fields Too Large](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/431) error depending on your backend web server configuration.
2022-11-07 20:19:17 +01:00
## Producing a Response
You can respond to middleware directly by returning a `NextResponse` (responding from middleware is available since Next.js v13.0.0).
To enable middleware responses, update `next.config.js` :
```js
// next.config.js
module.exports = {
experimental: {
allowMiddlewareResponseBody: true,
},
}
```
Once enabled, you can provide a response from middleware using the `Response` or `NextResponse` API:
```ts
// middleware.ts
import { NextRequest, NextResponse } from 'next/server'
import { isAuthenticated } from '@lib/auth'
// Limit the middleware to paths starting with `/api/`
export const config = {
matcher: '/api/:function*',
}
export function middleware(request: NextRequest) {
// Call our authentication function to check the request
if (!isAuthenticated(request)) {
// Respond with JSON indicating an error message
return new NextResponse(
JSON.stringify({ success: false, message: 'authentication failed' }),
{ status: 401, headers: { 'content-type': 'application/json' } }
)
}
}
```
2021-10-26 17:07:32 +02:00
## Related
2022-06-28 17:22:48 +02:00
< div class = "card" >
< a href = "/docs/api-reference/edge-runtime.md" >
< b > Edge Runtime< / b >
< small > Learn more about the supported Web APIs available.< / small >
< / a >
< / div >
2021-10-26 17:07:32 +02:00
< div class = "card" >
< a href = "/docs/api-reference/next/server.md" >
< b > Middleware API Reference< / b >
< small > Learn more about the supported APIs for Middleware.< / small >
< / a >
< / div >
< div class = "card" >
2022-06-28 17:22:48 +02:00
< a href = "/docs/api-routes/edge-api-routes.md" >
< b > Edge API Routes< / b >
< small > Build high performance APIs in Next.js. < / small >
2021-10-26 17:07:32 +02:00
< / a >
< / div >