File size: 8,967 Bytes
b91e262
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
---
title: Uncached data was accessed outside of `<Suspense>`
---

## Why This Error Occurred

When the `cacheComponents` feature is enabled, Next.js expects a parent `Suspense` boundary around any component that awaits data that should be accessed on every user request. The purpose of this requirement is so that Next.js can provide a useful fallback while this data is accessed and rendered.

While some data is inherently only available when a user request is being handled, such as request headers, Next.js assumes that by default any asynchronous data is expected to be accessed each time a user request is being handled unless you specifically cache it using `"use cache"`.

The proper fix for this specific error depends on what data you are accessing and how you want your Next.js app to behave.

## Possible Ways to Fix It

### Accessing Data

When you access data using `fetch`, a database client, or any other module which does asynchronous IO, Next.js interprets your intent as expecting the data to load on every user request.

If you are expecting this data to be used while fully or partially prerendering a page you must cache is using `"use cache"`.

Before:

```jsx filename="app/page.js"
async function getRecentArticles() {
  return db.query(...)
}

export default async function Page() {
  const articles = await getRecentArticles(token);
  return <ArticleList articles={articles}>
}
```

After:

```jsx filename="app/page.js"
import { cacheTag, cacheLife } from 'next/cache'

async function getRecentArticles() {
  "use cache"
  // This cache can be revalidated by webhook or server action
  // when you call revalidateTag("articles")
  cacheTag("articles")
  // This cache will revalidate after an hour even if no explicit
  // revalidate instruction was received
  cacheLife('hours')
  return db.query(...)
}

export default async function Page() {
  const articles = await getRecentArticles(token);
  return <ArticleList articles={articles}>
}
```

If this data should be accessed on every user request you must provide a fallback UI using `Suspense` from React. Where you put this Suspense boundary in your application should be informed by the kind of fallback UI you want to render. It can be immediately above the component accessing this data or even in your Root Layout.

Before:

```jsx filename="app/page.js"
async function getLatestTransactions() {
  return db.query(...)
}

export default async function Page() {
  const transactions = await getLatestTransactions(token);
  return <TransactionList transactions={transactions}>
}
```

After:

```jsx filename="app/page.js"
import { Suspense } from 'react'

async function TransactionList() {
  const transactions = await db.query(...)
  return ...
}

function TransactionSkeleton() {
  return <ul>...</ul>
}

export default async function Page() {
  return (
    <Suspense fallback={<TransactionSkeleton />}>
      <TransactionList/>
    </Suspense>
  )
}
```

### Headers

If you are accessing request headers using `headers()`, `cookies()`, or `draftMode()`. Consider whether you can move the use of these APIs deeper into your existing component tree.

Before:

```jsx filename="app/inbox.js"
export async function Inbox({ token }) {
  const email = await getEmail(token)
  return (
    <ul>
      {email.map((e) => (
        <EmailRow key={e.id} />
      ))}
    </ul>
  )
}
```

```jsx filename="app/page.js"
import { cookies } from 'next/headers'

import { Inbox } from './inbox'

export default async function Page() {
  const token = (await cookies()).get('token')
  return (
    <Suspense fallback="loading your inbox...">
      <Inbox token={token}>
    </Suspense>
  )
}
```

After:

```jsx filename="app/inbox.js"
import { cookies } from 'next/headers'

export async function Inbox() {
  const token = (await cookies()).get('token')
  const email = await getEmail(token)
  return (
    <ul>
      {email.map((e) => (
        <EmailRow key={e.id} />
      ))}
    </ul>
  )
}
```

```jsx filename="app/page.js"
import { Inbox } from './inbox'

export default async function Page() {
  return (
    <Suspense fallback="loading your inbox...">
      <Inbox>
    </Suspense>
  )
}
```

Alternatively you can add a Suspense boundary above the component that is accessing Request headers.

### Params and SearchParams

Layout `params`, and Page `params` and `searchParams` props are promises. If you await them in the Layout or Page component you might be accessing these props higher than is actually required. Try passing these props to deeper components as a promise and awaiting them closer to where the actual param or searchParam is required

Before:

```jsx filename="app/map.js"
export async function Map({ lat, lng }) {
  const mapData = await fetch(`https://...?lat=${lat}&lng=${lng}`)
  return drawMap(mapData)
}
```

```jsx filename="app/page.js"
import { cookies } from 'next/headers'

import { Map } from './map'

export default async function Page({ searchParams }) {
  const { lat, lng } = await searchParams;
  return (
    <Suspense fallback="loading your inbox...">
      <Map lat={lat} lng={lng}>
    </Suspense>
  )
}
```

After:

```jsx filename="app/map.js"
export async function Map({ coords }) {
  const { lat, lng } = await coords
  const mapData = await fetch(`https://...?lat=${lat}&lng=${lng}`)
  return drawMap(mapData)
}
```

```jsx filename="app/page.js"
import { cookies } from 'next/headers'

import { Map } from './map'

export default async function Page({ searchParams }) {
  const coords = searchParams.then(sp => ({ lat: sp.lat, lng: sp.lng }))
  return (
    <Suspense fallback="loading your inbox...">
      <Map coord={coords}>
    </Suspense>
  )
}
```

Alternatively you can add a Suspense boundary above the component that is accessing `params` or `searchParams` so Next.js understands what UI should be used when while waiting for this request data to be accessed.

#### `generateStaticParams`

For Layout and Page `params`, you can use [`generateStaticParams`](/docs/app/api-reference/functions/generate-static-params) to provide sample values for build-time validation, which allows you to await params directly without Suspense.

```jsx filename="app/blog/[slug]/page.js"
export async function generateStaticParams() {
  return [{ slug: 'hello-world' }]
}

export default async function Page({ params }) {
  const { slug } = await params //  Valid with generateStaticParams
  return <div>Blog post: {slug}</div>
}
```

Note that validation is path-dependent. Runtime parameters may trigger conditional branches accessing runtime APIs without Suspense, or dynamic content without Suspense or `use cache`, resulting in errors. See [Dynamic Routes with Cache Components](/docs/app/api-reference/file-conventions/dynamic-routes#with-cache-components).

### Short-lived Caches

`"use cache"` allows you to describe a [`cacheLife()`](/docs/app/api-reference/functions/cacheLife) that might be too short to be practical to prerender. The utility of doing this is that it can still describe a non-zero caching time for the client router cache to reuse the cache entry in the browser and it can also be useful for protecting upstream APIs while experiencing high request traffic.

If you expected the `"use cache"` entry to be prerenderable try describing a slightly longer `cacheLife()`.

Before:

```jsx filename="app/page.js"
import { cacheLife } from 'next/cache'

async function getDashboard() {
  "use cache"
  // This cache will revalidate after 1 second. It is so short
  // Next.js won't prerender it on the server but the client router
  // can reuse the result for up to 30 seconds unless the user manually refreshes
  cacheLife('seconds')
  return db.query(...)
}

export default async function Page() {
  const data = await getDashboard(token);
  return <Dashboard data={data}>
}
```

After:

```jsx filename="app/page.js"
import { cacheLife } from 'next/cache'

async function getDashboard() {
  "use cache"
  // This cache will revalidate after 1 minute. It's long enough that
  // Next.js will still produce a fully or partially prerendered page
  cacheLife('minutes')
  return db.query(...)
}

export default async function Page() {
  const data = await getDashboard(token);
  return <Dashboard data={data}>
}
```

Alternatively you can add a Suspense boundary above the component that is accessing this short-lived cached data so Next.js understands what UI should be used while accessing this data on a user request.

## Useful Links

- [`Suspense` React API](https://react.dev/reference/react/Suspense)
- [`headers` function](/docs/app/api-reference/functions/headers)
- [`cookies` function](/docs/app/api-reference/functions/cookies)
- [`draftMode` function](/docs/app/api-reference/functions/draft-mode)
- [`connection` function](/docs/app/api-reference/functions/connection)
- [`cacheLife` function](/docs/app/api-reference/functions/cacheLife)
- [`cacheTag` function](/docs/app/api-reference/functions/cacheTag)