Skip to content

Commit

Permalink
add the middleware.ts API reference file convention (#61037)
Browse files Browse the repository at this point in the history
This PR adds a new docs page under the File Conventions section for
the`middleware.ts` file. It includes:

- Explanation of `middleware.ts` usage in Next.js.
- Code examples in TypeScript and JavaScript.
- Information on `matcher` function, `NextResponse`, and middleware
runtime environment.
- Version history of middleware feature updates.

---------

Co-authored-by: Delba de Oliveira <32464864+delbaoliveira@users.noreply.github.com>
Co-authored-by: Michael Novotny <manovotny@gmail.com>
  • Loading branch information
3 people committed Jan 30, 2024
1 parent 1eecfc7 commit bc22b21
Showing 1 changed file with 145 additions and 0 deletions.
145 changes: 145 additions & 0 deletions docs/02-app/02-api-reference/02-file-conventions/middleware.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
---
title: middleware.js
description: API reference for the middleware.js file.
related:
title: Learn more about Middleware
links:
- app/building-your-application/routing/middleware
---

The `middleware.js|ts` file is used to write [Middleware](/docs/app/building-your-application/routing/middleware) and run code on the server 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.

Middleware executes before routes are rendered. It's particularly useful for implementing custom server-side logic like authentication, logging, or handling redirects.

Use the file `middleware.ts` (or .js) in the root of your project to define Middleware. For example, at the same level as `app` or `pages`, or inside `src` if applicable.

```tsx filename="middleware.ts" switcher
import { NextResponse, 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))
}

export const config = {
matcher: '/about/:path*',
}
```

```js filename="middleware.js" switcher
import { NextResponse } from 'next/server'

// This function can be marked `async` if using `await` inside
export function middleware(request) {
return NextResponse.redirect(new URL('/home', request.url))
}

export const config = {
matcher: '/about/:path*',
}
```

## Exports

### Middleware function

The file must export a single function, either as a default export or named `middleware`. Note that multiple middleware from the same file are not supported.

```js filename="middleware.js"
// Example of default export
export default function middleware(request) {
// Middleware logic
}
```

### Config object (optional)

Optionally, a config object can be exported alongside the Middleware function. This object includes the [matcher](#matcher) to specify paths where the Middleware applies as well as the `regions` option.

#### Matcher

The `matcher` option allows you to target specific paths for the Middleware to run on. You can specify these paths in several ways:

- For a single path: Directly use a string to define the path, like `'/about'`.
- For multiple paths: Use an array to list multiple paths, such as `matcher: ['/about', '/contact']`, which applies the Middleware to both `/about` and `/contact`.

Additionally, `matcher` supports complex path specifications through regular expressions, such as `matcher: ['/((?!api|_next/static|_next/image|.*\\.png$).*)']`, enabling precise control over which paths to include or exclude.

The `matcher` option also accepts an array of objects with the following keys:

- `source`: The path or pattern used to match the request paths. It can be a string for direct path matching or a pattern for more complex matching.
- `regexp` (optional): A regular expression string that fine-tunes the matching based on the source. It provides additional control over which paths are included or excluded.
- `locale` (optional): A boolean that, when set to `false`, ignores locale-based routing in path matching.
- `has` (optional): Specifies conditions based on the presence of specific request elements such as headers, query parameters, or cookies.
- `missing` (optional): Focuses on conditions where certain request elements are absent, like missing headers or cookies.

```js filename="middleware.js"
export const config = {
matcher: [
{
source: '/api/*',
regexp: '^/api/(.*)',
locale: false,
has: [
{ type: 'header', key: 'Authorization', value: 'Bearer Token' },
{ type: 'query', key: 'userId', value: '123' },
],
missing: [{ type: 'cookie', key: 'session', value: 'active' }],
},
],
}
```

#### Regions

The `regions` option allows you to specify the geographic locations where the Middleware runs. By default, Middleware runs in all regions.

```js filename="middleware.js"
export const config = {
regions: ['us-east-1', 'us-west-1'],
}
```

## Params

### `request`

When defining Middleware, the default export function accepts a single parameter, `request`. This parameter is an instance of `NextRequest`, which represents the incoming HTTP request.

```tsx filename="middleware.ts" switcher
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
// Middleware logic goes here
}
```

```js filename="middleware.js" switcher
export function middleware(request) {
// Middleware logic goes here
}
```

> **Good to know**:
>
> - `NextRequest` is a type that represents incoming HTTP requests in Next.js Middleware, whereas [`NextResponse`](#nextresponse) is a class used to manipulate and send back HTTP responses.
## NextResponse

Middleware can use the [`NextResponse`](/docs/app/building-your-application/routing/middleware#nextresponse) object which extends the [Web Response API](https://developer.mozilla.org/en-US/docs/Web/API/Response). By returning a `NextResponse` object, you can directly manipulate cookies, set headers, implement redirects, and rewrite paths.

> **Good to know**: For redirects, you can also use `Response.redirect` instead of `NextResponse.redirect`.
## Runtime

Middleware only supports the [Edge runtime](/docs/app/building-your-application/rendering/edge-and-nodejs-runtimes). The Node.js runtime cannot be used.

## Version History

| Version | Changes |
| --------- | --------------------------------------------------------------------------------------------- |
| `v13.1.0` | Advanced Middleware flags added |
| `v13.0.0` | Middleware can modify request headers, response headers, and send responses |
| `v12.2.0` | Middleware is stable, please see the [upgrade guide](/docs/messages/middleware-upgrade-guide) |
| `v12.0.9` | Enforce absolute URLs in Edge Runtime ([PR](https://github.com/vercel/next.js/pull/33410)) |
| `v12.0.0` | Middleware (Beta) added |

1 comment on commit bc22b21

@ijjk
Copy link
Member

@ijjk ijjk commented on bc22b21 Jan 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stats from current release

Default Build (Increase detected ⚠️)
General Overall increase ⚠️
vercel/next.js canary v14.1.0 vercel/next.js canary Change
buildDuration 12.6s 22.6s ⚠️ +10s
buildDurationCached 7s 5.2s N/A
nodeModulesSize 200 MB 200 MB ⚠️ +150 kB
nextStartRea..uration (ms) 435ms 427ms N/A
Client Bundles (main, webpack) Overall increase ⚠️
vercel/next.js canary v14.1.0 vercel/next.js canary Change
193.HASH.js gzip 181 B 181 B
3f784ff6-HASH.js gzip 53.4 kB 53.4 kB N/A
433-HASH.js gzip 28.9 kB 29.9 kB ⚠️ +920 B
framework-HASH.js gzip 45.2 kB 45.2 kB
main-app-HASH.js gzip 241 B 240 B N/A
main-HASH.js gzip 31.8 kB 31.8 kB N/A
webpack-HASH.js gzip 1.7 kB 1.7 kB N/A
Overall change 74.3 kB 75.3 kB ⚠️ +920 B
Legacy Client Bundles (polyfills)
vercel/next.js canary v14.1.0 vercel/next.js canary Change
polyfills-HASH.js gzip 31 kB 31 kB N/A
Overall change 0 B 0 B
Client Pages
vercel/next.js canary v14.1.0 vercel/next.js canary Change
_app-HASH.js gzip 194 B 195 B N/A
_error-HASH.js gzip 183 B 181 B N/A
amp-HASH.js gzip 504 B 502 B N/A
css-HASH.js gzip 321 B 322 B N/A
dynamic-HASH.js gzip 2.5 kB 2.5 kB N/A
edge-ssr-HASH.js gzip 255 B 256 B N/A
head-HASH.js gzip 350 B 349 B N/A
hooks-HASH.js gzip 369 B 369 B
image-HASH.js gzip 4.18 kB 4.18 kB N/A
index-HASH.js gzip 255 B 256 B N/A
link-HASH.js gzip 2.61 kB 2.61 kB N/A
routerDirect..HASH.js gzip 312 B 311 B N/A
script-HASH.js gzip 385 B 383 B N/A
withRouter-HASH.js gzip 307 B 308 B N/A
1afbb74e6ecf..834.css gzip 106 B 106 B
Overall change 475 B 475 B
Client Build Manifests
vercel/next.js canary v14.1.0 vercel/next.js canary Change
_buildManifest.js gzip 484 B 484 B
Overall change 484 B 484 B
Rendered Page Sizes
vercel/next.js canary v14.1.0 vercel/next.js canary Change
index.html gzip 528 B 526 B N/A
link.html gzip 541 B 540 B N/A
withRouter.html gzip 524 B 521 B N/A
Overall change 0 B 0 B
Edge SSR bundle Size Overall increase ⚠️
vercel/next.js canary v14.1.0 vercel/next.js canary Change
edge-ssr.js gzip 94 kB 94 kB N/A
page.js gzip 148 kB 150 kB ⚠️ +1.14 kB
Overall change 148 kB 150 kB ⚠️ +1.14 kB
Middleware size Overall increase ⚠️
vercel/next.js canary v14.1.0 vercel/next.js canary Change
middleware-b..fest.js gzip 624 B 623 B N/A
middleware-r..fest.js gzip 151 B 149 B N/A
middleware.js gzip 37.5 kB 37.6 kB ⚠️ +109 B
edge-runtime..pack.js gzip 1.92 kB 1.92 kB
Overall change 39.4 kB 39.5 kB ⚠️ +109 B
Next Runtimes Overall increase ⚠️
vercel/next.js canary v14.1.0 vercel/next.js canary Change
app-page-exp...dev.js gzip 169 kB 170 kB ⚠️ +252 B
app-page-exp..prod.js gzip 95.6 kB 95.8 kB ⚠️ +175 B
app-page-tur..prod.js gzip 96.3 kB 96.4 kB ⚠️ +186 B
app-page-tur..prod.js gzip 90.8 kB 91 kB ⚠️ +170 B
app-page.run...dev.js gzip 142 kB 142 kB ⚠️ +252 B
app-page.run..prod.js gzip 90.2 kB 90.3 kB ⚠️ +170 B
app-route-ex...dev.js gzip 24.2 kB 22.2 kB N/A
app-route-ex..prod.js gzip 16.8 kB 14.9 kB N/A
app-route-tu..prod.js gzip 16.8 kB 14.9 kB N/A
app-route-tu..prod.js gzip 16.4 kB 14.5 kB N/A
app-route.ru...dev.js gzip 23.6 kB 21.7 kB N/A
app-route.ru..prod.js gzip 16.4 kB 14.5 kB N/A
pages-api-tu..prod.js gzip 9.39 kB 9.43 kB N/A
pages-api.ru...dev.js gzip 9.67 kB 9.7 kB N/A
pages-api.ru..prod.js gzip 9.39 kB 9.43 kB N/A
pages-turbo...prod.js gzip 22 kB 22 kB N/A
pages.runtim...dev.js gzip 22.6 kB 22.7 kB N/A
pages.runtim..prod.js gzip 22 kB 22 kB N/A
server.runti..prod.js gzip 49.7 kB 49.7 kB N/A
Overall change 684 kB 686 kB ⚠️ +1.21 kB
Diff details
Diff for page.js

Diff too large to display

Diff for middleware.js

Diff too large to display

Diff for edge-ssr.js

Diff too large to display

Diff for 433-HASH.js

Diff too large to display

Diff for main-HASH.js

Diff too large to display

Diff for polyfills-HASH.js

Diff too large to display

Diff for webpack-HASH.js
@@ -219,7 +219,7 @@
     /******/ __webpack_require__.u = function (chunkId) {
       /******/ // return url for filenames based on template
       /******/ return (
-        "static/chunks/" + chunkId + "." + "c5e2cfe7cce91fe0" + ".js"
+        "static/chunks/" + chunkId + "." + "8b02db2463a3a176" + ".js"
       );
       /******/
     };
@@ -282,6 +282,7 @@
           /******/
         }
         /******/ script.setAttribute("data-webpack", dataWebpackPrefix + key);
+        /******/
         /******/ script.src = __webpack_require__.tu(url);
         /******/
       }
Diff for app-page-exp..ntime.dev.js
failed to diff
Diff for app-page-exp..time.prod.js

Diff too large to display

Diff for app-page-tur..time.prod.js

Diff too large to display

Diff for app-page-tur..time.prod.js

Diff too large to display

Diff for app-page.runtime.dev.js
failed to diff
Diff for app-page.runtime.prod.js

Diff too large to display

Diff for app-route-ex..ntime.dev.js

Diff too large to display

Diff for app-route-ex..time.prod.js

Diff too large to display

Diff for app-route-tu..time.prod.js

Diff too large to display

Diff for app-route-tu..time.prod.js

Diff too large to display

Diff for app-route.runtime.dev.js

Diff too large to display

Diff for app-route.ru..time.prod.js

Diff too large to display

Diff for pages-api-tu..time.prod.js

Diff too large to display

Diff for pages-api.runtime.dev.js

Diff too large to display

Diff for pages-api.ru..time.prod.js

Diff too large to display

Diff for pages-turbo...time.prod.js

Diff too large to display

Diff for pages.runtime.dev.js

Diff too large to display

Diff for pages.runtime.prod.js

Diff too large to display

Diff for server.runtime.prod.js

Diff too large to display

Please sign in to comment.