Skip to content

Commit 7f25da7

Browse files
docs: simplify streaming metadata (#84253)
Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
1 parent ce56f8a commit 7f25da7

File tree

3 files changed

+64
-14
lines changed

3 files changed

+64
-14
lines changed

docs/01-app/01-getting-started/14-metadata-and-og-images.mdx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ related:
1313
- app/api-reference/file-conventions/metadata/opengraph-image
1414
- app/api-reference/file-conventions/metadata/robots
1515
- app/api-reference/file-conventions/metadata/sitemap
16+
- app/api-reference/config/next-config-js/htmlLimitedBots
1617
---
1718

1819
The Metadata APIs can be used to define your application metadata for improved SEO and web shareability and include:
@@ -117,9 +118,15 @@ export default function Page({ params, searchParams }) {}
117118

118119
### Streaming metadata
119120

120-
For dynamically rendered pages, if resolving `generateMetadata` might block rendering, Next.js streams the resolved metadata separately and injects it into the HTML as soon as it's ready.
121+
For dynamically rendered pages, Next.js streams metadata separately, injecting it into the HTML once `generateMetadata` resolves, without blocking UI rendering.
121122

122-
Statically rendered pages don’t use this behavior since metadata is resolved at build time.
123+
Streaming metadata improves perceived performance by allowing visual content to stream first.
124+
125+
Streaming metadata is **disabled for bots and crawlers** that expect metadata to be in the `<head>` tag (e.g. `Twitterbot`, `Slackbot`, `Bingbot`). These are detected by using the User Agent header from the incoming request.
126+
127+
You can customize or **disable** streaming metadata completely, with the [`htmlLimitedBots`](/docs/app/api-reference/config/next-config-js/htmlLimitedBots#disabling) option in your Next.js config file.
128+
129+
Statically rendered pages don’t use streaming since metadata is resolved at build time.
123130

124131
Learn more about [streaming metadata](/docs/app/api-reference/functions/generate-metadata#streaming-metadata).
125132

docs/01-app/03-api-reference/04-functions/generate-metadata.mdx

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ export default function Page() {}
4141

4242
Dynamic metadata depends on **dynamic information**, such as the current route parameters, external data, or `metadata` in parent segments, can be set by exporting a `generateMetadata` function that returns a [`Metadata` object](#metadata-fields).
4343

44+
Resolving `generateMetadata` is part of rendering the page. If the page can be pre-rendered and `generateMetadata` doesn't introduce dynamic behavior, the resulting metadata is included in the page’s initial HTML.
45+
46+
Otherwise the metadata resolved from `generateMetadata` [can be streamed](/docs/app/api-reference/functions/generate-metadata#streaming-metadata) after sending the initial UI.
47+
4448
```tsx filename="app/products/[id]/page.tsx" switcher
4549
import type { Metadata, ResolvingMetadata } from 'next'
4650

@@ -104,8 +108,6 @@ For type completion of `params` and `searchParams`, you can type the first argum
104108
> - The `metadata` object and `generateMetadata` function exports are **only supported in Server Components**.
105109
> - You cannot export both the `metadata` object and `generateMetadata` function from the same route segment.
106110
> - `fetch` requests inside `generateMetadata` are automatically [memoized](/docs/app/guides/caching#request-memoization) for the same data across `generateMetadata`, `generateStaticParams`, Layouts, Pages, and Server Components.
107-
> - Resolving `generateMetadata` is part of rendering the page. If the page can be pre-rendered and `generateMetadata` doesn't introduce dynamic behavior, its result is included in the page’s initial HTML.
108-
> - `generateMetadata` [can stream results](/docs/app/api-reference/functions/generate-metadata#streaming-metadata) to improve page load performance.
109111
> - React [`cache` can be used](/docs/app/guides/caching#react-cache-function) if `fetch` is unavailable.
110112
> - [File-based metadata](/docs/app/api-reference/file-conventions/metadata) has the higher priority and will override the `metadata` object and `generateMetadata` function.
111113
@@ -1170,33 +1172,33 @@ There are two default `meta` tags that are always added even if a route doesn't
11701172
11711173
### Streaming metadata
11721174
1173-
Metadata returned by `generateMetadata` is streamed to the client. This allows Next.js to inject metadata into the HTML as soon as it's resolved.
1175+
Streaming metadata allows Next.js to render and send the initial UI to the browser, without waiting for `generateMetadata` to complete.
11741176
1175-
Streamed metadata is appended to the `<body>` tag. Since metadata mainly targets bots and crawlers, Next.js streams metadata for bots that can execute JavaScript and inspect the full DOM (e.g. `Googlebot`). We have verified that these bots interpret the metadata correctly.
1177+
When `generateMetadata` resolves, the resulting metadata tags are appended to the `<body>` tag. We have verified that metadata is interpreted correctly by bots that execute JavaScript and inspect the full DOM (e.g. `Googlebot`).
11761178
1177-
For **HTML-limited** bots that can’t run JavaScript (e.g. `Twitterbot`), metadata continues to block page rendering and is placed in the `<head>` tag.
1179+
For **HTML-limited bots** that can’t execute JavaScript (e.g. `facebookexternalhit`), metadata continues to block page rendering. The resulting metadata will be available in the `<head>` tag.
11781180
1179-
Next.js automatically detects the user agent of incoming requests to determine whether to serve streaming metadata or fallback to blocking metadata.
1181+
Next.js automatically detects **HTML-limited bots** by looking at the User Agent header. You can use the [`htmlLimitedBots`](/docs/app/api-reference/config/next-config-js/htmlLimitedBots) option in your Next.js config file to override the default [User Agent list](https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/router/utils/html-bots.ts).
11801182
1181-
If you need to customize this list, you can define them manually using the `htmlLimitedBots` option in `next.config.js`. Next.js will ensure user agents matching this regex receive blocking metadata when requesting your web page.
1183+
To fully disable streaming metadata:
11821184
11831185
```ts filename="next.config.ts" switcher
11841186
import type { NextConfig } from 'next'
11851187
11861188
const config: NextConfig = {
1187-
htmlLimitedBots: /MySpecialBot|MyAnotherSpecialBot|SimpleCrawler/,
1189+
htmlLimitedBots: /.*/,
11881190
}
11891191
11901192
export default config
11911193
```
11921194
11931195
```js filename="next.config.js" switcher
11941196
module.exports = {
1195-
htmlLimitedBots: /MySpecialBot|MyAnotherSpecialBot|SimpleCrawler/,
1197+
htmlLimitedBots: /.*/,
11961198
}
11971199
```
11981200
1199-
Specifying a `htmlLimitedBots` config will override the Next.js' default list, allowing you full control over what user agents should opt into this behavior.
1201+
Streaming metadata improves perceived performance by reducing [TTFB](https://developer.mozilla.org/docs/Glossary/Time_to_first_byte) and can help lowering [LCP](https://developer.mozilla.org/docs/Glossary/Largest_contentful_paint) time.
12001202
12011203
Overriding `htmlLimitedBots` could lead to longer response times. Streaming metadata is an advanced feature, and the default should be sufficient for most cases.
12021204

docs/01-app/03-api-reference/05-config/01-next-config-js/htmlLimitedBots.mdx

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,50 @@ module.exports = {
2323

2424
## Default list
2525

26-
Next.js includes [a default list of HTML limited bots](https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/router/utils/html-bots.ts).
26+
Next.js includes a default list of HTML limited bots, including:
2727

28-
Specifying a `htmlLimitedBots` config will override the Next.js' default list, allowing you full control over what user agents should opt into this behavior. However, this is advanced behavior, and the default should be sufficient for most cases.
28+
- Google crawlers (e.g. Mediapartners-Google, AdsBot-Google, Google-PageRenderer)
29+
- Bingbot
30+
- Twitterbot
31+
- Slackbot
32+
33+
See the full list [here](https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/router/utils/html-bots.ts).
34+
35+
Specifying a `htmlLimitedBots` config will override the Next.js' default list. However, this is advanced behavior, and the default should be sufficient for most cases.
36+
37+
```ts filename="next.config.ts" switcher
38+
const config: NextConfig = {
39+
htmlLimitedBots: /MySpecialBot|MyAnotherSpecialBot|SimpleCrawler/,
40+
}
41+
42+
export default config
43+
```
44+
45+
```js filename="next.config.js" switcher
46+
module.exports = {
47+
htmlLimitedBots: /MySpecialBot|MyAnotherSpecialBot|SimpleCrawler/,
48+
}
49+
```
50+
51+
## Disabling
52+
53+
To fully disable streaming metadata:
54+
55+
```ts filename="next.config.ts"
56+
import type { NextConfig } from 'next'
57+
58+
const config: NextConfig = {
59+
htmlLimitedBots: /.*/,
60+
}
61+
62+
export default config
63+
```
64+
65+
```js filename="next.config.js" switcher
66+
module.exports = {
67+
htmlLimitedBots: /.*/,
68+
}
69+
```
2970

3071
## Version History
3172

0 commit comments

Comments
 (0)