Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update Middleware documentation #37992

Closed
wants to merge 48 commits into from
Closed
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
f903c34
Initial outline added for middleware docs
molebox Jun 7, 2022
08c812e
Feedback changes - not included new user agent yet
molebox Jun 10, 2022
8f10228
Merge branch 'canary' into middleware-docs
molebox Jun 20, 2022
9476a0b
edge api routes docs
molebox Jun 22, 2022
879d58c
middleware page some cleanup
molebox Jun 22, 2022
273dec4
Merge branch 'canary' into middleware-docs
molebox Jun 22, 2022
861b526
moved api stuff to next server, added useragent
molebox Jun 22, 2022
bf087f4
waitUntil example added
molebox Jun 22, 2022
47e37b5
Updated env vars section
molebox Jun 22, 2022
cae2e64
Merge branch 'canary' into middleware-docs
molebox Jun 22, 2022
4e9c1bf
Added cookies on the request object example
molebox Jun 22, 2022
3176b4e
Merge branch 'canary' into middleware-docs
molebox Jun 22, 2022
7291023
fixed naming
molebox Jun 22, 2022
82b18b8
fixed import typo
molebox Jun 22, 2022
b5d0d41
Merge branch 'canary' into middleware-docs
molebox Jun 22, 2022
45e528f
Amy feedback
molebox Jun 22, 2022
1e97c04
Update docs/advanced-features/middleware.md
molebox Jun 23, 2022
d97c754
first commit
ismaelrumzan Jun 24, 2022
a5f5a8e
more fixes
ismaelrumzan Jun 24, 2022
b172775
re-structuring based on feedback
ismaelrumzan Jun 24, 2022
098db80
changes to middleware.md
ismaelrumzan Jun 24, 2022
175a14f
updates to edge-api-routes
ismaelrumzan Jun 24, 2022
b91774b
code typo
ismaelrumzan Jun 24, 2022
c090d71
Update docs/advanced-features/middleware.md
leerob Jun 25, 2022
096f75a
Update edge-api-routes.md
leerob Jun 26, 2022
7246b79
Update Edge Runtime API docs
leerob Jun 26, 2022
d5cab08
Merge branch 'canary' into middleware-docs-update
leerob Jun 26, 2022
f916aea
Clarify API docs
leerob Jun 26, 2022
96dbd4c
Update
leerob Jun 26, 2022
1b248cf
Update docs/advanced-features/middleware.md
leerob Jun 26, 2022
bffe484
Update switchable runtime docs
leerob Jun 26, 2022
4f00571
Update response
leerob Jun 26, 2022
c30c0c7
experimental-edge
leerob Jun 26, 2022
af91624
Update docs/advanced-features/middleware.md
leerob Jun 26, 2022
405ed88
Add example of forwarding headers and address comments
leerob Jun 27, 2022
6639915
Add proxying headers to middleware upgrade guide
leerob Jun 27, 2022
c6e0190
Merge branch 'canary' into middleware-docs-update
balazsorban44 Jun 27, 2022
400ca74
Apply suggestions from code review
leerob Jun 27, 2022
4080629
fix middleware directory spec
ismaelrumzan Jun 27, 2022
2f42c0a
localization explanation
ismaelrumzan Jun 27, 2022
6ef2b6f
update detecting runtime
ismaelrumzan Jun 28, 2022
fce31ff
Update docs/advanced-features/react-18/switchable-runtime.md
ismaelrumzan Jun 28, 2022
d0f3623
fix prettier issues
ismaelrumzan Jun 28, 2022
80f5fb9
Merge branch 'middleware-docs-update' of https://github.com/ismaelrum…
ismaelrumzan Jun 28, 2022
003fe75
table fix
ismaelrumzan Jun 28, 2022
bb2a562
Update docs/advanced-features/react-18/switchable-runtime.md
ismaelrumzan Jun 28, 2022
efe31e6
Update docs/api-routes/edge-api-routes.md
ismaelrumzan Jun 28, 2022
877cd0c
Update docs/advanced-features/react-18/switchable-runtime.md
leerob Jun 28, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
183 changes: 127 additions & 56 deletions docs/advanced-features/middleware.md
Original file line number Diff line number Diff line change
@@ -1,95 +1,166 @@
---
description: Learn how to use Middleware in Next.js to run code before a request is completed.
description: Learn how to use Middleware to run code before a request is completed.
---

# Middleware (Beta)
# Middleware

<details open>
<summary><b>Version History</b></summary>
<summary><b>Version History</b></summary>

| Version | Changes |
| --------- | ------------------------------------------------------------------------------------------------------- |
| `canary` | Preparing for stability, see [upgrade guide](https://nextjs.org/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. |
| Version | Changes |

| --------- | ------------------------------------------------------------------------------------------ |

| `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 |

</details>

Middleware enables you to run code before a request is completed. Based on the user's incoming request, you can modify the response by rewriting, redirecting, adding headers, or even streaming HTML.
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.

## Usage
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.
leerob marked this conversation as resolved.
Show resolved Hide resolved
leerob marked this conversation as resolved.
Show resolved Hide resolved
ismaelrumzan marked this conversation as resolved.
Show resolved Hide resolved

1. Install the canary version of Next.js:
> **Note:** If you were using Middleware prior to `12.2`, please see the [upgrade guide](https://nextjs.org/docs/messages/middleware-upgrade-guide).

```jsx
npm install next@canary
```
## Using Middleware

2. Then, create a `middleware.ts` file under your project root directory.
To begin using Middleware, follow the steps below:

3. Finally, export a middleware function from the `middleware.ts` file.
1. Install the latest version of Next.js:

```jsx
```bash
npm install next@latest
leerob marked this conversation as resolved.
Show resolved Hide resolved
```

2. Create a `middleware.ts` (or `.js`) file under your project root directory.
ismaelrumzan marked this conversation as resolved.
Show resolved Hide resolved
3. Export a middleware function from the `middleware.ts` file:

```typescript
// middleware.ts
import { NextResponse } from 'next/server’
leerob marked this conversation as resolved.
Show resolved Hide resolved
import type { NextRequest } from 'next/server'

import type { NextRequest, NextResponse } from 'next/server'
import { areCredentialsValid } from '../lib'
// This function can be marked `async` if using `await` inside
export function middleware(request: NextRequest) {
return NextResponse.redirect(new URL('/about-2', request.url));
}

export function middleware(req: NextRequest) {
if (areCredentialsValid(req.headers.get('authorization'))) {
return NextResponse.next()
}
return NextResponse.redirect(
new URL(`/login?from=${req.nextUrl.pathname}`, req.url)
)
// See "Matching Paths" below to learn more
export const config = {
matcher: '/about/:path*'
}
```

In this example, we use the standard Web API Response ([MDN](https://developer.mozilla.org/en-US/docs/Web/API/Response)).
## Matching Paths

## API
Middleware will be invoked for **every route in your project**. The following is the execution order:

Middleware is created by using a `middleware` function that lives inside a `middleware` file. Its API is based upon the native [`FetchEvent`](https://developer.mozilla.org/en-US/docs/Web/API/FetchEvent), [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response), and [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) objects.
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`

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.
There are two ways to define which paths Middleware will run on:

The function signature:
1. Custom matcher config
2. Conditional statements

```ts
import type { NextFetchEvent } from 'next/server'
import type { NextRequest } from 'next/server'
### Matcher

`matcher` allows you to filter Middleware to run on specific paths.

export type Middleware = (
request: NextRequest,
event: NextFetchEvent
) => Promise<Response | undefined> | Response | undefined
```js
export const config = {
matcher: '/about/:path*',
}
```

The function can be a default export and as such, does **not** have to be named `middleware`. Though this is a convention. Also note that you only need to make the function `async` if you are running asynchronous code.
You can match a single path or multiple paths with an array syntax:

Read the full [Middleware API reference](/docs/api-reference/edge-runtime.md), note [Node.js APIs are not supported in this environment](/docs/api-reference/edge-runtime.md#unsupported-apis)
```js
export const config = {
matcher: ['/about/:path*', '/dashboard/:path*'],
}
```

## Examples
### Conditional Statements

Middleware can be used for anything that shares logic for a set of pages, including:
```typescript
// middleware.ts

- [Authentication](https://github.com/vercel/examples/tree/main/edge-functions)
- [Bot protection](https://github.com/vercel/examples/tree/main/edge-functions)
- [Redirects and rewrites](https://github.com/vercel/examples/tree/main/edge-functions)
- [Handling unsupported browsers](https://github.com/vercel/examples/tree/main/edge-functions/user-agent-based-rendering)
- [Feature flags and A/B tests](https://github.com/vercel/examples/tree/main/edge-functions)
- [Advanced i18n routing requirements](https://github.com/vercel/examples/tree/main/edge-functions)
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

## Execution Order
export function middleware(request: NextRequest) {
if (request.nextUrl.pathname.startsWith('/about')) {
return NextResponse.rewrite(new URL('/about-2', request.url))
}

Middleware runs directly after `redirects` and `headers`, before the first filesystem lookup. This excludes `/_next` files.
if (request.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.rewrite(new URL('/dashboard/user', request.url))
}
}
```

## Deployment
## NextResponse

Middleware uses a [strict runtime](/docs/api-reference/edge-runtime.md) that supports standard Web APIs like `fetch`. This works out of the box using `next start`, as well as on Edge platforms like Vercel, which use [Edge Functions](http://www.vercel.com/edge).
leerob marked this conversation as resolved.
Show resolved Hide resolved
The [`NextResponse`](#nextresponse) API allows you to:

- `redirect` the incoming request to a different URL
- `rewrite` 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](/docs/basic-features/pages.md) or [Edge API Routes](/docs/api-routes/edge-api-routes.md)) that produces a response.
leerob marked this conversation as resolved.
Show resolved Hide resolved

## Using Cookies

The `cookies` API extends [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) and allows you to `get`, `set`, and `delete` cookies. It also includes methods like [entries](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/entries) and [values](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/entries).

```typescript
// 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
}
```

## Related

<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>
leerob marked this conversation as resolved.
Show resolved Hide resolved

<div class="card">
<a href="/docs/api-reference/next/server.md">
<b>Middleware API Reference</b>
Expand All @@ -98,8 +169,8 @@ Middleware uses a [strict runtime](/docs/api-reference/edge-runtime.md) that sup
</div>

<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 href="/docs/api-routes/edge-api-routes.md">
<b>Edge API Routes</b>
<small>Build high performance APIs in Next.js. </small>
</a>
</div>
</div>
61 changes: 54 additions & 7 deletions docs/advanced-features/react-18/switchable-runtime.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
# Switchable Runtime (Alpha)

By default, Next.js uses Node.js as the runtime for page rendering, including pre-rendering and server-side rendering.
Next.js has two _server runtimes_ to run your application: the **Node.js Runtime** (default) and the [**Edge Runtime**](/docs/api-reference/edge-runtime.md). When server-rendering or serving API routes, the application code will be executed in the Node.js Runtime by default; and for [Middleware](/docs/middleware.md), it will be running in the Edge Runtime.

> Note: `runtime` option only effects pages but not middleware
  | Node (server) | Node (lambda) | Edge
-- | -- | -- | --
[Cold Boot](https://vercel.com/docs/concepts/functions/conceptual-model#cold-and-hot-boots) | / | ~250ms | Instant
ismaelrumzan marked this conversation as resolved.
Show resolved Hide resolved
[HTTP Streaming](https://github.com/reactwg/react-18/discussions/37) | Yes | No | Yes
IO | All | All | `fetch`
Scalability | / | High | Highest
Security | Normal | High | Highest
Latency | Normal | Low | Lowest
Code Size | / | 50MB | 1MB
NPM Packages | All | All | A smaller subset

If you have [React 18](/docs/advanced-features/react-18/overview) installed, there is a new experimental feature that lets you switch the page runtime between Node.js and the [Edge Runtime](/docs/api-reference/edge-runtime). Changing the runtime affects [SSR streaming](/docs/advanced-features/react-18/streaming) and [Server Components](/docs/advanced-features/react-18/server-components) features, as well.
Next.js' default runtime configuration is good for most use cases, but there’re still many reasons to change to one runtime over the other one. For example, to enable [React 18's](/docs/advanced-features/react-18/overview) [SSR streaming](/docs/advanced-features/react-18/streaming.md) feature, you need to use a runtime that is compatiable with Web Streams. For API routes that rely on native Node.js APIs, they need to run with the **Node.js Runtime**. However, if an API only uses a simple cookie-based authentication, using Middleware and the [**Edge Runtime**](/docs/api-reference/edge-runtime.md) will be a better choice due to its lower latency as well as better scalability.
ismaelrumzan marked this conversation as resolved.
Show resolved Hide resolved

Starting with `12.2`, Next.js enables you to customize the runtime for each Next.js route, for both Pages and API routes.

## Global Runtime Option

Expand All @@ -14,7 +25,7 @@ You can set the experimental option `runtime` to either `'nodejs'` or `'experime
// next.config.js
module.exports = {
experimental: {
runtime: 'nodejs',
runtime: 'experimental-edge',
},
}
```
Expand All @@ -26,13 +37,49 @@ This option determines which runtime should be used as the default rendering run
On each page, you can optionally export a `runtime` config set to either `'nodejs'` or `'experimental-edge'`:

```jsx
// pages/index.js
export default function Index () { ... }

export function getServerSideProps() { ... }

export const config = {
runtime: 'nodejs',
runtime: 'experimental-edge',
}
```

When both the per-page runtime and global runtime are set, the per-page runtime overrides the global runtime. If the per-page runtime is _not_ set, the global runtime option will be used.

You can refer to the [Switchable Next.js Runtime RFC](https://github.com/vercel/next.js/discussions/34179) for more information.
## Edge API Routes

[Edge API Routes](/docs/api-routes/edge-api-routes.md) enable you to build high performance APIs with Next.js using the Edge Runtime.

```typescript
export const config = {
runtime: 'experimental-edge',
}

export default (req) => new Response('Hello world!')
```

## Related

<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>

<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>

**Note:** The page runtime option is not supported in [API Routes](/docs/api-routes/introduction.md) currently.
<div class="card">
<a href="/docs/api-routes/edge-api-routes.md">
<b>Edge API Routes</b>
<small>Build high performance APIs in Next.js. </small>
</a>
</div>
Loading