Skip to content

Commit

Permalink
docs: Next.js 15 RC updates (#67839)
Browse files Browse the repository at this point in the history
[DOC-3018](https://linear.app/vercel/issue/DOC-3018/nextjs-15-rc-updates)

New APIs: 
- Fetch HMR cache
- Static Indicator
- `onRequestError`

---------

Co-authored-by: Hendrik Liebau <[email protected]>
Co-authored-by: JJ Kasper <[email protected]>
  • Loading branch information
3 people authored Jul 31, 2024
1 parent 4d589db commit cf44916
Show file tree
Hide file tree
Showing 51 changed files with 213 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,35 @@ related:
- app/building-your-application/optimizing/instrumentation
---

The `instrumentation.js|ts` file is used to integrate monitoring and logging tools into your application. This allows you to track the performance and behavior of your application, and to debug issues in production.
The `instrumentation.js|ts` file is used to integrate observability tools into your application, allowing you to track the performance and behavior, and to debug issues in production.

To use it, place the file in the **root** of your application or inside a [`src` folder](/docs/app/building-your-application/configuring/src-directory) if using one.

## Config Option
## Enabling Instrumentation

Instrumentation is currently an experimental feature, to use the `instrumentation` file, you must explicitly opt-in by defining [`experimental.instrumentationHook = true;`](/docs/app/api-reference/next-config-js/instrumentationHook) in your `next.config.js`:
Instrumentation is currently an experimental feature, to use the `instrumentation.js` file, you must explicitly opt-in by defining [`experimental.instrumentationHook = true;`](/docs/app/api-reference/next-config-js/instrumentationHook) in your `next.config.js`:

```js filename="next.config.js"
module.exports = {
```ts filename="next.config.ts" switcher
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
experimental: {
instrumentationHook: true,
},
}

export default nextConfig
```

```js filename="next.config.js" switcher
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
instrumentationHook: true,
},
}

module.exports = nextConfig
```

## Exports
Expand All @@ -45,9 +60,82 @@ export function register() {
}
```

### `onRequestError` (optional)

You can optionally export an `onRequestError` function to track and send **server** errors to an observability tool.

```ts filename="instrumentation.ts" switcher
import { type Instrumentation } from 'next'

export const onRequestError: Instrumentation.onRequestError = (
err,
request,
context
) => {
fetch('https://.../write-log', {
method: 'POST',
body: JSON.stringify({
message: err.message,
request,
context,
}),
headers: {
'Content-Type': 'application/json',
},
})
}
```

```js filename="instrumentation.js" switcher
export function onRequestError(err, request, context) {
fetch('https://.../write-log', {
method: 'POST',
body: JSON.stringify({
message: err.message,
request,
context,
}),
headers: {
'Content-Type': 'application/json',
},
})
}
```

#### Parameters

The function accepts three parameters: `error`, `request`, and `context`.

```ts filename="Types"
export function onRequestError(
error: { digest: string } & Error,
request: {
url: string // full URL
method: string // request method. e.g. GET, POST, etc
headers: { [key: string]: string }
},
context: {
routerKind: 'Pages Router' | 'App Router' // the router type
routePath: string // the route file path, e.g. /app/blog/[dynamic]
routeType: 'render' | 'route' | 'action' | 'middleware' // the context in which the error occurred
renderSource:
| 'react-server-components'
| 'react-server-components-payload'
| 'server-rendering'
revalidateReason: 'on-demand' | 'stale' | undefined // undefined is a normal request without revalidation
renderType: 'dynamic' | 'dynamic-resume' // 'dynamic-resume' for PPR
}
)
```

- `error`: The caught error itself (type is always `Error`), and a `digest` property which is the unique ID of the error.
- `request`: Read-only request information associated with the error.
- `context`: The context in which the error occurred. This can be the type of router (App or Pages Router), and/or (Server Components (`'render'`), Route Handlers (`'route'`), Server Actions (`'action'`), or Middleware (`'middleware'`)).

## Version History

| Version | Changes |
| --------- | ------------------------------------------------------- |
| `v15.0.0` | `onRequestError` introduced |
| `v14.0.4` | Turbopack support for `instrumentation` |
| `v13.2.0` | `instrumentation` introduced as an experimental feature |
10 changes: 10 additions & 0 deletions docs/02-app/02-api-reference/04-functions/fetch.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,16 @@ fetch(`https://...`, { next: { tags: ['collection'] } })

Set the cache tags of a resource. Data can then be revalidated on-demand using [`revalidateTag`](https://nextjs.org/docs/app/api-reference/functions/revalidateTag). The max length for a custom tag is 256 characters and the max tag items is 64.

## Troubleshooting

## Fetch `cache: 'no-store'` not showing fresh data in development

Next.js caches `fetch` responses in Server Components across Hot Module Replacement (HMR) in local development for faster responses and to reduce costs for billed API calls.

By default, the [HMR cache](docs/app/api-reference/next-config-js/servercomponentshmrcache) applies to all fetch requests, including those with the `cache: 'no-store'` option. This means uncached requests will not show fresh data between HMR refreshes. However, the cache will be cleared on navigation or full-page reloads.

See the [`serverComponentsHmrCache`](docs/app/api-reference/next-config-js/servercomponentshmrcache) docs for more information.

## Version History

| Version | Changes |
Expand Down
76 changes: 68 additions & 8 deletions docs/02-app/02-api-reference/05-next-config-js/devIndicators.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,52 @@ description: Optimized pages include an indicator to let you know if it's being

<AppOnly>

`devIndicators` allows you to configure the on-screen indicators that give context about the current route you're viewing during development.

```ts filename="Types"
devIndicators: {
appIsrStatus?: boolean, // defaults to true
buildActivity?: boolean, // defaults to true
buildActivityPosition?: 'bottom-right'
| 'bottom-left'
| 'top-right'
| 'top-left', // defaults to 'bottom-right'
},
```

## `appIsrStatus` (Static Indicator)

Next.js displays a static indicator in the bottom corner of the screen that signals if a route will be prerendered at build time. This makes it easier to understand whether a route is static or dynamic, and for you to identify if a route [opts out of static rendering](#static-route-not-showing-the-indicator).

{/* TODO: Add screenshot - waiting for design */}

You can disable the indicator by closing it, or using the config option `next.config.js`:

```ts filename="next.config.ts" switcher
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
devIndicators: {
appIsrStatus: false,
},
}

export default nextConfig
```

```js filename="next.config.js" switcher
/** @type {import('next').NextConfig} */
const nextConfig = {
devIndicators: {
appIsrStatus: false,
},
}

module.exports = nextConfig
```

## `buildActivity` (Compilation Indicator)

When you edit your code, and Next.js is compiling the application, a compilation indicator appears in the bottom right corner of the page.

> **Good to know**: This indicator is only present in development mode and will not appear when building and running the app in production mode.
Expand All @@ -21,7 +67,7 @@ module.exports = {
}
```

In some cases this indicator might not be useful for you. To remove it, open `next.config.js` and disable the `buildActivity` config in `devIndicators` object:
In some cases, this indicator might not be useful for you. To remove it, open `next.config.js` and disable the `buildActivity` config in `devIndicators` object:

```js filename="next.config.js"
module.exports = {
Expand All @@ -31,16 +77,30 @@ module.exports = {
}
```

There is also an indicator to show whether a page will be prerendered during a build in dev. It can be hidden per-page by clicking although if you never want it to show it can be disabled:
## Troubleshooting

```js filename="next.config.js"
module.exports = {
devIndicators: {
appIsrStatus: false,
},
}
### Static route not showing the indicator

If you expect a route to be static and the indicator is enabled but not showing, it's likely the route has opted out of static rendering.

You can confirm if a route is [static](/docs/app/building-your-application/rendering/server-components#static-rendering-default) or [dynamic](/docs/app/building-your-application/rendering/server-components#dynamic-rendering) by building your application using `next build --debug`, and checking the output in your terminal. Static (or prerendered) routes will display a `` symbol, whereas dynamic routes will display a `ƒ` symbol. For example:

```bash filename="Build Output"
Route (app) Size First Load JS
┌ ○ /_not-found 0 B 0 kB
└ ƒ /products/[id] 0 B 0 kB

○ (Static) prerendered as static content
ƒ (Dynamic) server-rendered on demand
```

There are two reasons a route might opt out of static rendering:

- The presence of [Dynamic APIs](/docs/app/building-your-application/rendering/server-components#dynamic-functions) which rely on runtime information.
- An [uncached data request](/docs/app/building-your-application/data-fetching/fetching#fetch-api).

Check your route for any of these conditions, and if you are not able to statically render the route, then consider using [`loading.js`](/docs/app/api-reference/file-conventions/loading) or [`<Suspense />`](https://react.dev/reference/react/Suspense) to leverage [streaming](/docs/app/building-your-application/routing/loading-ui-and-streaming#what-is-streaming).

</AppOnly>

<PagesOnly>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
title: severComponentsHmrCache
description: Configure whether fetch responses in Server Components are cached across HMR refresh requests.
---

The experimental `serverComponentsHmrCache` option allows you to cache `fetch` responses in Server Components across Hot Module Replacement (HMR) refreshes in local development. This results in faster responses and reduced costs for billed API calls.

By default, the HMR cache applies to all `fetch` requests, including those with the `cache: 'no-store'` option. This means uncached requests will not show fresh data between HMR refreshes. However, the cache will be cleared on navigation or full-page reloads.

You can disable the HMR cache by setting `serverComponentsHmrCache` to `false` in your `next.config.js` file:

```ts filename="next.config.ts" switcher
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
experimental: {
serverComponentsHmrCache: false, // defaults to true
},
}

export default nextConfig
```

```js filename="next.config.js" switcher
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
serverComponentsHmrCache: false, // defaults to true
},
}

module.exports = nextConfig
```

> **Good to know:** For better observability, we recommend using the [`logging.fetches`](/docs/app/api-reference/next-config-js/logging) option which logs fetch cache hits and misses in the console during development.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
title: instrumentation.js
description: API reference for the instrumentation.js file.
source: app/api-reference/file-conventions/instrumentation
---

{/* DO NOT EDIT. The content of this doc is generated from the source above. To edit the content of this page, navigate to the source page in your editor. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}

0 comments on commit cf44916

Please sign in to comment.