\n00015| \n00025| \n00026| >\n00027| )\n00028| }\n00029| \n\n(End of file - total 29 lines)\n","title":"pages/index.tsx","metadata":{"preview":"import Head from 'next/head'\n\nexport default function Home() {\n return (\n <>\n \n Home Page\n \n \n \n \n \n
Home
\n
Welcome to our Next.js application!
\n
}>\n00261| \n00262| \n00263| >\n00264| )\n00265| }\n00266| \n00267| type Post = { id: string; title: string; author: string; date: string }\n00268| \n00269| // Everyone sees the same blog posts (revalidated every hour)\n00270| async function BlogPosts() {\n00271| 'use cache'\n00272| cacheLife('hours')\n00273| cacheTag('posts')\n00274| \n00275| const res = await fetch('https://api.vercel.app/blog')\n00276| const posts: Post[] = await res.json()\n00277| \n00278| return (\n00279| \n00280|
Latest Posts
\n00281|
\n00282| {posts.map((post) => (\n00283|
\n00284|
{post.title}
\n00285|
\n00286| By {post.author} on {post.date}\n00287|
\n00288|
\n00289| ))}\n00290|
\n00291| \n00292| )\n00293| }\n00294| \n00295| // UI that depends on a value stored in cookies\n00296| async function UserPreferences() {\n00297| const theme = (await cookies()).get('theme')?.value || 'light'\n00298| const favoriteCategory = (await cookies()).get('category')?.value\n00299| \n00300| return (\n00301| \n00305| )\n00306| }\n00307| ```\n00308| \n00309| During prerendering, the header (static) and blog posts (cached with `use cache`) become part of the static shell, along with the fallback UI for user preferences. The UI preferences stored in cookies stream in at request time.\n00310| \n00311| Reading `cookies()` here doesn't opt-in the whole route into dynamic rendering, the way the previous rendering model did. The Suspense boundary provides fallback UI where the runtime access streams, while static and cached content still ship in the initial HTML.\n00312| \n00313| Just as `` contains async access, an **error boundary** contains failures: wrap them around a subtree that might error during rendering. Use [`unstable_catchError`](/docs/app/api-reference/functions/catchError) for component-level boundaries, or the [`error.js`](/docs/app/api-reference/file-conventions/error) file convention for route-level boundaries.\n00314| \n00315| As you build, consider that inside [`generateMetadata`](/docs/app/api-reference/functions/generate-metadata#with-cache-components) and [`generateViewport`](/docs/app/api-reference/functions/generate-viewport#with-cache-components), uncached fetches or runtime data access surface the same insights and errors as in your page, guiding you to the rendering you intend. For incremental static regeneration with both known and unknown param values, see [ISR with Cache Components](/docs/app/guides/incremental-static-regeneration-cache-components).\n00316| \n00317| ## Random values and timestamps\n00318| \n00319| Operations like `Math.random()`, `Date.now()`, or `crypto.randomUUID()` produce different values each time they execute. Cache Components requires you to explicitly handle these.\n00320| \n00321| > **Good to know:** `performance.now()` is meant for telemetry. Pass the value to your logger or metrics rather than rendering it.\n00322| \n00323| **To generate unique values per request**, defer to request time by calling [`connection()`](/docs/app/api-reference/functions/connection) before these operations, and wrap the component in ``:\n00324| \n00325| ```tsx filename=\"page.tsx\"\n00326| import { connection } from 'next/server'\n00327| import { Suspense } from 'react'\n00328| \n00329| async function UniqueContent() {\n00330| await connection()\n00331| const uuid = crypto.randomUUID()\n00332| return
Request ID: {uuid}
\n00333| }\n00334| \n00335| export default function Page() {\n00336| return (\n00337| Loading...}>\n00338| \n00339| \n00340| )\n00341| }\n00342| ```\n00343| \n00344| Alternatively, you can **cache the result** so all users see the same value until revalidation:\n00345| \n00346| ```tsx filename=\"page.tsx\"\n00347| export default async function Page() {\n00348| 'use cache'\n00349| const buildId = crypto.randomUUID()\n00350| return
Build ID: {buildId}
\n00351| }\n00352| ```\n00353| \n00354| You don't need to memorize which operations behave this way. The dev overlay surfaces a **blocking-prerender-random**, **blocking-prerender-current-time**, or **blocking-prerender-crypto** insight (depending on the call) with these fixes:\n00355| \n00356| \n00357| ' },\n00365| ]}\n00366| />\n00367| \n00377| \n00378| \n00379| ## Synchronous I/O and pure computations\n00380| \n00381| Unlike random or time-based APIs, synchronous I/O, module imports, and pure computations are predictable: the same inputs produce the same outputs. Components using only these operations are prerendered automatically, and their output becomes part of the static HTML at build time.\n00382| \n00383| ```tsx filename=\"page.tsx\"\n00384| import fs from 'node:fs'\n00385| \n00386| export default async function Page() {\n00387| const constants = await import('./constants.json')\n00388| const content = fs.readFileSync('./config.json', 'utf-8')\n00389| const items = JSON.parse(content).items ?? []\n00390| \n00391| return (\n00392|
\n00393|
{constants.appName}
\n00394|
\n00395| {items.map((item) => (\n00396|
{item.value}
\n00397| ))}\n00398|
\n00399|
\n00400| )\n00401| }\n00402| ```\n00403| \n00404| > **Good to know:** This includes queries to embedded databases with synchronous APIs, such as `better-sqlite3` or Node.js's built-in [`node:sqlite`](https://nodejs.org/api/sqlite.html). If you need per-request data from a synchronous source, call [`connection()`](/docs/app/api-reference/functions/connection) before the query.\n00405| \n00406| ## Prerendering\n00407| \n00408| At build time, Next.js renders your route's component tree. How each component is handled depends on the APIs it uses:\n00409| \n00410| - [`use cache`](#usage): the result is cached and included in the static shell\n00411| - [``](#streaming-uncached-data): fallback UI is included in the static shell while the content streams at request time\n00412| - [Synchronous I/O and pure computations](#synchronous-io-and-pure-computations): module imports, `fs.readFileSync`, and pure computations complete during prerender and are included in the static shell automatically\n00413| - [Random values and timestamps](#random-values-and-timestamps): use `connection()` + `` to get a unique value per request, or `use cache` to share one across users\n00414| \n00415| This generates a static shell consisting of HTML for initial page loads and a serialized [RSC Payload](/docs/app/getting-started/server-and-client-components#on-the-server) for client-side navigation, ensuring the browser receives fully rendered content instantly whether users navigate directly to the URL or transition from another page. This rendering approach is called **Partial Prerendering (PPR)**, the default behavior with Cache Components.\n00416| \n00417| \n00424| \n00425| Every produced static shell can be served directly from a CDN, without going through to the upstream server. This makes direct navigations [instant](#instant-navigation).\n00426| \n00427| Next.js requires you to explicitly handle components that can't complete during prerendering. It surfaces a validation insight in the dev overlay and dev server console that names the route and points at fixes (cache the access, move it into a `` boundary, or opt the route out). This validation keeps every route producing a static shell, so direct navigations stay instant.\n00428| \n00429| \n00436| \n00437| > **🎥 Watch:** Why Partial Prerendering and how it works → [YouTube (10 minutes)](https://www.youtube.com/watch?v=MTcPrTIBkpA).\n00438| \n00439| ### Bots and crawlers\n00440| \n00441| Browsers receive the static shell instantly. Bots and crawlers are detected by their user agent and handled differently: because they need a complete document, Next.js skips the shell and renders the entire page dynamically at request time, then sends the finished HTML once the render completes.\n00442| \n00443| Because the shell is re-rendered instead of reused, work that completed during prerendering now runs at request time for a bot. If part of your shell depends on inputs that only exist while prerendering, such as build-time data or values that are not reachable in the request-time environment, a page that loads for a person can fail to render for a crawler. Make sure the data your shell relies on is also available at request time. See [Bots and crawlers](/docs/app/guides/streaming#bots-and-crawlers) for more details.\n00444| \n00445| ### Maximizing the static shell\n00446| \n00447| The deeper your async work sits in the tree, the more of the page can be prerendered. This is the structural pattern Cache Components rewards: a general practice worth applying everywhere, and the foundation for the instant navigation and runtime prefetching that follow. It applies to all [runtime APIs](#working-with-runtime-apis) and async operations like data fetches.\n00448| \n00449| Consider a layout that destructures `params` at the top level:\n00450| \n00451| ```tsx filename=\"app/shop/[slug]/layout.tsx\"\n00452| export default async function Layout({\n00453| children,\n00454| params,\n00455| }: LayoutProps<'/shop/[slug]'>) {\n00456| const { slug } = await params\n00457| \n00458| return (\n00459|
\n00460| \n00461|
{slug}
\n00462| {children}\n00463|
\n00464| )\n00465| }\n00466| ```\n00467| \n00468| If this param is dynamic (not provided by [`generateStaticParams`](/docs/app/api-reference/functions/generate-static-params)), it is runtime data and the layout cannot be prerendered.\n00469| \n00470| However, it is often possible to read the parameter value further down the tree. Instead of awaiting at the layout level, pass the params promise down and await there:\n00471| \n00472| ```tsx filename=\"app/shop/[slug]/layout.tsx\" highlight={3,10-13}\n00473| import { Suspense } from 'react'\n00474| \n00475| export default function Layout({\n00476| children,\n00477| params,\n00478| }: LayoutProps<'/shop/[slug]'>) {\n00479| return (\n00480|
\n00494| }\n00495| ```\n00496| \n00497| Now ``, `{children}`, and the Suspense fallback are all part of the static shell. Only `SlugHeading` streams in at request time. You can also pass the entire `params` promise and await it in the child component.\n00498| \n00499| The same principle applies to `cookies()`, `headers()`, `searchParams`, and data fetches. See [Sharing data with context and `React.cache`](/docs/app/getting-started/fetching-data#sharing-data-with-context-and-reactcache) for a related pattern.\n00500| \n00501| ### Instant navigation\n00502| \n00503| Cache Components shipped in 16.0.0 with verification that direct visits to a route produce a static shell. Client navigations are different: a `` boundary that covers a direct visit may not be part of the render during a transition. Getting that structure right is easier when the framework steps in. Cache Components now validates these navigations too, giving you insights and errors that guide you to make navigations to your route instant. For example, wrap data in ``, cache it with `use cache`, or move where the access happens.\n00504| \n00505| Read the [Instant navigation guide](/docs/app/guides/instant-navigation) for examples and inspection tools.\n00506| \n00507| ### Runtime prefetching\n00508| \n00509| With [`prefetch = 'allow-runtime'`](/docs/app/api-reference/file-conventions/route-segment-config/prefetch) on a route, Next.js renders that route's component tree again at prefetch time, this time with the user's cookies, headers, and full URL available. The same rules apply, but more of the tree resolves now that runtime data is in scope:\n00510| \n00511| - [`use cache`](#usage) called with values extracted from runtime APIs (passed as arguments) joins the runtime prerender\n00512| - [`use cache: private`](/docs/app/api-reference/directives/use-cache-private) executes on the server, reads runtime data directly, and caches the result in the browser, joining the runtime prerender\n00513| - [``](#streaming-uncached-data) fallbacks stay in the runtime prerender while uncached content streams at request time\n00514| \n00515| This generates a **runtime prerender** that extends past the static shell with content the user's request unlocks. Because it happens during the prefetch, the navigation has nothing to wait on. The cost is a server invocation per prefetchable link.\n00516| \n00517| For example, take a dashboard that reads the user's session cookie and opts into runtime prefetching:\n00518| \n00519| ```tsx filename=\"app/dashboard/page.tsx\"\n00520| import { cookies } from 'next/headers'\n00521| import { Suspense } from 'react'\n00522| \n00523| export const prefetch = 'allow-runtime'\n00524| \n00525| export default function Dashboard() {\n00526| return (\n00527| Loading...}>\n00528| \n00529| \n00530| )\n00531| }\n00532| \n00533| async function Stats() {\n00534| const session = (await cookies()).get('session')?.value\n00535| if (!session) return
\n00538| }\n00539| \n00540| async function getStats(session: string) {\n00541| 'use cache'\n00542| return db.users.getStats(session)\n00543| }\n00544| ```\n00545| \n00546| On a direct visit, `` streams in behind the fallback. When a user navigates to `/dashboard` from another route, the framework prefetches with their session cookie. `getStats` is cached, so its result joins the runtime prerender before the click.\n00547| \n00548| See the [Runtime prefetching guide](/docs/app/guides/runtime-prefetching) for full patterns and the [`prefetch` reference](/docs/app/api-reference/file-conventions/route-segment-config/prefetch) for all modes.\n00549| \n00550| {/* I wonder if we need a small section that develops ISR briefly and links to the ISR w/ CC guide */}\n00551| \n\n(End of file - total 551 lines)\n","title":"node_modules/next/dist/docs/01-app/01-getting-started/08-caching.md","metadata":{"preview":"---\ntitle: Caching\ndescription: Learn how to cache data and UI in Next.js\nrelated:\n title: Next Steps\n description: Learn more about revalidation and the APIs mentioned on this page.\n links:\n - app/getting-started/revalidating\n - app/api-reference/directives/use-cache\n - app/api-reference/config/next-config-js/cacheComponents\n - app/guides/instant-navigation\n---\n\n> This page covers caching with [Cache Components](/docs/app/api-reference/config/next-config-js/cacheComponents), enabled by setting [`cacheComponents: true`](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.ts` file. If you're not using Cache Components, see the [Caching and Revalidating (Previous Model)](/docs/app/guides/caching-without-cache-components) guide.\n\nCaching is a technique for storing the result of data fetching and other computations so that future requests for the same data can be served faster, without doing the work again.\n\n## Enabling Cache Components\n\nYou can enable Cache Components by adding the [`cacheComponents`](/docs/app/api-reference/config/next-config-js/cacheComponents) option to your Next config file:"},"time":{"start":1781392515771,"end":1781392515774}}}}
+{"type":"tool_use","timestamp":1781392515868,"sessionID":"ses_13cbb9c4fffe5TDZ1DwM35w4Zl","part":{"id":"prt_ec344a2bd001jMKNYK3XwsRVwj","sessionID":"ses_13cbb9c4fffe5TDZ1DwM35w4Zl","messageID":"msg_ec34490c9001zc1GxYz6EOzVOq","type":"tool","callID":"read_9","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/node_modules/next/dist/docs/01-app/01-getting-started/05-server-and-client-components.md"},"output":"\n00001| ---\n00002| title: Server and Client Components\n00003| description: Learn how you can use React Server and Client Components to render parts of your application on the server or the client.\n00004| related:\n00005| title: Next Steps\n00006| description: Learn more about the APIs mentioned in this page.\n00007| links:\n00008| - app/api-reference/directives/use-client\n00009| ---\n00010| \n00011| By default, layouts and pages are [Server Components](https://react.dev/reference/rsc/server-components), which lets you fetch data and render parts of your UI on the server, optionally cache the result, and stream it to the client. When you need interactivity or browser APIs, you can use [Client Components](https://react.dev/reference/rsc/use-client) to layer in functionality.\n00012| \n00013| This page explains how Server and Client Components work in Next.js and when to use them, with examples of how to compose them together in your application.\n00014| \n00015| ## When to use Server and Client Components?\n00016| \n00017| The client and server environments have different capabilities. Server and Client components allow you to run logic in each environment depending on your use case.\n00018| \n00019| Use **Client Components** when you need:\n00020| \n00021| - [State](https://react.dev/learn/managing-state) and [event handlers](https://react.dev/learn/responding-to-events). E.g. `onClick`, `onChange`.\n00022| - [Lifecycle logic](https://react.dev/learn/lifecycle-of-reactive-effects). E.g. `useEffect`.\n00023| - Browser-only APIs. E.g. `localStorage`, `window`, `Navigator.geolocation`, etc.\n00024| - [Custom hooks](https://react.dev/learn/reusing-logic-with-custom-hooks).\n00025| \n00026| Use **Server Components** when you need:\n00027| \n00028| - Fetch data from databases or APIs close to the source.\n00029| - Use API keys, tokens, and other secrets without exposing them to the client.\n00030| - Reduce the amount of JavaScript sent to the browser.\n00031| - Improve the [First Contentful Paint (FCP)](https://web.dev/fcp/), and stream content progressively to the client.\n00032| \n00033| For example, the `` component is a Server Component that fetches data about a post, and passes it as props to the `` which handles client-side interactivity.\n00034| \n00035| ```tsx filename=\"app/[id]/page.tsx\" highlight={1,17} switcher\n00036| import LikeButton from '@/app/ui/like-button'\n00037| import { getPost } from '@/lib/data'\n00038| \n00039| export default async function Page({\n00040| params,\n00041| }: {\n00042| params: Promise<{ id: string }>\n00043| }) {\n00044| const { id } = await params\n00045| const post = await getPost(id)\n00046| \n00047| return (\n00048|
\n00049| \n00050|
{post.title}
\n00051| {/* ... */}\n00052| \n00053| \n00054|
\n00055| )\n00056| }\n00057| ```\n00058| \n00059| ```jsx filename=\"app/[id]/page.js\" highlight={1,12} switcher\n00060| import LikeButton from '@/app/ui/like-button'\n00061| import { getPost } from '@/lib/data'\n00062| \n00063| export default async function Page({ params }) {\n00064| const post = await getPost(params.id)\n00065| \n00066| return (\n00067|
\n00068| \n00069|
{post.title}
\n00070| {/* ... */}\n00071| \n00072| \n00073|
\n00074| )\n00075| }\n00076| ```\n00077| \n00078| ```tsx filename=\"app/ui/like-button.tsx\" highlight={1} switcher\n00079| 'use client'\n00080| \n00081| import { useState } from 'react'\n00082| \n00083| export default function LikeButton({ likes }: { likes: number }) {\n00084| // ...\n00085| }\n00086| ```\n00087| \n00088| ```jsx filename=\"app/ui/like-button.js\" highlight={1} switcher\n00089| 'use client'\n00090| \n00091| import { useState } from 'react'\n00092| \n00093| export default function LikeButton({ likes }) {\n00094| // ...\n00095| }\n00096| ```\n00097| \n00098| ## How do Server and Client Components work in Next.js?\n00099| \n00100| ### On the server\n00101| \n00102| On the server, Next.js uses React's APIs to orchestrate rendering. The rendering work is split into chunks, by individual route segments ([layouts and pages](/docs/app/getting-started/layouts-and-pages)):\n00103| \n00104| - **Server Components** are rendered into a special data format called the React Server Component Payload (RSC Payload).\n00105| - **Client Components** and the RSC Payload are used to [prerender](/docs/app/glossary#prerendering) HTML.\n00106| \n00107| > **What is the React Server Component Payload (RSC)?**\n00108| >\n00109| > The RSC Payload is a compact binary representation of the rendered React Server Components tree. It's used by React on the client to update the browser's DOM. The RSC Payload contains:\n00110| >\n00111| > - The rendered result of Server Components\n00112| > - Placeholders for where Client Components should be rendered and references to their JavaScript files\n00113| > - Any props passed from a Server Component to a Client Component\n00114| \n00115| ### On the client (first load)\n00116| \n00117| Then, on the client:\n00118| \n00119| 1. **HTML** is used to immediately show a fast non-interactive preview of the route to the user.\n00120| 2. **RSC Payload** is used to reconcile the Client and Server Component trees.\n00121| 3. **JavaScript** is used to hydrate Client Components and make the application interactive.\n00122| \n00123| > **What is hydration?**\n00124| >\n00125| > Hydration is React's process for attaching [event handlers](https://react.dev/learn/responding-to-events) to the DOM, to make the static HTML interactive.\n00126| \n00127| ### Subsequent Navigations\n00128| \n00129| On subsequent navigations:\n00130| \n00131| - The **RSC Payload** is prefetched and cached for instant navigation.\n00132| - **Client Components** are rendered entirely on the client, without the server-rendered HTML.\n00133| \n00134| ## Examples\n00135| \n00136| ### Using Client Components\n00137| \n00138| You can create a Client Component by adding the [`\"use client\"`](https://react.dev/reference/react/use-client) directive at the top of the file, above your imports.\n00139| \n00140| ```tsx filename=\"app/ui/counter.tsx\" highlight={1} switcher\n00141| 'use client'\n00142| \n00143| import { useState } from 'react'\n00144| \n00145| export default function Counter() {\n00146| const [count, setCount] = useState(0)\n00147| \n00148| return (\n00149|
\n00170| )\n00171| }\n00172| ```\n00173| \n00174| `\"use client\"` is used to declare a **boundary** between the Server and Client module graphs (trees).\n00175| \n00176| Once a file is marked with `\"use client\"`, **all of its imports and the components it directly renders are included in the client bundle**. This means you don’t need to add the directive to every component that is intended for the client.\n00177| \n00178| This behavior applies to components that are part of the Client Component’s [module graph](/docs/app/glossary#module-graph), which includes the modules it imports and the components it renders directly. It does not apply to Server Components passed as children or other props. Those components are not imported into the Client Component’s module graph. They are rendered on the server and passed to the Client Component as rendered output.\n00179| \n00180| See [Interleaving Server and Client Components](/docs/app/getting-started/server-and-client-components#interleaving-server-and-client-components) for how Server and Client Components can be combined.\n00181| \n00182| ### Reducing JS bundle size\n00183| \n00184| To reduce the size of your client JavaScript bundles, add `'use client'` to specific interactive components instead of marking large parts of your UI as Client Components.\n00185| \n00186| For example, the `` component contains mostly static elements like a logo and navigation links, but includes an interactive search bar. `` is interactive and needs to be a Client Component, however, the rest of the layout can remain a Server Component.\n00187| \n00188| ```tsx filename=\"app/layout.tsx\" highlight={12} switcher\n00189| // Client Component\n00190| import Search from './search'\n00191| // Server Component\n00192| import Logo from './logo'\n00193| \n00194| // Layout is a Server Component by default\n00195| export default function Layout({ children }: { children: React.ReactNode }) {\n00196| return (\n00197| <>\n00198| \n00199| \n00200| \n00201| \n00202| {children}\n00203| >\n00204| )\n00205| }\n00206| ```\n00207| \n00208| ```jsx filename=\"app/layout.js\" highlight={12} switcher\n00209| // Client Component\n00210| import Search from './search'\n00211| // Server Component\n00212| import Logo from './logo'\n00213| \n00214| // Layout is a Server Component by default\n00215| export default function Layout({ children }) {\n00216| return (\n00217| <>\n00218| \n00219| \n00220| \n00221| \n00222| {children}\n00223| >\n00224| )\n00225| }\n00226| ```\n00227| \n00228| ```tsx filename=\"app/ui/search.tsx\" highlight={1} switcher\n00229| 'use client'\n00230| \n00231| export default function Search() {\n00232| // ...\n00233| }\n00234| ```\n00235| \n00236| ```jsx filename=\"app/ui/search.js\" highlight={1} switcher\n00237| 'use client'\n00238| \n00239| export default function Search() {\n00240| // ...\n00241| }\n00242| ```\n00243| \n00244| ### Passing data from Server to Client Components\n00245| \n00246| You can pass data from Server Components to Client Components using props.\n00247| \n00248| ```tsx filename=\"app/[id]/page.tsx\" highlight={1,12} switcher\n00249| import LikeButton from '@/app/ui/like-button'\n00250| import { getPost } from '@/lib/data'\n00251| \n00252| export default async function Page({\n00253| params,\n00254| }: {\n00255| params: Promise<{ id: string }>\n00256| }) {\n00257| const { id } = await params\n00258| const post = await getPost(id)\n00259| \n00260| return \n00261| }\n00262| ```\n00263| \n00264| ```jsx filename=\"app/[id]/page.js\" highlight={1,7} switcher\n00265| import LikeButton from '@/app/ui/like-button'\n00266| import { getPost } from '@/lib/data'\n00267| \n00268| export default async function Page({ params }) {\n00269| const post = await getPost(params.id)\n00270| \n00271| return \n00272| }\n00273| ```\n00274| \n00275| ```tsx filename=\"app/ui/like-button.tsx\" highlight={1} switcher\n00276| 'use client'\n00277| \n00278| export default function LikeButton({ likes }: { likes: number }) {\n00279| // ...\n00280| }\n00281| ```\n00282| \n00283| ```jsx filename=\"app/ui/like-button.js\" highlight={1} switcher\n00284| 'use client'\n00285| \n00286| export default function LikeButton({ likes }) {\n00287| // ...\n00288| }\n00289| ```\n00290| \n00291| Alternatively, you can stream data from a Server Component to a Client Component with the [`use` API](https://react.dev/reference/react/use). See an [example](/docs/app/getting-started/fetching-data#streaming-data-with-the-use-api).\n00292| \n00293| > **Good to know**: Props passed to Client Components need to be [serializable](https://react.dev/reference/react/use-server#serializable-parameters-and-return-values) by React.\n00294| \n00295| ### Interleaving Server and Client Components\n00296| \n00297| You can pass Server Components as a prop to a Client Component. This allows you to visually nest server-rendered UI within Client components.\n00298| \n00299| A common pattern is to use `children` to create a _slot_ in a ``. For example, a `` component that fetches data on the server, inside a `` component that uses client state to toggle visibility.\n00300| \n00301| ```tsx filename=\"app/ui/modal.tsx\" switcher\n00302| 'use client'\n00303| \n00304| export default function Modal({ children }: { children: React.ReactNode }) {\n00305| return
{children}
\n00306| }\n00307| ```\n00308| \n00309| ```jsx filename=\"app/ui/modal.js\" switcher\n00310| 'use client'\n00311| \n00312| export default function Modal({ children }) {\n00313| return
{children}
\n00314| }\n00315| ```\n00316| \n00317| Then, in a parent Server Component (e.g.``), you can pass a `` as the child of the ``:\n00318| \n00319| ```tsx filename=\"app/page.tsx\" highlight={7} switcher\n00320| import Modal from './ui/modal'\n00321| import Cart from './ui/cart'\n00322| \n00323| export default function Page() {\n00324| return (\n00325| \n00326| \n00327| \n00328| )\n00329| }\n00330| ```\n00331| \n00332| ```jsx filename=\"app/page.js\" highlight={7} switcher\n00333| import Modal from './ui/modal'\n00334| import Cart from './ui/cart'\n00335| \n00336| export default function Page() {\n00337| return (\n00338| \n00339| \n00340| \n00341| )\n00342| }\n00343| ```\n00344| \n00345| In this pattern, Server Components are rendered on the server ahead of time, even when passed as props to Client Components. The React Server Component Payload contains the rendered result of those Server Components, plus placeholders for where Client Components should be rendered and references to their JavaScript files.\n00346| \n00347| ### Context providers\n00348| \n00349| [React context](https://react.dev/learn/passing-data-deeply-with-context) is commonly used to share global state like the current theme. However, React context is not supported in Server Components.\n00350| \n00351| To use context, create a Client Component that accepts `children`:\n00352| \n00353| ```tsx filename=\"app/theme-provider.tsx\" switcher\n00354| 'use client'\n00355| \n00356| import { createContext } from 'react'\n00357| \n00358| export const ThemeContext = createContext({})\n00359| \n00360| export default function ThemeProvider({\n00361| children,\n00362| }: {\n00363| children: React.ReactNode\n00364| }) {\n00365| return {children}\n00366| }\n00367| ```\n00368| \n00369| ```jsx filename=\"app/theme-provider.js\" switcher\n00370| 'use client'\n00371| \n00372| import { createContext } from 'react'\n00373| \n00374| export const ThemeContext = createContext({})\n00375| \n00376| export default function ThemeProvider({ children }) {\n00377| return {children}\n00378| }\n00379| ```\n00380| \n00381| Then, import it into a Server Component (e.g. `layout`):\n00382| \n00383| ```tsx filename=\"app/layout.tsx\" switcher\n00384| import ThemeProvider from './theme-provider'\n00385| \n00386| export default function RootLayout({\n00387| children,\n00388| }: {\n00389| children: React.ReactNode\n00390| }) {\n00391| return (\n00392| \n00393| \n00394| {children}\n00395| \n00396| \n00397| )\n00398| }\n00399| ```\n00400| \n00401| ```jsx filename=\"app/layout.js\" switcher\n00402| import ThemeProvider from './theme-provider'\n00403| \n00404| export default function RootLayout({ children }) {\n00405| return (\n00406| \n00407| \n00408| {children}\n00409| \n00410| \n00411| )\n00412| }\n00413| ```\n00414| \n00415| Your Server Component will now be able to directly render your provider, and all other Client Components throughout your app will be able to consume this context.\n00416| \n00417| > **Good to know**: You should render providers as deep as possible in the tree – notice how `ThemeProvider` only wraps `{children}` instead of the entire `` document. This makes it easier for Next.js to optimize the static parts of your Server Components.\n00418| \n00419| ### Third-party components\n00420| \n00421| When using a third-party component that relies on client-only features, you can wrap it in a Client Component to ensure it works as expected.\n00422| \n00423| For example, the `` can be imported from the `acme-carousel` package. This component uses `useState`, but it doesn't yet have the `\"use client\"` directive.\n00424| \n00425| If you use `` within a Client Component, it will work as expected:\n00426| \n00427| ```tsx filename=\"app/gallery.tsx\" switcher\n00428| 'use client'\n00429| \n00430| import { useState } from 'react'\n00431| import { Carousel } from 'acme-carousel'\n00432| \n00433| export default function Gallery() {\n00434| const [isOpen, setIsOpen] = useState(false)\n00435| \n00436| return (\n00437|
\n00438| \n00439| {/* Works, since Carousel is used within a Client Component */}\n00440| {isOpen && }\n00441|
\n00457| \n00458| {/* Works, since Carousel is used within a Client Component */}\n00459| {isOpen && }\n00460|
\n00461| )\n00462| }\n00463| ```\n00464| \n00465| However, if you try to use it directly within a Server Component, you'll see an error. This is because Next.js doesn't know `` is using client-only features.\n00466| \n00467| To fix this, you can wrap third-party components that rely on client-only features in your own Client Components:\n00468| \n00469| ```tsx filename=\"app/carousel.tsx\" switcher\n00470| 'use client'\n00471| \n00472| import { Carousel } from 'acme-carousel'\n00473| \n00474| export default Carousel\n00475| ```\n00476| \n00477| ```jsx filename=\"app/carousel.js\" switcher\n00478| 'use client'\n00479| \n00480| import { Carousel } from 'acme-carousel'\n00481| \n00482| export default Carousel\n00483| ```\n00484| \n00485| Now, you can use `` directly within a Server Component:\n00486| \n00487| ```tsx filename=\"app/page.tsx\" switcher\n00488| import Carousel from './carousel'\n00489| \n00490| export default function Page() {\n00491| return (\n00492|
\n00493|
View pictures
\n00494| {/* Works, since Carousel is a Client Component */}\n00495| \n00496|
\n00497| )\n00498| }\n00499| ```\n00500| \n00501| ```jsx filename=\"app/page.js\" switcher\n00502| import Carousel from './carousel'\n00503| \n00504| export default function Page() {\n00505| return (\n00506|
\n00507|
View pictures
\n00508| {/* Works, since Carousel is a Client Component */}\n00509| \n00510|
\n00511| )\n00512| }\n00513| ```\n00514| \n00515| > **Advice for Library Authors**\n00516| >\n00517| > If you’re building a component library, add the `\"use client\"` directive to entry points that rely on client-only features. This lets your users import components into Server Components without needing to create wrappers.\n00518| >\n00519| > It's worth noting some bundlers might strip out `\"use client\"` directives. You can find an example of how to configure esbuild to include the `\"use client\"` directive in the [React Wrap Balancer](https://github.com/shuding/react-wrap-balancer/blob/main/tsup.config.ts#L10-L13) and [Vercel Analytics](https://github.com/vercel/analytics/blob/main/packages/web/tsup.config.js#L26-L30) repositories.\n00520| \n00521| ### Preventing environment poisoning\n00522| \n00523| JavaScript modules can be shared between both Server and Client Components modules. This means it's possible to accidentally import server-only code into the client. For example, consider the following function:\n00524| \n00525| ```ts filename=\"lib/data.ts\" switcher\n00526| export async function getData() {\n00527| const res = await fetch('https://external-service.com/data', {\n00528| headers: {\n00529| authorization: process.env.API_KEY,\n00530| },\n00531| })\n00532| \n00533| return res.json()\n00534| }\n00535| ```\n00536| \n00537| ```js filename=\"lib/data.js\" switcher\n00538| export async function getData() {\n00539| const res = await fetch('https://external-service.com/data', {\n00540| headers: {\n00541| authorization: process.env.API_KEY,\n00542| },\n00543| })\n00544| \n00545| return res.json()\n00546| }\n00547| ```\n00548| \n00549| This function contains an `API_KEY` that should never be exposed to the client.\n00550| \n00551| In Next.js, only environment variables prefixed with `NEXT_PUBLIC_` are included in the client bundle. If variables are not prefixed, Next.js replaces them with an empty string.\n00552| \n00553| As a result, even though `getData()` can be imported and executed on the client, it won't work as expected.\n00554| \n00555| To prevent accidental usage in Client Components, you can use the [`server-only` package](https://www.npmjs.com/package/server-only).\n00556| \n00557| Then, import the package into a file that contains server-only code:\n00558| \n00559| ```js filename=\"lib/data.js\"\n00560| import 'server-only'\n00561| \n00562| export async function getData() {\n00563| const res = await fetch('https://external-service.com/data', {\n00564| headers: {\n00565| authorization: process.env.API_KEY,\n00566| },\n00567| })\n00568| \n00569| return res.json()\n00570| }\n00571| ```\n00572| \n00573| Now, if you try to import the module into a Client Component, there will be a build-time error.\n00574| \n00575| The corresponding [`client-only` package](https://www.npmjs.com/package/client-only) can be used to mark modules that contain client-only logic like code that accesses the `window` object.\n00576| \n00577| In Next.js, installing `server-only` or `client-only` is **optional**. However, if your linting rules flag extraneous dependencies, you may install them to avoid issues.\n00578| \n00579| ```bash package=\"npm\"\n00580| npm install server-only\n00581| ```\n00582| \n00583| ```bash package=\"yarn\"\n00584| yarn add server-only\n00585| ```\n00586| \n00587| ```bash package=\"pnpm\"\n00588| pnpm add server-only\n00589| ```\n00590| \n00591| ```bash package=\"bun\"\n00592| bun add server-only\n00593| ```\n00594| \n00595| Next.js handles `server-only` and `client-only` imports internally to provide clearer error messages when a module is used in the wrong environment. The contents of these packages from NPM are not used by Next.js.\n00596| \n00597| Next.js also provides its own type declarations for `server-only` and `client-only`, for TypeScript configurations where [`noUncheckedSideEffectImports`](https://www.typescriptlang.org/tsconfig/#noUncheckedSideEffectImports) is active.\n00598| \n\n(End of file - total 598 lines)\n","title":"node_modules/next/dist/docs/01-app/01-getting-started/05-server-and-client-components.md","metadata":{"preview":"---\ntitle: Server and Client Components\ndescription: Learn how you can use React Server and Client Components to render parts of your application on the server or the client.\nrelated:\n title: Next Steps\n description: Learn more about the APIs mentioned in this page.\n links:\n - app/api-reference/directives/use-client\n---\n\nBy default, layouts and pages are [Server Components](https://react.dev/reference/rsc/server-components), which lets you fetch data and render parts of your UI on the server, optionally cache the result, and stream it to the client. When you need interactivity or browser APIs, you can use [Client Components](https://react.dev/reference/rsc/use-client) to layer in functionality.\n\nThis page explains how Server and Client Components work in Next.js and when to use them, with examples of how to compose them together in your application.\n\n## When to use Server and Client Components?\n\nThe client and server environments have different capabilities. Server and Client components allow you to run logic in each environment depending on your use case.\n\nUse **Client Components** when you need:\n"},"time":{"start":1781392515864,"end":1781392515867}}}}
+{"type":"step_finish","timestamp":1781392515872,"sessionID":"ses_13cbb9c4fffe5TDZ1DwM35w4Zl","part":{"id":"prt_ec344a31c001DO6c4nOWNMqDbt","sessionID":"ses_13cbb9c4fffe5TDZ1DwM35w4Zl","messageID":"msg_ec34490c9001zc1GxYz6EOzVOq","type":"step-finish","reason":"tool-calls","snapshot":"54efff247862815d10297e8a8aea21f2cba03a22","cost":0.00426621,"tokens":{"input":2243,"output":114,"reasoning":0,"cache":{"read":10496,"write":0}}}}
+{"type":"step_start","timestamp":1781392520428,"sessionID":"ses_13cbb9c4fffe5TDZ1DwM35w4Zl","part":{"id":"prt_ec344b4e9001cpMYwJrg1zf3lK","sessionID":"ses_13cbb9c4fffe5TDZ1DwM35w4Zl","messageID":"msg_ec344a3290010B9QkG8mrHGKUz","type":"step-start","snapshot":"54efff247862815d10297e8a8aea21f2cba03a22"}}
+{"type":"tool_use","timestamp":1781392523932,"sessionID":"ses_13cbb9c4fffe5TDZ1DwM35w4Zl","part":{"id":"prt_ec344c1b7001aVNiJgpPhhgv6v","sessionID":"ses_13cbb9c4fffe5TDZ1DwM35w4Zl","messageID":"msg_ec344a3290010B9QkG8mrHGKUz","type":"tool","callID":"read_10","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/next.config.ts"},"output":"\n00001| import type { NextConfig } from 'next'\n00002| \n00003| const nextConfig: NextConfig = {}\n00004| \n00005| export default nextConfig\n00006| \n\n(End of file - total 6 lines)\n","title":"next.config.ts","metadata":{"preview":"import type { NextConfig } from 'next'\n\nconst nextConfig: NextConfig = {}\n\nexport default nextConfig\n"},"time":{"start":1781392523929,"end":1781392523931}}}}
+{"type":"tool_use","timestamp":1781392524023,"sessionID":"ses_13cbb9c4fffe5TDZ1DwM35w4Zl","part":{"id":"prt_ec344c29b0016oxrwm4kfXzFdz","sessionID":"ses_13cbb9c4fffe5TDZ1DwM35w4Zl","messageID":"msg_ec344a3290010B9QkG8mrHGKUz","type":"tool","callID":"read_11","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/package.json"},"output":"\n00001| {\n00002| \"private\": true,\n00003| \"type\": \"module\",\n00004| \"scripts\": {\n00005| \"dev\": \"next dev\",\n00006| \"build\": \"next build\",\n00007| \"start\": \"next start\"\n00008| },\n00009| \"dependencies\": {\n00010| \"@ai-sdk/react\": \"2.0.0-beta.28\",\n00011| \"@modelcontextprotocol/sdk\": \"^1.17.0\",\n00012| \"ai\": \"5.0.59\",\n00013| \"next\": \"^16.3.0-canary.50\",\n00014| \"react\": \"19.1.0\",\n00015| \"react-dom\": \"19.1.0\",\n00016| \"zod\": \"^4.0.10\"\n00017| },\n00018| \"devDependencies\": {\n00019| \"@types/node\": \"^20\",\n00020| \"@types/react\": \"^19\",\n00021| \"@types/react-dom\": \"^19\",\n00022| \"@vitejs/plugin-react\": \"^4.4.1\",\n00023| \"typescript\": \"^5\",\n00024| \"vite-tsconfig-paths\": \"^5.1.4\",\n00025| \"vitest\": \"^3.1.3\"\n00026| }\n00027| }\n00028| \n\n(End of file - total 28 lines)\n","title":"package.json","metadata":{"preview":"{\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"next dev\",\n \"build\": \"next build\",\n \"start\": \"next start\"\n },\n \"dependencies\": {\n \"@ai-sdk/react\": \"2.0.0-beta.28\",\n \"@modelcontextprotocol/sdk\": \"^1.17.0\",\n \"ai\": \"5.0.59\",\n \"next\": \"^16.3.0-canary.50\",\n \"react\": \"19.1.0\",\n \"react-dom\": \"19.1.0\",\n \"zod\": \"^4.0.10\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^20\",\n \"@types/react\": \"^19\","},"time":{"start":1781392524020,"end":1781392524022}}}}
+{"type":"step_finish","timestamp":1781392524026,"sessionID":"ses_13cbb9c4fffe5TDZ1DwM35w4Zl","part":{"id":"prt_ec344c2f6001MEaJ1oDleCFyDv","sessionID":"ses_13cbb9c4fffe5TDZ1DwM35w4Zl","messageID":"msg_ec344a3290010B9QkG8mrHGKUz","type":"step-finish","reason":"tool-calls","snapshot":"54efff247862815d10297e8a8aea21f2cba03a22","cost":0.02344519,"tokens":{"input":21657,"output":216,"reasoning":0,"cache":{"read":12544,"write":0}}}}
+{"type":"step_start","timestamp":1781392525872,"sessionID":"ses_13cbb9c4fffe5TDZ1DwM35w4Zl","part":{"id":"prt_ec344ca2b001sm4NYRCrnZmZ9m","sessionID":"ses_13cbb9c4fffe5TDZ1DwM35w4Zl","messageID":"msg_ec344c302001EAUPMMXIBBSJB9","type":"step-start","snapshot":"54efff247862815d10297e8a8aea21f2cba03a22"}}
+{"type":"tool_use","timestamp":1781392548822,"sessionID":"ses_13cbb9c4fffe5TDZ1DwM35w4Zl","part":{"id":"prt_ec345082b001FSGSHIHtjlq2Lh","sessionID":"ses_13cbb9c4fffe5TDZ1DwM35w4Zl","messageID":"msg_ec344c302001EAUPMMXIBBSJB9","type":"tool","callID":"edit_12","tool":"edit","state":{"status":"completed","input":{"filePath":"/workspace/app/UserDashboard.tsx","oldString":"export default function UserDashboard() {\n // TODO: Implement user dashboard that needs to fetch user-specific data on each request\n return (\n
\n
User Dashboard
\n
User dashboard content goes here
\n
\n )\n}\n","newString":"type UserPreferences = {\n [key: string]: unknown\n}\n\nasync function getUserPreferences(): Promise {\n const res = await fetch('https://api.example.com/user/preferences')\n\n if (!res.ok) {\n throw new Error(`Failed to fetch user preferences: ${res.status}`)\n }\n\n return res.json()\n}\n\nexport default async function UserDashboard() {\n const preferences = await getUserPreferences()\n\n return (\n
\n
User Dashboard
\n
{JSON.stringify(preferences, null, 2)}
\n
\n )\n}\n"},"output":"","title":"app/UserDashboard.tsx","metadata":{"diagnostics":{"/workspace/app/layout.tsx":[],"/workspace/app/UserDashboard.tsx":[],"/workspace/app/page.tsx":[],"/workspace/next.config.ts":[]},"diff":"Index: /workspace/app/UserDashboard.tsx\n===================================================================\n--- /workspace/app/UserDashboard.tsx\n+++ /workspace/app/UserDashboard.tsx\n@@ -1,9 +1,24 @@\n-export default function UserDashboard() {\n- // TODO: Implement user dashboard that needs to fetch user-specific data on each request\n+type UserPreferences = {\n+ [key: string]: unknown\n+}\n+\n+async function getUserPreferences(): Promise {\n+ const res = await fetch('https://api.example.com/user/preferences')\n+\n+ if (!res.ok) {\n+ throw new Error(`Failed to fetch user preferences: ${res.status}`)\n+ }\n+\n+ return res.json()\n+}\n+\n+export default async function UserDashboard() {\n+ const preferences = await getUserPreferences()\n+\n return (\n
\n
User Dashboard
\n-
User dashboard content goes here
\n+
{JSON.stringify(preferences, null, 2)}
\n
\n )\n }\n","filediff":{"file":"/workspace/app/UserDashboard.tsx","before":"export default function UserDashboard() {\n // TODO: Implement user dashboard that needs to fetch user-specific data on each request\n return (\n
\n
User Dashboard
\n
User dashboard content goes here
\n
\n )\n}\n","after":"type UserPreferences = {\n [key: string]: unknown\n}\n\nasync function getUserPreferences(): Promise {\n const res = await fetch('https://api.example.com/user/preferences')\n\n if (!res.ok) {\n throw new Error(`Failed to fetch user preferences: ${res.status}`)\n }\n\n return res.json()\n}\n\nexport default async function UserDashboard() {\n const preferences = await getUserPreferences()\n\n return (\n
\n
User Dashboard
\n
{JSON.stringify(preferences, null, 2)}
\n
\n )\n}\n","additions":18,"deletions":3}},"time":{"start":1781392545804,"end":1781392548821}}}}
+{"type":"tool_use","timestamp":1781392554174,"sessionID":"ses_13cbb9c4fffe5TDZ1DwM35w4Zl","part":{"id":"prt_ec3451816001IHhd63Ueng2s2v","sessionID":"ses_13cbb9c4fffe5TDZ1DwM35w4Zl","messageID":"msg_ec344c302001EAUPMMXIBBSJB9","type":"tool","callID":"edit_13","tool":"edit","state":{"status":"completed","input":{"filePath":"/workspace/app/page.tsx","oldString":"import UserDashboard from './UserDashboard'\n\n// Example of App Router data fetching\nasync function getStaticData() {\n try {\n const res = await fetch('https://api.example.com/stats')\n return res.json()\n } catch {\n // Return mock data for build time\n return { users: 100 }\n }\n}\n\nexport default async function Page() {\n const stats = await getStaticData()\n\n return (\n
\n
Dashboard
\n
Total users: {stats.users}
\n \n
\n )\n}\n","newString":"import { Suspense } from 'react'\nimport UserDashboard from './UserDashboard'\n\n// Example of App Router data fetching\nasync function getStaticData() {\n try {\n const res = await fetch('https://api.example.com/stats')\n return res.json()\n } catch {\n // Return mock data for build time\n return { users: 100 }\n }\n}\n\nexport default async function Page() {\n const stats = await getStaticData()\n\n return (\n
\n
Dashboard
\n
Total users: {stats.users}
\n Loading user preferences...}>\n \n \n
\n )\n}\n"},"output":"","title":"app/page.tsx","metadata":{"diagnostics":{"/workspace/app/layout.tsx":[],"/workspace/app/UserDashboard.tsx":[],"/workspace/app/page.tsx":[],"/workspace/next.config.ts":[]},"diff":"Index: /workspace/app/page.tsx\n===================================================================\n--- /workspace/app/page.tsx\n+++ /workspace/app/page.tsx\n@@ -1,4 +1,5 @@\n+import { Suspense } from 'react'\n import UserDashboard from './UserDashboard'\n \n // Example of App Router data fetching\n async function getStaticData() {\n@@ -17,8 +18,10 @@\n return (\n
\n
Dashboard
\n
Total users: {stats.users}
\n- \n+ Loading user preferences...}>\n+ \n+ \n
\n )\n }\n","filediff":{"file":"/workspace/app/page.tsx","before":"import UserDashboard from './UserDashboard'\n\n// Example of App Router data fetching\nasync function getStaticData() {\n try {\n const res = await fetch('https://api.example.com/stats')\n return res.json()\n } catch {\n // Return mock data for build time\n return { users: 100 }\n }\n}\n\nexport default async function Page() {\n const stats = await getStaticData()\n\n return (\n
\n
Dashboard
\n
Total users: {stats.users}
\n \n
\n )\n}\n","after":"import { Suspense } from 'react'\nimport UserDashboard from './UserDashboard'\n\n// Example of App Router data fetching\nasync function getStaticData() {\n try {\n const res = await fetch('https://api.example.com/stats')\n return res.json()\n } catch {\n // Return mock data for build time\n return { users: 100 }\n }\n}\n\nexport default async function Page() {\n const stats = await getStaticData()\n\n return (\n
\n
Dashboard
\n
Total users: {stats.users}
\n Loading user preferences...}>\n \n \n
\n )\n}\n","additions":4,"deletions":1}},"time":{"start":1781392551165,"end":1781392554171}}}}
+{"type":"step_finish","timestamp":1781392554179,"sessionID":"ses_13cbb9c4fffe5TDZ1DwM35w4Zl","part":{"id":"prt_ec34538bc001wY1e4AHPUo3XId","sessionID":"ses_13cbb9c4fffe5TDZ1DwM35w4Zl","messageID":"msg_ec344c302001EAUPMMXIBBSJB9","type":"step-finish","reason":"tool-calls","snapshot":"675a9fcd98a56f9dfa707e66fa5f7dbf7e9fb03b","cost":0.01224963,"tokens":{"input":781,"output":1515,"reasoning":0,"cache":{"read":34048,"write":0}}}}
+{"type":"step_start","timestamp":1781392556333,"sessionID":"ses_13cbb9c4fffe5TDZ1DwM35w4Zl","part":{"id":"prt_ec3454126001wTDVBzV7F4kEGd","sessionID":"ses_13cbb9c4fffe5TDZ1DwM35w4Zl","messageID":"msg_ec34538d6001exV41o4opzXoED","type":"step-start","snapshot":"675a9fcd98a56f9dfa707e66fa5f7dbf7e9fb03b"}}
+{"type":"tool_use","timestamp":1781392556960,"sessionID":"ses_13cbb9c4fffe5TDZ1DwM35w4Zl","part":{"id":"prt_ec34542690019U8YcM44fbrD3t","sessionID":"ses_13cbb9c4fffe5TDZ1DwM35w4Zl","messageID":"msg_ec34538d6001exV41o4opzXoED","type":"tool","callID":"read_14","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/app/UserDashboard.tsx"},"output":"\n00001| type UserPreferences = {\n00002| [key: string]: unknown\n00003| }\n00004| \n00005| async function getUserPreferences(): Promise {\n00006| const res = await fetch('https://api.example.com/user/preferences')\n00007| \n00008| if (!res.ok) {\n00009| throw new Error(`Failed to fetch user preferences: ${res.status}`)\n00010| }\n00011| \n00012| return res.json()\n00013| }\n00014| \n00015| export default async function UserDashboard() {\n00016| const preferences = await getUserPreferences()\n00017| \n00018| return (\n00019|
\n00020|
User Dashboard
\n00021|
{JSON.stringify(preferences, null, 2)}
\n00022|
\n00023| )\n00024| }\n00025| \n\n(End of file - total 25 lines)\n","title":"app/UserDashboard.tsx","metadata":{"preview":"type UserPreferences = {\n [key: string]: unknown\n}\n\nasync function getUserPreferences(): Promise {\n const res = await fetch('https://api.example.com/user/preferences')\n\n if (!res.ok) {\n throw new Error(`Failed to fetch user preferences: ${res.status}`)\n }\n\n return res.json()\n}\n\nexport default async function UserDashboard() {\n const preferences = await getUserPreferences()\n\n return (\n
\n
User Dashboard
"},"time":{"start":1781392556954,"end":1781392556957}}}}
+{"type":"tool_use","timestamp":1781392557009,"sessionID":"ses_13cbb9c4fffe5TDZ1DwM35w4Zl","part":{"id":"prt_ec345439c001iqlRczhFIze6VS","sessionID":"ses_13cbb9c4fffe5TDZ1DwM35w4Zl","messageID":"msg_ec34538d6001exV41o4opzXoED","type":"tool","callID":"read_15","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/app/page.tsx"},"output":"\n00001| import { Suspense } from 'react'\n00002| import UserDashboard from './UserDashboard'\n00003| \n00004| // Example of App Router data fetching\n00005| async function getStaticData() {\n00006| try {\n00007| const res = await fetch('https://api.example.com/stats')\n00008| return res.json()\n00009| } catch {\n00010| // Return mock data for build time\n00011| return { users: 100 }\n00012| }\n00013| }\n00014| \n00015| export default async function Page() {\n00016| const stats = await getStaticData()\n00017| \n00018| return (\n00019|
\n00020|
Dashboard
\n00021|
Total users: {stats.users}
\n00022| Loading user preferences...}>\n00023| \n00024| \n00025|
\n00026| )\n00027| }\n00028| \n\n(End of file - total 28 lines)\n","title":"app/page.tsx","metadata":{"preview":"import { Suspense } from 'react'\nimport UserDashboard from './UserDashboard'\n\n// Example of App Router data fetching\nasync function getStaticData() {\n try {\n const res = await fetch('https://api.example.com/stats')\n return res.json()\n } catch {\n // Return mock data for build time\n return { users: 100 }\n }\n}\n\nexport default async function Page() {\n const stats = await getStaticData()\n\n return (\n
\n
Dashboard
"},"time":{"start":1781392557002,"end":1781392557005}}}}
+{"type":"step_finish","timestamp":1781392557013,"sessionID":"ses_13cbb9c4fffe5TDZ1DwM35w4Zl","part":{"id":"prt_ec34543cd001KSOH3ueONMahJM","sessionID":"ses_13cbb9c4fffe5TDZ1DwM35w4Zl","messageID":"msg_ec34538d6001exV41o4opzXoED","type":"step-finish","reason":"tool-calls","snapshot":"675a9fcd98a56f9dfa707e66fa5f7dbf7e9fb03b","cost":0.00725926,"tokens":{"input":1546,"output":55,"reasoning":0,"cache":{"read":34816,"write":0}}}}
+{"type":"step_start","timestamp":1781392558979,"sessionID":"ses_13cbb9c4fffe5TDZ1DwM35w4Zl","part":{"id":"prt_ec3454b7d001T2hnwafESw63V0","sessionID":"ses_13cbb9c4fffe5TDZ1DwM35w4Zl","messageID":"msg_ec34543e20016yacCnlVlU3D7Q","type":"step-start","snapshot":"675a9fcd98a56f9dfa707e66fa5f7dbf7e9fb03b"}}
+{"type":"tool_use","timestamp":1781392563780,"sessionID":"ses_13cbb9c4fffe5TDZ1DwM35w4Zl","part":{"id":"prt_ec3455664001ahY43BDd0yxzSK","sessionID":"ses_13cbb9c4fffe5TDZ1DwM35w4Zl","messageID":"msg_ec34543e20016yacCnlVlU3D7Q","type":"tool","callID":"bash_16","tool":"bash","state":{"status":"completed","input":{"command":"npx tsc --noEmit","description":"Run TypeScript type check","workdir":"/workspace"},"output":"","title":"Run TypeScript type check","metadata":{"output":"","exit":0,"description":"Run TypeScript type check"},"time":{"start":1781392562064,"end":1781392563777}}}}
+{"type":"step_finish","timestamp":1781392563786,"sessionID":"ses_13cbb9c4fffe5TDZ1DwM35w4Zl","part":{"id":"prt_ec3455e42001Xfm3DNUyvENC0H","sessionID":"ses_13cbb9c4fffe5TDZ1DwM35w4Zl","messageID":"msg_ec34543e20016yacCnlVlU3D7Q","type":"step-finish","reason":"tool-calls","snapshot":"ce4aded82df550744290a4329bd9512ebe8549e7","cost":0.00727552,"tokens":{"input":576,"output":228,"reasoning":0,"cache":{"read":36352,"write":0}}}}
+{"type":"step_start","timestamp":1781392565743,"sessionID":"ses_13cbb9c4fffe5TDZ1DwM35w4Zl","part":{"id":"prt_ec34565ec001lJZZACPjYP3cRy","sessionID":"ses_13cbb9c4fffe5TDZ1DwM35w4Zl","messageID":"msg_ec3455e580013lrzBbh1kImYZD","type":"step-start","snapshot":"ce4aded82df550744290a4329bd9512ebe8549e7"}}
+{"type":"text","timestamp":1781392567240,"sessionID":"ses_13cbb9c4fffe5TDZ1DwM35w4Zl","part":{"id":"prt_ec345671d001UsmxutokZ0uooA","sessionID":"ses_13cbb9c4fffe5TDZ1DwM35w4Zl","messageID":"msg_ec3455e580013lrzBbh1kImYZD","type":"text","text":"Implemented `UserDashboard` as an async Server Component in `app/UserDashboard.tsx:15` that fetches from `https://api.example.com/user/preferences` on each request and renders the JSON result.\n\nAlso wrapped it in a `` boundary in `app/page.tsx:22` so the rest of the page can render while user-specific preferences stream in. Type check passes.","time":{"start":1781392567239,"end":1781392567239}}}
+{"type":"step_finish","timestamp":1781392567243,"sessionID":"ses_13cbb9c4fffe5TDZ1DwM35w4Zl","part":{"id":"prt_ec3456bc7001M8oFMdsboY8Uy5","sessionID":"ses_13cbb9c4fffe5TDZ1DwM35w4Zl","messageID":"msg_ec3455e580013lrzBbh1kImYZD","type":"step-finish","reason":"stop","snapshot":"ce4aded82df550744290a4329bd9512ebe8549e7","cost":0.00659579,"tokens":{"input":309,"output":101,"reasoning":0,"cache":{"read":36864,"write":0}}}}
\ No newline at end of file
diff --git a/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-023-avoid-getserversideprops/run-1/transcript.json b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-023-avoid-getserversideprops/run-1/transcript.json
new file mode 100644
index 000000000..d416025e3
--- /dev/null
+++ b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-023-avoid-getserversideprops/run-1/transcript.json
@@ -0,0 +1,1304 @@
+{
+ "agent": "vercel-ai-gateway/opencode",
+ "model": "vercel/moonshotai/kimi-k2.7-code",
+ "events": [
+ {
+ "timestamp": "2026-06-13T23:15:02.158Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "shell",
+ "originalName": "bash",
+ "args": {
+ "command": "ls -la /workspace",
+ "description": "List files in workspace",
+ "workdir": "/workspace",
+ "_extractedCommand": "ls -la /workspace"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392502158,
+ "sessionID": "ses_13cbb9c4fffe5TDZ1DwM35w4Zl",
+ "part": {
+ "id": "prt_ec3446baa001TZymk0hgczXkdG",
+ "sessionID": "ses_13cbb9c4fffe5TDZ1DwM35w4Zl",
+ "messageID": "msg_ec344640700188AYvj2Z5e31Xn",
+ "type": "tool",
+ "callID": "bash_0",
+ "tool": "bash",
+ "state": {
+ "status": "completed",
+ "input": {
+ "command": "ls -la /workspace",
+ "description": "List files in workspace",
+ "workdir": "/workspace"
+ },
+ "output": "total 196\ndrwxr-xr-x 5 vercel-sandbox vercel-sandbox 227 Jun 13 23:14 .\ndrwxr-xr-x 20 root root 286 Jun 13 23:14 ..\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 154 Jun 13 23:14 .git\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 14 Jun 13 23:14 .gitignore\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 327 Jun 13 23:14 AGENTS.md\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 11 Jun 13 23:14 CLAUDE.md\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 11 Jun 13 23:14 GEMINI.md\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 65 Jun 13 23:14 app\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 101 Jun 13 23:14 next.config.ts\ndrwxr-xr-x 179 vercel-sandbox vercel-sandbox 8192 Jun 13 23:14 node_modules\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 1549 Jun 13 23:14 opencode.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 154377 Jun 13 23:14 package-lock.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 603 Jun 13 23:14 package.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 599 Jun 13 23:14 tsconfig.json\n",
+ "title": "List files in workspace",
+ "metadata": {
+ "output": "total 196\ndrwxr-xr-x 5 vercel-sandbox vercel-sandbox 227 Jun 13 23:14 .\ndrwxr-xr-x 20 root root 286 Jun 13 23:14 ..\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 154 Jun 13 23:14 .git\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 14 Jun 13 23:14 .gitignore\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 327 Jun 13 23:14 AGENTS.md\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 11 Jun 13 23:14 CLAUDE.md\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 11 Jun 13 23:14 GEMINI.md\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 65 Jun 13 23:14 app\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 101 Jun 13 23:14 next.config.ts\ndrwxr-xr-x 179 vercel-sandbox vercel-sandbox 8192 Jun 13 23:14 node_modules\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 1549 Jun 13 23:14 opencode.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 154377 Jun 13 23:14 package-lock.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 603 Jun 13 23:14 package.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 599 Jun 13 23:14 tsconfig.json\n",
+ "exit": 0,
+ "description": "List files in workspace"
+ },
+ "time": {
+ "start": 1781392502113,
+ "end": 1781392502150
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:02.158Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "shell",
+ "originalName": "bash",
+ "result": "total 196\ndrwxr-xr-x 5 vercel-sandbox vercel-sandbox 227 Jun 13 23:14 .\ndrwxr-xr-x 20 root root 286 Jun 13 23:14 ..\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 154 Jun 13 23:14 .git\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 14 Jun 13 23:14 .gitignore\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 327 Jun 13 23:14 AGENTS.md\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 11 Jun 13 23:14 CLAUDE.md\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 11 Jun 13 23:14 GEMINI.md\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 65 Jun 13 23:14 app\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 101 Jun 13 23:14 next.config.ts\ndrwxr-xr-x 179 vercel-sandbox vercel-sandbox 8192 Jun 13 23:14 node_modules\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 1549 Jun 13 23:14 opencode.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 154377 Jun 13 23:14 package-lock.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 603 Jun 13 23:14 package.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 599 Jun 13 23:14 tsconfig.json\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "command": "ls -la /workspace",
+ "description": "List files in workspace",
+ "workdir": "/workspace"
+ },
+ "output": "total 196\ndrwxr-xr-x 5 vercel-sandbox vercel-sandbox 227 Jun 13 23:14 .\ndrwxr-xr-x 20 root root 286 Jun 13 23:14 ..\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 154 Jun 13 23:14 .git\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 14 Jun 13 23:14 .gitignore\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 327 Jun 13 23:14 AGENTS.md\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 11 Jun 13 23:14 CLAUDE.md\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 11 Jun 13 23:14 GEMINI.md\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 65 Jun 13 23:14 app\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 101 Jun 13 23:14 next.config.ts\ndrwxr-xr-x 179 vercel-sandbox vercel-sandbox 8192 Jun 13 23:14 node_modules\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 1549 Jun 13 23:14 opencode.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 154377 Jun 13 23:14 package-lock.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 603 Jun 13 23:14 package.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 599 Jun 13 23:14 tsconfig.json\n",
+ "title": "List files in workspace",
+ "metadata": {
+ "output": "total 196\ndrwxr-xr-x 5 vercel-sandbox vercel-sandbox 227 Jun 13 23:14 .\ndrwxr-xr-x 20 root root 286 Jun 13 23:14 ..\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 154 Jun 13 23:14 .git\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 14 Jun 13 23:14 .gitignore\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 327 Jun 13 23:14 AGENTS.md\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 11 Jun 13 23:14 CLAUDE.md\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 11 Jun 13 23:14 GEMINI.md\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 65 Jun 13 23:14 app\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 101 Jun 13 23:14 next.config.ts\ndrwxr-xr-x 179 vercel-sandbox vercel-sandbox 8192 Jun 13 23:14 node_modules\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 1549 Jun 13 23:14 opencode.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 154377 Jun 13 23:14 package-lock.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 603 Jun 13 23:14 package.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 599 Jun 13 23:14 tsconfig.json\n",
+ "exit": 0,
+ "description": "List files in workspace"
+ },
+ "time": {
+ "start": 1781392502113,
+ "end": 1781392502150
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:04.406Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "shell",
+ "originalName": "bash",
+ "args": {
+ "command": "find /workspace/app -type f -o -type d | sort",
+ "description": "List all files in app directory",
+ "workdir": "/workspace",
+ "_extractedCommand": "find /workspace/app -type f -o -type d | sort"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392504406,
+ "sessionID": "ses_13cbb9c4fffe5TDZ1DwM35w4Zl",
+ "part": {
+ "id": "prt_ec344743c001Ulnh8MjsiTmLeo",
+ "sessionID": "ses_13cbb9c4fffe5TDZ1DwM35w4Zl",
+ "messageID": "msg_ec3446daa001nDL3bFGG80636i",
+ "type": "tool",
+ "callID": "bash_1",
+ "tool": "bash",
+ "state": {
+ "status": "completed",
+ "input": {
+ "command": "find /workspace/app -type f -o -type d | sort",
+ "description": "List all files in app directory",
+ "workdir": "/workspace"
+ },
+ "output": "/workspace/app\n/workspace/app/UserDashboard.tsx\n/workspace/app/layout.tsx\n/workspace/app/page.tsx\n",
+ "title": "List all files in app directory",
+ "metadata": {
+ "output": "/workspace/app\n/workspace/app/UserDashboard.tsx\n/workspace/app/layout.tsx\n/workspace/app/page.tsx\n",
+ "exit": 0,
+ "description": "List all files in app directory"
+ },
+ "time": {
+ "start": 1781392504387,
+ "end": 1781392504402
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:04.406Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "shell",
+ "originalName": "bash",
+ "result": "/workspace/app\n/workspace/app/UserDashboard.tsx\n/workspace/app/layout.tsx\n/workspace/app/page.tsx\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "command": "find /workspace/app -type f -o -type d | sort",
+ "description": "List all files in app directory",
+ "workdir": "/workspace"
+ },
+ "output": "/workspace/app\n/workspace/app/UserDashboard.tsx\n/workspace/app/layout.tsx\n/workspace/app/page.tsx\n",
+ "title": "List all files in app directory",
+ "metadata": {
+ "output": "/workspace/app\n/workspace/app/UserDashboard.tsx\n/workspace/app/layout.tsx\n/workspace/app/page.tsx\n",
+ "exit": 0,
+ "description": "List all files in app directory"
+ },
+ "time": {
+ "start": 1781392504387,
+ "end": 1781392504402
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:06.835Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "args": {
+ "filePath": "/workspace/app/UserDashboard.tsx",
+ "_extractedPath": "/workspace/app/UserDashboard.tsx"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392506835,
+ "sessionID": "ses_13cbb9c4fffe5TDZ1DwM35w4Zl",
+ "part": {
+ "id": "prt_ec3447e35001Fv3nEYbORYIaE5",
+ "sessionID": "ses_13cbb9c4fffe5TDZ1DwM35w4Zl",
+ "messageID": "msg_ec3447663001Kqeo0bqbymwibd",
+ "type": "tool",
+ "callID": "read_2",
+ "tool": "read",
+ "state": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/app/UserDashboard.tsx"
+ },
+ "output": "\n00001| export default function UserDashboard() {\n00002| // TODO: Implement user dashboard that needs to fetch user-specific data on each request\n00003| return (\n00004|
\n00005|
User Dashboard
\n00006|
User dashboard content goes here
\n00007|
\n00008| )\n00009| }\n00010| \n\n(End of file - total 10 lines)\n",
+ "title": "app/UserDashboard.tsx",
+ "metadata": {
+ "preview": "export default function UserDashboard() {\n // TODO: Implement user dashboard that needs to fetch user-specific data on each request\n return (\n
\n
User Dashboard
\n
User dashboard content goes here
\n
\n )\n}\n"
+ },
+ "time": {
+ "start": 1781392506831,
+ "end": 1781392506834
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:06.835Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| export default function UserDashboard() {\n00002| // TODO: Implement user dashboard that needs to fetch user-specific data on each request\n00003| return (\n00004|
\n00005|
User Dashboard
\n00006|
User dashboard content goes here
\n00007|
\n00008| )\n00009| }\n00010| \n\n(End of file - total 10 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/app/UserDashboard.tsx"
+ },
+ "output": "\n00001| export default function UserDashboard() {\n00002| // TODO: Implement user dashboard that needs to fetch user-specific data on each request\n00003| return (\n00004|
\n00005|
User Dashboard
\n00006|
User dashboard content goes here
\n00007|
\n00008| )\n00009| }\n00010| \n\n(End of file - total 10 lines)\n",
+ "title": "app/UserDashboard.tsx",
+ "metadata": {
+ "preview": "export default function UserDashboard() {\n // TODO: Implement user dashboard that needs to fetch user-specific data on each request\n return (\n
\n00054| )\n00055| }\n00056| ```\n00057| \n00058| > **Good to know:**\n00059| >\n00060| > - Identical `fetch` requests in a React component tree are [memoized](/docs/app/glossary#memoization) by default, so you can fetch data in the component that needs it instead of drilling props.\n00061| > - `fetch` requests are not cached by default and will block the page from rendering until the request is complete. Use the [`use cache`](/docs/app/api-reference/directives/use-cache) directive to cache results, or wrap the fetching component in [``](/docs/app/getting-started/caching#streaming-uncached-data) to stream fresh data at request time. See [caching](/docs/app/getting-started/caching) for details.\n00062| > - During development, you can log `fetch` calls for better visibility and debugging. See the [`logging` API reference](/docs/app/api-reference/config/next-config-js/logging).\n00063| \n00064| #### With an ORM or database\n00065| \n00066| Since Server Components are rendered on the server, credentials and query logic will not be included in the client bundle so you can safely make database queries using an ORM or database client.\n00067| \n00068| ```tsx filename=\"app/blog/page.tsx\" switcher\n00069| import { db, posts } from '@/lib/db'\n00070| \n00071| export default async function Page() {\n00072| const allPosts = await db.select().from(posts)\n00073| return (\n00074|
\n00094| )\n00095| }\n00096| ```\n00097| \n00098| You should still ensure requests are properly authenticated and authorized. For best practices on securing server-side data access, see the [data security guide](/docs/app/guides/data-security).\n00099| \n00100| ### Streaming\n00101| \n00102| When you fetch data in Server Components, the data is fetched and rendered on the server for each request. If you have any slow data requests, the whole route will be blocked from rendering until all the data is fetched.\n00103| \n00104| To improve the initial load time and user experience, you can break the page into smaller _chunks_ and progressively send those chunks from the server to the client. This is called streaming. See the [Streaming guide](/docs/app/guides/streaming) for a deeper look at how streaming works, including the HTTP contract, infrastructure considerations, and performance trade-offs.\n00105| \n00106| \n00113| \n00114| There are two ways you can use streaming in your application:\n00115| \n00116| 1. Wrapping a page with a [`loading.js` file](#with-loadingjs)\n00117| 2. Wrapping a component with [``](#with-suspense)\n00118| \n00119| > **Good to know:** Bots and crawlers are served differently from browsers. Next.js waits for data fetching to finish and sends the fully rendered page instead of streaming it progressively. See [Bots and crawlers](/docs/app/guides/streaming#bots-and-crawlers).\n00120| \n00121| #### With `loading.js`\n00122| \n00123| You can create a `loading.js` file in the same folder as your page to stream the **entire page** while the data is being fetched. For example, to stream `app/blog/page.js`, add the file inside the `app/blog` folder.\n00124| \n00125| \n00132| \n00133| ```tsx filename=\"app/blog/loading.tsx\" switcher\n00134| export default function Loading() {\n00135| // Define the Loading UI here\n00136| return
Loading...
\n00137| }\n00138| ```\n00139| \n00140| ```jsx filename=\"app/blog/loading.js\" switcher\n00141| export default function Loading() {\n00142| // Define the Loading UI here\n00143| return
Loading...
\n00144| }\n00145| ```\n00146| \n00147| On navigation, the user will immediately see the layout and a [loading state](#creating-meaningful-loading-states) while the page is being rendered. The new content will then be automatically swapped in once rendering is complete.\n00148| \n00149| \n00156| \n00157| Behind the scenes, `loading.js` will be [nested inside `layout.js`](/docs/app/getting-started/project-structure#component-hierarchy), and will automatically wrap the `page.js` file and any children below in a `` boundary.\n00158| \n00159| \n00166| \n00167| Because of this, a layout that accesses uncached or runtime data (e.g. `cookies()`, `headers()`, or uncached fetches) does not fall back to a same route segment `loading.js`. Instead, it blocks navigation until the layout finishes rendering. [Cache Components](/docs/app/getting-started/caching) prevents this by guiding you with a build-time error.\n00168| \n00169| To fix this, wrap the uncached access in its own [``](#with-suspense) boundary with a fallback, or move the data fetching into `page.js` where `loading.js` can cover it. See [`loading.js`](/docs/app/api-reference/file-conventions/loading) for more details.\n00170| \n00171| This is why, while `loading.js` works well for streaming route segments, using `` closer to the runtime or uncached data access is recommended.\n00172| \n00173| #### With ``\n00174| \n00175| `` allows you to be more granular about what parts of the page to stream. For example, you can immediately show any page content that falls outside of the `` boundary, and stream in the list of blog posts inside the boundary.\n00176| \n00177| ```tsx filename=\"app/blog/page.tsx\" switcher\n00178| import { Suspense } from 'react'\n00179| import BlogList from '@/components/BlogList'\n00180| import BlogListSkeleton from '@/components/BlogListSkeleton'\n00181| \n00182| export default function BlogPage() {\n00183| return (\n00184|
\n00185| {/* This content will be sent to the client immediately */}\n00186| \n00187|
Welcome to the Blog
\n00188|
Read the latest posts below.
\n00189| \n00190| \n00191| {/* If there's any dynamic content inside this boundary, it will be streamed in */}\n00192| }>\n00193| \n00194| \n00195| \n00196|
\n00197| )\n00198| }\n00199| ```\n00200| \n00201| ```jsx filename=\"app/blog/page.js\" switcher\n00202| import { Suspense } from 'react'\n00203| import BlogList from '@/components/BlogList'\n00204| import BlogListSkeleton from '@/components/BlogListSkeleton'\n00205| \n00206| export default function BlogPage() {\n00207| return (\n00208|
\n00209| {/* This content will be sent to the client immediately */}\n00210| \n00211|
Welcome to the Blog
\n00212|
Read the latest posts below.
\n00213| \n00214| \n00215| {/* If there's any dynamic content inside this boundary, it will be streamed in */}\n00216| }>\n00217| \n00218| \n00219| \n00220|
\n00221| )\n00222| }\n00223| ```\n00224| \n00225| #### Creating meaningful loading states\n00226| \n00227| An instant loading state is fallback UI that is shown immediately to the user after navigation. For the best user experience, we recommend designing loading states that are meaningful and help users understand the app is responding. For example, you can use skeletons and spinners, or a small but meaningful part of future screens such as a cover photo, title, etc.\n00228| \n00229| In development, you can preview and inspect the loading state of your components using the [React Devtools](https://react.dev/learn/react-developer-tools).\n00230| \n00231| ### Client Components\n00232| \n00233| There are two ways to fetch data in Client Components, using:\n00234| \n00235| 1. React's [`use` API](https://react.dev/reference/react/use)\n00236| 2. A community library like [SWR](https://swr.vercel.app/) or [React Query](https://tanstack.com/query/latest)\n00237| \n00238| #### Streaming data with the `use` API\n00239| \n00240| You can use React's [`use` API](https://react.dev/reference/react/use) to [stream](#streaming) data from the server to client. Start by fetching data in your Server component, and pass the promise to your Client Component as prop:\n00241| \n00242| ```tsx filename=\"app/blog/page.tsx\" switcher\n00243| import Posts from '@/app/ui/posts'\n00244| import { Suspense } from 'react'\n00245| \n00246| export default function Page() {\n00247| // Don't await the data fetching function\n00248| const posts = getPosts()\n00249| \n00250| return (\n00251| Loading...
}>\n00252| \n00253| \n00254| )\n00255| }\n00256| ```\n00257| \n00258| ```jsx filename=\"app/blog/page.js\" switcher\n00259| import Posts from '@/app/ui/posts'\n00260| import { Suspense } from 'react'\n00261| \n00262| export default function Page() {\n00263| // Don't await the data fetching function\n00264| const posts = getPosts()\n00265| \n00266| return (\n00267| Loading...
}>\n00268| \n00269| \n00270| )\n00271| }\n00272| ```\n00273| \n00274| Then, in your Client Component, use the `use` API to read the promise:\n00275| \n00276| ```tsx filename=\"app/ui/posts.tsx\" switcher\n00277| 'use client'\n00278| import { use } from 'react'\n00279| \n00280| export default function Posts({\n00281| posts,\n00282| }: {\n00283| posts: Promise<{ id: string; title: string }[]>\n00284| }) {\n00285| const allPosts = use(posts)\n00286| \n00287| return (\n00288|
\n00310| )\n00311| }\n00312| ```\n00313| \n00314| In the example above, the `` component is wrapped in a [`` boundary](https://react.dev/reference/react/Suspense). This means the fallback will be shown while the promise is being resolved. Learn more about [streaming](#streaming).\n00315| \n00316| #### Community libraries\n00317| \n00318| You can use a community library like [SWR](https://swr.vercel.app/) or [React Query](https://tanstack.com/query/latest) to fetch data in Client Components. These libraries have their own semantics for caching, streaming, and other features. For example, with SWR:\n00319| \n00320| ```tsx filename=\"app/blog/page.tsx\" switcher\n00321| 'use client'\n00322| import useSWR from 'swr'\n00323| \n00324| const fetcher = (url) => fetch(url).then((r) => r.json())\n00325| \n00326| export default function BlogPage() {\n00327| const { data, error, isLoading } = useSWR(\n00328| 'https://api.vercel.app/blog',\n00329| fetcher\n00330| )\n00331| \n00332| if (isLoading) return
\n00367| )\n00368| }\n00369| ```\n00370| \n00371| ## Examples\n00372| \n00373| ### Sequential data fetching\n00374| \n00375| Sequential data fetching happens when one request depends on data from another.\n00376| \n00377| For example, `` can only fetch data after `` completes because it needs the `artistID`:\n00378| \n00379| ```tsx filename=\"app/artist/[username]/page.tsx\" switcher\n00380| export default async function Page({\n00381| params,\n00382| }: {\n00383| params: Promise<{ username: string }>\n00384| }) {\n00385| const { username } = await params\n00386| // Get artist information\n00387| const artist = await getArtist(username)\n00388| \n00389| return (\n00390| <>\n00391|
{artist.name}
\n00392| {/* Show fallback UI while the Playlists component is loading */}\n00393| Loading...
}>\n00394| {/* Pass the artist ID to the Playlists component */}\n00395| \n00396| \n00397| >\n00398| )\n00399| }\n00400| \n00401| async function Playlists({ artistID }: { artistID: string }) {\n00402| // Use the artist ID to fetch playlists\n00403| const playlists = await getArtistPlaylists(artistID)\n00404| \n00405| return (\n00406|
\n00407| {playlists.map((playlist) => (\n00408|
{playlist.name}
\n00409| ))}\n00410|
\n00411| )\n00412| }\n00413| ```\n00414| \n00415| ```jsx filename=\"app/artist/[username]/page.js\" switcher\n00416| export default async function Page({ params }) {\n00417| const { username } = await params\n00418| // Get artist information\n00419| const artist = await getArtist(username)\n00420| \n00421| return (\n00422| <>\n00423|
{artist.name}
\n00424| {/* Show fallback UI while the Playlists component is loading */}\n00425| Loading...
}>\n00426| {/* Pass the artist ID to the Playlists component */}\n00427| \n00428| \n00429| >\n00430| )\n00431| }\n00432| \n00433| async function Playlists({ artistID }) {\n00434| // Use the artist ID to fetch playlists\n00435| const playlists = await getArtistPlaylists(artistID)\n00436| \n00437| return (\n00438|
\n00439| {playlists.map((playlist) => (\n00440|
{playlist.name}
\n00441| ))}\n00442|
\n00443| )\n00444| }\n00445| ```\n00446| \n00447| In this example, `` allows the playlists to stream in after the artist data loads. However, the page still waits for the artist data before displaying anything. To prevent this, you can wrap the entire page component in a `` boundary (for example, using a [`loading.js` file](#with-loadingjs)) to show a loading state immediately.\n00448| \n00449| Ensure your data source can resolve the first request quickly, as it blocks everything else. If you can't optimize the request further, consider [caching](/docs/app/getting-started/caching) the result if the data changes infrequently.\n00450| \n00451| ### Parallel data fetching\n00452| \n00453| Parallel data fetching happens when data requests in a route are eagerly initiated and start at the same time.\n00454| \n00455| By default, [layouts and pages](/docs/app/getting-started/layouts-and-pages) are rendered in parallel. So each segment starts fetching data as soon as possible.\n00456| \n00457| However, within _any_ component, multiple `async`/`await` requests can still be sequential if placed after the other. For example, `getAlbums` will be blocked until `getArtist` is resolved:\n00458| \n00459| ```tsx filename=\"app/artist/[username]/page.tsx\" switcher\n00460| import { getArtist, getAlbums } from '@/app/lib/data'\n00461| \n00462| export default async function Page({ params }) {\n00463| // These requests will be sequential\n00464| const { username } = await params\n00465| const artist = await getArtist(username)\n00466| const albums = await getAlbums(username)\n00467| return
{artist.name}
\n00468| }\n00469| ```\n00470| \n00471| Start multiple requests by calling `fetch`, then await them with [`Promise.all`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all). Requests begin as soon as `fetch` is called.\n00472| \n00473| ```tsx filename=\"app/artist/[username]/page.tsx\" highlight={3,8,24} switcher\n00474| import Albums from './albums'\n00475| \n00476| async function getArtist(username: string) {\n00477| const res = await fetch(`https://api.example.com/artist/${username}`)\n00478| return res.json()\n00479| }\n00480| \n00481| async function getAlbums(username: string) {\n00482| const res = await fetch(`https://api.example.com/artist/${username}/albums`)\n00483| return res.json()\n00484| }\n00485| \n00486| export default async function Page({\n00487| params,\n00488| }: {\n00489| params: Promise<{ username: string }>\n00490| }) {\n00491| const { username } = await params\n00492| \n00493| // Initiate requests\n00494| const artistData = getArtist(username)\n00495| const albumsData = getAlbums(username)\n00496| \n00497| const [artist, albums] = await Promise.all([artistData, albumsData])\n00498| \n00499| return (\n00500| <>\n00501|
\n00533| \n00534| >\n00535| )\n00536| }\n00537| ```\n00538| \n00539| > **Good to know:** If one request fails when using `Promise.all`, the entire operation will fail. To handle this, you can use the [`Promise.allSettled`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled) method instead.\n00540| \n00541| ### Sharing data with context and `React.cache`\n00542| \n00543| You can share fetched data across both Server and Client Components by combining [`React.cache`](https://react.dev/reference/react/cache) with context providers.\n00544| \n00545| Create a cached function that fetches data:\n00546| \n00547| ```ts filename=\"app/lib/user.ts\" switcher\n00548| import { cache } from 'react'\n00549| \n00550| export const getUser = cache(async () => {\n00551| const res = await fetch('https://api.example.com/user')\n00552| return res.json()\n00553| })\n00554| ```\n00555| \n00556| ```js filename=\"app/lib/user.js\" switcher\n00557| import { cache } from 'react'\n00558| \n00559| export const getUser = cache(async () => {\n00560| const res = await fetch('https://api.example.com/user')\n00561| return res.json()\n00562| })\n00563| ```\n00564| \n00565| Create a context provider that stores the promise:\n00566| \n00567| ```tsx filename=\"app/user-provider.tsx\" switcher\n00568| 'use client'\n00569| \n00570| import { createContext } from 'react'\n00571| \n00572| type User = {\n00573| id: string\n00574| name: string\n00575| }\n00576| \n00577| export const UserContext = createContext | null>(null)\n00578| \n00579| export default function UserProvider({\n00580| children,\n00581| userPromise,\n00582| }: {\n00583| children: React.ReactNode\n00584| userPromise: Promise\n00585| }) {\n00586| return {children}\n00587| }\n00588| ```\n00589| \n00590| ```jsx filename=\"app/user-provider.js\" switcher\n00591| 'use client'\n00592| \n00593| import { createContext } from 'react'\n00594| \n00595| export const UserContext = createContext(null)\n00596| \n00597| export default function UserProvider({ children, userPromise }) {\n00598| return {children}\n00599| }\n00600| ```\n00601| \n00602| In a layout, pass the promise to the provider without awaiting:\n00603| \n00604| ```tsx filename=\"app/layout.tsx\" switcher\n00605| import UserProvider from './user-provider'\n00606| import { getUser } from './lib/user'\n00607| \n00608| export default function RootLayout({\n00609| children,\n00610| }: {\n00611| children: React.ReactNode\n00612| }) {\n00613| const userPromise = getUser() // Don't await\n00614| \n00615| return (\n00616| \n00617| \n00618| {children}\n00619| \n00620| \n00621| )\n00622| }\n00623| ```\n00624| \n00625| ```jsx filename=\"app/layout.js\" switcher\n00626| import UserProvider from './user-provider'\n00627| import { getUser } from './lib/user'\n00628| \n00629| export default function RootLayout({ children }) {\n00630| const userPromise = getUser() // Don't await\n00631| \n00632| return (\n00633| \n00634| \n00635| {children}\n00636| \n00637| \n00638| )\n00639| }\n00640| ```\n00641| \n00642| Client Components use [`use()`](https://react.dev/reference/react/use) to resolve the promise from context, wrapped in `` for fallback UI:\n00643| \n00644| ```tsx filename=\"app/ui/profile.tsx\" switcher\n00645| 'use client'\n00646| \n00647| import { use, useContext } from 'react'\n00648| import { UserContext } from '../user-provider'\n00649| \n00650| export function Profile() {\n00651| const userPromise = useContext(UserContext)\n00652| if (!userPromise) {\n00653| throw new Error('useContext must be used within a UserProvider')\n00654| }\n00655| const user = use(userPromise)\n00656| return
Welcome, {user.name}
\n00657| }\n00658| ```\n00659| \n00660| ```jsx filename=\"app/ui/profile.js\" switcher\n00661| 'use client'\n00662| \n00663| import { use, useContext } from 'react'\n00664| import { UserContext } from '../user-provider'\n00665| \n00666| export function Profile() {\n00667| const userPromise = useContext(UserContext)\n00668| if (!userPromise) {\n00669| throw new Error('useContext must be used within a UserProvider')\n00670| }\n00671| const user = use(userPromise)\n00672| return
Welcome, {user.name}
\n00673| }\n00674| ```\n00675| \n00676| ```tsx filename=\"app/page.tsx\" switcher\n00677| import { Suspense } from 'react'\n00678| import { Profile } from './ui/profile'\n00679| \n00680| export default function Page() {\n00681| return (\n00682| Loading profile...}>\n00683| \n00684| \n00685| )\n00686| }\n00687| ```\n00688| \n00689| ```jsx filename=\"app/page.js\" switcher\n00690| import { Suspense } from 'react'\n00691| import { Profile } from './ui/profile'\n00692| \n00693| export default function Page() {\n00694| return (\n00695| Loading profile...}>\n00696| \n00697| \n00698| )\n00699| }\n00700| ```\n00701| \n00702| Server Components can also call `getUser()` directly:\n00703| \n00704| ```tsx filename=\"app/dashboard/page.tsx\" switcher\n00705| import { getUser } from '../lib/user'\n00706| \n00707| export default async function DashboardPage() {\n00708| const user = await getUser() // Cached - same request, no duplicate fetch\n00709| return
Dashboard for {user.name}
\n00710| }\n00711| ```\n00712| \n00713| ```jsx filename=\"app/dashboard/page.js\" switcher\n00714| import { getUser } from '../lib/user'\n00715| \n00716| export default async function DashboardPage() {\n00717| const user = await getUser() // Cached - same request, no duplicate fetch\n00718| return
Dashboard for {user.name}
\n00719| }\n00720| ```\n00721| \n00722| Since `getUser` is wrapped with `React.cache`, multiple calls within the same request return the same memoized result, whether called directly in Server Components or resolved via context in Client Components.\n00723| \n00724| > **Good to know**: `React.cache` is scoped to the current request only. Each request gets its own memoization scope with no sharing between requests.\n00725| \n\n(End of file - total 725 lines)\n",
+ "title": "node_modules/next/dist/docs/01-app/01-getting-started/06-fetching-data.md",
+ "metadata": {
+ "preview": "---\ntitle: Fetching Data\ndescription: Learn how to fetch data and stream content that depends on data.\nrelated:\n title: API Reference\n description: Learn more about the features mentioned in this page by reading the API Reference.\n links:\n - app/guides/data-security\n - app/api-reference/functions/fetch\n - app/api-reference/file-conventions/loading\n - app/api-reference/config/next-config-js/logging\n - app/api-reference/config/next-config-js/taint\n---\n\nThis page will walk you through how you can fetch data in [Server](#server-components) and [Client](#client-components) Components, and how to [stream](#streaming) components that depend on uncached data.\n\n## Fetching data\n\n### Server Components\n"
+ },
+ "time": {
+ "start": 1781392514793,
+ "end": 1781392514798
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:14.800Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| ---\n00002| title: Fetching Data\n00003| description: Learn how to fetch data and stream content that depends on data.\n00004| related:\n00005| title: API Reference\n00006| description: Learn more about the features mentioned in this page by reading the API Reference.\n00007| links:\n00008| - app/guides/data-security\n00009| - app/api-reference/functions/fetch\n00010| - app/api-reference/file-conventions/loading\n00011| - app/api-reference/config/next-config-js/logging\n00012| - app/api-reference/config/next-config-js/taint\n00013| ---\n00014| \n00015| This page will walk you through how you can fetch data in [Server](#server-components) and [Client](#client-components) Components, and how to [stream](#streaming) components that depend on uncached data.\n00016| \n00017| ## Fetching data\n00018| \n00019| ### Server Components\n00020| \n00021| You can fetch data in Server Components using any asynchronous I/O, such as:\n00022| \n00023| 1. The [`fetch` API](#with-the-fetch-api)\n00024| 2. An [ORM or database](#with-an-orm-or-database)\n00025| \n00026| #### With the `fetch` API\n00027| \n00028| To fetch data with the `fetch` API, turn your component into an asynchronous function, and await the `fetch` call. For example:\n00029| \n00030| ```tsx filename=\"app/blog/page.tsx\" switcher\n00031| export default async function Page() {\n00032| const data = await fetch('https://api.vercel.app/blog')\n00033| const posts = await data.json()\n00034| return (\n00035|
\n00054| )\n00055| }\n00056| ```\n00057| \n00058| > **Good to know:**\n00059| >\n00060| > - Identical `fetch` requests in a React component tree are [memoized](/docs/app/glossary#memoization) by default, so you can fetch data in the component that needs it instead of drilling props.\n00061| > - `fetch` requests are not cached by default and will block the page from rendering until the request is complete. Use the [`use cache`](/docs/app/api-reference/directives/use-cache) directive to cache results, or wrap the fetching component in [``](/docs/app/getting-started/caching#streaming-uncached-data) to stream fresh data at request time. See [caching](/docs/app/getting-started/caching) for details.\n00062| > - During development, you can log `fetch` calls for better visibility and debugging. See the [`logging` API reference](/docs/app/api-reference/config/next-config-js/logging).\n00063| \n00064| #### With an ORM or database\n00065| \n00066| Since Server Components are rendered on the server, credentials and query logic will not be included in the client bundle so you can safely make database queries using an ORM or database client.\n00067| \n00068| ```tsx filename=\"app/blog/page.tsx\" switcher\n00069| import { db, posts } from '@/lib/db'\n00070| \n00071| export default async function Page() {\n00072| const allPosts = await db.select().from(posts)\n00073| return (\n00074|
\n00094| )\n00095| }\n00096| ```\n00097| \n00098| You should still ensure requests are properly authenticated and authorized. For best practices on securing server-side data access, see the [data security guide](/docs/app/guides/data-security).\n00099| \n00100| ### Streaming\n00101| \n00102| When you fetch data in Server Components, the data is fetched and rendered on the server for each request. If you have any slow data requests, the whole route will be blocked from rendering until all the data is fetched.\n00103| \n00104| To improve the initial load time and user experience, you can break the page into smaller _chunks_ and progressively send those chunks from the server to the client. This is called streaming. See the [Streaming guide](/docs/app/guides/streaming) for a deeper look at how streaming works, including the HTTP contract, infrastructure considerations, and performance trade-offs.\n00105| \n00106| \n00113| \n00114| There are two ways you can use streaming in your application:\n00115| \n00116| 1. Wrapping a page with a [`loading.js` file](#with-loadingjs)\n00117| 2. Wrapping a component with [``](#with-suspense)\n00118| \n00119| > **Good to know:** Bots and crawlers are served differently from browsers. Next.js waits for data fetching to finish and sends the fully rendered page instead of streaming it progressively. See [Bots and crawlers](/docs/app/guides/streaming#bots-and-crawlers).\n00120| \n00121| #### With `loading.js`\n00122| \n00123| You can create a `loading.js` file in the same folder as your page to stream the **entire page** while the data is being fetched. For example, to stream `app/blog/page.js`, add the file inside the `app/blog` folder.\n00124| \n00125| \n00132| \n00133| ```tsx filename=\"app/blog/loading.tsx\" switcher\n00134| export default function Loading() {\n00135| // Define the Loading UI here\n00136| return
Loading...
\n00137| }\n00138| ```\n00139| \n00140| ```jsx filename=\"app/blog/loading.js\" switcher\n00141| export default function Loading() {\n00142| // Define the Loading UI here\n00143| return
Loading...
\n00144| }\n00145| ```\n00146| \n00147| On navigation, the user will immediately see the layout and a [loading state](#creating-meaningful-loading-states) while the page is being rendered. The new content will then be automatically swapped in once rendering is complete.\n00148| \n00149| \n00156| \n00157| Behind the scenes, `loading.js` will be [nested inside `layout.js`](/docs/app/getting-started/project-structure#component-hierarchy), and will automatically wrap the `page.js` file and any children below in a `` boundary.\n00158| \n00159| \n00166| \n00167| Because of this, a layout that accesses uncached or runtime data (e.g. `cookies()`, `headers()`, or uncached fetches) does not fall back to a same route segment `loading.js`. Instead, it blocks navigation until the layout finishes rendering. [Cache Components](/docs/app/getting-started/caching) prevents this by guiding you with a build-time error.\n00168| \n00169| To fix this, wrap the uncached access in its own [``](#with-suspense) boundary with a fallback, or move the data fetching into `page.js` where `loading.js` can cover it. See [`loading.js`](/docs/app/api-reference/file-conventions/loading) for more details.\n00170| \n00171| This is why, while `loading.js` works well for streaming route segments, using `` closer to the runtime or uncached data access is recommended.\n00172| \n00173| #### With ``\n00174| \n00175| `` allows you to be more granular about what parts of the page to stream. For example, you can immediately show any page content that falls outside of the `` boundary, and stream in the list of blog posts inside the boundary.\n00176| \n00177| ```tsx filename=\"app/blog/page.tsx\" switcher\n00178| import { Suspense } from 'react'\n00179| import BlogList from '@/components/BlogList'\n00180| import BlogListSkeleton from '@/components/BlogListSkeleton'\n00181| \n00182| export default function BlogPage() {\n00183| return (\n00184|
\n00185| {/* This content will be sent to the client immediately */}\n00186| \n00187|
Welcome to the Blog
\n00188|
Read the latest posts below.
\n00189| \n00190| \n00191| {/* If there's any dynamic content inside this boundary, it will be streamed in */}\n00192| }>\n00193| \n00194| \n00195| \n00196|
\n00197| )\n00198| }\n00199| ```\n00200| \n00201| ```jsx filename=\"app/blog/page.js\" switcher\n00202| import { Suspense } from 'react'\n00203| import BlogList from '@/components/BlogList'\n00204| import BlogListSkeleton from '@/components/BlogListSkeleton'\n00205| \n00206| export default function BlogPage() {\n00207| return (\n00208|
\n00209| {/* This content will be sent to the client immediately */}\n00210| \n00211|
Welcome to the Blog
\n00212|
Read the latest posts below.
\n00213| \n00214| \n00215| {/* If there's any dynamic content inside this boundary, it will be streamed in */}\n00216| }>\n00217| \n00218| \n00219| \n00220|
\n00221| )\n00222| }\n00223| ```\n00224| \n00225| #### Creating meaningful loading states\n00226| \n00227| An instant loading state is fallback UI that is shown immediately to the user after navigation. For the best user experience, we recommend designing loading states that are meaningful and help users understand the app is responding. For example, you can use skeletons and spinners, or a small but meaningful part of future screens such as a cover photo, title, etc.\n00228| \n00229| In development, you can preview and inspect the loading state of your components using the [React Devtools](https://react.dev/learn/react-developer-tools).\n00230| \n00231| ### Client Components\n00232| \n00233| There are two ways to fetch data in Client Components, using:\n00234| \n00235| 1. React's [`use` API](https://react.dev/reference/react/use)\n00236| 2. A community library like [SWR](https://swr.vercel.app/) or [React Query](https://tanstack.com/query/latest)\n00237| \n00238| #### Streaming data with the `use` API\n00239| \n00240| You can use React's [`use` API](https://react.dev/reference/react/use) to [stream](#streaming) data from the server to client. Start by fetching data in your Server component, and pass the promise to your Client Component as prop:\n00241| \n00242| ```tsx filename=\"app/blog/page.tsx\" switcher\n00243| import Posts from '@/app/ui/posts'\n00244| import { Suspense } from 'react'\n00245| \n00246| export default function Page() {\n00247| // Don't await the data fetching function\n00248| const posts = getPosts()\n00249| \n00250| return (\n00251| Loading...}>\n00252| \n00253| \n00254| )\n00255| }\n00256| ```\n00257| \n00258| ```jsx filename=\"app/blog/page.js\" switcher\n00259| import Posts from '@/app/ui/posts'\n00260| import { Suspense } from 'react'\n00261| \n00262| export default function Page() {\n00263| // Don't await the data fetching function\n00264| const posts = getPosts()\n00265| \n00266| return (\n00267| Loading...}>\n00268| \n00269| \n00270| )\n00271| }\n00272| ```\n00273| \n00274| Then, in your Client Component, use the `use` API to read the promise:\n00275| \n00276| ```tsx filename=\"app/ui/posts.tsx\" switcher\n00277| 'use client'\n00278| import { use } from 'react'\n00279| \n00280| export default function Posts({\n00281| posts,\n00282| }: {\n00283| posts: Promise<{ id: string; title: string }[]>\n00284| }) {\n00285| const allPosts = use(posts)\n00286| \n00287| return (\n00288|
\n00310| )\n00311| }\n00312| ```\n00313| \n00314| In the example above, the `` component is wrapped in a [`` boundary](https://react.dev/reference/react/Suspense). This means the fallback will be shown while the promise is being resolved. Learn more about [streaming](#streaming).\n00315| \n00316| #### Community libraries\n00317| \n00318| You can use a community library like [SWR](https://swr.vercel.app/) or [React Query](https://tanstack.com/query/latest) to fetch data in Client Components. These libraries have their own semantics for caching, streaming, and other features. For example, with SWR:\n00319| \n00320| ```tsx filename=\"app/blog/page.tsx\" switcher\n00321| 'use client'\n00322| import useSWR from 'swr'\n00323| \n00324| const fetcher = (url) => fetch(url).then((r) => r.json())\n00325| \n00326| export default function BlogPage() {\n00327| const { data, error, isLoading } = useSWR(\n00328| 'https://api.vercel.app/blog',\n00329| fetcher\n00330| )\n00331| \n00332| if (isLoading) return
\n00367| )\n00368| }\n00369| ```\n00370| \n00371| ## Examples\n00372| \n00373| ### Sequential data fetching\n00374| \n00375| Sequential data fetching happens when one request depends on data from another.\n00376| \n00377| For example, `` can only fetch data after `` completes because it needs the `artistID`:\n00378| \n00379| ```tsx filename=\"app/artist/[username]/page.tsx\" switcher\n00380| export default async function Page({\n00381| params,\n00382| }: {\n00383| params: Promise<{ username: string }>\n00384| }) {\n00385| const { username } = await params\n00386| // Get artist information\n00387| const artist = await getArtist(username)\n00388| \n00389| return (\n00390| <>\n00391|
{artist.name}
\n00392| {/* Show fallback UI while the Playlists component is loading */}\n00393| Loading...}>\n00394| {/* Pass the artist ID to the Playlists component */}\n00395| \n00396| \n00397| >\n00398| )\n00399| }\n00400| \n00401| async function Playlists({ artistID }: { artistID: string }) {\n00402| // Use the artist ID to fetch playlists\n00403| const playlists = await getArtistPlaylists(artistID)\n00404| \n00405| return (\n00406|
\n00407| {playlists.map((playlist) => (\n00408|
{playlist.name}
\n00409| ))}\n00410|
\n00411| )\n00412| }\n00413| ```\n00414| \n00415| ```jsx filename=\"app/artist/[username]/page.js\" switcher\n00416| export default async function Page({ params }) {\n00417| const { username } = await params\n00418| // Get artist information\n00419| const artist = await getArtist(username)\n00420| \n00421| return (\n00422| <>\n00423|
{artist.name}
\n00424| {/* Show fallback UI while the Playlists component is loading */}\n00425| Loading...}>\n00426| {/* Pass the artist ID to the Playlists component */}\n00427| \n00428| \n00429| >\n00430| )\n00431| }\n00432| \n00433| async function Playlists({ artistID }) {\n00434| // Use the artist ID to fetch playlists\n00435| const playlists = await getArtistPlaylists(artistID)\n00436| \n00437| return (\n00438|
\n00439| {playlists.map((playlist) => (\n00440|
{playlist.name}
\n00441| ))}\n00442|
\n00443| )\n00444| }\n00445| ```\n00446| \n00447| In this example, `` allows the playlists to stream in after the artist data loads. However, the page still waits for the artist data before displaying anything. To prevent this, you can wrap the entire page component in a `` boundary (for example, using a [`loading.js` file](#with-loadingjs)) to show a loading state immediately.\n00448| \n00449| Ensure your data source can resolve the first request quickly, as it blocks everything else. If you can't optimize the request further, consider [caching](/docs/app/getting-started/caching) the result if the data changes infrequently.\n00450| \n00451| ### Parallel data fetching\n00452| \n00453| Parallel data fetching happens when data requests in a route are eagerly initiated and start at the same time.\n00454| \n00455| By default, [layouts and pages](/docs/app/getting-started/layouts-and-pages) are rendered in parallel. So each segment starts fetching data as soon as possible.\n00456| \n00457| However, within _any_ component, multiple `async`/`await` requests can still be sequential if placed after the other. For example, `getAlbums` will be blocked until `getArtist` is resolved:\n00458| \n00459| ```tsx filename=\"app/artist/[username]/page.tsx\" switcher\n00460| import { getArtist, getAlbums } from '@/app/lib/data'\n00461| \n00462| export default async function Page({ params }) {\n00463| // These requests will be sequential\n00464| const { username } = await params\n00465| const artist = await getArtist(username)\n00466| const albums = await getAlbums(username)\n00467| return
{artist.name}
\n00468| }\n00469| ```\n00470| \n00471| Start multiple requests by calling `fetch`, then await them with [`Promise.all`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all). Requests begin as soon as `fetch` is called.\n00472| \n00473| ```tsx filename=\"app/artist/[username]/page.tsx\" highlight={3,8,24} switcher\n00474| import Albums from './albums'\n00475| \n00476| async function getArtist(username: string) {\n00477| const res = await fetch(`https://api.example.com/artist/${username}`)\n00478| return res.json()\n00479| }\n00480| \n00481| async function getAlbums(username: string) {\n00482| const res = await fetch(`https://api.example.com/artist/${username}/albums`)\n00483| return res.json()\n00484| }\n00485| \n00486| export default async function Page({\n00487| params,\n00488| }: {\n00489| params: Promise<{ username: string }>\n00490| }) {\n00491| const { username } = await params\n00492| \n00493| // Initiate requests\n00494| const artistData = getArtist(username)\n00495| const albumsData = getAlbums(username)\n00496| \n00497| const [artist, albums] = await Promise.all([artistData, albumsData])\n00498| \n00499| return (\n00500| <>\n00501|
\n00533| \n00534| >\n00535| )\n00536| }\n00537| ```\n00538| \n00539| > **Good to know:** If one request fails when using `Promise.all`, the entire operation will fail. To handle this, you can use the [`Promise.allSettled`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled) method instead.\n00540| \n00541| ### Sharing data with context and `React.cache`\n00542| \n00543| You can share fetched data across both Server and Client Components by combining [`React.cache`](https://react.dev/reference/react/cache) with context providers.\n00544| \n00545| Create a cached function that fetches data:\n00546| \n00547| ```ts filename=\"app/lib/user.ts\" switcher\n00548| import { cache } from 'react'\n00549| \n00550| export const getUser = cache(async () => {\n00551| const res = await fetch('https://api.example.com/user')\n00552| return res.json()\n00553| })\n00554| ```\n00555| \n00556| ```js filename=\"app/lib/user.js\" switcher\n00557| import { cache } from 'react'\n00558| \n00559| export const getUser = cache(async () => {\n00560| const res = await fetch('https://api.example.com/user')\n00561| return res.json()\n00562| })\n00563| ```\n00564| \n00565| Create a context provider that stores the promise:\n00566| \n00567| ```tsx filename=\"app/user-provider.tsx\" switcher\n00568| 'use client'\n00569| \n00570| import { createContext } from 'react'\n00571| \n00572| type User = {\n00573| id: string\n00574| name: string\n00575| }\n00576| \n00577| export const UserContext = createContext | null>(null)\n00578| \n00579| export default function UserProvider({\n00580| children,\n00581| userPromise,\n00582| }: {\n00583| children: React.ReactNode\n00584| userPromise: Promise\n00585| }) {\n00586| return {children}\n00587| }\n00588| ```\n00589| \n00590| ```jsx filename=\"app/user-provider.js\" switcher\n00591| 'use client'\n00592| \n00593| import { createContext } from 'react'\n00594| \n00595| export const UserContext = createContext(null)\n00596| \n00597| export default function UserProvider({ children, userPromise }) {\n00598| return {children}\n00599| }\n00600| ```\n00601| \n00602| In a layout, pass the promise to the provider without awaiting:\n00603| \n00604| ```tsx filename=\"app/layout.tsx\" switcher\n00605| import UserProvider from './user-provider'\n00606| import { getUser } from './lib/user'\n00607| \n00608| export default function RootLayout({\n00609| children,\n00610| }: {\n00611| children: React.ReactNode\n00612| }) {\n00613| const userPromise = getUser() // Don't await\n00614| \n00615| return (\n00616| \n00617| \n00618| {children}\n00619| \n00620| \n00621| )\n00622| }\n00623| ```\n00624| \n00625| ```jsx filename=\"app/layout.js\" switcher\n00626| import UserProvider from './user-provider'\n00627| import { getUser } from './lib/user'\n00628| \n00629| export default function RootLayout({ children }) {\n00630| const userPromise = getUser() // Don't await\n00631| \n00632| return (\n00633| \n00634| \n00635| {children}\n00636| \n00637| \n00638| )\n00639| }\n00640| ```\n00641| \n00642| Client Components use [`use()`](https://react.dev/reference/react/use) to resolve the promise from context, wrapped in `` for fallback UI:\n00643| \n00644| ```tsx filename=\"app/ui/profile.tsx\" switcher\n00645| 'use client'\n00646| \n00647| import { use, useContext } from 'react'\n00648| import { UserContext } from '../user-provider'\n00649| \n00650| export function Profile() {\n00651| const userPromise = useContext(UserContext)\n00652| if (!userPromise) {\n00653| throw new Error('useContext must be used within a UserProvider')\n00654| }\n00655| const user = use(userPromise)\n00656| return
Welcome, {user.name}
\n00657| }\n00658| ```\n00659| \n00660| ```jsx filename=\"app/ui/profile.js\" switcher\n00661| 'use client'\n00662| \n00663| import { use, useContext } from 'react'\n00664| import { UserContext } from '../user-provider'\n00665| \n00666| export function Profile() {\n00667| const userPromise = useContext(UserContext)\n00668| if (!userPromise) {\n00669| throw new Error('useContext must be used within a UserProvider')\n00670| }\n00671| const user = use(userPromise)\n00672| return
Welcome, {user.name}
\n00673| }\n00674| ```\n00675| \n00676| ```tsx filename=\"app/page.tsx\" switcher\n00677| import { Suspense } from 'react'\n00678| import { Profile } from './ui/profile'\n00679| \n00680| export default function Page() {\n00681| return (\n00682| Loading profile...}>\n00683| \n00684| \n00685| )\n00686| }\n00687| ```\n00688| \n00689| ```jsx filename=\"app/page.js\" switcher\n00690| import { Suspense } from 'react'\n00691| import { Profile } from './ui/profile'\n00692| \n00693| export default function Page() {\n00694| return (\n00695| Loading profile...}>\n00696| \n00697| \n00698| )\n00699| }\n00700| ```\n00701| \n00702| Server Components can also call `getUser()` directly:\n00703| \n00704| ```tsx filename=\"app/dashboard/page.tsx\" switcher\n00705| import { getUser } from '../lib/user'\n00706| \n00707| export default async function DashboardPage() {\n00708| const user = await getUser() // Cached - same request, no duplicate fetch\n00709| return
Dashboard for {user.name}
\n00710| }\n00711| ```\n00712| \n00713| ```jsx filename=\"app/dashboard/page.js\" switcher\n00714| import { getUser } from '../lib/user'\n00715| \n00716| export default async function DashboardPage() {\n00717| const user = await getUser() // Cached - same request, no duplicate fetch\n00718| return
Dashboard for {user.name}
\n00719| }\n00720| ```\n00721| \n00722| Since `getUser` is wrapped with `React.cache`, multiple calls within the same request return the same memoized result, whether called directly in Server Components or resolved via context in Client Components.\n00723| \n00724| > **Good to know**: `React.cache` is scoped to the current request only. Each request gets its own memoization scope with no sharing between requests.\n00725| \n\n(End of file - total 725 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/01-getting-started/06-fetching-data.md"
+ },
+ "output": "\n00001| ---\n00002| title: Fetching Data\n00003| description: Learn how to fetch data and stream content that depends on data.\n00004| related:\n00005| title: API Reference\n00006| description: Learn more about the features mentioned in this page by reading the API Reference.\n00007| links:\n00008| - app/guides/data-security\n00009| - app/api-reference/functions/fetch\n00010| - app/api-reference/file-conventions/loading\n00011| - app/api-reference/config/next-config-js/logging\n00012| - app/api-reference/config/next-config-js/taint\n00013| ---\n00014| \n00015| This page will walk you through how you can fetch data in [Server](#server-components) and [Client](#client-components) Components, and how to [stream](#streaming) components that depend on uncached data.\n00016| \n00017| ## Fetching data\n00018| \n00019| ### Server Components\n00020| \n00021| You can fetch data in Server Components using any asynchronous I/O, such as:\n00022| \n00023| 1. The [`fetch` API](#with-the-fetch-api)\n00024| 2. An [ORM or database](#with-an-orm-or-database)\n00025| \n00026| #### With the `fetch` API\n00027| \n00028| To fetch data with the `fetch` API, turn your component into an asynchronous function, and await the `fetch` call. For example:\n00029| \n00030| ```tsx filename=\"app/blog/page.tsx\" switcher\n00031| export default async function Page() {\n00032| const data = await fetch('https://api.vercel.app/blog')\n00033| const posts = await data.json()\n00034| return (\n00035|
\n00054| )\n00055| }\n00056| ```\n00057| \n00058| > **Good to know:**\n00059| >\n00060| > - Identical `fetch` requests in a React component tree are [memoized](/docs/app/glossary#memoization) by default, so you can fetch data in the component that needs it instead of drilling props.\n00061| > - `fetch` requests are not cached by default and will block the page from rendering until the request is complete. Use the [`use cache`](/docs/app/api-reference/directives/use-cache) directive to cache results, or wrap the fetching component in [``](/docs/app/getting-started/caching#streaming-uncached-data) to stream fresh data at request time. See [caching](/docs/app/getting-started/caching) for details.\n00062| > - During development, you can log `fetch` calls for better visibility and debugging. See the [`logging` API reference](/docs/app/api-reference/config/next-config-js/logging).\n00063| \n00064| #### With an ORM or database\n00065| \n00066| Since Server Components are rendered on the server, credentials and query logic will not be included in the client bundle so you can safely make database queries using an ORM or database client.\n00067| \n00068| ```tsx filename=\"app/blog/page.tsx\" switcher\n00069| import { db, posts } from '@/lib/db'\n00070| \n00071| export default async function Page() {\n00072| const allPosts = await db.select().from(posts)\n00073| return (\n00074|
\n00094| )\n00095| }\n00096| ```\n00097| \n00098| You should still ensure requests are properly authenticated and authorized. For best practices on securing server-side data access, see the [data security guide](/docs/app/guides/data-security).\n00099| \n00100| ### Streaming\n00101| \n00102| When you fetch data in Server Components, the data is fetched and rendered on the server for each request. If you have any slow data requests, the whole route will be blocked from rendering until all the data is fetched.\n00103| \n00104| To improve the initial load time and user experience, you can break the page into smaller _chunks_ and progressively send those chunks from the server to the client. This is called streaming. See the [Streaming guide](/docs/app/guides/streaming) for a deeper look at how streaming works, including the HTTP contract, infrastructure considerations, and performance trade-offs.\n00105| \n00106| \n00113| \n00114| There are two ways you can use streaming in your application:\n00115| \n00116| 1. Wrapping a page with a [`loading.js` file](#with-loadingjs)\n00117| 2. Wrapping a component with [``](#with-suspense)\n00118| \n00119| > **Good to know:** Bots and crawlers are served differently from browsers. Next.js waits for data fetching to finish and sends the fully rendered page instead of streaming it progressively. See [Bots and crawlers](/docs/app/guides/streaming#bots-and-crawlers).\n00120| \n00121| #### With `loading.js`\n00122| \n00123| You can create a `loading.js` file in the same folder as your page to stream the **entire page** while the data is being fetched. For example, to stream `app/blog/page.js`, add the file inside the `app/blog` folder.\n00124| \n00125| \n00132| \n00133| ```tsx filename=\"app/blog/loading.tsx\" switcher\n00134| export default function Loading() {\n00135| // Define the Loading UI here\n00136| return
Loading...
\n00137| }\n00138| ```\n00139| \n00140| ```jsx filename=\"app/blog/loading.js\" switcher\n00141| export default function Loading() {\n00142| // Define the Loading UI here\n00143| return
Loading...
\n00144| }\n00145| ```\n00146| \n00147| On navigation, the user will immediately see the layout and a [loading state](#creating-meaningful-loading-states) while the page is being rendered. The new content will then be automatically swapped in once rendering is complete.\n00148| \n00149| \n00156| \n00157| Behind the scenes, `loading.js` will be [nested inside `layout.js`](/docs/app/getting-started/project-structure#component-hierarchy), and will automatically wrap the `page.js` file and any children below in a `` boundary.\n00158| \n00159| \n00166| \n00167| Because of this, a layout that accesses uncached or runtime data (e.g. `cookies()`, `headers()`, or uncached fetches) does not fall back to a same route segment `loading.js`. Instead, it blocks navigation until the layout finishes rendering. [Cache Components](/docs/app/getting-started/caching) prevents this by guiding you with a build-time error.\n00168| \n00169| To fix this, wrap the uncached access in its own [``](#with-suspense) boundary with a fallback, or move the data fetching into `page.js` where `loading.js` can cover it. See [`loading.js`](/docs/app/api-reference/file-conventions/loading) for more details.\n00170| \n00171| This is why, while `loading.js` works well for streaming route segments, using `` closer to the runtime or uncached data access is recommended.\n00172| \n00173| #### With ``\n00174| \n00175| `` allows you to be more granular about what parts of the page to stream. For example, you can immediately show any page content that falls outside of the `` boundary, and stream in the list of blog posts inside the boundary.\n00176| \n00177| ```tsx filename=\"app/blog/page.tsx\" switcher\n00178| import { Suspense } from 'react'\n00179| import BlogList from '@/components/BlogList'\n00180| import BlogListSkeleton from '@/components/BlogListSkeleton'\n00181| \n00182| export default function BlogPage() {\n00183| return (\n00184|
\n00185| {/* This content will be sent to the client immediately */}\n00186| \n00187|
Welcome to the Blog
\n00188|
Read the latest posts below.
\n00189| \n00190| \n00191| {/* If there's any dynamic content inside this boundary, it will be streamed in */}\n00192| }>\n00193| \n00194| \n00195| \n00196|
\n00197| )\n00198| }\n00199| ```\n00200| \n00201| ```jsx filename=\"app/blog/page.js\" switcher\n00202| import { Suspense } from 'react'\n00203| import BlogList from '@/components/BlogList'\n00204| import BlogListSkeleton from '@/components/BlogListSkeleton'\n00205| \n00206| export default function BlogPage() {\n00207| return (\n00208|
\n00209| {/* This content will be sent to the client immediately */}\n00210| \n00211|
Welcome to the Blog
\n00212|
Read the latest posts below.
\n00213| \n00214| \n00215| {/* If there's any dynamic content inside this boundary, it will be streamed in */}\n00216| }>\n00217| \n00218| \n00219| \n00220|
\n00221| )\n00222| }\n00223| ```\n00224| \n00225| #### Creating meaningful loading states\n00226| \n00227| An instant loading state is fallback UI that is shown immediately to the user after navigation. For the best user experience, we recommend designing loading states that are meaningful and help users understand the app is responding. For example, you can use skeletons and spinners, or a small but meaningful part of future screens such as a cover photo, title, etc.\n00228| \n00229| In development, you can preview and inspect the loading state of your components using the [React Devtools](https://react.dev/learn/react-developer-tools).\n00230| \n00231| ### Client Components\n00232| \n00233| There are two ways to fetch data in Client Components, using:\n00234| \n00235| 1. React's [`use` API](https://react.dev/reference/react/use)\n00236| 2. A community library like [SWR](https://swr.vercel.app/) or [React Query](https://tanstack.com/query/latest)\n00237| \n00238| #### Streaming data with the `use` API\n00239| \n00240| You can use React's [`use` API](https://react.dev/reference/react/use) to [stream](#streaming) data from the server to client. Start by fetching data in your Server component, and pass the promise to your Client Component as prop:\n00241| \n00242| ```tsx filename=\"app/blog/page.tsx\" switcher\n00243| import Posts from '@/app/ui/posts'\n00244| import { Suspense } from 'react'\n00245| \n00246| export default function Page() {\n00247| // Don't await the data fetching function\n00248| const posts = getPosts()\n00249| \n00250| return (\n00251| Loading...}>\n00252| \n00253| \n00254| )\n00255| }\n00256| ```\n00257| \n00258| ```jsx filename=\"app/blog/page.js\" switcher\n00259| import Posts from '@/app/ui/posts'\n00260| import { Suspense } from 'react'\n00261| \n00262| export default function Page() {\n00263| // Don't await the data fetching function\n00264| const posts = getPosts()\n00265| \n00266| return (\n00267| Loading...}>\n00268| \n00269| \n00270| )\n00271| }\n00272| ```\n00273| \n00274| Then, in your Client Component, use the `use` API to read the promise:\n00275| \n00276| ```tsx filename=\"app/ui/posts.tsx\" switcher\n00277| 'use client'\n00278| import { use } from 'react'\n00279| \n00280| export default function Posts({\n00281| posts,\n00282| }: {\n00283| posts: Promise<{ id: string; title: string }[]>\n00284| }) {\n00285| const allPosts = use(posts)\n00286| \n00287| return (\n00288|
\n00310| )\n00311| }\n00312| ```\n00313| \n00314| In the example above, the `` component is wrapped in a [`` boundary](https://react.dev/reference/react/Suspense). This means the fallback will be shown while the promise is being resolved. Learn more about [streaming](#streaming).\n00315| \n00316| #### Community libraries\n00317| \n00318| You can use a community library like [SWR](https://swr.vercel.app/) or [React Query](https://tanstack.com/query/latest) to fetch data in Client Components. These libraries have their own semantics for caching, streaming, and other features. For example, with SWR:\n00319| \n00320| ```tsx filename=\"app/blog/page.tsx\" switcher\n00321| 'use client'\n00322| import useSWR from 'swr'\n00323| \n00324| const fetcher = (url) => fetch(url).then((r) => r.json())\n00325| \n00326| export default function BlogPage() {\n00327| const { data, error, isLoading } = useSWR(\n00328| 'https://api.vercel.app/blog',\n00329| fetcher\n00330| )\n00331| \n00332| if (isLoading) return
\n00367| )\n00368| }\n00369| ```\n00370| \n00371| ## Examples\n00372| \n00373| ### Sequential data fetching\n00374| \n00375| Sequential data fetching happens when one request depends on data from another.\n00376| \n00377| For example, `` can only fetch data after `` completes because it needs the `artistID`:\n00378| \n00379| ```tsx filename=\"app/artist/[username]/page.tsx\" switcher\n00380| export default async function Page({\n00381| params,\n00382| }: {\n00383| params: Promise<{ username: string }>\n00384| }) {\n00385| const { username } = await params\n00386| // Get artist information\n00387| const artist = await getArtist(username)\n00388| \n00389| return (\n00390| <>\n00391|
{artist.name}
\n00392| {/* Show fallback UI while the Playlists component is loading */}\n00393| Loading...}>\n00394| {/* Pass the artist ID to the Playlists component */}\n00395| \n00396| \n00397| >\n00398| )\n00399| }\n00400| \n00401| async function Playlists({ artistID }: { artistID: string }) {\n00402| // Use the artist ID to fetch playlists\n00403| const playlists = await getArtistPlaylists(artistID)\n00404| \n00405| return (\n00406|
\n00407| {playlists.map((playlist) => (\n00408|
{playlist.name}
\n00409| ))}\n00410|
\n00411| )\n00412| }\n00413| ```\n00414| \n00415| ```jsx filename=\"app/artist/[username]/page.js\" switcher\n00416| export default async function Page({ params }) {\n00417| const { username } = await params\n00418| // Get artist information\n00419| const artist = await getArtist(username)\n00420| \n00421| return (\n00422| <>\n00423|
{artist.name}
\n00424| {/* Show fallback UI while the Playlists component is loading */}\n00425| Loading...}>\n00426| {/* Pass the artist ID to the Playlists component */}\n00427| \n00428| \n00429| >\n00430| )\n00431| }\n00432| \n00433| async function Playlists({ artistID }) {\n00434| // Use the artist ID to fetch playlists\n00435| const playlists = await getArtistPlaylists(artistID)\n00436| \n00437| return (\n00438|
\n00439| {playlists.map((playlist) => (\n00440|
{playlist.name}
\n00441| ))}\n00442|
\n00443| )\n00444| }\n00445| ```\n00446| \n00447| In this example, `` allows the playlists to stream in after the artist data loads. However, the page still waits for the artist data before displaying anything. To prevent this, you can wrap the entire page component in a `` boundary (for example, using a [`loading.js` file](#with-loadingjs)) to show a loading state immediately.\n00448| \n00449| Ensure your data source can resolve the first request quickly, as it blocks everything else. If you can't optimize the request further, consider [caching](/docs/app/getting-started/caching) the result if the data changes infrequently.\n00450| \n00451| ### Parallel data fetching\n00452| \n00453| Parallel data fetching happens when data requests in a route are eagerly initiated and start at the same time.\n00454| \n00455| By default, [layouts and pages](/docs/app/getting-started/layouts-and-pages) are rendered in parallel. So each segment starts fetching data as soon as possible.\n00456| \n00457| However, within _any_ component, multiple `async`/`await` requests can still be sequential if placed after the other. For example, `getAlbums` will be blocked until `getArtist` is resolved:\n00458| \n00459| ```tsx filename=\"app/artist/[username]/page.tsx\" switcher\n00460| import { getArtist, getAlbums } from '@/app/lib/data'\n00461| \n00462| export default async function Page({ params }) {\n00463| // These requests will be sequential\n00464| const { username } = await params\n00465| const artist = await getArtist(username)\n00466| const albums = await getAlbums(username)\n00467| return
{artist.name}
\n00468| }\n00469| ```\n00470| \n00471| Start multiple requests by calling `fetch`, then await them with [`Promise.all`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all). Requests begin as soon as `fetch` is called.\n00472| \n00473| ```tsx filename=\"app/artist/[username]/page.tsx\" highlight={3,8,24} switcher\n00474| import Albums from './albums'\n00475| \n00476| async function getArtist(username: string) {\n00477| const res = await fetch(`https://api.example.com/artist/${username}`)\n00478| return res.json()\n00479| }\n00480| \n00481| async function getAlbums(username: string) {\n00482| const res = await fetch(`https://api.example.com/artist/${username}/albums`)\n00483| return res.json()\n00484| }\n00485| \n00486| export default async function Page({\n00487| params,\n00488| }: {\n00489| params: Promise<{ username: string }>\n00490| }) {\n00491| const { username } = await params\n00492| \n00493| // Initiate requests\n00494| const artistData = getArtist(username)\n00495| const albumsData = getAlbums(username)\n00496| \n00497| const [artist, albums] = await Promise.all([artistData, albumsData])\n00498| \n00499| return (\n00500| <>\n00501|
\n00533| \n00534| >\n00535| )\n00536| }\n00537| ```\n00538| \n00539| > **Good to know:** If one request fails when using `Promise.all`, the entire operation will fail. To handle this, you can use the [`Promise.allSettled`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled) method instead.\n00540| \n00541| ### Sharing data with context and `React.cache`\n00542| \n00543| You can share fetched data across both Server and Client Components by combining [`React.cache`](https://react.dev/reference/react/cache) with context providers.\n00544| \n00545| Create a cached function that fetches data:\n00546| \n00547| ```ts filename=\"app/lib/user.ts\" switcher\n00548| import { cache } from 'react'\n00549| \n00550| export const getUser = cache(async () => {\n00551| const res = await fetch('https://api.example.com/user')\n00552| return res.json()\n00553| })\n00554| ```\n00555| \n00556| ```js filename=\"app/lib/user.js\" switcher\n00557| import { cache } from 'react'\n00558| \n00559| export const getUser = cache(async () => {\n00560| const res = await fetch('https://api.example.com/user')\n00561| return res.json()\n00562| })\n00563| ```\n00564| \n00565| Create a context provider that stores the promise:\n00566| \n00567| ```tsx filename=\"app/user-provider.tsx\" switcher\n00568| 'use client'\n00569| \n00570| import { createContext } from 'react'\n00571| \n00572| type User = {\n00573| id: string\n00574| name: string\n00575| }\n00576| \n00577| export const UserContext = createContext | null>(null)\n00578| \n00579| export default function UserProvider({\n00580| children,\n00581| userPromise,\n00582| }: {\n00583| children: React.ReactNode\n00584| userPromise: Promise\n00585| }) {\n00586| return {children}\n00587| }\n00588| ```\n00589| \n00590| ```jsx filename=\"app/user-provider.js\" switcher\n00591| 'use client'\n00592| \n00593| import { createContext } from 'react'\n00594| \n00595| export const UserContext = createContext(null)\n00596| \n00597| export default function UserProvider({ children, userPromise }) {\n00598| return {children}\n00599| }\n00600| ```\n00601| \n00602| In a layout, pass the promise to the provider without awaiting:\n00603| \n00604| ```tsx filename=\"app/layout.tsx\" switcher\n00605| import UserProvider from './user-provider'\n00606| import { getUser } from './lib/user'\n00607| \n00608| export default function RootLayout({\n00609| children,\n00610| }: {\n00611| children: React.ReactNode\n00612| }) {\n00613| const userPromise = getUser() // Don't await\n00614| \n00615| return (\n00616| \n00617| \n00618| {children}\n00619| \n00620| \n00621| )\n00622| }\n00623| ```\n00624| \n00625| ```jsx filename=\"app/layout.js\" switcher\n00626| import UserProvider from './user-provider'\n00627| import { getUser } from './lib/user'\n00628| \n00629| export default function RootLayout({ children }) {\n00630| const userPromise = getUser() // Don't await\n00631| \n00632| return (\n00633| \n00634| \n00635| {children}\n00636| \n00637| \n00638| )\n00639| }\n00640| ```\n00641| \n00642| Client Components use [`use()`](https://react.dev/reference/react/use) to resolve the promise from context, wrapped in `` for fallback UI:\n00643| \n00644| ```tsx filename=\"app/ui/profile.tsx\" switcher\n00645| 'use client'\n00646| \n00647| import { use, useContext } from 'react'\n00648| import { UserContext } from '../user-provider'\n00649| \n00650| export function Profile() {\n00651| const userPromise = useContext(UserContext)\n00652| if (!userPromise) {\n00653| throw new Error('useContext must be used within a UserProvider')\n00654| }\n00655| const user = use(userPromise)\n00656| return
Welcome, {user.name}
\n00657| }\n00658| ```\n00659| \n00660| ```jsx filename=\"app/ui/profile.js\" switcher\n00661| 'use client'\n00662| \n00663| import { use, useContext } from 'react'\n00664| import { UserContext } from '../user-provider'\n00665| \n00666| export function Profile() {\n00667| const userPromise = useContext(UserContext)\n00668| if (!userPromise) {\n00669| throw new Error('useContext must be used within a UserProvider')\n00670| }\n00671| const user = use(userPromise)\n00672| return
Welcome, {user.name}
\n00673| }\n00674| ```\n00675| \n00676| ```tsx filename=\"app/page.tsx\" switcher\n00677| import { Suspense } from 'react'\n00678| import { Profile } from './ui/profile'\n00679| \n00680| export default function Page() {\n00681| return (\n00682| Loading profile...}>\n00683| \n00684| \n00685| )\n00686| }\n00687| ```\n00688| \n00689| ```jsx filename=\"app/page.js\" switcher\n00690| import { Suspense } from 'react'\n00691| import { Profile } from './ui/profile'\n00692| \n00693| export default function Page() {\n00694| return (\n00695| Loading profile...}>\n00696| \n00697| \n00698| )\n00699| }\n00700| ```\n00701| \n00702| Server Components can also call `getUser()` directly:\n00703| \n00704| ```tsx filename=\"app/dashboard/page.tsx\" switcher\n00705| import { getUser } from '../lib/user'\n00706| \n00707| export default async function DashboardPage() {\n00708| const user = await getUser() // Cached - same request, no duplicate fetch\n00709| return
Dashboard for {user.name}
\n00710| }\n00711| ```\n00712| \n00713| ```jsx filename=\"app/dashboard/page.js\" switcher\n00714| import { getUser } from '../lib/user'\n00715| \n00716| export default async function DashboardPage() {\n00717| const user = await getUser() // Cached - same request, no duplicate fetch\n00718| return
Dashboard for {user.name}
\n00719| }\n00720| ```\n00721| \n00722| Since `getUser` is wrapped with `React.cache`, multiple calls within the same request return the same memoized result, whether called directly in Server Components or resolved via context in Client Components.\n00723| \n00724| > **Good to know**: `React.cache` is scoped to the current request only. Each request gets its own memoization scope with no sharing between requests.\n00725| \n\n(End of file - total 725 lines)\n",
+ "title": "node_modules/next/dist/docs/01-app/01-getting-started/06-fetching-data.md",
+ "metadata": {
+ "preview": "---\ntitle: Fetching Data\ndescription: Learn how to fetch data and stream content that depends on data.\nrelated:\n title: API Reference\n description: Learn more about the features mentioned in this page by reading the API Reference.\n links:\n - app/guides/data-security\n - app/api-reference/functions/fetch\n - app/api-reference/file-conventions/loading\n - app/api-reference/config/next-config-js/logging\n - app/api-reference/config/next-config-js/taint\n---\n\nThis page will walk you through how you can fetch data in [Server](#server-components) and [Client](#client-components) Components, and how to [stream](#streaming) components that depend on uncached data.\n\n## Fetching data\n\n### Server Components\n"
+ },
+ "time": {
+ "start": 1781392514793,
+ "end": 1781392514798
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:15.775Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "args": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/01-getting-started/08-caching.md",
+ "_extractedPath": "/workspace/node_modules/next/dist/docs/01-app/01-getting-started/08-caching.md"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392515775,
+ "sessionID": "ses_13cbb9c4fffe5TDZ1DwM35w4Zl",
+ "part": {
+ "id": "prt_ec3449eed001NlmwV1QvR7WAYq",
+ "sessionID": "ses_13cbb9c4fffe5TDZ1DwM35w4Zl",
+ "messageID": "msg_ec34490c9001zc1GxYz6EOzVOq",
+ "type": "tool",
+ "callID": "read_8",
+ "tool": "read",
+ "state": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/01-getting-started/08-caching.md"
+ },
+ "output": "\n00001| ---\n00002| title: Caching\n00003| description: Learn how to cache data and UI in Next.js\n00004| related:\n00005| title: Next Steps\n00006| description: Learn more about revalidation and the APIs mentioned on this page.\n00007| links:\n00008| - app/getting-started/revalidating\n00009| - app/api-reference/directives/use-cache\n00010| - app/api-reference/config/next-config-js/cacheComponents\n00011| - app/guides/instant-navigation\n00012| ---\n00013| \n00014| > This page covers caching with [Cache Components](/docs/app/api-reference/config/next-config-js/cacheComponents), enabled by setting [`cacheComponents: true`](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.ts` file. If you're not using Cache Components, see the [Caching and Revalidating (Previous Model)](/docs/app/guides/caching-without-cache-components) guide.\n00015| \n00016| Caching is a technique for storing the result of data fetching and other computations so that future requests for the same data can be served faster, without doing the work again.\n00017| \n00018| ## Enabling Cache Components\n00019| \n00020| You can enable Cache Components by adding the [`cacheComponents`](/docs/app/api-reference/config/next-config-js/cacheComponents) option to your Next config file:\n00021| \n00022| ```ts filename=\"next.config.ts\" switcher\n00023| import type { NextConfig } from 'next'\n00024| \n00025| const nextConfig: NextConfig = {\n00026| cacheComponents: true,\n00027| }\n00028| \n00029| export default nextConfig\n00030| ```\n00031| \n00032| ```js filename=\"next.config.js\" switcher\n00033| /** @type {import('next').NextConfig} */\n00034| const nextConfig = {\n00035| cacheComponents: true,\n00036| }\n00037| \n00038| module.exports = nextConfig\n00039| ```\n00040| \n00041| > **Good to know:** When Cache Components is enabled, `GET` Route Handlers follow the same prerendering model as pages. See [Route Handlers with Cache Components](/docs/app/getting-started/route-handlers#with-cache-components) for details.\n00042| \n00043| ## Usage\n00044| \n00045| The [`use cache`](/docs/app/api-reference/directives/use-cache) directive caches the return value of async functions and components. You can apply it at two levels:\n00046| \n00047| - **Data-level**: Cache a function that fetches or computes data (e.g., `getProducts()`, `getUser(id)`)\n00048| - **UI-level**: Cache an entire component or page (e.g., `async function BlogPosts()`)\n00049| \n00050| Two variants cover specific scenarios: [`\"use cache: remote\"`](/docs/app/api-reference/directives/use-cache-remote) for durable, shared remote storage, and [`\"use cache: private\"`](/docs/app/api-reference/directives/use-cache-private) for caching functions that read runtime data.\n00051| \n00052| > Arguments and any closed-over values from parent scopes automatically become part of the [cache key](/docs/app/api-reference/directives/use-cache#cache-keys), which means different inputs will produce separate cache entries. This enables personalized or parameterized cached content. See [serialization requirements and constraints](/docs/app/api-reference/directives/use-cache#constraints) for details on what can be cached and how arguments work.\n00053| \n00054| ### Data-level caching\n00055| \n00056| To cache an asynchronous function that fetches data, add the `use cache` directive at the top of the function body:\n00057| \n00058| ```tsx filename=\"app/lib/data.ts\" highlight={3,4,5}\n00059| import { cacheLife } from 'next/cache'\n00060| \n00061| export async function getUsers() {\n00062| 'use cache'\n00063| cacheLife('hours')\n00064| return db.query('SELECT * FROM users')\n00065| }\n00066| ```\n00067| \n00068| Data-level caching is useful when the same data is used across multiple components, or when you want to cache the data independently from the UI.\n00069| \n00070| ### UI-level caching\n00071| \n00072| To cache an entire component, page, or layout, add the `use cache` directive at the top of the component or page body:\n00073| \n00074| ```tsx filename=\"app/page.tsx\" highlight={1,4,5}\n00075| import { cacheLife } from 'next/cache'\n00076| \n00077| export default async function Page() {\n00078| 'use cache'\n00079| cacheLife('hours')\n00080| \n00081| const users = await db.query('SELECT * FROM users')\n00082| \n00083| return (\n00084|
\n00085| {users.map((user) => (\n00086|
{user.name}
\n00087| ))}\n00088|
\n00089| )\n00090| }\n00091| ```\n00092| \n00093| > If you add \"`use cache`\" at the top of a file, all exported functions in the file will be cached.\n00094| \n00095| ### Streaming uncached data\n00096| \n00097| For components that fetch data from an asynchronous source such as an API, a database, or any other async operation, and require fresh data on every request, do not use `\"use cache\"`.\n00098| \n00099| Instead, wrap the component in [``](https://react.dev/reference/react/Suspense) and provide a fallback UI. The fallback ships with the prerendered shell while the async work runs at request time.\n00100| \n00101| ```tsx filename=\"page.tsx\"\n00102| import { Suspense } from 'react'\n00103| \n00104| async function LatestPosts() {\n00105| const data = await fetch('https://api.example.com/posts')\n00106| const posts = await data.json()\n00107| return (\n00108|
\n00120| Loading posts...}>\n00121| \n00122| \n00123| >\n00124| )\n00125| }\n00126| ```\n00127| \n00128| For example, `
Loading posts...
` is included in the static shell, and the posts stream in at request time.\n00129| \n00130| Without a `` boundary around the uncached read, the dev overlay surfaces the **blocking-route** insight with this fix:\n00131| \n00132| \n00133| ', highlight: true },\n00139| { text: ' ' },\n00140| { text: '', highlight: true },\n00141| ]}\n00142| />\n00143| \n00144| \n00145| > **Good to know:** Each fix card links to a detailed walkthrough with patterns, code samples, and trade-offs. Click a card to dive in.\n00146| \n00147| {/* xref to the sync io section - that section should also emphaize that these are not random or timestamp sync invokations, in the referenced section */}\n00148| `` provides a fallback UI while async work completes, but it does not itself opt a component into dynamic rendering. If a component only performs synchronous work, it will complete during prerendering regardless of whether it is wrapped in ``.\n00149| \n00150| ## Working with runtime APIs\n00151| \n00152| Runtime APIs require information that is only available when a user makes a request. These include:\n00153| \n00154| - [`cookies`](/docs/app/api-reference/functions/cookies) - User's cookie data\n00155| - [`headers`](/docs/app/api-reference/functions/headers) - Request headers\n00156| - [`searchParams`](/docs/app/api-reference/file-conventions/page#searchparams-optional) - URL query parameters\n00157| - [`params`](/docs/app/api-reference/file-conventions/page#params-optional) - Dynamic route parameters. Use [`generateStaticParams`](/docs/app/api-reference/functions/generate-static-params) to prerender specific values at build time, or [ISR with Cache Components](/docs/app/guides/incremental-static-regeneration-cache-components) to serve an App Shell while unknown params resolve in the background.\n00158| \n00159| Components that access runtime APIs should be wrapped in ``:\n00160| \n00161| ```tsx filename=\"page.tsx\"\n00162| import { cookies } from 'next/headers'\n00163| import { Suspense } from 'react'\n00164| \n00165| async function UserGreeting() {\n00166| const cookieStore = await cookies()\n00167| const theme = cookieStore.get('theme')?.value || 'light'\n00168| return
\n00175| Loading...}>\n00176| \n00177| \n00178| >\n00179| )\n00180| }\n00181| ```\n00182| \n00183| A runtime API access without `` surfaces the same **blocking-route** insight in the dev overlay, with the same fix:\n00184| \n00185| \n00186| ', highlight: true },\n00192| { text: ' ' },\n00193| { text: '', highlight: true },\n00194| ]}\n00195| />\n00196| \n00197| \n00198| ### Passing runtime values to cached functions\n00199| \n00200| You can extract values from runtime APIs and pass them as arguments to cached functions:\n00201| \n00202| ```tsx filename=\"app/profile/page.tsx\"\n00203| import { cookies } from 'next/headers'\n00204| import { Suspense } from 'react'\n00205| \n00206| export default function Page() {\n00207| return (\n00208| Loading...}>\n00209| \n00210| \n00211| )\n00212| }\n00213| \n00214| // Component (not cached) reads runtime data\n00215| async function ProfileContent() {\n00216| const session = (await cookies()).get('session')?.value\n00217| return \n00218| }\n00219| \n00220| // Cached component receives extracted value as a prop\n00221| async function CachedContent({ sessionId }: { sessionId: string }) {\n00222| 'use cache'\n00223| // sessionId becomes part of the cache key\n00224| const data = await fetchUserData(sessionId)\n00225| return
{data}
\n00226| }\n00227| ```\n00228| \n00229| At request time, `CachedContent` executes if no matching cache entry is found, and stores the result for future requests with the same `sessionId`.\n00230| \n00231| This pattern also unlocks [runtime prefetching](#runtime-prefetching): on a client transition, the framework can prerender `CachedContent` with the user's actual session and have the result ready before the click.\n00232| \n00233| By default, `use cache` stores entries [in-memory](/docs/app/api-reference/directives/use-cache#runtime-caching-considerations). In serverless environments where memory doesn't persist across requests, `CachedContent` may re-evaluate on every request. Consider [`'use cache: remote'`](/docs/app/api-reference/directives/use-cache-remote) for durable, shared caching.\n00234| \n00235| ## Static, cached, and streaming\n00236| \n00237| Here's a complete example showing static content, cached dynamic content, and streaming dynamic content working together on a single page:\n00238| \n00239| ```tsx filename=\"app/blog/page.tsx\"\n00240| import { Suspense } from 'react'\n00241| import { cookies } from 'next/headers'\n00242| import { cacheLife, cacheTag } from 'next/cache'\n00243| import Link from 'next/link'\n00244| \n00245| export default function BlogPage() {\n00246| return (\n00247| <>\n00248| {/* Static content - prerendered automatically */}\n00249| \n00250|
Our Blog
\n00251| \n00252| Home | About\n00253| \n00254| \n00255| \n00256| {/* Cached dynamic content - included in the static shell */}\n00257| \n00258| \n00259| {/* Runtime dynamic content - streams at request time */}\n00260| Loading your preferences...}>\n00261| \n00262| \n00263| >\n00264| )\n00265| }\n00266| \n00267| type Post = { id: string; title: string; author: string; date: string }\n00268| \n00269| // Everyone sees the same blog posts (revalidated every hour)\n00270| async function BlogPosts() {\n00271| 'use cache'\n00272| cacheLife('hours')\n00273| cacheTag('posts')\n00274| \n00275| const res = await fetch('https://api.vercel.app/blog')\n00276| const posts: Post[] = await res.json()\n00277| \n00278| return (\n00279| \n00280|
Latest Posts
\n00281|
\n00282| {posts.map((post) => (\n00283|
\n00284|
{post.title}
\n00285|
\n00286| By {post.author} on {post.date}\n00287|
\n00288|
\n00289| ))}\n00290|
\n00291| \n00292| )\n00293| }\n00294| \n00295| // UI that depends on a value stored in cookies\n00296| async function UserPreferences() {\n00297| const theme = (await cookies()).get('theme')?.value || 'light'\n00298| const favoriteCategory = (await cookies()).get('category')?.value\n00299| \n00300| return (\n00301| \n00305| )\n00306| }\n00307| ```\n00308| \n00309| During prerendering, the header (static) and blog posts (cached with `use cache`) become part of the static shell, along with the fallback UI for user preferences. The UI preferences stored in cookies stream in at request time.\n00310| \n00311| Reading `cookies()` here doesn't opt-in the whole route into dynamic rendering, the way the previous rendering model did. The Suspense boundary provides fallback UI where the runtime access streams, while static and cached content still ship in the initial HTML.\n00312| \n00313| Just as `` contains async access, an **error boundary** contains failures: wrap them around a subtree that might error during rendering. Use [`unstable_catchError`](/docs/app/api-reference/functions/catchError) for component-level boundaries, or the [`error.js`](/docs/app/api-reference/file-conventions/error) file convention for route-level boundaries.\n00314| \n00315| As you build, consider that inside [`generateMetadata`](/docs/app/api-reference/functions/generate-metadata#with-cache-components) and [`generateViewport`](/docs/app/api-reference/functions/generate-viewport#with-cache-components), uncached fetches or runtime data access surface the same insights and errors as in your page, guiding you to the rendering you intend. For incremental static regeneration with both known and unknown param values, see [ISR with Cache Components](/docs/app/guides/incremental-static-regeneration-cache-components).\n00316| \n00317| ## Random values and timestamps\n00318| \n00319| Operations like `Math.random()`, `Date.now()`, or `crypto.randomUUID()` produce different values each time they execute. Cache Components requires you to explicitly handle these.\n00320| \n00321| > **Good to know:** `performance.now()` is meant for telemetry. Pass the value to your logger or metrics rather than rendering it.\n00322| \n00323| **To generate unique values per request**, defer to request time by calling [`connection()`](/docs/app/api-reference/functions/connection) before these operations, and wrap the component in ``:\n00324| \n00325| ```tsx filename=\"page.tsx\"\n00326| import { connection } from 'next/server'\n00327| import { Suspense } from 'react'\n00328| \n00329| async function UniqueContent() {\n00330| await connection()\n00331| const uuid = crypto.randomUUID()\n00332| return
Request ID: {uuid}
\n00333| }\n00334| \n00335| export default function Page() {\n00336| return (\n00337| Loading...}>\n00338| \n00339| \n00340| )\n00341| }\n00342| ```\n00343| \n00344| Alternatively, you can **cache the result** so all users see the same value until revalidation:\n00345| \n00346| ```tsx filename=\"page.tsx\"\n00347| export default async function Page() {\n00348| 'use cache'\n00349| const buildId = crypto.randomUUID()\n00350| return
Build ID: {buildId}
\n00351| }\n00352| ```\n00353| \n00354| You don't need to memorize which operations behave this way. The dev overlay surfaces a **blocking-prerender-random**, **blocking-prerender-current-time**, or **blocking-prerender-crypto** insight (depending on the call) with these fixes:\n00355| \n00356| \n00357| ' },\n00365| ]}\n00366| />\n00367| \n00377| \n00378| \n00379| ## Synchronous I/O and pure computations\n00380| \n00381| Unlike random or time-based APIs, synchronous I/O, module imports, and pure computations are predictable: the same inputs produce the same outputs. Components using only these operations are prerendered automatically, and their output becomes part of the static HTML at build time.\n00382| \n00383| ```tsx filename=\"page.tsx\"\n00384| import fs from 'node:fs'\n00385| \n00386| export default async function Page() {\n00387| const constants = await import('./constants.json')\n00388| const content = fs.readFileSync('./config.json', 'utf-8')\n00389| const items = JSON.parse(content).items ?? []\n00390| \n00391| return (\n00392|
\n00393|
{constants.appName}
\n00394|
\n00395| {items.map((item) => (\n00396|
{item.value}
\n00397| ))}\n00398|
\n00399|
\n00400| )\n00401| }\n00402| ```\n00403| \n00404| > **Good to know:** This includes queries to embedded databases with synchronous APIs, such as `better-sqlite3` or Node.js's built-in [`node:sqlite`](https://nodejs.org/api/sqlite.html). If you need per-request data from a synchronous source, call [`connection()`](/docs/app/api-reference/functions/connection) before the query.\n00405| \n00406| ## Prerendering\n00407| \n00408| At build time, Next.js renders your route's component tree. How each component is handled depends on the APIs it uses:\n00409| \n00410| - [`use cache`](#usage): the result is cached and included in the static shell\n00411| - [``](#streaming-uncached-data): fallback UI is included in the static shell while the content streams at request time\n00412| - [Synchronous I/O and pure computations](#synchronous-io-and-pure-computations): module imports, `fs.readFileSync`, and pure computations complete during prerender and are included in the static shell automatically\n00413| - [Random values and timestamps](#random-values-and-timestamps): use `connection()` + `` to get a unique value per request, or `use cache` to share one across users\n00414| \n00415| This generates a static shell consisting of HTML for initial page loads and a serialized [RSC Payload](/docs/app/getting-started/server-and-client-components#on-the-server) for client-side navigation, ensuring the browser receives fully rendered content instantly whether users navigate directly to the URL or transition from another page. This rendering approach is called **Partial Prerendering (PPR)**, the default behavior with Cache Components.\n00416| \n00417| \n00424| \n00425| Every produced static shell can be served directly from a CDN, without going through to the upstream server. This makes direct navigations [instant](#instant-navigation).\n00426| \n00427| Next.js requires you to explicitly handle components that can't complete during prerendering. It surfaces a validation insight in the dev overlay and dev server console that names the route and points at fixes (cache the access, move it into a `` boundary, or opt the route out). This validation keeps every route producing a static shell, so direct navigations stay instant.\n00428| \n00429| \n00436| \n00437| > **🎥 Watch:** Why Partial Prerendering and how it works → [YouTube (10 minutes)](https://www.youtube.com/watch?v=MTcPrTIBkpA).\n00438| \n00439| ### Bots and crawlers\n00440| \n00441| Browsers receive the static shell instantly. Bots and crawlers are detected by their user agent and handled differently: because they need a complete document, Next.js skips the shell and renders the entire page dynamically at request time, then sends the finished HTML once the render completes.\n00442| \n00443| Because the shell is re-rendered instead of reused, work that completed during prerendering now runs at request time for a bot. If part of your shell depends on inputs that only exist while prerendering, such as build-time data or values that are not reachable in the request-time environment, a page that loads for a person can fail to render for a crawler. Make sure the data your shell relies on is also available at request time. See [Bots and crawlers](/docs/app/guides/streaming#bots-and-crawlers) for more details.\n00444| \n00445| ### Maximizing the static shell\n00446| \n00447| The deeper your async work sits in the tree, the more of the page can be prerendered. This is the structural pattern Cache Components rewards: a general practice worth applying everywhere, and the foundation for the instant navigation and runtime prefetching that follow. It applies to all [runtime APIs](#working-with-runtime-apis) and async operations like data fetches.\n00448| \n00449| Consider a layout that destructures `params` at the top level:\n00450| \n00451| ```tsx filename=\"app/shop/[slug]/layout.tsx\"\n00452| export default async function Layout({\n00453| children,\n00454| params,\n00455| }: LayoutProps<'/shop/[slug]'>) {\n00456| const { slug } = await params\n00457| \n00458| return (\n00459|
\n00460| \n00461|
{slug}
\n00462| {children}\n00463|
\n00464| )\n00465| }\n00466| ```\n00467| \n00468| If this param is dynamic (not provided by [`generateStaticParams`](/docs/app/api-reference/functions/generate-static-params)), it is runtime data and the layout cannot be prerendered.\n00469| \n00470| However, it is often possible to read the parameter value further down the tree. Instead of awaiting at the layout level, pass the params promise down and await there:\n00471| \n00472| ```tsx filename=\"app/shop/[slug]/layout.tsx\" highlight={3,10-13}\n00473| import { Suspense } from 'react'\n00474| \n00475| export default function Layout({\n00476| children,\n00477| params,\n00478| }: LayoutProps<'/shop/[slug]'>) {\n00479| return (\n00480|
\n00494| }\n00495| ```\n00496| \n00497| Now ``, `{children}`, and the Suspense fallback are all part of the static shell. Only `SlugHeading` streams in at request time. You can also pass the entire `params` promise and await it in the child component.\n00498| \n00499| The same principle applies to `cookies()`, `headers()`, `searchParams`, and data fetches. See [Sharing data with context and `React.cache`](/docs/app/getting-started/fetching-data#sharing-data-with-context-and-reactcache) for a related pattern.\n00500| \n00501| ### Instant navigation\n00502| \n00503| Cache Components shipped in 16.0.0 with verification that direct visits to a route produce a static shell. Client navigations are different: a `` boundary that covers a direct visit may not be part of the render during a transition. Getting that structure right is easier when the framework steps in. Cache Components now validates these navigations too, giving you insights and errors that guide you to make navigations to your route instant. For example, wrap data in ``, cache it with `use cache`, or move where the access happens.\n00504| \n00505| Read the [Instant navigation guide](/docs/app/guides/instant-navigation) for examples and inspection tools.\n00506| \n00507| ### Runtime prefetching\n00508| \n00509| With [`prefetch = 'allow-runtime'`](/docs/app/api-reference/file-conventions/route-segment-config/prefetch) on a route, Next.js renders that route's component tree again at prefetch time, this time with the user's cookies, headers, and full URL available. The same rules apply, but more of the tree resolves now that runtime data is in scope:\n00510| \n00511| - [`use cache`](#usage) called with values extracted from runtime APIs (passed as arguments) joins the runtime prerender\n00512| - [`use cache: private`](/docs/app/api-reference/directives/use-cache-private) executes on the server, reads runtime data directly, and caches the result in the browser, joining the runtime prerender\n00513| - [``](#streaming-uncached-data) fallbacks stay in the runtime prerender while uncached content streams at request time\n00514| \n00515| This generates a **runtime prerender** that extends past the static shell with content the user's request unlocks. Because it happens during the prefetch, the navigation has nothing to wait on. The cost is a server invocation per prefetchable link.\n00516| \n00517| For example, take a dashboard that reads the user's session cookie and opts into runtime prefetching:\n00518| \n00519| ```tsx filename=\"app/dashboard/page.tsx\"\n00520| import { cookies } from 'next/headers'\n00521| import { Suspense } from 'react'\n00522| \n00523| export const prefetch = 'allow-runtime'\n00524| \n00525| export default function Dashboard() {\n00526| return (\n00527| Loading...}>\n00528| \n00529| \n00530| )\n00531| }\n00532| \n00533| async function Stats() {\n00534| const session = (await cookies()).get('session')?.value\n00535| if (!session) return
\n00538| }\n00539| \n00540| async function getStats(session: string) {\n00541| 'use cache'\n00542| return db.users.getStats(session)\n00543| }\n00544| ```\n00545| \n00546| On a direct visit, `` streams in behind the fallback. When a user navigates to `/dashboard` from another route, the framework prefetches with their session cookie. `getStats` is cached, so its result joins the runtime prerender before the click.\n00547| \n00548| See the [Runtime prefetching guide](/docs/app/guides/runtime-prefetching) for full patterns and the [`prefetch` reference](/docs/app/api-reference/file-conventions/route-segment-config/prefetch) for all modes.\n00549| \n00550| {/* I wonder if we need a small section that develops ISR briefly and links to the ISR w/ CC guide */}\n00551| \n\n(End of file - total 551 lines)\n",
+ "title": "node_modules/next/dist/docs/01-app/01-getting-started/08-caching.md",
+ "metadata": {
+ "preview": "---\ntitle: Caching\ndescription: Learn how to cache data and UI in Next.js\nrelated:\n title: Next Steps\n description: Learn more about revalidation and the APIs mentioned on this page.\n links:\n - app/getting-started/revalidating\n - app/api-reference/directives/use-cache\n - app/api-reference/config/next-config-js/cacheComponents\n - app/guides/instant-navigation\n---\n\n> This page covers caching with [Cache Components](/docs/app/api-reference/config/next-config-js/cacheComponents), enabled by setting [`cacheComponents: true`](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.ts` file. If you're not using Cache Components, see the [Caching and Revalidating (Previous Model)](/docs/app/guides/caching-without-cache-components) guide.\n\nCaching is a technique for storing the result of data fetching and other computations so that future requests for the same data can be served faster, without doing the work again.\n\n## Enabling Cache Components\n\nYou can enable Cache Components by adding the [`cacheComponents`](/docs/app/api-reference/config/next-config-js/cacheComponents) option to your Next config file:"
+ },
+ "time": {
+ "start": 1781392515771,
+ "end": 1781392515774
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:15.775Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| ---\n00002| title: Caching\n00003| description: Learn how to cache data and UI in Next.js\n00004| related:\n00005| title: Next Steps\n00006| description: Learn more about revalidation and the APIs mentioned on this page.\n00007| links:\n00008| - app/getting-started/revalidating\n00009| - app/api-reference/directives/use-cache\n00010| - app/api-reference/config/next-config-js/cacheComponents\n00011| - app/guides/instant-navigation\n00012| ---\n00013| \n00014| > This page covers caching with [Cache Components](/docs/app/api-reference/config/next-config-js/cacheComponents), enabled by setting [`cacheComponents: true`](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.ts` file. If you're not using Cache Components, see the [Caching and Revalidating (Previous Model)](/docs/app/guides/caching-without-cache-components) guide.\n00015| \n00016| Caching is a technique for storing the result of data fetching and other computations so that future requests for the same data can be served faster, without doing the work again.\n00017| \n00018| ## Enabling Cache Components\n00019| \n00020| You can enable Cache Components by adding the [`cacheComponents`](/docs/app/api-reference/config/next-config-js/cacheComponents) option to your Next config file:\n00021| \n00022| ```ts filename=\"next.config.ts\" switcher\n00023| import type { NextConfig } from 'next'\n00024| \n00025| const nextConfig: NextConfig = {\n00026| cacheComponents: true,\n00027| }\n00028| \n00029| export default nextConfig\n00030| ```\n00031| \n00032| ```js filename=\"next.config.js\" switcher\n00033| /** @type {import('next').NextConfig} */\n00034| const nextConfig = {\n00035| cacheComponents: true,\n00036| }\n00037| \n00038| module.exports = nextConfig\n00039| ```\n00040| \n00041| > **Good to know:** When Cache Components is enabled, `GET` Route Handlers follow the same prerendering model as pages. See [Route Handlers with Cache Components](/docs/app/getting-started/route-handlers#with-cache-components) for details.\n00042| \n00043| ## Usage\n00044| \n00045| The [`use cache`](/docs/app/api-reference/directives/use-cache) directive caches the return value of async functions and components. You can apply it at two levels:\n00046| \n00047| - **Data-level**: Cache a function that fetches or computes data (e.g., `getProducts()`, `getUser(id)`)\n00048| - **UI-level**: Cache an entire component or page (e.g., `async function BlogPosts()`)\n00049| \n00050| Two variants cover specific scenarios: [`\"use cache: remote\"`](/docs/app/api-reference/directives/use-cache-remote) for durable, shared remote storage, and [`\"use cache: private\"`](/docs/app/api-reference/directives/use-cache-private) for caching functions that read runtime data.\n00051| \n00052| > Arguments and any closed-over values from parent scopes automatically become part of the [cache key](/docs/app/api-reference/directives/use-cache#cache-keys), which means different inputs will produce separate cache entries. This enables personalized or parameterized cached content. See [serialization requirements and constraints](/docs/app/api-reference/directives/use-cache#constraints) for details on what can be cached and how arguments work.\n00053| \n00054| ### Data-level caching\n00055| \n00056| To cache an asynchronous function that fetches data, add the `use cache` directive at the top of the function body:\n00057| \n00058| ```tsx filename=\"app/lib/data.ts\" highlight={3,4,5}\n00059| import { cacheLife } from 'next/cache'\n00060| \n00061| export async function getUsers() {\n00062| 'use cache'\n00063| cacheLife('hours')\n00064| return db.query('SELECT * FROM users')\n00065| }\n00066| ```\n00067| \n00068| Data-level caching is useful when the same data is used across multiple components, or when you want to cache the data independently from the UI.\n00069| \n00070| ### UI-level caching\n00071| \n00072| To cache an entire component, page, or layout, add the `use cache` directive at the top of the component or page body:\n00073| \n00074| ```tsx filename=\"app/page.tsx\" highlight={1,4,5}\n00075| import { cacheLife } from 'next/cache'\n00076| \n00077| export default async function Page() {\n00078| 'use cache'\n00079| cacheLife('hours')\n00080| \n00081| const users = await db.query('SELECT * FROM users')\n00082| \n00083| return (\n00084|
\n00085| {users.map((user) => (\n00086|
{user.name}
\n00087| ))}\n00088|
\n00089| )\n00090| }\n00091| ```\n00092| \n00093| > If you add \"`use cache`\" at the top of a file, all exported functions in the file will be cached.\n00094| \n00095| ### Streaming uncached data\n00096| \n00097| For components that fetch data from an asynchronous source such as an API, a database, or any other async operation, and require fresh data on every request, do not use `\"use cache\"`.\n00098| \n00099| Instead, wrap the component in [``](https://react.dev/reference/react/Suspense) and provide a fallback UI. The fallback ships with the prerendered shell while the async work runs at request time.\n00100| \n00101| ```tsx filename=\"page.tsx\"\n00102| import { Suspense } from 'react'\n00103| \n00104| async function LatestPosts() {\n00105| const data = await fetch('https://api.example.com/posts')\n00106| const posts = await data.json()\n00107| return (\n00108|
\n00120| Loading posts...}>\n00121| \n00122| \n00123| >\n00124| )\n00125| }\n00126| ```\n00127| \n00128| For example, `
Loading posts...
` is included in the static shell, and the posts stream in at request time.\n00129| \n00130| Without a `` boundary around the uncached read, the dev overlay surfaces the **blocking-route** insight with this fix:\n00131| \n00132| \n00133| ', highlight: true },\n00139| { text: ' ' },\n00140| { text: '', highlight: true },\n00141| ]}\n00142| />\n00143| \n00144| \n00145| > **Good to know:** Each fix card links to a detailed walkthrough with patterns, code samples, and trade-offs. Click a card to dive in.\n00146| \n00147| {/* xref to the sync io section - that section should also emphaize that these are not random or timestamp sync invokations, in the referenced section */}\n00148| `` provides a fallback UI while async work completes, but it does not itself opt a component into dynamic rendering. If a component only performs synchronous work, it will complete during prerendering regardless of whether it is wrapped in ``.\n00149| \n00150| ## Working with runtime APIs\n00151| \n00152| Runtime APIs require information that is only available when a user makes a request. These include:\n00153| \n00154| - [`cookies`](/docs/app/api-reference/functions/cookies) - User's cookie data\n00155| - [`headers`](/docs/app/api-reference/functions/headers) - Request headers\n00156| - [`searchParams`](/docs/app/api-reference/file-conventions/page#searchparams-optional) - URL query parameters\n00157| - [`params`](/docs/app/api-reference/file-conventions/page#params-optional) - Dynamic route parameters. Use [`generateStaticParams`](/docs/app/api-reference/functions/generate-static-params) to prerender specific values at build time, or [ISR with Cache Components](/docs/app/guides/incremental-static-regeneration-cache-components) to serve an App Shell while unknown params resolve in the background.\n00158| \n00159| Components that access runtime APIs should be wrapped in ``:\n00160| \n00161| ```tsx filename=\"page.tsx\"\n00162| import { cookies } from 'next/headers'\n00163| import { Suspense } from 'react'\n00164| \n00165| async function UserGreeting() {\n00166| const cookieStore = await cookies()\n00167| const theme = cookieStore.get('theme')?.value || 'light'\n00168| return
\n00175| Loading...}>\n00176| \n00177| \n00178| >\n00179| )\n00180| }\n00181| ```\n00182| \n00183| A runtime API access without `` surfaces the same **blocking-route** insight in the dev overlay, with the same fix:\n00184| \n00185| \n00186| ', highlight: true },\n00192| { text: ' ' },\n00193| { text: '', highlight: true },\n00194| ]}\n00195| />\n00196| \n00197| \n00198| ### Passing runtime values to cached functions\n00199| \n00200| You can extract values from runtime APIs and pass them as arguments to cached functions:\n00201| \n00202| ```tsx filename=\"app/profile/page.tsx\"\n00203| import { cookies } from 'next/headers'\n00204| import { Suspense } from 'react'\n00205| \n00206| export default function Page() {\n00207| return (\n00208| Loading...}>\n00209| \n00210| \n00211| )\n00212| }\n00213| \n00214| // Component (not cached) reads runtime data\n00215| async function ProfileContent() {\n00216| const session = (await cookies()).get('session')?.value\n00217| return \n00218| }\n00219| \n00220| // Cached component receives extracted value as a prop\n00221| async function CachedContent({ sessionId }: { sessionId: string }) {\n00222| 'use cache'\n00223| // sessionId becomes part of the cache key\n00224| const data = await fetchUserData(sessionId)\n00225| return
{data}
\n00226| }\n00227| ```\n00228| \n00229| At request time, `CachedContent` executes if no matching cache entry is found, and stores the result for future requests with the same `sessionId`.\n00230| \n00231| This pattern also unlocks [runtime prefetching](#runtime-prefetching): on a client transition, the framework can prerender `CachedContent` with the user's actual session and have the result ready before the click.\n00232| \n00233| By default, `use cache` stores entries [in-memory](/docs/app/api-reference/directives/use-cache#runtime-caching-considerations). In serverless environments where memory doesn't persist across requests, `CachedContent` may re-evaluate on every request. Consider [`'use cache: remote'`](/docs/app/api-reference/directives/use-cache-remote) for durable, shared caching.\n00234| \n00235| ## Static, cached, and streaming\n00236| \n00237| Here's a complete example showing static content, cached dynamic content, and streaming dynamic content working together on a single page:\n00238| \n00239| ```tsx filename=\"app/blog/page.tsx\"\n00240| import { Suspense } from 'react'\n00241| import { cookies } from 'next/headers'\n00242| import { cacheLife, cacheTag } from 'next/cache'\n00243| import Link from 'next/link'\n00244| \n00245| export default function BlogPage() {\n00246| return (\n00247| <>\n00248| {/* Static content - prerendered automatically */}\n00249| \n00250|
Our Blog
\n00251| \n00252| Home | About\n00253| \n00254| \n00255| \n00256| {/* Cached dynamic content - included in the static shell */}\n00257| \n00258| \n00259| {/* Runtime dynamic content - streams at request time */}\n00260| Loading your preferences...}>\n00261| \n00262| \n00263| >\n00264| )\n00265| }\n00266| \n00267| type Post = { id: string; title: string; author: string; date: string }\n00268| \n00269| // Everyone sees the same blog posts (revalidated every hour)\n00270| async function BlogPosts() {\n00271| 'use cache'\n00272| cacheLife('hours')\n00273| cacheTag('posts')\n00274| \n00275| const res = await fetch('https://api.vercel.app/blog')\n00276| const posts: Post[] = await res.json()\n00277| \n00278| return (\n00279| \n00280|
Latest Posts
\n00281|
\n00282| {posts.map((post) => (\n00283|
\n00284|
{post.title}
\n00285|
\n00286| By {post.author} on {post.date}\n00287|
\n00288|
\n00289| ))}\n00290|
\n00291| \n00292| )\n00293| }\n00294| \n00295| // UI that depends on a value stored in cookies\n00296| async function UserPreferences() {\n00297| const theme = (await cookies()).get('theme')?.value || 'light'\n00298| const favoriteCategory = (await cookies()).get('category')?.value\n00299| \n00300| return (\n00301| \n00305| )\n00306| }\n00307| ```\n00308| \n00309| During prerendering, the header (static) and blog posts (cached with `use cache`) become part of the static shell, along with the fallback UI for user preferences. The UI preferences stored in cookies stream in at request time.\n00310| \n00311| Reading `cookies()` here doesn't opt-in the whole route into dynamic rendering, the way the previous rendering model did. The Suspense boundary provides fallback UI where the runtime access streams, while static and cached content still ship in the initial HTML.\n00312| \n00313| Just as `` contains async access, an **error boundary** contains failures: wrap them around a subtree that might error during rendering. Use [`unstable_catchError`](/docs/app/api-reference/functions/catchError) for component-level boundaries, or the [`error.js`](/docs/app/api-reference/file-conventions/error) file convention for route-level boundaries.\n00314| \n00315| As you build, consider that inside [`generateMetadata`](/docs/app/api-reference/functions/generate-metadata#with-cache-components) and [`generateViewport`](/docs/app/api-reference/functions/generate-viewport#with-cache-components), uncached fetches or runtime data access surface the same insights and errors as in your page, guiding you to the rendering you intend. For incremental static regeneration with both known and unknown param values, see [ISR with Cache Components](/docs/app/guides/incremental-static-regeneration-cache-components).\n00316| \n00317| ## Random values and timestamps\n00318| \n00319| Operations like `Math.random()`, `Date.now()`, or `crypto.randomUUID()` produce different values each time they execute. Cache Components requires you to explicitly handle these.\n00320| \n00321| > **Good to know:** `performance.now()` is meant for telemetry. Pass the value to your logger or metrics rather than rendering it.\n00322| \n00323| **To generate unique values per request**, defer to request time by calling [`connection()`](/docs/app/api-reference/functions/connection) before these operations, and wrap the component in ``:\n00324| \n00325| ```tsx filename=\"page.tsx\"\n00326| import { connection } from 'next/server'\n00327| import { Suspense } from 'react'\n00328| \n00329| async function UniqueContent() {\n00330| await connection()\n00331| const uuid = crypto.randomUUID()\n00332| return
Request ID: {uuid}
\n00333| }\n00334| \n00335| export default function Page() {\n00336| return (\n00337| Loading...}>\n00338| \n00339| \n00340| )\n00341| }\n00342| ```\n00343| \n00344| Alternatively, you can **cache the result** so all users see the same value until revalidation:\n00345| \n00346| ```tsx filename=\"page.tsx\"\n00347| export default async function Page() {\n00348| 'use cache'\n00349| const buildId = crypto.randomUUID()\n00350| return
Build ID: {buildId}
\n00351| }\n00352| ```\n00353| \n00354| You don't need to memorize which operations behave this way. The dev overlay surfaces a **blocking-prerender-random**, **blocking-prerender-current-time**, or **blocking-prerender-crypto** insight (depending on the call) with these fixes:\n00355| \n00356| \n00357| ' },\n00365| ]}\n00366| />\n00367| \n00377| \n00378| \n00379| ## Synchronous I/O and pure computations\n00380| \n00381| Unlike random or time-based APIs, synchronous I/O, module imports, and pure computations are predictable: the same inputs produce the same outputs. Components using only these operations are prerendered automatically, and their output becomes part of the static HTML at build time.\n00382| \n00383| ```tsx filename=\"page.tsx\"\n00384| import fs from 'node:fs'\n00385| \n00386| export default async function Page() {\n00387| const constants = await import('./constants.json')\n00388| const content = fs.readFileSync('./config.json', 'utf-8')\n00389| const items = JSON.parse(content).items ?? []\n00390| \n00391| return (\n00392|
\n00393|
{constants.appName}
\n00394|
\n00395| {items.map((item) => (\n00396|
{item.value}
\n00397| ))}\n00398|
\n00399|
\n00400| )\n00401| }\n00402| ```\n00403| \n00404| > **Good to know:** This includes queries to embedded databases with synchronous APIs, such as `better-sqlite3` or Node.js's built-in [`node:sqlite`](https://nodejs.org/api/sqlite.html). If you need per-request data from a synchronous source, call [`connection()`](/docs/app/api-reference/functions/connection) before the query.\n00405| \n00406| ## Prerendering\n00407| \n00408| At build time, Next.js renders your route's component tree. How each component is handled depends on the APIs it uses:\n00409| \n00410| - [`use cache`](#usage): the result is cached and included in the static shell\n00411| - [``](#streaming-uncached-data): fallback UI is included in the static shell while the content streams at request time\n00412| - [Synchronous I/O and pure computations](#synchronous-io-and-pure-computations): module imports, `fs.readFileSync`, and pure computations complete during prerender and are included in the static shell automatically\n00413| - [Random values and timestamps](#random-values-and-timestamps): use `connection()` + `` to get a unique value per request, or `use cache` to share one across users\n00414| \n00415| This generates a static shell consisting of HTML for initial page loads and a serialized [RSC Payload](/docs/app/getting-started/server-and-client-components#on-the-server) for client-side navigation, ensuring the browser receives fully rendered content instantly whether users navigate directly to the URL or transition from another page. This rendering approach is called **Partial Prerendering (PPR)**, the default behavior with Cache Components.\n00416| \n00417| \n00424| \n00425| Every produced static shell can be served directly from a CDN, without going through to the upstream server. This makes direct navigations [instant](#instant-navigation).\n00426| \n00427| Next.js requires you to explicitly handle components that can't complete during prerendering. It surfaces a validation insight in the dev overlay and dev server console that names the route and points at fixes (cache the access, move it into a `` boundary, or opt the route out). This validation keeps every route producing a static shell, so direct navigations stay instant.\n00428| \n00429| \n00436| \n00437| > **🎥 Watch:** Why Partial Prerendering and how it works → [YouTube (10 minutes)](https://www.youtube.com/watch?v=MTcPrTIBkpA).\n00438| \n00439| ### Bots and crawlers\n00440| \n00441| Browsers receive the static shell instantly. Bots and crawlers are detected by their user agent and handled differently: because they need a complete document, Next.js skips the shell and renders the entire page dynamically at request time, then sends the finished HTML once the render completes.\n00442| \n00443| Because the shell is re-rendered instead of reused, work that completed during prerendering now runs at request time for a bot. If part of your shell depends on inputs that only exist while prerendering, such as build-time data or values that are not reachable in the request-time environment, a page that loads for a person can fail to render for a crawler. Make sure the data your shell relies on is also available at request time. See [Bots and crawlers](/docs/app/guides/streaming#bots-and-crawlers) for more details.\n00444| \n00445| ### Maximizing the static shell\n00446| \n00447| The deeper your async work sits in the tree, the more of the page can be prerendered. This is the structural pattern Cache Components rewards: a general practice worth applying everywhere, and the foundation for the instant navigation and runtime prefetching that follow. It applies to all [runtime APIs](#working-with-runtime-apis) and async operations like data fetches.\n00448| \n00449| Consider a layout that destructures `params` at the top level:\n00450| \n00451| ```tsx filename=\"app/shop/[slug]/layout.tsx\"\n00452| export default async function Layout({\n00453| children,\n00454| params,\n00455| }: LayoutProps<'/shop/[slug]'>) {\n00456| const { slug } = await params\n00457| \n00458| return (\n00459|
\n00460| \n00461|
{slug}
\n00462| {children}\n00463|
\n00464| )\n00465| }\n00466| ```\n00467| \n00468| If this param is dynamic (not provided by [`generateStaticParams`](/docs/app/api-reference/functions/generate-static-params)), it is runtime data and the layout cannot be prerendered.\n00469| \n00470| However, it is often possible to read the parameter value further down the tree. Instead of awaiting at the layout level, pass the params promise down and await there:\n00471| \n00472| ```tsx filename=\"app/shop/[slug]/layout.tsx\" highlight={3,10-13}\n00473| import { Suspense } from 'react'\n00474| \n00475| export default function Layout({\n00476| children,\n00477| params,\n00478| }: LayoutProps<'/shop/[slug]'>) {\n00479| return (\n00480|
\n00494| }\n00495| ```\n00496| \n00497| Now ``, `{children}`, and the Suspense fallback are all part of the static shell. Only `SlugHeading` streams in at request time. You can also pass the entire `params` promise and await it in the child component.\n00498| \n00499| The same principle applies to `cookies()`, `headers()`, `searchParams`, and data fetches. See [Sharing data with context and `React.cache`](/docs/app/getting-started/fetching-data#sharing-data-with-context-and-reactcache) for a related pattern.\n00500| \n00501| ### Instant navigation\n00502| \n00503| Cache Components shipped in 16.0.0 with verification that direct visits to a route produce a static shell. Client navigations are different: a `` boundary that covers a direct visit may not be part of the render during a transition. Getting that structure right is easier when the framework steps in. Cache Components now validates these navigations too, giving you insights and errors that guide you to make navigations to your route instant. For example, wrap data in ``, cache it with `use cache`, or move where the access happens.\n00504| \n00505| Read the [Instant navigation guide](/docs/app/guides/instant-navigation) for examples and inspection tools.\n00506| \n00507| ### Runtime prefetching\n00508| \n00509| With [`prefetch = 'allow-runtime'`](/docs/app/api-reference/file-conventions/route-segment-config/prefetch) on a route, Next.js renders that route's component tree again at prefetch time, this time with the user's cookies, headers, and full URL available. The same rules apply, but more of the tree resolves now that runtime data is in scope:\n00510| \n00511| - [`use cache`](#usage) called with values extracted from runtime APIs (passed as arguments) joins the runtime prerender\n00512| - [`use cache: private`](/docs/app/api-reference/directives/use-cache-private) executes on the server, reads runtime data directly, and caches the result in the browser, joining the runtime prerender\n00513| - [``](#streaming-uncached-data) fallbacks stay in the runtime prerender while uncached content streams at request time\n00514| \n00515| This generates a **runtime prerender** that extends past the static shell with content the user's request unlocks. Because it happens during the prefetch, the navigation has nothing to wait on. The cost is a server invocation per prefetchable link.\n00516| \n00517| For example, take a dashboard that reads the user's session cookie and opts into runtime prefetching:\n00518| \n00519| ```tsx filename=\"app/dashboard/page.tsx\"\n00520| import { cookies } from 'next/headers'\n00521| import { Suspense } from 'react'\n00522| \n00523| export const prefetch = 'allow-runtime'\n00524| \n00525| export default function Dashboard() {\n00526| return (\n00527| Loading...}>\n00528| \n00529| \n00530| )\n00531| }\n00532| \n00533| async function Stats() {\n00534| const session = (await cookies()).get('session')?.value\n00535| if (!session) return
\n00538| }\n00539| \n00540| async function getStats(session: string) {\n00541| 'use cache'\n00542| return db.users.getStats(session)\n00543| }\n00544| ```\n00545| \n00546| On a direct visit, `` streams in behind the fallback. When a user navigates to `/dashboard` from another route, the framework prefetches with their session cookie. `getStats` is cached, so its result joins the runtime prerender before the click.\n00547| \n00548| See the [Runtime prefetching guide](/docs/app/guides/runtime-prefetching) for full patterns and the [`prefetch` reference](/docs/app/api-reference/file-conventions/route-segment-config/prefetch) for all modes.\n00549| \n00550| {/* I wonder if we need a small section that develops ISR briefly and links to the ISR w/ CC guide */}\n00551| \n\n(End of file - total 551 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/01-getting-started/08-caching.md"
+ },
+ "output": "\n00001| ---\n00002| title: Caching\n00003| description: Learn how to cache data and UI in Next.js\n00004| related:\n00005| title: Next Steps\n00006| description: Learn more about revalidation and the APIs mentioned on this page.\n00007| links:\n00008| - app/getting-started/revalidating\n00009| - app/api-reference/directives/use-cache\n00010| - app/api-reference/config/next-config-js/cacheComponents\n00011| - app/guides/instant-navigation\n00012| ---\n00013| \n00014| > This page covers caching with [Cache Components](/docs/app/api-reference/config/next-config-js/cacheComponents), enabled by setting [`cacheComponents: true`](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.ts` file. If you're not using Cache Components, see the [Caching and Revalidating (Previous Model)](/docs/app/guides/caching-without-cache-components) guide.\n00015| \n00016| Caching is a technique for storing the result of data fetching and other computations so that future requests for the same data can be served faster, without doing the work again.\n00017| \n00018| ## Enabling Cache Components\n00019| \n00020| You can enable Cache Components by adding the [`cacheComponents`](/docs/app/api-reference/config/next-config-js/cacheComponents) option to your Next config file:\n00021| \n00022| ```ts filename=\"next.config.ts\" switcher\n00023| import type { NextConfig } from 'next'\n00024| \n00025| const nextConfig: NextConfig = {\n00026| cacheComponents: true,\n00027| }\n00028| \n00029| export default nextConfig\n00030| ```\n00031| \n00032| ```js filename=\"next.config.js\" switcher\n00033| /** @type {import('next').NextConfig} */\n00034| const nextConfig = {\n00035| cacheComponents: true,\n00036| }\n00037| \n00038| module.exports = nextConfig\n00039| ```\n00040| \n00041| > **Good to know:** When Cache Components is enabled, `GET` Route Handlers follow the same prerendering model as pages. See [Route Handlers with Cache Components](/docs/app/getting-started/route-handlers#with-cache-components) for details.\n00042| \n00043| ## Usage\n00044| \n00045| The [`use cache`](/docs/app/api-reference/directives/use-cache) directive caches the return value of async functions and components. You can apply it at two levels:\n00046| \n00047| - **Data-level**: Cache a function that fetches or computes data (e.g., `getProducts()`, `getUser(id)`)\n00048| - **UI-level**: Cache an entire component or page (e.g., `async function BlogPosts()`)\n00049| \n00050| Two variants cover specific scenarios: [`\"use cache: remote\"`](/docs/app/api-reference/directives/use-cache-remote) for durable, shared remote storage, and [`\"use cache: private\"`](/docs/app/api-reference/directives/use-cache-private) for caching functions that read runtime data.\n00051| \n00052| > Arguments and any closed-over values from parent scopes automatically become part of the [cache key](/docs/app/api-reference/directives/use-cache#cache-keys), which means different inputs will produce separate cache entries. This enables personalized or parameterized cached content. See [serialization requirements and constraints](/docs/app/api-reference/directives/use-cache#constraints) for details on what can be cached and how arguments work.\n00053| \n00054| ### Data-level caching\n00055| \n00056| To cache an asynchronous function that fetches data, add the `use cache` directive at the top of the function body:\n00057| \n00058| ```tsx filename=\"app/lib/data.ts\" highlight={3,4,5}\n00059| import { cacheLife } from 'next/cache'\n00060| \n00061| export async function getUsers() {\n00062| 'use cache'\n00063| cacheLife('hours')\n00064| return db.query('SELECT * FROM users')\n00065| }\n00066| ```\n00067| \n00068| Data-level caching is useful when the same data is used across multiple components, or when you want to cache the data independently from the UI.\n00069| \n00070| ### UI-level caching\n00071| \n00072| To cache an entire component, page, or layout, add the `use cache` directive at the top of the component or page body:\n00073| \n00074| ```tsx filename=\"app/page.tsx\" highlight={1,4,5}\n00075| import { cacheLife } from 'next/cache'\n00076| \n00077| export default async function Page() {\n00078| 'use cache'\n00079| cacheLife('hours')\n00080| \n00081| const users = await db.query('SELECT * FROM users')\n00082| \n00083| return (\n00084|
\n00085| {users.map((user) => (\n00086|
{user.name}
\n00087| ))}\n00088|
\n00089| )\n00090| }\n00091| ```\n00092| \n00093| > If you add \"`use cache`\" at the top of a file, all exported functions in the file will be cached.\n00094| \n00095| ### Streaming uncached data\n00096| \n00097| For components that fetch data from an asynchronous source such as an API, a database, or any other async operation, and require fresh data on every request, do not use `\"use cache\"`.\n00098| \n00099| Instead, wrap the component in [``](https://react.dev/reference/react/Suspense) and provide a fallback UI. The fallback ships with the prerendered shell while the async work runs at request time.\n00100| \n00101| ```tsx filename=\"page.tsx\"\n00102| import { Suspense } from 'react'\n00103| \n00104| async function LatestPosts() {\n00105| const data = await fetch('https://api.example.com/posts')\n00106| const posts = await data.json()\n00107| return (\n00108|
\n00120| Loading posts...}>\n00121| \n00122| \n00123| >\n00124| )\n00125| }\n00126| ```\n00127| \n00128| For example, `
Loading posts...
` is included in the static shell, and the posts stream in at request time.\n00129| \n00130| Without a `` boundary around the uncached read, the dev overlay surfaces the **blocking-route** insight with this fix:\n00131| \n00132| \n00133| ', highlight: true },\n00139| { text: ' ' },\n00140| { text: '', highlight: true },\n00141| ]}\n00142| />\n00143| \n00144| \n00145| > **Good to know:** Each fix card links to a detailed walkthrough with patterns, code samples, and trade-offs. Click a card to dive in.\n00146| \n00147| {/* xref to the sync io section - that section should also emphaize that these are not random or timestamp sync invokations, in the referenced section */}\n00148| `` provides a fallback UI while async work completes, but it does not itself opt a component into dynamic rendering. If a component only performs synchronous work, it will complete during prerendering regardless of whether it is wrapped in ``.\n00149| \n00150| ## Working with runtime APIs\n00151| \n00152| Runtime APIs require information that is only available when a user makes a request. These include:\n00153| \n00154| - [`cookies`](/docs/app/api-reference/functions/cookies) - User's cookie data\n00155| - [`headers`](/docs/app/api-reference/functions/headers) - Request headers\n00156| - [`searchParams`](/docs/app/api-reference/file-conventions/page#searchparams-optional) - URL query parameters\n00157| - [`params`](/docs/app/api-reference/file-conventions/page#params-optional) - Dynamic route parameters. Use [`generateStaticParams`](/docs/app/api-reference/functions/generate-static-params) to prerender specific values at build time, or [ISR with Cache Components](/docs/app/guides/incremental-static-regeneration-cache-components) to serve an App Shell while unknown params resolve in the background.\n00158| \n00159| Components that access runtime APIs should be wrapped in ``:\n00160| \n00161| ```tsx filename=\"page.tsx\"\n00162| import { cookies } from 'next/headers'\n00163| import { Suspense } from 'react'\n00164| \n00165| async function UserGreeting() {\n00166| const cookieStore = await cookies()\n00167| const theme = cookieStore.get('theme')?.value || 'light'\n00168| return
\n00175| Loading...}>\n00176| \n00177| \n00178| >\n00179| )\n00180| }\n00181| ```\n00182| \n00183| A runtime API access without `` surfaces the same **blocking-route** insight in the dev overlay, with the same fix:\n00184| \n00185| \n00186| ', highlight: true },\n00192| { text: ' ' },\n00193| { text: '', highlight: true },\n00194| ]}\n00195| />\n00196| \n00197| \n00198| ### Passing runtime values to cached functions\n00199| \n00200| You can extract values from runtime APIs and pass them as arguments to cached functions:\n00201| \n00202| ```tsx filename=\"app/profile/page.tsx\"\n00203| import { cookies } from 'next/headers'\n00204| import { Suspense } from 'react'\n00205| \n00206| export default function Page() {\n00207| return (\n00208| Loading...}>\n00209| \n00210| \n00211| )\n00212| }\n00213| \n00214| // Component (not cached) reads runtime data\n00215| async function ProfileContent() {\n00216| const session = (await cookies()).get('session')?.value\n00217| return \n00218| }\n00219| \n00220| // Cached component receives extracted value as a prop\n00221| async function CachedContent({ sessionId }: { sessionId: string }) {\n00222| 'use cache'\n00223| // sessionId becomes part of the cache key\n00224| const data = await fetchUserData(sessionId)\n00225| return
{data}
\n00226| }\n00227| ```\n00228| \n00229| At request time, `CachedContent` executes if no matching cache entry is found, and stores the result for future requests with the same `sessionId`.\n00230| \n00231| This pattern also unlocks [runtime prefetching](#runtime-prefetching): on a client transition, the framework can prerender `CachedContent` with the user's actual session and have the result ready before the click.\n00232| \n00233| By default, `use cache` stores entries [in-memory](/docs/app/api-reference/directives/use-cache#runtime-caching-considerations). In serverless environments where memory doesn't persist across requests, `CachedContent` may re-evaluate on every request. Consider [`'use cache: remote'`](/docs/app/api-reference/directives/use-cache-remote) for durable, shared caching.\n00234| \n00235| ## Static, cached, and streaming\n00236| \n00237| Here's a complete example showing static content, cached dynamic content, and streaming dynamic content working together on a single page:\n00238| \n00239| ```tsx filename=\"app/blog/page.tsx\"\n00240| import { Suspense } from 'react'\n00241| import { cookies } from 'next/headers'\n00242| import { cacheLife, cacheTag } from 'next/cache'\n00243| import Link from 'next/link'\n00244| \n00245| export default function BlogPage() {\n00246| return (\n00247| <>\n00248| {/* Static content - prerendered automatically */}\n00249| \n00250|
Our Blog
\n00251| \n00252| Home | About\n00253| \n00254| \n00255| \n00256| {/* Cached dynamic content - included in the static shell */}\n00257| \n00258| \n00259| {/* Runtime dynamic content - streams at request time */}\n00260| Loading your preferences...}>\n00261| \n00262| \n00263| >\n00264| )\n00265| }\n00266| \n00267| type Post = { id: string; title: string; author: string; date: string }\n00268| \n00269| // Everyone sees the same blog posts (revalidated every hour)\n00270| async function BlogPosts() {\n00271| 'use cache'\n00272| cacheLife('hours')\n00273| cacheTag('posts')\n00274| \n00275| const res = await fetch('https://api.vercel.app/blog')\n00276| const posts: Post[] = await res.json()\n00277| \n00278| return (\n00279| \n00280|
Latest Posts
\n00281|
\n00282| {posts.map((post) => (\n00283|
\n00284|
{post.title}
\n00285|
\n00286| By {post.author} on {post.date}\n00287|
\n00288|
\n00289| ))}\n00290|
\n00291| \n00292| )\n00293| }\n00294| \n00295| // UI that depends on a value stored in cookies\n00296| async function UserPreferences() {\n00297| const theme = (await cookies()).get('theme')?.value || 'light'\n00298| const favoriteCategory = (await cookies()).get('category')?.value\n00299| \n00300| return (\n00301| \n00305| )\n00306| }\n00307| ```\n00308| \n00309| During prerendering, the header (static) and blog posts (cached with `use cache`) become part of the static shell, along with the fallback UI for user preferences. The UI preferences stored in cookies stream in at request time.\n00310| \n00311| Reading `cookies()` here doesn't opt-in the whole route into dynamic rendering, the way the previous rendering model did. The Suspense boundary provides fallback UI where the runtime access streams, while static and cached content still ship in the initial HTML.\n00312| \n00313| Just as `` contains async access, an **error boundary** contains failures: wrap them around a subtree that might error during rendering. Use [`unstable_catchError`](/docs/app/api-reference/functions/catchError) for component-level boundaries, or the [`error.js`](/docs/app/api-reference/file-conventions/error) file convention for route-level boundaries.\n00314| \n00315| As you build, consider that inside [`generateMetadata`](/docs/app/api-reference/functions/generate-metadata#with-cache-components) and [`generateViewport`](/docs/app/api-reference/functions/generate-viewport#with-cache-components), uncached fetches or runtime data access surface the same insights and errors as in your page, guiding you to the rendering you intend. For incremental static regeneration with both known and unknown param values, see [ISR with Cache Components](/docs/app/guides/incremental-static-regeneration-cache-components).\n00316| \n00317| ## Random values and timestamps\n00318| \n00319| Operations like `Math.random()`, `Date.now()`, or `crypto.randomUUID()` produce different values each time they execute. Cache Components requires you to explicitly handle these.\n00320| \n00321| > **Good to know:** `performance.now()` is meant for telemetry. Pass the value to your logger or metrics rather than rendering it.\n00322| \n00323| **To generate unique values per request**, defer to request time by calling [`connection()`](/docs/app/api-reference/functions/connection) before these operations, and wrap the component in ``:\n00324| \n00325| ```tsx filename=\"page.tsx\"\n00326| import { connection } from 'next/server'\n00327| import { Suspense } from 'react'\n00328| \n00329| async function UniqueContent() {\n00330| await connection()\n00331| const uuid = crypto.randomUUID()\n00332| return
Request ID: {uuid}
\n00333| }\n00334| \n00335| export default function Page() {\n00336| return (\n00337| Loading...}>\n00338| \n00339| \n00340| )\n00341| }\n00342| ```\n00343| \n00344| Alternatively, you can **cache the result** so all users see the same value until revalidation:\n00345| \n00346| ```tsx filename=\"page.tsx\"\n00347| export default async function Page() {\n00348| 'use cache'\n00349| const buildId = crypto.randomUUID()\n00350| return
Build ID: {buildId}
\n00351| }\n00352| ```\n00353| \n00354| You don't need to memorize which operations behave this way. The dev overlay surfaces a **blocking-prerender-random**, **blocking-prerender-current-time**, or **blocking-prerender-crypto** insight (depending on the call) with these fixes:\n00355| \n00356| \n00357| ' },\n00365| ]}\n00366| />\n00367| \n00377| \n00378| \n00379| ## Synchronous I/O and pure computations\n00380| \n00381| Unlike random or time-based APIs, synchronous I/O, module imports, and pure computations are predictable: the same inputs produce the same outputs. Components using only these operations are prerendered automatically, and their output becomes part of the static HTML at build time.\n00382| \n00383| ```tsx filename=\"page.tsx\"\n00384| import fs from 'node:fs'\n00385| \n00386| export default async function Page() {\n00387| const constants = await import('./constants.json')\n00388| const content = fs.readFileSync('./config.json', 'utf-8')\n00389| const items = JSON.parse(content).items ?? []\n00390| \n00391| return (\n00392|
\n00393|
{constants.appName}
\n00394|
\n00395| {items.map((item) => (\n00396|
{item.value}
\n00397| ))}\n00398|
\n00399|
\n00400| )\n00401| }\n00402| ```\n00403| \n00404| > **Good to know:** This includes queries to embedded databases with synchronous APIs, such as `better-sqlite3` or Node.js's built-in [`node:sqlite`](https://nodejs.org/api/sqlite.html). If you need per-request data from a synchronous source, call [`connection()`](/docs/app/api-reference/functions/connection) before the query.\n00405| \n00406| ## Prerendering\n00407| \n00408| At build time, Next.js renders your route's component tree. How each component is handled depends on the APIs it uses:\n00409| \n00410| - [`use cache`](#usage): the result is cached and included in the static shell\n00411| - [``](#streaming-uncached-data): fallback UI is included in the static shell while the content streams at request time\n00412| - [Synchronous I/O and pure computations](#synchronous-io-and-pure-computations): module imports, `fs.readFileSync`, and pure computations complete during prerender and are included in the static shell automatically\n00413| - [Random values and timestamps](#random-values-and-timestamps): use `connection()` + `` to get a unique value per request, or `use cache` to share one across users\n00414| \n00415| This generates a static shell consisting of HTML for initial page loads and a serialized [RSC Payload](/docs/app/getting-started/server-and-client-components#on-the-server) for client-side navigation, ensuring the browser receives fully rendered content instantly whether users navigate directly to the URL or transition from another page. This rendering approach is called **Partial Prerendering (PPR)**, the default behavior with Cache Components.\n00416| \n00417| \n00424| \n00425| Every produced static shell can be served directly from a CDN, without going through to the upstream server. This makes direct navigations [instant](#instant-navigation).\n00426| \n00427| Next.js requires you to explicitly handle components that can't complete during prerendering. It surfaces a validation insight in the dev overlay and dev server console that names the route and points at fixes (cache the access, move it into a `` boundary, or opt the route out). This validation keeps every route producing a static shell, so direct navigations stay instant.\n00428| \n00429| \n00436| \n00437| > **🎥 Watch:** Why Partial Prerendering and how it works → [YouTube (10 minutes)](https://www.youtube.com/watch?v=MTcPrTIBkpA).\n00438| \n00439| ### Bots and crawlers\n00440| \n00441| Browsers receive the static shell instantly. Bots and crawlers are detected by their user agent and handled differently: because they need a complete document, Next.js skips the shell and renders the entire page dynamically at request time, then sends the finished HTML once the render completes.\n00442| \n00443| Because the shell is re-rendered instead of reused, work that completed during prerendering now runs at request time for a bot. If part of your shell depends on inputs that only exist while prerendering, such as build-time data or values that are not reachable in the request-time environment, a page that loads for a person can fail to render for a crawler. Make sure the data your shell relies on is also available at request time. See [Bots and crawlers](/docs/app/guides/streaming#bots-and-crawlers) for more details.\n00444| \n00445| ### Maximizing the static shell\n00446| \n00447| The deeper your async work sits in the tree, the more of the page can be prerendered. This is the structural pattern Cache Components rewards: a general practice worth applying everywhere, and the foundation for the instant navigation and runtime prefetching that follow. It applies to all [runtime APIs](#working-with-runtime-apis) and async operations like data fetches.\n00448| \n00449| Consider a layout that destructures `params` at the top level:\n00450| \n00451| ```tsx filename=\"app/shop/[slug]/layout.tsx\"\n00452| export default async function Layout({\n00453| children,\n00454| params,\n00455| }: LayoutProps<'/shop/[slug]'>) {\n00456| const { slug } = await params\n00457| \n00458| return (\n00459|
\n00460| \n00461|
{slug}
\n00462| {children}\n00463|
\n00464| )\n00465| }\n00466| ```\n00467| \n00468| If this param is dynamic (not provided by [`generateStaticParams`](/docs/app/api-reference/functions/generate-static-params)), it is runtime data and the layout cannot be prerendered.\n00469| \n00470| However, it is often possible to read the parameter value further down the tree. Instead of awaiting at the layout level, pass the params promise down and await there:\n00471| \n00472| ```tsx filename=\"app/shop/[slug]/layout.tsx\" highlight={3,10-13}\n00473| import { Suspense } from 'react'\n00474| \n00475| export default function Layout({\n00476| children,\n00477| params,\n00478| }: LayoutProps<'/shop/[slug]'>) {\n00479| return (\n00480|
\n00494| }\n00495| ```\n00496| \n00497| Now ``, `{children}`, and the Suspense fallback are all part of the static shell. Only `SlugHeading` streams in at request time. You can also pass the entire `params` promise and await it in the child component.\n00498| \n00499| The same principle applies to `cookies()`, `headers()`, `searchParams`, and data fetches. See [Sharing data with context and `React.cache`](/docs/app/getting-started/fetching-data#sharing-data-with-context-and-reactcache) for a related pattern.\n00500| \n00501| ### Instant navigation\n00502| \n00503| Cache Components shipped in 16.0.0 with verification that direct visits to a route produce a static shell. Client navigations are different: a `` boundary that covers a direct visit may not be part of the render during a transition. Getting that structure right is easier when the framework steps in. Cache Components now validates these navigations too, giving you insights and errors that guide you to make navigations to your route instant. For example, wrap data in ``, cache it with `use cache`, or move where the access happens.\n00504| \n00505| Read the [Instant navigation guide](/docs/app/guides/instant-navigation) for examples and inspection tools.\n00506| \n00507| ### Runtime prefetching\n00508| \n00509| With [`prefetch = 'allow-runtime'`](/docs/app/api-reference/file-conventions/route-segment-config/prefetch) on a route, Next.js renders that route's component tree again at prefetch time, this time with the user's cookies, headers, and full URL available. The same rules apply, but more of the tree resolves now that runtime data is in scope:\n00510| \n00511| - [`use cache`](#usage) called with values extracted from runtime APIs (passed as arguments) joins the runtime prerender\n00512| - [`use cache: private`](/docs/app/api-reference/directives/use-cache-private) executes on the server, reads runtime data directly, and caches the result in the browser, joining the runtime prerender\n00513| - [``](#streaming-uncached-data) fallbacks stay in the runtime prerender while uncached content streams at request time\n00514| \n00515| This generates a **runtime prerender** that extends past the static shell with content the user's request unlocks. Because it happens during the prefetch, the navigation has nothing to wait on. The cost is a server invocation per prefetchable link.\n00516| \n00517| For example, take a dashboard that reads the user's session cookie and opts into runtime prefetching:\n00518| \n00519| ```tsx filename=\"app/dashboard/page.tsx\"\n00520| import { cookies } from 'next/headers'\n00521| import { Suspense } from 'react'\n00522| \n00523| export const prefetch = 'allow-runtime'\n00524| \n00525| export default function Dashboard() {\n00526| return (\n00527| Loading...}>\n00528| \n00529| \n00530| )\n00531| }\n00532| \n00533| async function Stats() {\n00534| const session = (await cookies()).get('session')?.value\n00535| if (!session) return
\n00538| }\n00539| \n00540| async function getStats(session: string) {\n00541| 'use cache'\n00542| return db.users.getStats(session)\n00543| }\n00544| ```\n00545| \n00546| On a direct visit, `` streams in behind the fallback. When a user navigates to `/dashboard` from another route, the framework prefetches with their session cookie. `getStats` is cached, so its result joins the runtime prerender before the click.\n00547| \n00548| See the [Runtime prefetching guide](/docs/app/guides/runtime-prefetching) for full patterns and the [`prefetch` reference](/docs/app/api-reference/file-conventions/route-segment-config/prefetch) for all modes.\n00549| \n00550| {/* I wonder if we need a small section that develops ISR briefly and links to the ISR w/ CC guide */}\n00551| \n\n(End of file - total 551 lines)\n",
+ "title": "node_modules/next/dist/docs/01-app/01-getting-started/08-caching.md",
+ "metadata": {
+ "preview": "---\ntitle: Caching\ndescription: Learn how to cache data and UI in Next.js\nrelated:\n title: Next Steps\n description: Learn more about revalidation and the APIs mentioned on this page.\n links:\n - app/getting-started/revalidating\n - app/api-reference/directives/use-cache\n - app/api-reference/config/next-config-js/cacheComponents\n - app/guides/instant-navigation\n---\n\n> This page covers caching with [Cache Components](/docs/app/api-reference/config/next-config-js/cacheComponents), enabled by setting [`cacheComponents: true`](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.ts` file. If you're not using Cache Components, see the [Caching and Revalidating (Previous Model)](/docs/app/guides/caching-without-cache-components) guide.\n\nCaching is a technique for storing the result of data fetching and other computations so that future requests for the same data can be served faster, without doing the work again.\n\n## Enabling Cache Components\n\nYou can enable Cache Components by adding the [`cacheComponents`](/docs/app/api-reference/config/next-config-js/cacheComponents) option to your Next config file:"
+ },
+ "time": {
+ "start": 1781392515771,
+ "end": 1781392515774
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:15.868Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "args": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/01-getting-started/05-server-and-client-components.md",
+ "_extractedPath": "/workspace/node_modules/next/dist/docs/01-app/01-getting-started/05-server-and-client-components.md"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392515868,
+ "sessionID": "ses_13cbb9c4fffe5TDZ1DwM35w4Zl",
+ "part": {
+ "id": "prt_ec344a2bd001jMKNYK3XwsRVwj",
+ "sessionID": "ses_13cbb9c4fffe5TDZ1DwM35w4Zl",
+ "messageID": "msg_ec34490c9001zc1GxYz6EOzVOq",
+ "type": "tool",
+ "callID": "read_9",
+ "tool": "read",
+ "state": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/01-getting-started/05-server-and-client-components.md"
+ },
+ "output": "\n00001| ---\n00002| title: Server and Client Components\n00003| description: Learn how you can use React Server and Client Components to render parts of your application on the server or the client.\n00004| related:\n00005| title: Next Steps\n00006| description: Learn more about the APIs mentioned in this page.\n00007| links:\n00008| - app/api-reference/directives/use-client\n00009| ---\n00010| \n00011| By default, layouts and pages are [Server Components](https://react.dev/reference/rsc/server-components), which lets you fetch data and render parts of your UI on the server, optionally cache the result, and stream it to the client. When you need interactivity or browser APIs, you can use [Client Components](https://react.dev/reference/rsc/use-client) to layer in functionality.\n00012| \n00013| This page explains how Server and Client Components work in Next.js and when to use them, with examples of how to compose them together in your application.\n00014| \n00015| ## When to use Server and Client Components?\n00016| \n00017| The client and server environments have different capabilities. Server and Client components allow you to run logic in each environment depending on your use case.\n00018| \n00019| Use **Client Components** when you need:\n00020| \n00021| - [State](https://react.dev/learn/managing-state) and [event handlers](https://react.dev/learn/responding-to-events). E.g. `onClick`, `onChange`.\n00022| - [Lifecycle logic](https://react.dev/learn/lifecycle-of-reactive-effects). E.g. `useEffect`.\n00023| - Browser-only APIs. E.g. `localStorage`, `window`, `Navigator.geolocation`, etc.\n00024| - [Custom hooks](https://react.dev/learn/reusing-logic-with-custom-hooks).\n00025| \n00026| Use **Server Components** when you need:\n00027| \n00028| - Fetch data from databases or APIs close to the source.\n00029| - Use API keys, tokens, and other secrets without exposing them to the client.\n00030| - Reduce the amount of JavaScript sent to the browser.\n00031| - Improve the [First Contentful Paint (FCP)](https://web.dev/fcp/), and stream content progressively to the client.\n00032| \n00033| For example, the `` component is a Server Component that fetches data about a post, and passes it as props to the `` which handles client-side interactivity.\n00034| \n00035| ```tsx filename=\"app/[id]/page.tsx\" highlight={1,17} switcher\n00036| import LikeButton from '@/app/ui/like-button'\n00037| import { getPost } from '@/lib/data'\n00038| \n00039| export default async function Page({\n00040| params,\n00041| }: {\n00042| params: Promise<{ id: string }>\n00043| }) {\n00044| const { id } = await params\n00045| const post = await getPost(id)\n00046| \n00047| return (\n00048|
\n00049| \n00050|
{post.title}
\n00051| {/* ... */}\n00052| \n00053| \n00054|
\n00055| )\n00056| }\n00057| ```\n00058| \n00059| ```jsx filename=\"app/[id]/page.js\" highlight={1,12} switcher\n00060| import LikeButton from '@/app/ui/like-button'\n00061| import { getPost } from '@/lib/data'\n00062| \n00063| export default async function Page({ params }) {\n00064| const post = await getPost(params.id)\n00065| \n00066| return (\n00067|
\n00068| \n00069|
{post.title}
\n00070| {/* ... */}\n00071| \n00072| \n00073|
\n00074| )\n00075| }\n00076| ```\n00077| \n00078| ```tsx filename=\"app/ui/like-button.tsx\" highlight={1} switcher\n00079| 'use client'\n00080| \n00081| import { useState } from 'react'\n00082| \n00083| export default function LikeButton({ likes }: { likes: number }) {\n00084| // ...\n00085| }\n00086| ```\n00087| \n00088| ```jsx filename=\"app/ui/like-button.js\" highlight={1} switcher\n00089| 'use client'\n00090| \n00091| import { useState } from 'react'\n00092| \n00093| export default function LikeButton({ likes }) {\n00094| // ...\n00095| }\n00096| ```\n00097| \n00098| ## How do Server and Client Components work in Next.js?\n00099| \n00100| ### On the server\n00101| \n00102| On the server, Next.js uses React's APIs to orchestrate rendering. The rendering work is split into chunks, by individual route segments ([layouts and pages](/docs/app/getting-started/layouts-and-pages)):\n00103| \n00104| - **Server Components** are rendered into a special data format called the React Server Component Payload (RSC Payload).\n00105| - **Client Components** and the RSC Payload are used to [prerender](/docs/app/glossary#prerendering) HTML.\n00106| \n00107| > **What is the React Server Component Payload (RSC)?**\n00108| >\n00109| > The RSC Payload is a compact binary representation of the rendered React Server Components tree. It's used by React on the client to update the browser's DOM. The RSC Payload contains:\n00110| >\n00111| > - The rendered result of Server Components\n00112| > - Placeholders for where Client Components should be rendered and references to their JavaScript files\n00113| > - Any props passed from a Server Component to a Client Component\n00114| \n00115| ### On the client (first load)\n00116| \n00117| Then, on the client:\n00118| \n00119| 1. **HTML** is used to immediately show a fast non-interactive preview of the route to the user.\n00120| 2. **RSC Payload** is used to reconcile the Client and Server Component trees.\n00121| 3. **JavaScript** is used to hydrate Client Components and make the application interactive.\n00122| \n00123| > **What is hydration?**\n00124| >\n00125| > Hydration is React's process for attaching [event handlers](https://react.dev/learn/responding-to-events) to the DOM, to make the static HTML interactive.\n00126| \n00127| ### Subsequent Navigations\n00128| \n00129| On subsequent navigations:\n00130| \n00131| - The **RSC Payload** is prefetched and cached for instant navigation.\n00132| - **Client Components** are rendered entirely on the client, without the server-rendered HTML.\n00133| \n00134| ## Examples\n00135| \n00136| ### Using Client Components\n00137| \n00138| You can create a Client Component by adding the [`\"use client\"`](https://react.dev/reference/react/use-client) directive at the top of the file, above your imports.\n00139| \n00140| ```tsx filename=\"app/ui/counter.tsx\" highlight={1} switcher\n00141| 'use client'\n00142| \n00143| import { useState } from 'react'\n00144| \n00145| export default function Counter() {\n00146| const [count, setCount] = useState(0)\n00147| \n00148| return (\n00149|
\n00170| )\n00171| }\n00172| ```\n00173| \n00174| `\"use client\"` is used to declare a **boundary** between the Server and Client module graphs (trees).\n00175| \n00176| Once a file is marked with `\"use client\"`, **all of its imports and the components it directly renders are included in the client bundle**. This means you don’t need to add the directive to every component that is intended for the client.\n00177| \n00178| This behavior applies to components that are part of the Client Component’s [module graph](/docs/app/glossary#module-graph), which includes the modules it imports and the components it renders directly. It does not apply to Server Components passed as children or other props. Those components are not imported into the Client Component’s module graph. They are rendered on the server and passed to the Client Component as rendered output.\n00179| \n00180| See [Interleaving Server and Client Components](/docs/app/getting-started/server-and-client-components#interleaving-server-and-client-components) for how Server and Client Components can be combined.\n00181| \n00182| ### Reducing JS bundle size\n00183| \n00184| To reduce the size of your client JavaScript bundles, add `'use client'` to specific interactive components instead of marking large parts of your UI as Client Components.\n00185| \n00186| For example, the `` component contains mostly static elements like a logo and navigation links, but includes an interactive search bar. `` is interactive and needs to be a Client Component, however, the rest of the layout can remain a Server Component.\n00187| \n00188| ```tsx filename=\"app/layout.tsx\" highlight={12} switcher\n00189| // Client Component\n00190| import Search from './search'\n00191| // Server Component\n00192| import Logo from './logo'\n00193| \n00194| // Layout is a Server Component by default\n00195| export default function Layout({ children }: { children: React.ReactNode }) {\n00196| return (\n00197| <>\n00198| \n00199| \n00200| \n00201| \n00202| {children}\n00203| >\n00204| )\n00205| }\n00206| ```\n00207| \n00208| ```jsx filename=\"app/layout.js\" highlight={12} switcher\n00209| // Client Component\n00210| import Search from './search'\n00211| // Server Component\n00212| import Logo from './logo'\n00213| \n00214| // Layout is a Server Component by default\n00215| export default function Layout({ children }) {\n00216| return (\n00217| <>\n00218| \n00219| \n00220| \n00221| \n00222| {children}\n00223| >\n00224| )\n00225| }\n00226| ```\n00227| \n00228| ```tsx filename=\"app/ui/search.tsx\" highlight={1} switcher\n00229| 'use client'\n00230| \n00231| export default function Search() {\n00232| // ...\n00233| }\n00234| ```\n00235| \n00236| ```jsx filename=\"app/ui/search.js\" highlight={1} switcher\n00237| 'use client'\n00238| \n00239| export default function Search() {\n00240| // ...\n00241| }\n00242| ```\n00243| \n00244| ### Passing data from Server to Client Components\n00245| \n00246| You can pass data from Server Components to Client Components using props.\n00247| \n00248| ```tsx filename=\"app/[id]/page.tsx\" highlight={1,12} switcher\n00249| import LikeButton from '@/app/ui/like-button'\n00250| import { getPost } from '@/lib/data'\n00251| \n00252| export default async function Page({\n00253| params,\n00254| }: {\n00255| params: Promise<{ id: string }>\n00256| }) {\n00257| const { id } = await params\n00258| const post = await getPost(id)\n00259| \n00260| return \n00261| }\n00262| ```\n00263| \n00264| ```jsx filename=\"app/[id]/page.js\" highlight={1,7} switcher\n00265| import LikeButton from '@/app/ui/like-button'\n00266| import { getPost } from '@/lib/data'\n00267| \n00268| export default async function Page({ params }) {\n00269| const post = await getPost(params.id)\n00270| \n00271| return \n00272| }\n00273| ```\n00274| \n00275| ```tsx filename=\"app/ui/like-button.tsx\" highlight={1} switcher\n00276| 'use client'\n00277| \n00278| export default function LikeButton({ likes }: { likes: number }) {\n00279| // ...\n00280| }\n00281| ```\n00282| \n00283| ```jsx filename=\"app/ui/like-button.js\" highlight={1} switcher\n00284| 'use client'\n00285| \n00286| export default function LikeButton({ likes }) {\n00287| // ...\n00288| }\n00289| ```\n00290| \n00291| Alternatively, you can stream data from a Server Component to a Client Component with the [`use` API](https://react.dev/reference/react/use). See an [example](/docs/app/getting-started/fetching-data#streaming-data-with-the-use-api).\n00292| \n00293| > **Good to know**: Props passed to Client Components need to be [serializable](https://react.dev/reference/react/use-server#serializable-parameters-and-return-values) by React.\n00294| \n00295| ### Interleaving Server and Client Components\n00296| \n00297| You can pass Server Components as a prop to a Client Component. This allows you to visually nest server-rendered UI within Client components.\n00298| \n00299| A common pattern is to use `children` to create a _slot_ in a ``. For example, a `` component that fetches data on the server, inside a `` component that uses client state to toggle visibility.\n00300| \n00301| ```tsx filename=\"app/ui/modal.tsx\" switcher\n00302| 'use client'\n00303| \n00304| export default function Modal({ children }: { children: React.ReactNode }) {\n00305| return
{children}
\n00306| }\n00307| ```\n00308| \n00309| ```jsx filename=\"app/ui/modal.js\" switcher\n00310| 'use client'\n00311| \n00312| export default function Modal({ children }) {\n00313| return
{children}
\n00314| }\n00315| ```\n00316| \n00317| Then, in a parent Server Component (e.g.``), you can pass a `` as the child of the ``:\n00318| \n00319| ```tsx filename=\"app/page.tsx\" highlight={7} switcher\n00320| import Modal from './ui/modal'\n00321| import Cart from './ui/cart'\n00322| \n00323| export default function Page() {\n00324| return (\n00325| \n00326| \n00327| \n00328| )\n00329| }\n00330| ```\n00331| \n00332| ```jsx filename=\"app/page.js\" highlight={7} switcher\n00333| import Modal from './ui/modal'\n00334| import Cart from './ui/cart'\n00335| \n00336| export default function Page() {\n00337| return (\n00338| \n00339| \n00340| \n00341| )\n00342| }\n00343| ```\n00344| \n00345| In this pattern, Server Components are rendered on the server ahead of time, even when passed as props to Client Components. The React Server Component Payload contains the rendered result of those Server Components, plus placeholders for where Client Components should be rendered and references to their JavaScript files.\n00346| \n00347| ### Context providers\n00348| \n00349| [React context](https://react.dev/learn/passing-data-deeply-with-context) is commonly used to share global state like the current theme. However, React context is not supported in Server Components.\n00350| \n00351| To use context, create a Client Component that accepts `children`:\n00352| \n00353| ```tsx filename=\"app/theme-provider.tsx\" switcher\n00354| 'use client'\n00355| \n00356| import { createContext } from 'react'\n00357| \n00358| export const ThemeContext = createContext({})\n00359| \n00360| export default function ThemeProvider({\n00361| children,\n00362| }: {\n00363| children: React.ReactNode\n00364| }) {\n00365| return {children}\n00366| }\n00367| ```\n00368| \n00369| ```jsx filename=\"app/theme-provider.js\" switcher\n00370| 'use client'\n00371| \n00372| import { createContext } from 'react'\n00373| \n00374| export const ThemeContext = createContext({})\n00375| \n00376| export default function ThemeProvider({ children }) {\n00377| return {children}\n00378| }\n00379| ```\n00380| \n00381| Then, import it into a Server Component (e.g. `layout`):\n00382| \n00383| ```tsx filename=\"app/layout.tsx\" switcher\n00384| import ThemeProvider from './theme-provider'\n00385| \n00386| export default function RootLayout({\n00387| children,\n00388| }: {\n00389| children: React.ReactNode\n00390| }) {\n00391| return (\n00392| \n00393| \n00394| {children}\n00395| \n00396| \n00397| )\n00398| }\n00399| ```\n00400| \n00401| ```jsx filename=\"app/layout.js\" switcher\n00402| import ThemeProvider from './theme-provider'\n00403| \n00404| export default function RootLayout({ children }) {\n00405| return (\n00406| \n00407| \n00408| {children}\n00409| \n00410| \n00411| )\n00412| }\n00413| ```\n00414| \n00415| Your Server Component will now be able to directly render your provider, and all other Client Components throughout your app will be able to consume this context.\n00416| \n00417| > **Good to know**: You should render providers as deep as possible in the tree – notice how `ThemeProvider` only wraps `{children}` instead of the entire `` document. This makes it easier for Next.js to optimize the static parts of your Server Components.\n00418| \n00419| ### Third-party components\n00420| \n00421| When using a third-party component that relies on client-only features, you can wrap it in a Client Component to ensure it works as expected.\n00422| \n00423| For example, the `` can be imported from the `acme-carousel` package. This component uses `useState`, but it doesn't yet have the `\"use client\"` directive.\n00424| \n00425| If you use `` within a Client Component, it will work as expected:\n00426| \n00427| ```tsx filename=\"app/gallery.tsx\" switcher\n00428| 'use client'\n00429| \n00430| import { useState } from 'react'\n00431| import { Carousel } from 'acme-carousel'\n00432| \n00433| export default function Gallery() {\n00434| const [isOpen, setIsOpen] = useState(false)\n00435| \n00436| return (\n00437|
\n00438| \n00439| {/* Works, since Carousel is used within a Client Component */}\n00440| {isOpen && }\n00441|
\n00457| \n00458| {/* Works, since Carousel is used within a Client Component */}\n00459| {isOpen && }\n00460|
\n00461| )\n00462| }\n00463| ```\n00464| \n00465| However, if you try to use it directly within a Server Component, you'll see an error. This is because Next.js doesn't know `` is using client-only features.\n00466| \n00467| To fix this, you can wrap third-party components that rely on client-only features in your own Client Components:\n00468| \n00469| ```tsx filename=\"app/carousel.tsx\" switcher\n00470| 'use client'\n00471| \n00472| import { Carousel } from 'acme-carousel'\n00473| \n00474| export default Carousel\n00475| ```\n00476| \n00477| ```jsx filename=\"app/carousel.js\" switcher\n00478| 'use client'\n00479| \n00480| import { Carousel } from 'acme-carousel'\n00481| \n00482| export default Carousel\n00483| ```\n00484| \n00485| Now, you can use `` directly within a Server Component:\n00486| \n00487| ```tsx filename=\"app/page.tsx\" switcher\n00488| import Carousel from './carousel'\n00489| \n00490| export default function Page() {\n00491| return (\n00492|
\n00493|
View pictures
\n00494| {/* Works, since Carousel is a Client Component */}\n00495| \n00496|
\n00497| )\n00498| }\n00499| ```\n00500| \n00501| ```jsx filename=\"app/page.js\" switcher\n00502| import Carousel from './carousel'\n00503| \n00504| export default function Page() {\n00505| return (\n00506|
\n00507|
View pictures
\n00508| {/* Works, since Carousel is a Client Component */}\n00509| \n00510|
\n00511| )\n00512| }\n00513| ```\n00514| \n00515| > **Advice for Library Authors**\n00516| >\n00517| > If you’re building a component library, add the `\"use client\"` directive to entry points that rely on client-only features. This lets your users import components into Server Components without needing to create wrappers.\n00518| >\n00519| > It's worth noting some bundlers might strip out `\"use client\"` directives. You can find an example of how to configure esbuild to include the `\"use client\"` directive in the [React Wrap Balancer](https://github.com/shuding/react-wrap-balancer/blob/main/tsup.config.ts#L10-L13) and [Vercel Analytics](https://github.com/vercel/analytics/blob/main/packages/web/tsup.config.js#L26-L30) repositories.\n00520| \n00521| ### Preventing environment poisoning\n00522| \n00523| JavaScript modules can be shared between both Server and Client Components modules. This means it's possible to accidentally import server-only code into the client. For example, consider the following function:\n00524| \n00525| ```ts filename=\"lib/data.ts\" switcher\n00526| export async function getData() {\n00527| const res = await fetch('https://external-service.com/data', {\n00528| headers: {\n00529| authorization: process.env.API_KEY,\n00530| },\n00531| })\n00532| \n00533| return res.json()\n00534| }\n00535| ```\n00536| \n00537| ```js filename=\"lib/data.js\" switcher\n00538| export async function getData() {\n00539| const res = await fetch('https://external-service.com/data', {\n00540| headers: {\n00541| authorization: process.env.API_KEY,\n00542| },\n00543| })\n00544| \n00545| return res.json()\n00546| }\n00547| ```\n00548| \n00549| This function contains an `API_KEY` that should never be exposed to the client.\n00550| \n00551| In Next.js, only environment variables prefixed with `NEXT_PUBLIC_` are included in the client bundle. If variables are not prefixed, Next.js replaces them with an empty string.\n00552| \n00553| As a result, even though `getData()` can be imported and executed on the client, it won't work as expected.\n00554| \n00555| To prevent accidental usage in Client Components, you can use the [`server-only` package](https://www.npmjs.com/package/server-only).\n00556| \n00557| Then, import the package into a file that contains server-only code:\n00558| \n00559| ```js filename=\"lib/data.js\"\n00560| import 'server-only'\n00561| \n00562| export async function getData() {\n00563| const res = await fetch('https://external-service.com/data', {\n00564| headers: {\n00565| authorization: process.env.API_KEY,\n00566| },\n00567| })\n00568| \n00569| return res.json()\n00570| }\n00571| ```\n00572| \n00573| Now, if you try to import the module into a Client Component, there will be a build-time error.\n00574| \n00575| The corresponding [`client-only` package](https://www.npmjs.com/package/client-only) can be used to mark modules that contain client-only logic like code that accesses the `window` object.\n00576| \n00577| In Next.js, installing `server-only` or `client-only` is **optional**. However, if your linting rules flag extraneous dependencies, you may install them to avoid issues.\n00578| \n00579| ```bash package=\"npm\"\n00580| npm install server-only\n00581| ```\n00582| \n00583| ```bash package=\"yarn\"\n00584| yarn add server-only\n00585| ```\n00586| \n00587| ```bash package=\"pnpm\"\n00588| pnpm add server-only\n00589| ```\n00590| \n00591| ```bash package=\"bun\"\n00592| bun add server-only\n00593| ```\n00594| \n00595| Next.js handles `server-only` and `client-only` imports internally to provide clearer error messages when a module is used in the wrong environment. The contents of these packages from NPM are not used by Next.js.\n00596| \n00597| Next.js also provides its own type declarations for `server-only` and `client-only`, for TypeScript configurations where [`noUncheckedSideEffectImports`](https://www.typescriptlang.org/tsconfig/#noUncheckedSideEffectImports) is active.\n00598| \n\n(End of file - total 598 lines)\n",
+ "title": "node_modules/next/dist/docs/01-app/01-getting-started/05-server-and-client-components.md",
+ "metadata": {
+ "preview": "---\ntitle: Server and Client Components\ndescription: Learn how you can use React Server and Client Components to render parts of your application on the server or the client.\nrelated:\n title: Next Steps\n description: Learn more about the APIs mentioned in this page.\n links:\n - app/api-reference/directives/use-client\n---\n\nBy default, layouts and pages are [Server Components](https://react.dev/reference/rsc/server-components), which lets you fetch data and render parts of your UI on the server, optionally cache the result, and stream it to the client. When you need interactivity or browser APIs, you can use [Client Components](https://react.dev/reference/rsc/use-client) to layer in functionality.\n\nThis page explains how Server and Client Components work in Next.js and when to use them, with examples of how to compose them together in your application.\n\n## When to use Server and Client Components?\n\nThe client and server environments have different capabilities. Server and Client components allow you to run logic in each environment depending on your use case.\n\nUse **Client Components** when you need:\n"
+ },
+ "time": {
+ "start": 1781392515864,
+ "end": 1781392515867
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:15.868Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| ---\n00002| title: Server and Client Components\n00003| description: Learn how you can use React Server and Client Components to render parts of your application on the server or the client.\n00004| related:\n00005| title: Next Steps\n00006| description: Learn more about the APIs mentioned in this page.\n00007| links:\n00008| - app/api-reference/directives/use-client\n00009| ---\n00010| \n00011| By default, layouts and pages are [Server Components](https://react.dev/reference/rsc/server-components), which lets you fetch data and render parts of your UI on the server, optionally cache the result, and stream it to the client. When you need interactivity or browser APIs, you can use [Client Components](https://react.dev/reference/rsc/use-client) to layer in functionality.\n00012| \n00013| This page explains how Server and Client Components work in Next.js and when to use them, with examples of how to compose them together in your application.\n00014| \n00015| ## When to use Server and Client Components?\n00016| \n00017| The client and server environments have different capabilities. Server and Client components allow you to run logic in each environment depending on your use case.\n00018| \n00019| Use **Client Components** when you need:\n00020| \n00021| - [State](https://react.dev/learn/managing-state) and [event handlers](https://react.dev/learn/responding-to-events). E.g. `onClick`, `onChange`.\n00022| - [Lifecycle logic](https://react.dev/learn/lifecycle-of-reactive-effects). E.g. `useEffect`.\n00023| - Browser-only APIs. E.g. `localStorage`, `window`, `Navigator.geolocation`, etc.\n00024| - [Custom hooks](https://react.dev/learn/reusing-logic-with-custom-hooks).\n00025| \n00026| Use **Server Components** when you need:\n00027| \n00028| - Fetch data from databases or APIs close to the source.\n00029| - Use API keys, tokens, and other secrets without exposing them to the client.\n00030| - Reduce the amount of JavaScript sent to the browser.\n00031| - Improve the [First Contentful Paint (FCP)](https://web.dev/fcp/), and stream content progressively to the client.\n00032| \n00033| For example, the `` component is a Server Component that fetches data about a post, and passes it as props to the `` which handles client-side interactivity.\n00034| \n00035| ```tsx filename=\"app/[id]/page.tsx\" highlight={1,17} switcher\n00036| import LikeButton from '@/app/ui/like-button'\n00037| import { getPost } from '@/lib/data'\n00038| \n00039| export default async function Page({\n00040| params,\n00041| }: {\n00042| params: Promise<{ id: string }>\n00043| }) {\n00044| const { id } = await params\n00045| const post = await getPost(id)\n00046| \n00047| return (\n00048|
\n00049| \n00050|
{post.title}
\n00051| {/* ... */}\n00052| \n00053| \n00054|
\n00055| )\n00056| }\n00057| ```\n00058| \n00059| ```jsx filename=\"app/[id]/page.js\" highlight={1,12} switcher\n00060| import LikeButton from '@/app/ui/like-button'\n00061| import { getPost } from '@/lib/data'\n00062| \n00063| export default async function Page({ params }) {\n00064| const post = await getPost(params.id)\n00065| \n00066| return (\n00067|
\n00068| \n00069|
{post.title}
\n00070| {/* ... */}\n00071| \n00072| \n00073|
\n00074| )\n00075| }\n00076| ```\n00077| \n00078| ```tsx filename=\"app/ui/like-button.tsx\" highlight={1} switcher\n00079| 'use client'\n00080| \n00081| import { useState } from 'react'\n00082| \n00083| export default function LikeButton({ likes }: { likes: number }) {\n00084| // ...\n00085| }\n00086| ```\n00087| \n00088| ```jsx filename=\"app/ui/like-button.js\" highlight={1} switcher\n00089| 'use client'\n00090| \n00091| import { useState } from 'react'\n00092| \n00093| export default function LikeButton({ likes }) {\n00094| // ...\n00095| }\n00096| ```\n00097| \n00098| ## How do Server and Client Components work in Next.js?\n00099| \n00100| ### On the server\n00101| \n00102| On the server, Next.js uses React's APIs to orchestrate rendering. The rendering work is split into chunks, by individual route segments ([layouts and pages](/docs/app/getting-started/layouts-and-pages)):\n00103| \n00104| - **Server Components** are rendered into a special data format called the React Server Component Payload (RSC Payload).\n00105| - **Client Components** and the RSC Payload are used to [prerender](/docs/app/glossary#prerendering) HTML.\n00106| \n00107| > **What is the React Server Component Payload (RSC)?**\n00108| >\n00109| > The RSC Payload is a compact binary representation of the rendered React Server Components tree. It's used by React on the client to update the browser's DOM. The RSC Payload contains:\n00110| >\n00111| > - The rendered result of Server Components\n00112| > - Placeholders for where Client Components should be rendered and references to their JavaScript files\n00113| > - Any props passed from a Server Component to a Client Component\n00114| \n00115| ### On the client (first load)\n00116| \n00117| Then, on the client:\n00118| \n00119| 1. **HTML** is used to immediately show a fast non-interactive preview of the route to the user.\n00120| 2. **RSC Payload** is used to reconcile the Client and Server Component trees.\n00121| 3. **JavaScript** is used to hydrate Client Components and make the application interactive.\n00122| \n00123| > **What is hydration?**\n00124| >\n00125| > Hydration is React's process for attaching [event handlers](https://react.dev/learn/responding-to-events) to the DOM, to make the static HTML interactive.\n00126| \n00127| ### Subsequent Navigations\n00128| \n00129| On subsequent navigations:\n00130| \n00131| - The **RSC Payload** is prefetched and cached for instant navigation.\n00132| - **Client Components** are rendered entirely on the client, without the server-rendered HTML.\n00133| \n00134| ## Examples\n00135| \n00136| ### Using Client Components\n00137| \n00138| You can create a Client Component by adding the [`\"use client\"`](https://react.dev/reference/react/use-client) directive at the top of the file, above your imports.\n00139| \n00140| ```tsx filename=\"app/ui/counter.tsx\" highlight={1} switcher\n00141| 'use client'\n00142| \n00143| import { useState } from 'react'\n00144| \n00145| export default function Counter() {\n00146| const [count, setCount] = useState(0)\n00147| \n00148| return (\n00149|
\n00170| )\n00171| }\n00172| ```\n00173| \n00174| `\"use client\"` is used to declare a **boundary** between the Server and Client module graphs (trees).\n00175| \n00176| Once a file is marked with `\"use client\"`, **all of its imports and the components it directly renders are included in the client bundle**. This means you don’t need to add the directive to every component that is intended for the client.\n00177| \n00178| This behavior applies to components that are part of the Client Component’s [module graph](/docs/app/glossary#module-graph), which includes the modules it imports and the components it renders directly. It does not apply to Server Components passed as children or other props. Those components are not imported into the Client Component’s module graph. They are rendered on the server and passed to the Client Component as rendered output.\n00179| \n00180| See [Interleaving Server and Client Components](/docs/app/getting-started/server-and-client-components#interleaving-server-and-client-components) for how Server and Client Components can be combined.\n00181| \n00182| ### Reducing JS bundle size\n00183| \n00184| To reduce the size of your client JavaScript bundles, add `'use client'` to specific interactive components instead of marking large parts of your UI as Client Components.\n00185| \n00186| For example, the `` component contains mostly static elements like a logo and navigation links, but includes an interactive search bar. `` is interactive and needs to be a Client Component, however, the rest of the layout can remain a Server Component.\n00187| \n00188| ```tsx filename=\"app/layout.tsx\" highlight={12} switcher\n00189| // Client Component\n00190| import Search from './search'\n00191| // Server Component\n00192| import Logo from './logo'\n00193| \n00194| // Layout is a Server Component by default\n00195| export default function Layout({ children }: { children: React.ReactNode }) {\n00196| return (\n00197| <>\n00198| \n00199| \n00200| \n00201| \n00202| {children}\n00203| >\n00204| )\n00205| }\n00206| ```\n00207| \n00208| ```jsx filename=\"app/layout.js\" highlight={12} switcher\n00209| // Client Component\n00210| import Search from './search'\n00211| // Server Component\n00212| import Logo from './logo'\n00213| \n00214| // Layout is a Server Component by default\n00215| export default function Layout({ children }) {\n00216| return (\n00217| <>\n00218| \n00219| \n00220| \n00221| \n00222| {children}\n00223| >\n00224| )\n00225| }\n00226| ```\n00227| \n00228| ```tsx filename=\"app/ui/search.tsx\" highlight={1} switcher\n00229| 'use client'\n00230| \n00231| export default function Search() {\n00232| // ...\n00233| }\n00234| ```\n00235| \n00236| ```jsx filename=\"app/ui/search.js\" highlight={1} switcher\n00237| 'use client'\n00238| \n00239| export default function Search() {\n00240| // ...\n00241| }\n00242| ```\n00243| \n00244| ### Passing data from Server to Client Components\n00245| \n00246| You can pass data from Server Components to Client Components using props.\n00247| \n00248| ```tsx filename=\"app/[id]/page.tsx\" highlight={1,12} switcher\n00249| import LikeButton from '@/app/ui/like-button'\n00250| import { getPost } from '@/lib/data'\n00251| \n00252| export default async function Page({\n00253| params,\n00254| }: {\n00255| params: Promise<{ id: string }>\n00256| }) {\n00257| const { id } = await params\n00258| const post = await getPost(id)\n00259| \n00260| return \n00261| }\n00262| ```\n00263| \n00264| ```jsx filename=\"app/[id]/page.js\" highlight={1,7} switcher\n00265| import LikeButton from '@/app/ui/like-button'\n00266| import { getPost } from '@/lib/data'\n00267| \n00268| export default async function Page({ params }) {\n00269| const post = await getPost(params.id)\n00270| \n00271| return \n00272| }\n00273| ```\n00274| \n00275| ```tsx filename=\"app/ui/like-button.tsx\" highlight={1} switcher\n00276| 'use client'\n00277| \n00278| export default function LikeButton({ likes }: { likes: number }) {\n00279| // ...\n00280| }\n00281| ```\n00282| \n00283| ```jsx filename=\"app/ui/like-button.js\" highlight={1} switcher\n00284| 'use client'\n00285| \n00286| export default function LikeButton({ likes }) {\n00287| // ...\n00288| }\n00289| ```\n00290| \n00291| Alternatively, you can stream data from a Server Component to a Client Component with the [`use` API](https://react.dev/reference/react/use). See an [example](/docs/app/getting-started/fetching-data#streaming-data-with-the-use-api).\n00292| \n00293| > **Good to know**: Props passed to Client Components need to be [serializable](https://react.dev/reference/react/use-server#serializable-parameters-and-return-values) by React.\n00294| \n00295| ### Interleaving Server and Client Components\n00296| \n00297| You can pass Server Components as a prop to a Client Component. This allows you to visually nest server-rendered UI within Client components.\n00298| \n00299| A common pattern is to use `children` to create a _slot_ in a ``. For example, a `` component that fetches data on the server, inside a `` component that uses client state to toggle visibility.\n00300| \n00301| ```tsx filename=\"app/ui/modal.tsx\" switcher\n00302| 'use client'\n00303| \n00304| export default function Modal({ children }: { children: React.ReactNode }) {\n00305| return
{children}
\n00306| }\n00307| ```\n00308| \n00309| ```jsx filename=\"app/ui/modal.js\" switcher\n00310| 'use client'\n00311| \n00312| export default function Modal({ children }) {\n00313| return
{children}
\n00314| }\n00315| ```\n00316| \n00317| Then, in a parent Server Component (e.g.``), you can pass a `` as the child of the ``:\n00318| \n00319| ```tsx filename=\"app/page.tsx\" highlight={7} switcher\n00320| import Modal from './ui/modal'\n00321| import Cart from './ui/cart'\n00322| \n00323| export default function Page() {\n00324| return (\n00325| \n00326| \n00327| \n00328| )\n00329| }\n00330| ```\n00331| \n00332| ```jsx filename=\"app/page.js\" highlight={7} switcher\n00333| import Modal from './ui/modal'\n00334| import Cart from './ui/cart'\n00335| \n00336| export default function Page() {\n00337| return (\n00338| \n00339| \n00340| \n00341| )\n00342| }\n00343| ```\n00344| \n00345| In this pattern, Server Components are rendered on the server ahead of time, even when passed as props to Client Components. The React Server Component Payload contains the rendered result of those Server Components, plus placeholders for where Client Components should be rendered and references to their JavaScript files.\n00346| \n00347| ### Context providers\n00348| \n00349| [React context](https://react.dev/learn/passing-data-deeply-with-context) is commonly used to share global state like the current theme. However, React context is not supported in Server Components.\n00350| \n00351| To use context, create a Client Component that accepts `children`:\n00352| \n00353| ```tsx filename=\"app/theme-provider.tsx\" switcher\n00354| 'use client'\n00355| \n00356| import { createContext } from 'react'\n00357| \n00358| export const ThemeContext = createContext({})\n00359| \n00360| export default function ThemeProvider({\n00361| children,\n00362| }: {\n00363| children: React.ReactNode\n00364| }) {\n00365| return {children}\n00366| }\n00367| ```\n00368| \n00369| ```jsx filename=\"app/theme-provider.js\" switcher\n00370| 'use client'\n00371| \n00372| import { createContext } from 'react'\n00373| \n00374| export const ThemeContext = createContext({})\n00375| \n00376| export default function ThemeProvider({ children }) {\n00377| return {children}\n00378| }\n00379| ```\n00380| \n00381| Then, import it into a Server Component (e.g. `layout`):\n00382| \n00383| ```tsx filename=\"app/layout.tsx\" switcher\n00384| import ThemeProvider from './theme-provider'\n00385| \n00386| export default function RootLayout({\n00387| children,\n00388| }: {\n00389| children: React.ReactNode\n00390| }) {\n00391| return (\n00392| \n00393| \n00394| {children}\n00395| \n00396| \n00397| )\n00398| }\n00399| ```\n00400| \n00401| ```jsx filename=\"app/layout.js\" switcher\n00402| import ThemeProvider from './theme-provider'\n00403| \n00404| export default function RootLayout({ children }) {\n00405| return (\n00406| \n00407| \n00408| {children}\n00409| \n00410| \n00411| )\n00412| }\n00413| ```\n00414| \n00415| Your Server Component will now be able to directly render your provider, and all other Client Components throughout your app will be able to consume this context.\n00416| \n00417| > **Good to know**: You should render providers as deep as possible in the tree – notice how `ThemeProvider` only wraps `{children}` instead of the entire `` document. This makes it easier for Next.js to optimize the static parts of your Server Components.\n00418| \n00419| ### Third-party components\n00420| \n00421| When using a third-party component that relies on client-only features, you can wrap it in a Client Component to ensure it works as expected.\n00422| \n00423| For example, the `` can be imported from the `acme-carousel` package. This component uses `useState`, but it doesn't yet have the `\"use client\"` directive.\n00424| \n00425| If you use `` within a Client Component, it will work as expected:\n00426| \n00427| ```tsx filename=\"app/gallery.tsx\" switcher\n00428| 'use client'\n00429| \n00430| import { useState } from 'react'\n00431| import { Carousel } from 'acme-carousel'\n00432| \n00433| export default function Gallery() {\n00434| const [isOpen, setIsOpen] = useState(false)\n00435| \n00436| return (\n00437|
\n00438| \n00439| {/* Works, since Carousel is used within a Client Component */}\n00440| {isOpen && }\n00441|
\n00457| \n00458| {/* Works, since Carousel is used within a Client Component */}\n00459| {isOpen && }\n00460|
\n00461| )\n00462| }\n00463| ```\n00464| \n00465| However, if you try to use it directly within a Server Component, you'll see an error. This is because Next.js doesn't know `` is using client-only features.\n00466| \n00467| To fix this, you can wrap third-party components that rely on client-only features in your own Client Components:\n00468| \n00469| ```tsx filename=\"app/carousel.tsx\" switcher\n00470| 'use client'\n00471| \n00472| import { Carousel } from 'acme-carousel'\n00473| \n00474| export default Carousel\n00475| ```\n00476| \n00477| ```jsx filename=\"app/carousel.js\" switcher\n00478| 'use client'\n00479| \n00480| import { Carousel } from 'acme-carousel'\n00481| \n00482| export default Carousel\n00483| ```\n00484| \n00485| Now, you can use `` directly within a Server Component:\n00486| \n00487| ```tsx filename=\"app/page.tsx\" switcher\n00488| import Carousel from './carousel'\n00489| \n00490| export default function Page() {\n00491| return (\n00492|
\n00493|
View pictures
\n00494| {/* Works, since Carousel is a Client Component */}\n00495| \n00496|
\n00497| )\n00498| }\n00499| ```\n00500| \n00501| ```jsx filename=\"app/page.js\" switcher\n00502| import Carousel from './carousel'\n00503| \n00504| export default function Page() {\n00505| return (\n00506|
\n00507|
View pictures
\n00508| {/* Works, since Carousel is a Client Component */}\n00509| \n00510|
\n00511| )\n00512| }\n00513| ```\n00514| \n00515| > **Advice for Library Authors**\n00516| >\n00517| > If you’re building a component library, add the `\"use client\"` directive to entry points that rely on client-only features. This lets your users import components into Server Components without needing to create wrappers.\n00518| >\n00519| > It's worth noting some bundlers might strip out `\"use client\"` directives. You can find an example of how to configure esbuild to include the `\"use client\"` directive in the [React Wrap Balancer](https://github.com/shuding/react-wrap-balancer/blob/main/tsup.config.ts#L10-L13) and [Vercel Analytics](https://github.com/vercel/analytics/blob/main/packages/web/tsup.config.js#L26-L30) repositories.\n00520| \n00521| ### Preventing environment poisoning\n00522| \n00523| JavaScript modules can be shared between both Server and Client Components modules. This means it's possible to accidentally import server-only code into the client. For example, consider the following function:\n00524| \n00525| ```ts filename=\"lib/data.ts\" switcher\n00526| export async function getData() {\n00527| const res = await fetch('https://external-service.com/data', {\n00528| headers: {\n00529| authorization: process.env.API_KEY,\n00530| },\n00531| })\n00532| \n00533| return res.json()\n00534| }\n00535| ```\n00536| \n00537| ```js filename=\"lib/data.js\" switcher\n00538| export async function getData() {\n00539| const res = await fetch('https://external-service.com/data', {\n00540| headers: {\n00541| authorization: process.env.API_KEY,\n00542| },\n00543| })\n00544| \n00545| return res.json()\n00546| }\n00547| ```\n00548| \n00549| This function contains an `API_KEY` that should never be exposed to the client.\n00550| \n00551| In Next.js, only environment variables prefixed with `NEXT_PUBLIC_` are included in the client bundle. If variables are not prefixed, Next.js replaces them with an empty string.\n00552| \n00553| As a result, even though `getData()` can be imported and executed on the client, it won't work as expected.\n00554| \n00555| To prevent accidental usage in Client Components, you can use the [`server-only` package](https://www.npmjs.com/package/server-only).\n00556| \n00557| Then, import the package into a file that contains server-only code:\n00558| \n00559| ```js filename=\"lib/data.js\"\n00560| import 'server-only'\n00561| \n00562| export async function getData() {\n00563| const res = await fetch('https://external-service.com/data', {\n00564| headers: {\n00565| authorization: process.env.API_KEY,\n00566| },\n00567| })\n00568| \n00569| return res.json()\n00570| }\n00571| ```\n00572| \n00573| Now, if you try to import the module into a Client Component, there will be a build-time error.\n00574| \n00575| The corresponding [`client-only` package](https://www.npmjs.com/package/client-only) can be used to mark modules that contain client-only logic like code that accesses the `window` object.\n00576| \n00577| In Next.js, installing `server-only` or `client-only` is **optional**. However, if your linting rules flag extraneous dependencies, you may install them to avoid issues.\n00578| \n00579| ```bash package=\"npm\"\n00580| npm install server-only\n00581| ```\n00582| \n00583| ```bash package=\"yarn\"\n00584| yarn add server-only\n00585| ```\n00586| \n00587| ```bash package=\"pnpm\"\n00588| pnpm add server-only\n00589| ```\n00590| \n00591| ```bash package=\"bun\"\n00592| bun add server-only\n00593| ```\n00594| \n00595| Next.js handles `server-only` and `client-only` imports internally to provide clearer error messages when a module is used in the wrong environment. The contents of these packages from NPM are not used by Next.js.\n00596| \n00597| Next.js also provides its own type declarations for `server-only` and `client-only`, for TypeScript configurations where [`noUncheckedSideEffectImports`](https://www.typescriptlang.org/tsconfig/#noUncheckedSideEffectImports) is active.\n00598| \n\n(End of file - total 598 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/01-getting-started/05-server-and-client-components.md"
+ },
+ "output": "\n00001| ---\n00002| title: Server and Client Components\n00003| description: Learn how you can use React Server and Client Components to render parts of your application on the server or the client.\n00004| related:\n00005| title: Next Steps\n00006| description: Learn more about the APIs mentioned in this page.\n00007| links:\n00008| - app/api-reference/directives/use-client\n00009| ---\n00010| \n00011| By default, layouts and pages are [Server Components](https://react.dev/reference/rsc/server-components), which lets you fetch data and render parts of your UI on the server, optionally cache the result, and stream it to the client. When you need interactivity or browser APIs, you can use [Client Components](https://react.dev/reference/rsc/use-client) to layer in functionality.\n00012| \n00013| This page explains how Server and Client Components work in Next.js and when to use them, with examples of how to compose them together in your application.\n00014| \n00015| ## When to use Server and Client Components?\n00016| \n00017| The client and server environments have different capabilities. Server and Client components allow you to run logic in each environment depending on your use case.\n00018| \n00019| Use **Client Components** when you need:\n00020| \n00021| - [State](https://react.dev/learn/managing-state) and [event handlers](https://react.dev/learn/responding-to-events). E.g. `onClick`, `onChange`.\n00022| - [Lifecycle logic](https://react.dev/learn/lifecycle-of-reactive-effects). E.g. `useEffect`.\n00023| - Browser-only APIs. E.g. `localStorage`, `window`, `Navigator.geolocation`, etc.\n00024| - [Custom hooks](https://react.dev/learn/reusing-logic-with-custom-hooks).\n00025| \n00026| Use **Server Components** when you need:\n00027| \n00028| - Fetch data from databases or APIs close to the source.\n00029| - Use API keys, tokens, and other secrets without exposing them to the client.\n00030| - Reduce the amount of JavaScript sent to the browser.\n00031| - Improve the [First Contentful Paint (FCP)](https://web.dev/fcp/), and stream content progressively to the client.\n00032| \n00033| For example, the `` component is a Server Component that fetches data about a post, and passes it as props to the `` which handles client-side interactivity.\n00034| \n00035| ```tsx filename=\"app/[id]/page.tsx\" highlight={1,17} switcher\n00036| import LikeButton from '@/app/ui/like-button'\n00037| import { getPost } from '@/lib/data'\n00038| \n00039| export default async function Page({\n00040| params,\n00041| }: {\n00042| params: Promise<{ id: string }>\n00043| }) {\n00044| const { id } = await params\n00045| const post = await getPost(id)\n00046| \n00047| return (\n00048|
\n00049| \n00050|
{post.title}
\n00051| {/* ... */}\n00052| \n00053| \n00054|
\n00055| )\n00056| }\n00057| ```\n00058| \n00059| ```jsx filename=\"app/[id]/page.js\" highlight={1,12} switcher\n00060| import LikeButton from '@/app/ui/like-button'\n00061| import { getPost } from '@/lib/data'\n00062| \n00063| export default async function Page({ params }) {\n00064| const post = await getPost(params.id)\n00065| \n00066| return (\n00067|
\n00068| \n00069|
{post.title}
\n00070| {/* ... */}\n00071| \n00072| \n00073|
\n00074| )\n00075| }\n00076| ```\n00077| \n00078| ```tsx filename=\"app/ui/like-button.tsx\" highlight={1} switcher\n00079| 'use client'\n00080| \n00081| import { useState } from 'react'\n00082| \n00083| export default function LikeButton({ likes }: { likes: number }) {\n00084| // ...\n00085| }\n00086| ```\n00087| \n00088| ```jsx filename=\"app/ui/like-button.js\" highlight={1} switcher\n00089| 'use client'\n00090| \n00091| import { useState } from 'react'\n00092| \n00093| export default function LikeButton({ likes }) {\n00094| // ...\n00095| }\n00096| ```\n00097| \n00098| ## How do Server and Client Components work in Next.js?\n00099| \n00100| ### On the server\n00101| \n00102| On the server, Next.js uses React's APIs to orchestrate rendering. The rendering work is split into chunks, by individual route segments ([layouts and pages](/docs/app/getting-started/layouts-and-pages)):\n00103| \n00104| - **Server Components** are rendered into a special data format called the React Server Component Payload (RSC Payload).\n00105| - **Client Components** and the RSC Payload are used to [prerender](/docs/app/glossary#prerendering) HTML.\n00106| \n00107| > **What is the React Server Component Payload (RSC)?**\n00108| >\n00109| > The RSC Payload is a compact binary representation of the rendered React Server Components tree. It's used by React on the client to update the browser's DOM. The RSC Payload contains:\n00110| >\n00111| > - The rendered result of Server Components\n00112| > - Placeholders for where Client Components should be rendered and references to their JavaScript files\n00113| > - Any props passed from a Server Component to a Client Component\n00114| \n00115| ### On the client (first load)\n00116| \n00117| Then, on the client:\n00118| \n00119| 1. **HTML** is used to immediately show a fast non-interactive preview of the route to the user.\n00120| 2. **RSC Payload** is used to reconcile the Client and Server Component trees.\n00121| 3. **JavaScript** is used to hydrate Client Components and make the application interactive.\n00122| \n00123| > **What is hydration?**\n00124| >\n00125| > Hydration is React's process for attaching [event handlers](https://react.dev/learn/responding-to-events) to the DOM, to make the static HTML interactive.\n00126| \n00127| ### Subsequent Navigations\n00128| \n00129| On subsequent navigations:\n00130| \n00131| - The **RSC Payload** is prefetched and cached for instant navigation.\n00132| - **Client Components** are rendered entirely on the client, without the server-rendered HTML.\n00133| \n00134| ## Examples\n00135| \n00136| ### Using Client Components\n00137| \n00138| You can create a Client Component by adding the [`\"use client\"`](https://react.dev/reference/react/use-client) directive at the top of the file, above your imports.\n00139| \n00140| ```tsx filename=\"app/ui/counter.tsx\" highlight={1} switcher\n00141| 'use client'\n00142| \n00143| import { useState } from 'react'\n00144| \n00145| export default function Counter() {\n00146| const [count, setCount] = useState(0)\n00147| \n00148| return (\n00149|
\n00170| )\n00171| }\n00172| ```\n00173| \n00174| `\"use client\"` is used to declare a **boundary** between the Server and Client module graphs (trees).\n00175| \n00176| Once a file is marked with `\"use client\"`, **all of its imports and the components it directly renders are included in the client bundle**. This means you don’t need to add the directive to every component that is intended for the client.\n00177| \n00178| This behavior applies to components that are part of the Client Component’s [module graph](/docs/app/glossary#module-graph), which includes the modules it imports and the components it renders directly. It does not apply to Server Components passed as children or other props. Those components are not imported into the Client Component’s module graph. They are rendered on the server and passed to the Client Component as rendered output.\n00179| \n00180| See [Interleaving Server and Client Components](/docs/app/getting-started/server-and-client-components#interleaving-server-and-client-components) for how Server and Client Components can be combined.\n00181| \n00182| ### Reducing JS bundle size\n00183| \n00184| To reduce the size of your client JavaScript bundles, add `'use client'` to specific interactive components instead of marking large parts of your UI as Client Components.\n00185| \n00186| For example, the `` component contains mostly static elements like a logo and navigation links, but includes an interactive search bar. `` is interactive and needs to be a Client Component, however, the rest of the layout can remain a Server Component.\n00187| \n00188| ```tsx filename=\"app/layout.tsx\" highlight={12} switcher\n00189| // Client Component\n00190| import Search from './search'\n00191| // Server Component\n00192| import Logo from './logo'\n00193| \n00194| // Layout is a Server Component by default\n00195| export default function Layout({ children }: { children: React.ReactNode }) {\n00196| return (\n00197| <>\n00198| \n00199| \n00200| \n00201| \n00202| {children}\n00203| >\n00204| )\n00205| }\n00206| ```\n00207| \n00208| ```jsx filename=\"app/layout.js\" highlight={12} switcher\n00209| // Client Component\n00210| import Search from './search'\n00211| // Server Component\n00212| import Logo from './logo'\n00213| \n00214| // Layout is a Server Component by default\n00215| export default function Layout({ children }) {\n00216| return (\n00217| <>\n00218| \n00219| \n00220| \n00221| \n00222| {children}\n00223| >\n00224| )\n00225| }\n00226| ```\n00227| \n00228| ```tsx filename=\"app/ui/search.tsx\" highlight={1} switcher\n00229| 'use client'\n00230| \n00231| export default function Search() {\n00232| // ...\n00233| }\n00234| ```\n00235| \n00236| ```jsx filename=\"app/ui/search.js\" highlight={1} switcher\n00237| 'use client'\n00238| \n00239| export default function Search() {\n00240| // ...\n00241| }\n00242| ```\n00243| \n00244| ### Passing data from Server to Client Components\n00245| \n00246| You can pass data from Server Components to Client Components using props.\n00247| \n00248| ```tsx filename=\"app/[id]/page.tsx\" highlight={1,12} switcher\n00249| import LikeButton from '@/app/ui/like-button'\n00250| import { getPost } from '@/lib/data'\n00251| \n00252| export default async function Page({\n00253| params,\n00254| }: {\n00255| params: Promise<{ id: string }>\n00256| }) {\n00257| const { id } = await params\n00258| const post = await getPost(id)\n00259| \n00260| return \n00261| }\n00262| ```\n00263| \n00264| ```jsx filename=\"app/[id]/page.js\" highlight={1,7} switcher\n00265| import LikeButton from '@/app/ui/like-button'\n00266| import { getPost } from '@/lib/data'\n00267| \n00268| export default async function Page({ params }) {\n00269| const post = await getPost(params.id)\n00270| \n00271| return \n00272| }\n00273| ```\n00274| \n00275| ```tsx filename=\"app/ui/like-button.tsx\" highlight={1} switcher\n00276| 'use client'\n00277| \n00278| export default function LikeButton({ likes }: { likes: number }) {\n00279| // ...\n00280| }\n00281| ```\n00282| \n00283| ```jsx filename=\"app/ui/like-button.js\" highlight={1} switcher\n00284| 'use client'\n00285| \n00286| export default function LikeButton({ likes }) {\n00287| // ...\n00288| }\n00289| ```\n00290| \n00291| Alternatively, you can stream data from a Server Component to a Client Component with the [`use` API](https://react.dev/reference/react/use). See an [example](/docs/app/getting-started/fetching-data#streaming-data-with-the-use-api).\n00292| \n00293| > **Good to know**: Props passed to Client Components need to be [serializable](https://react.dev/reference/react/use-server#serializable-parameters-and-return-values) by React.\n00294| \n00295| ### Interleaving Server and Client Components\n00296| \n00297| You can pass Server Components as a prop to a Client Component. This allows you to visually nest server-rendered UI within Client components.\n00298| \n00299| A common pattern is to use `children` to create a _slot_ in a ``. For example, a `` component that fetches data on the server, inside a `` component that uses client state to toggle visibility.\n00300| \n00301| ```tsx filename=\"app/ui/modal.tsx\" switcher\n00302| 'use client'\n00303| \n00304| export default function Modal({ children }: { children: React.ReactNode }) {\n00305| return
{children}
\n00306| }\n00307| ```\n00308| \n00309| ```jsx filename=\"app/ui/modal.js\" switcher\n00310| 'use client'\n00311| \n00312| export default function Modal({ children }) {\n00313| return
{children}
\n00314| }\n00315| ```\n00316| \n00317| Then, in a parent Server Component (e.g.``), you can pass a `` as the child of the ``:\n00318| \n00319| ```tsx filename=\"app/page.tsx\" highlight={7} switcher\n00320| import Modal from './ui/modal'\n00321| import Cart from './ui/cart'\n00322| \n00323| export default function Page() {\n00324| return (\n00325| \n00326| \n00327| \n00328| )\n00329| }\n00330| ```\n00331| \n00332| ```jsx filename=\"app/page.js\" highlight={7} switcher\n00333| import Modal from './ui/modal'\n00334| import Cart from './ui/cart'\n00335| \n00336| export default function Page() {\n00337| return (\n00338| \n00339| \n00340| \n00341| )\n00342| }\n00343| ```\n00344| \n00345| In this pattern, Server Components are rendered on the server ahead of time, even when passed as props to Client Components. The React Server Component Payload contains the rendered result of those Server Components, plus placeholders for where Client Components should be rendered and references to their JavaScript files.\n00346| \n00347| ### Context providers\n00348| \n00349| [React context](https://react.dev/learn/passing-data-deeply-with-context) is commonly used to share global state like the current theme. However, React context is not supported in Server Components.\n00350| \n00351| To use context, create a Client Component that accepts `children`:\n00352| \n00353| ```tsx filename=\"app/theme-provider.tsx\" switcher\n00354| 'use client'\n00355| \n00356| import { createContext } from 'react'\n00357| \n00358| export const ThemeContext = createContext({})\n00359| \n00360| export default function ThemeProvider({\n00361| children,\n00362| }: {\n00363| children: React.ReactNode\n00364| }) {\n00365| return {children}\n00366| }\n00367| ```\n00368| \n00369| ```jsx filename=\"app/theme-provider.js\" switcher\n00370| 'use client'\n00371| \n00372| import { createContext } from 'react'\n00373| \n00374| export const ThemeContext = createContext({})\n00375| \n00376| export default function ThemeProvider({ children }) {\n00377| return {children}\n00378| }\n00379| ```\n00380| \n00381| Then, import it into a Server Component (e.g. `layout`):\n00382| \n00383| ```tsx filename=\"app/layout.tsx\" switcher\n00384| import ThemeProvider from './theme-provider'\n00385| \n00386| export default function RootLayout({\n00387| children,\n00388| }: {\n00389| children: React.ReactNode\n00390| }) {\n00391| return (\n00392| \n00393| \n00394| {children}\n00395| \n00396| \n00397| )\n00398| }\n00399| ```\n00400| \n00401| ```jsx filename=\"app/layout.js\" switcher\n00402| import ThemeProvider from './theme-provider'\n00403| \n00404| export default function RootLayout({ children }) {\n00405| return (\n00406| \n00407| \n00408| {children}\n00409| \n00410| \n00411| )\n00412| }\n00413| ```\n00414| \n00415| Your Server Component will now be able to directly render your provider, and all other Client Components throughout your app will be able to consume this context.\n00416| \n00417| > **Good to know**: You should render providers as deep as possible in the tree – notice how `ThemeProvider` only wraps `{children}` instead of the entire `` document. This makes it easier for Next.js to optimize the static parts of your Server Components.\n00418| \n00419| ### Third-party components\n00420| \n00421| When using a third-party component that relies on client-only features, you can wrap it in a Client Component to ensure it works as expected.\n00422| \n00423| For example, the `` can be imported from the `acme-carousel` package. This component uses `useState`, but it doesn't yet have the `\"use client\"` directive.\n00424| \n00425| If you use `` within a Client Component, it will work as expected:\n00426| \n00427| ```tsx filename=\"app/gallery.tsx\" switcher\n00428| 'use client'\n00429| \n00430| import { useState } from 'react'\n00431| import { Carousel } from 'acme-carousel'\n00432| \n00433| export default function Gallery() {\n00434| const [isOpen, setIsOpen] = useState(false)\n00435| \n00436| return (\n00437|
\n00438| \n00439| {/* Works, since Carousel is used within a Client Component */}\n00440| {isOpen && }\n00441|
\n00457| \n00458| {/* Works, since Carousel is used within a Client Component */}\n00459| {isOpen && }\n00460|
\n00461| )\n00462| }\n00463| ```\n00464| \n00465| However, if you try to use it directly within a Server Component, you'll see an error. This is because Next.js doesn't know `` is using client-only features.\n00466| \n00467| To fix this, you can wrap third-party components that rely on client-only features in your own Client Components:\n00468| \n00469| ```tsx filename=\"app/carousel.tsx\" switcher\n00470| 'use client'\n00471| \n00472| import { Carousel } from 'acme-carousel'\n00473| \n00474| export default Carousel\n00475| ```\n00476| \n00477| ```jsx filename=\"app/carousel.js\" switcher\n00478| 'use client'\n00479| \n00480| import { Carousel } from 'acme-carousel'\n00481| \n00482| export default Carousel\n00483| ```\n00484| \n00485| Now, you can use `` directly within a Server Component:\n00486| \n00487| ```tsx filename=\"app/page.tsx\" switcher\n00488| import Carousel from './carousel'\n00489| \n00490| export default function Page() {\n00491| return (\n00492|
\n00493|
View pictures
\n00494| {/* Works, since Carousel is a Client Component */}\n00495| \n00496|
\n00497| )\n00498| }\n00499| ```\n00500| \n00501| ```jsx filename=\"app/page.js\" switcher\n00502| import Carousel from './carousel'\n00503| \n00504| export default function Page() {\n00505| return (\n00506|
\n00507|
View pictures
\n00508| {/* Works, since Carousel is a Client Component */}\n00509| \n00510|
\n00511| )\n00512| }\n00513| ```\n00514| \n00515| > **Advice for Library Authors**\n00516| >\n00517| > If you’re building a component library, add the `\"use client\"` directive to entry points that rely on client-only features. This lets your users import components into Server Components without needing to create wrappers.\n00518| >\n00519| > It's worth noting some bundlers might strip out `\"use client\"` directives. You can find an example of how to configure esbuild to include the `\"use client\"` directive in the [React Wrap Balancer](https://github.com/shuding/react-wrap-balancer/blob/main/tsup.config.ts#L10-L13) and [Vercel Analytics](https://github.com/vercel/analytics/blob/main/packages/web/tsup.config.js#L26-L30) repositories.\n00520| \n00521| ### Preventing environment poisoning\n00522| \n00523| JavaScript modules can be shared between both Server and Client Components modules. This means it's possible to accidentally import server-only code into the client. For example, consider the following function:\n00524| \n00525| ```ts filename=\"lib/data.ts\" switcher\n00526| export async function getData() {\n00527| const res = await fetch('https://external-service.com/data', {\n00528| headers: {\n00529| authorization: process.env.API_KEY,\n00530| },\n00531| })\n00532| \n00533| return res.json()\n00534| }\n00535| ```\n00536| \n00537| ```js filename=\"lib/data.js\" switcher\n00538| export async function getData() {\n00539| const res = await fetch('https://external-service.com/data', {\n00540| headers: {\n00541| authorization: process.env.API_KEY,\n00542| },\n00543| })\n00544| \n00545| return res.json()\n00546| }\n00547| ```\n00548| \n00549| This function contains an `API_KEY` that should never be exposed to the client.\n00550| \n00551| In Next.js, only environment variables prefixed with `NEXT_PUBLIC_` are included in the client bundle. If variables are not prefixed, Next.js replaces them with an empty string.\n00552| \n00553| As a result, even though `getData()` can be imported and executed on the client, it won't work as expected.\n00554| \n00555| To prevent accidental usage in Client Components, you can use the [`server-only` package](https://www.npmjs.com/package/server-only).\n00556| \n00557| Then, import the package into a file that contains server-only code:\n00558| \n00559| ```js filename=\"lib/data.js\"\n00560| import 'server-only'\n00561| \n00562| export async function getData() {\n00563| const res = await fetch('https://external-service.com/data', {\n00564| headers: {\n00565| authorization: process.env.API_KEY,\n00566| },\n00567| })\n00568| \n00569| return res.json()\n00570| }\n00571| ```\n00572| \n00573| Now, if you try to import the module into a Client Component, there will be a build-time error.\n00574| \n00575| The corresponding [`client-only` package](https://www.npmjs.com/package/client-only) can be used to mark modules that contain client-only logic like code that accesses the `window` object.\n00576| \n00577| In Next.js, installing `server-only` or `client-only` is **optional**. However, if your linting rules flag extraneous dependencies, you may install them to avoid issues.\n00578| \n00579| ```bash package=\"npm\"\n00580| npm install server-only\n00581| ```\n00582| \n00583| ```bash package=\"yarn\"\n00584| yarn add server-only\n00585| ```\n00586| \n00587| ```bash package=\"pnpm\"\n00588| pnpm add server-only\n00589| ```\n00590| \n00591| ```bash package=\"bun\"\n00592| bun add server-only\n00593| ```\n00594| \n00595| Next.js handles `server-only` and `client-only` imports internally to provide clearer error messages when a module is used in the wrong environment. The contents of these packages from NPM are not used by Next.js.\n00596| \n00597| Next.js also provides its own type declarations for `server-only` and `client-only`, for TypeScript configurations where [`noUncheckedSideEffectImports`](https://www.typescriptlang.org/tsconfig/#noUncheckedSideEffectImports) is active.\n00598| \n\n(End of file - total 598 lines)\n",
+ "title": "node_modules/next/dist/docs/01-app/01-getting-started/05-server-and-client-components.md",
+ "metadata": {
+ "preview": "---\ntitle: Server and Client Components\ndescription: Learn how you can use React Server and Client Components to render parts of your application on the server or the client.\nrelated:\n title: Next Steps\n description: Learn more about the APIs mentioned in this page.\n links:\n - app/api-reference/directives/use-client\n---\n\nBy default, layouts and pages are [Server Components](https://react.dev/reference/rsc/server-components), which lets you fetch data and render parts of your UI on the server, optionally cache the result, and stream it to the client. When you need interactivity or browser APIs, you can use [Client Components](https://react.dev/reference/rsc/use-client) to layer in functionality.\n\nThis page explains how Server and Client Components work in Next.js and when to use them, with examples of how to compose them together in your application.\n\n## When to use Server and Client Components?\n\nThe client and server environments have different capabilities. Server and Client components allow you to run logic in each environment depending on your use case.\n\nUse **Client Components** when you need:\n"
+ },
+ "time": {
+ "start": 1781392515864,
+ "end": 1781392515867
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:23.932Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "args": {
+ "filePath": "/workspace/next.config.ts",
+ "_extractedPath": "/workspace/next.config.ts"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392523932,
+ "sessionID": "ses_13cbb9c4fffe5TDZ1DwM35w4Zl",
+ "part": {
+ "id": "prt_ec344c1b7001aVNiJgpPhhgv6v",
+ "sessionID": "ses_13cbb9c4fffe5TDZ1DwM35w4Zl",
+ "messageID": "msg_ec344a3290010B9QkG8mrHGKUz",
+ "type": "tool",
+ "callID": "read_10",
+ "tool": "read",
+ "state": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/next.config.ts"
+ },
+ "output": "\n00001| import type { NextConfig } from 'next'\n00002| \n00003| const nextConfig: NextConfig = {}\n00004| \n00005| export default nextConfig\n00006| \n\n(End of file - total 6 lines)\n",
+ "title": "next.config.ts",
+ "metadata": {
+ "preview": "import type { NextConfig } from 'next'\n\nconst nextConfig: NextConfig = {}\n\nexport default nextConfig\n"
+ },
+ "time": {
+ "start": 1781392523929,
+ "end": 1781392523931
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:23.932Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| import type { NextConfig } from 'next'\n00002| \n00003| const nextConfig: NextConfig = {}\n00004| \n00005| export default nextConfig\n00006| \n\n(End of file - total 6 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/next.config.ts"
+ },
+ "output": "\n00001| import type { NextConfig } from 'next'\n00002| \n00003| const nextConfig: NextConfig = {}\n00004| \n00005| export default nextConfig\n00006| \n\n(End of file - total 6 lines)\n",
+ "title": "next.config.ts",
+ "metadata": {
+ "preview": "import type { NextConfig } from 'next'\n\nconst nextConfig: NextConfig = {}\n\nexport default nextConfig\n"
+ },
+ "time": {
+ "start": 1781392523929,
+ "end": 1781392523931
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:24.023Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "args": {
+ "filePath": "/workspace/package.json",
+ "_extractedPath": "/workspace/package.json"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392524023,
+ "sessionID": "ses_13cbb9c4fffe5TDZ1DwM35w4Zl",
+ "part": {
+ "id": "prt_ec344c29b0016oxrwm4kfXzFdz",
+ "sessionID": "ses_13cbb9c4fffe5TDZ1DwM35w4Zl",
+ "messageID": "msg_ec344a3290010B9QkG8mrHGKUz",
+ "type": "tool",
+ "callID": "read_11",
+ "tool": "read",
+ "state": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/package.json"
+ },
+ "output": "\n00001| {\n00002| \"private\": true,\n00003| \"type\": \"module\",\n00004| \"scripts\": {\n00005| \"dev\": \"next dev\",\n00006| \"build\": \"next build\",\n00007| \"start\": \"next start\"\n00008| },\n00009| \"dependencies\": {\n00010| \"@ai-sdk/react\": \"2.0.0-beta.28\",\n00011| \"@modelcontextprotocol/sdk\": \"^1.17.0\",\n00012| \"ai\": \"5.0.59\",\n00013| \"next\": \"^16.3.0-canary.50\",\n00014| \"react\": \"19.1.0\",\n00015| \"react-dom\": \"19.1.0\",\n00016| \"zod\": \"^4.0.10\"\n00017| },\n00018| \"devDependencies\": {\n00019| \"@types/node\": \"^20\",\n00020| \"@types/react\": \"^19\",\n00021| \"@types/react-dom\": \"^19\",\n00022| \"@vitejs/plugin-react\": \"^4.4.1\",\n00023| \"typescript\": \"^5\",\n00024| \"vite-tsconfig-paths\": \"^5.1.4\",\n00025| \"vitest\": \"^3.1.3\"\n00026| }\n00027| }\n00028| \n\n(End of file - total 28 lines)\n",
+ "title": "package.json",
+ "metadata": {
+ "preview": "{\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"next dev\",\n \"build\": \"next build\",\n \"start\": \"next start\"\n },\n \"dependencies\": {\n \"@ai-sdk/react\": \"2.0.0-beta.28\",\n \"@modelcontextprotocol/sdk\": \"^1.17.0\",\n \"ai\": \"5.0.59\",\n \"next\": \"^16.3.0-canary.50\",\n \"react\": \"19.1.0\",\n \"react-dom\": \"19.1.0\",\n \"zod\": \"^4.0.10\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^20\",\n \"@types/react\": \"^19\","
+ },
+ "time": {
+ "start": 1781392524020,
+ "end": 1781392524022
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:24.023Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| {\n00002| \"private\": true,\n00003| \"type\": \"module\",\n00004| \"scripts\": {\n00005| \"dev\": \"next dev\",\n00006| \"build\": \"next build\",\n00007| \"start\": \"next start\"\n00008| },\n00009| \"dependencies\": {\n00010| \"@ai-sdk/react\": \"2.0.0-beta.28\",\n00011| \"@modelcontextprotocol/sdk\": \"^1.17.0\",\n00012| \"ai\": \"5.0.59\",\n00013| \"next\": \"^16.3.0-canary.50\",\n00014| \"react\": \"19.1.0\",\n00015| \"react-dom\": \"19.1.0\",\n00016| \"zod\": \"^4.0.10\"\n00017| },\n00018| \"devDependencies\": {\n00019| \"@types/node\": \"^20\",\n00020| \"@types/react\": \"^19\",\n00021| \"@types/react-dom\": \"^19\",\n00022| \"@vitejs/plugin-react\": \"^4.4.1\",\n00023| \"typescript\": \"^5\",\n00024| \"vite-tsconfig-paths\": \"^5.1.4\",\n00025| \"vitest\": \"^3.1.3\"\n00026| }\n00027| }\n00028| \n\n(End of file - total 28 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/package.json"
+ },
+ "output": "\n00001| {\n00002| \"private\": true,\n00003| \"type\": \"module\",\n00004| \"scripts\": {\n00005| \"dev\": \"next dev\",\n00006| \"build\": \"next build\",\n00007| \"start\": \"next start\"\n00008| },\n00009| \"dependencies\": {\n00010| \"@ai-sdk/react\": \"2.0.0-beta.28\",\n00011| \"@modelcontextprotocol/sdk\": \"^1.17.0\",\n00012| \"ai\": \"5.0.59\",\n00013| \"next\": \"^16.3.0-canary.50\",\n00014| \"react\": \"19.1.0\",\n00015| \"react-dom\": \"19.1.0\",\n00016| \"zod\": \"^4.0.10\"\n00017| },\n00018| \"devDependencies\": {\n00019| \"@types/node\": \"^20\",\n00020| \"@types/react\": \"^19\",\n00021| \"@types/react-dom\": \"^19\",\n00022| \"@vitejs/plugin-react\": \"^4.4.1\",\n00023| \"typescript\": \"^5\",\n00024| \"vite-tsconfig-paths\": \"^5.1.4\",\n00025| \"vitest\": \"^3.1.3\"\n00026| }\n00027| }\n00028| \n\n(End of file - total 28 lines)\n",
+ "title": "package.json",
+ "metadata": {
+ "preview": "{\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"next dev\",\n \"build\": \"next build\",\n \"start\": \"next start\"\n },\n \"dependencies\": {\n \"@ai-sdk/react\": \"2.0.0-beta.28\",\n \"@modelcontextprotocol/sdk\": \"^1.17.0\",\n \"ai\": \"5.0.59\",\n \"next\": \"^16.3.0-canary.50\",\n \"react\": \"19.1.0\",\n \"react-dom\": \"19.1.0\",\n \"zod\": \"^4.0.10\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^20\",\n \"@types/react\": \"^19\","
+ },
+ "time": {
+ "start": 1781392524020,
+ "end": 1781392524022
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:48.822Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_edit",
+ "originalName": "edit",
+ "args": {
+ "filePath": "/workspace/app/UserDashboard.tsx",
+ "oldString": "export default function UserDashboard() {\n // TODO: Implement user dashboard that needs to fetch user-specific data on each request\n return (\n
\n
User Dashboard
\n
User dashboard content goes here
\n
\n )\n}\n",
+ "newString": "type UserPreferences = {\n [key: string]: unknown\n}\n\nasync function getUserPreferences(): Promise {\n const res = await fetch('https://api.example.com/user/preferences')\n\n if (!res.ok) {\n throw new Error(`Failed to fetch user preferences: ${res.status}`)\n }\n\n return res.json()\n}\n\nexport default async function UserDashboard() {\n const preferences = await getUserPreferences()\n\n return (\n
\n )\n}\n",
+ "newString": "type UserPreferences = {\n [key: string]: unknown\n}\n\nasync function getUserPreferences(): Promise {\n const res = await fetch('https://api.example.com/user/preferences')\n\n if (!res.ok) {\n throw new Error(`Failed to fetch user preferences: ${res.status}`)\n }\n\n return res.json()\n}\n\nexport default async function UserDashboard() {\n const preferences = await getUserPreferences()\n\n return (\n
\n
User Dashboard
\n
{JSON.stringify(preferences, null, 2)}
\n
\n )\n}\n"
+ },
+ "output": "",
+ "title": "app/UserDashboard.tsx",
+ "metadata": {
+ "diagnostics": {
+ "/workspace/app/layout.tsx": [],
+ "/workspace/app/UserDashboard.tsx": [],
+ "/workspace/app/page.tsx": [],
+ "/workspace/next.config.ts": []
+ },
+ "diff": "Index: /workspace/app/UserDashboard.tsx\n===================================================================\n--- /workspace/app/UserDashboard.tsx\n+++ /workspace/app/UserDashboard.tsx\n@@ -1,9 +1,24 @@\n-export default function UserDashboard() {\n- // TODO: Implement user dashboard that needs to fetch user-specific data on each request\n+type UserPreferences = {\n+ [key: string]: unknown\n+}\n+\n+async function getUserPreferences(): Promise {\n+ const res = await fetch('https://api.example.com/user/preferences')\n+\n+ if (!res.ok) {\n+ throw new Error(`Failed to fetch user preferences: ${res.status}`)\n+ }\n+\n+ return res.json()\n+}\n+\n+export default async function UserDashboard() {\n+ const preferences = await getUserPreferences()\n+\n return (\n
\n
User Dashboard
\n-
User dashboard content goes here
\n+
{JSON.stringify(preferences, null, 2)}
\n
\n )\n }\n",
+ "filediff": {
+ "file": "/workspace/app/UserDashboard.tsx",
+ "before": "export default function UserDashboard() {\n // TODO: Implement user dashboard that needs to fetch user-specific data on each request\n return (\n
\n
User Dashboard
\n
User dashboard content goes here
\n
\n )\n}\n",
+ "after": "type UserPreferences = {\n [key: string]: unknown\n}\n\nasync function getUserPreferences(): Promise {\n const res = await fetch('https://api.example.com/user/preferences')\n\n if (!res.ok) {\n throw new Error(`Failed to fetch user preferences: ${res.status}`)\n }\n\n return res.json()\n}\n\nexport default async function UserDashboard() {\n const preferences = await getUserPreferences()\n\n return (\n
\n )\n}\n",
+ "newString": "type UserPreferences = {\n [key: string]: unknown\n}\n\nasync function getUserPreferences(): Promise {\n const res = await fetch('https://api.example.com/user/preferences')\n\n if (!res.ok) {\n throw new Error(`Failed to fetch user preferences: ${res.status}`)\n }\n\n return res.json()\n}\n\nexport default async function UserDashboard() {\n const preferences = await getUserPreferences()\n\n return (\n
\n
User Dashboard
\n
{JSON.stringify(preferences, null, 2)}
\n
\n )\n}\n"
+ },
+ "output": "",
+ "title": "app/UserDashboard.tsx",
+ "metadata": {
+ "diagnostics": {
+ "/workspace/app/layout.tsx": [],
+ "/workspace/app/UserDashboard.tsx": [],
+ "/workspace/app/page.tsx": [],
+ "/workspace/next.config.ts": []
+ },
+ "diff": "Index: /workspace/app/UserDashboard.tsx\n===================================================================\n--- /workspace/app/UserDashboard.tsx\n+++ /workspace/app/UserDashboard.tsx\n@@ -1,9 +1,24 @@\n-export default function UserDashboard() {\n- // TODO: Implement user dashboard that needs to fetch user-specific data on each request\n+type UserPreferences = {\n+ [key: string]: unknown\n+}\n+\n+async function getUserPreferences(): Promise {\n+ const res = await fetch('https://api.example.com/user/preferences')\n+\n+ if (!res.ok) {\n+ throw new Error(`Failed to fetch user preferences: ${res.status}`)\n+ }\n+\n+ return res.json()\n+}\n+\n+export default async function UserDashboard() {\n+ const preferences = await getUserPreferences()\n+\n return (\n
\n
User Dashboard
\n-
User dashboard content goes here
\n+
{JSON.stringify(preferences, null, 2)}
\n
\n )\n }\n",
+ "filediff": {
+ "file": "/workspace/app/UserDashboard.tsx",
+ "before": "export default function UserDashboard() {\n // TODO: Implement user dashboard that needs to fetch user-specific data on each request\n return (\n
\n
User Dashboard
\n
User dashboard content goes here
\n
\n )\n}\n",
+ "after": "type UserPreferences = {\n [key: string]: unknown\n}\n\nasync function getUserPreferences(): Promise {\n const res = await fetch('https://api.example.com/user/preferences')\n\n if (!res.ok) {\n throw new Error(`Failed to fetch user preferences: ${res.status}`)\n }\n\n return res.json()\n}\n\nexport default async function UserDashboard() {\n const preferences = await getUserPreferences()\n\n return (\n
\n00022| Loading user preferences...}>\n00023| \n00024| \n00025|
\n00026| )\n00027| }\n00028| \n\n(End of file - total 28 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/app/page.tsx"
+ },
+ "output": "\n00001| import { Suspense } from 'react'\n00002| import UserDashboard from './UserDashboard'\n00003| \n00004| // Example of App Router data fetching\n00005| async function getStaticData() {\n00006| try {\n00007| const res = await fetch('https://api.example.com/stats')\n00008| return res.json()\n00009| } catch {\n00010| // Return mock data for build time\n00011| return { users: 100 }\n00012| }\n00013| }\n00014| \n00015| export default async function Page() {\n00016| const stats = await getStaticData()\n00017| \n00018| return (\n00019|
\n00020|
Dashboard
\n00021|
Total users: {stats.users}
\n00022| Loading user preferences...}>\n00023| \n00024| \n00025|
\n00026| )\n00027| }\n00028| \n\n(End of file - total 28 lines)\n",
+ "title": "app/page.tsx",
+ "metadata": {
+ "preview": "import { Suspense } from 'react'\nimport UserDashboard from './UserDashboard'\n\n// Example of App Router data fetching\nasync function getStaticData() {\n try {\n const res = await fetch('https://api.example.com/stats')\n return res.json()\n } catch {\n // Return mock data for build time\n return { users: 100 }\n }\n}\n\nexport default async function Page() {\n const stats = await getStaticData()\n\n return (\n
\n
Dashboard
"
+ },
+ "time": {
+ "start": 1781392557002,
+ "end": 1781392557005
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:16:03.780Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "shell",
+ "originalName": "bash",
+ "args": {
+ "command": "npx tsc --noEmit",
+ "description": "Run TypeScript type check",
+ "workdir": "/workspace",
+ "_extractedCommand": "npx tsc --noEmit"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392563780,
+ "sessionID": "ses_13cbb9c4fffe5TDZ1DwM35w4Zl",
+ "part": {
+ "id": "prt_ec3455664001ahY43BDd0yxzSK",
+ "sessionID": "ses_13cbb9c4fffe5TDZ1DwM35w4Zl",
+ "messageID": "msg_ec34543e20016yacCnlVlU3D7Q",
+ "type": "tool",
+ "callID": "bash_16",
+ "tool": "bash",
+ "state": {
+ "status": "completed",
+ "input": {
+ "command": "npx tsc --noEmit",
+ "description": "Run TypeScript type check",
+ "workdir": "/workspace"
+ },
+ "output": "",
+ "title": "Run TypeScript type check",
+ "metadata": {
+ "output": "",
+ "exit": 0,
+ "description": "Run TypeScript type check"
+ },
+ "time": {
+ "start": 1781392562064,
+ "end": 1781392563777
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:16:03.780Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "shell",
+ "originalName": "bash",
+ "result": "",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "command": "npx tsc --noEmit",
+ "description": "Run TypeScript type check",
+ "workdir": "/workspace"
+ },
+ "output": "",
+ "title": "Run TypeScript type check",
+ "metadata": {
+ "output": "",
+ "exit": 0,
+ "description": "Run TypeScript type check"
+ },
+ "time": {
+ "start": 1781392562064,
+ "end": 1781392563777
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:16:07.240Z",
+ "type": "message",
+ "role": "assistant",
+ "content": "Implemented `UserDashboard` as an async Server Component in `app/UserDashboard.tsx:15` that fetches from `https://api.example.com/user/preferences` on each request and renders the JSON result.\n\nAlso wrapped it in a `` boundary in `app/page.tsx:22` so the rest of the page can render while user-specific preferences stream in. Type check passes.",
+ "raw": {
+ "type": "text",
+ "timestamp": 1781392567240,
+ "sessionID": "ses_13cbb9c4fffe5TDZ1DwM35w4Zl",
+ "part": {
+ "id": "prt_ec345671d001UsmxutokZ0uooA",
+ "sessionID": "ses_13cbb9c4fffe5TDZ1DwM35w4Zl",
+ "messageID": "msg_ec3455e580013lrzBbh1kImYZD",
+ "type": "text",
+ "text": "Implemented `UserDashboard` as an async Server Component in `app/UserDashboard.tsx:15` that fetches from `https://api.example.com/user/preferences` on each request and renders the JSON result.\n\nAlso wrapped it in a `` boundary in `app/page.tsx:22` so the rest of the page can render while user-specific preferences stream in. Type check passes.",
+ "time": {
+ "start": 1781392567239,
+ "end": 1781392567239
+ }
+ }
+ }
+ }
+ ],
+ "summary": {
+ "totalTurns": 1,
+ "toolCalls": {
+ "file_read": 10,
+ "file_write": 0,
+ "file_edit": 2,
+ "shell": 5,
+ "web_fetch": 0,
+ "web_search": 0,
+ "glob": 0,
+ "grep": 0,
+ "list_dir": 0,
+ "agent_task": 0,
+ "unknown": 0
+ },
+ "totalToolCalls": 17,
+ "webFetches": [],
+ "filesRead": [
+ "/workspace/app/UserDashboard.tsx",
+ "/workspace/app/page.tsx",
+ "/workspace/app/layout.tsx",
+ "/workspace/node_modules/next/dist/docs/01-app/01-getting-started/06-fetching-data.md",
+ "/workspace/node_modules/next/dist/docs/01-app/01-getting-started/08-caching.md",
+ "/workspace/node_modules/next/dist/docs/01-app/01-getting-started/05-server-and-client-components.md",
+ "/workspace/next.config.ts",
+ "/workspace/package.json"
+ ],
+ "filesModified": [
+ "/workspace/app/UserDashboard.tsx",
+ "/workspace/app/page.tsx"
+ ],
+ "shellCommands": [
+ {
+ "command": "ls -la /workspace",
+ "success": true
+ },
+ {
+ "command": "find /workspace/app -type f -o -type d | sort",
+ "success": true
+ },
+ {
+ "command": "ls /workspace/node_modules/next/dist/docs/",
+ "success": true
+ },
+ {
+ "command": "find /workspace/node_modules/next/dist/docs/01-app -type f | sort | head -100",
+ "success": true
+ },
+ {
+ "command": "npx tsc --noEmit",
+ "success": true
+ }
+ ],
+ "errors": [],
+ "thinkingBlocks": 0
+ },
+ "parseSuccess": true
+}
\ No newline at end of file
diff --git a/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-023-avoid-getserversideprops/run-2/outputs/eval.txt b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-023-avoid-getserversideprops/run-2/outputs/eval.txt
new file mode 100644
index 000000000..8867ed32b
--- /dev/null
+++ b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-023-avoid-getserversideprops/run-2/outputs/eval.txt
@@ -0,0 +1,10 @@
+
+ RUN v3.2.6 /workspace
+
+ ✓ EVAL.ts (3 tests) 3ms
+
+ Test Files 1 passed (1)
+ Tests 3 passed (3)
+ Start at 23:17:08
+ Duration 208ms (transform 28ms, setup 0ms, collect 18ms, tests 3ms, environment 0ms, prepare 66ms)
+
diff --git a/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-023-avoid-getserversideprops/run-2/outputs/scripts/build.txt b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-023-avoid-getserversideprops/run-2/outputs/scripts/build.txt
new file mode 100644
index 000000000..90dd2555e
--- /dev/null
+++ b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-023-avoid-getserversideprops/run-2/outputs/scripts/build.txt
@@ -0,0 +1,34 @@
+
+> build
+> next build
+
+Attention: Next.js now collects completely anonymous telemetry regarding usage.
+This information is used to shape Next.js' roadmap and prioritize features.
+You can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:
+https://nextjs.org/telemetry
+
+▲ Next.js 16.3.0-canary.50 (Turbopack)
+
+ Creating an optimized production build ...
+✓ Compiled successfully in 4.0s
+ Running TypeScript ...
+
+ We detected TypeScript in your project and reconfigured your tsconfig.json file for you.
+ The following suggested values were added to your tsconfig.json. These values can be changed to fit your project's needs:
+
+ - include was updated to add '.next/dev/types/**/*.ts'
+
+ Finished TypeScript in 1688ms ...
+ Collecting page data using 1 worker ...
+ Generating static pages using 1 worker (0/3) ...
+✓ Generating static pages using 1 worker (3/3) in 133ms
+ Finalizing page optimization ...
+
+Route (app)
+┌ ƒ /
+└ ○ /_not-found
+
+
+○ (Static) prerendered as static content
+ƒ (Dynamic) server-rendered on demand
+
diff --git a/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-023-avoid-getserversideprops/run-2/result.json b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-023-avoid-getserversideprops/run-2/result.json
new file mode 100644
index 000000000..2f0a842ad
--- /dev/null
+++ b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-023-avoid-getserversideprops/run-2/result.json
@@ -0,0 +1,48 @@
+{
+ "status": "passed",
+ "duration": 210.064,
+ "model": "vercel/moonshotai/kimi-k2.7-code",
+ "transcriptPath": "./transcript.json",
+ "transcriptRawPath": "./transcript-raw.jsonl",
+ "o11y": {
+ "totalTurns": 1,
+ "toolCalls": {
+ "file_read": 3,
+ "file_write": 0,
+ "file_edit": 2,
+ "shell": 1,
+ "web_fetch": 0,
+ "web_search": 0,
+ "glob": 0,
+ "grep": 0,
+ "list_dir": 0,
+ "agent_task": 0,
+ "unknown": 1
+ },
+ "totalToolCalls": 7,
+ "webFetches": [],
+ "filesRead": [
+ "/workspace/app/UserDashboard.tsx",
+ "/workspace/app/page.tsx",
+ "/workspace/package.json"
+ ],
+ "filesModified": [
+ "/workspace/app/UserDashboard.tsx",
+ "/workspace/app/page.tsx"
+ ],
+ "shellCommands": [
+ {
+ "command": "npx tsc --noEmit",
+ "success": true
+ }
+ ],
+ "errors": [],
+ "thinkingBlocks": 0
+ },
+ "outputPaths": {
+ "eval": "./outputs/eval.txt",
+ "scripts": {
+ "build": "./outputs/scripts/build.txt"
+ }
+ }
+}
\ No newline at end of file
diff --git a/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-023-avoid-getserversideprops/run-2/transcript-raw.jsonl b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-023-avoid-getserversideprops/run-2/transcript-raw.jsonl
new file mode 100644
index 000000000..b3bb10d96
--- /dev/null
+++ b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-023-avoid-getserversideprops/run-2/transcript-raw.jsonl
@@ -0,0 +1,22 @@
+{"type":"step_start","timestamp":1781392502783,"sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","part":{"id":"prt_ec3446ff50016hs9kRnuIZnRzm","sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","messageID":"msg_ec3446a090019pCu2gJBqlC8Xq","type":"step-start","snapshot":"54efff247862815d10297e8a8aea21f2cba03a22"}}
+{"type":"tool_use","timestamp":1781392592030,"sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","part":{"id":"prt_ec344781c001WiXigcKiHLmKXN","sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","messageID":"msg_ec3446a090019pCu2gJBqlC8Xq","type":"tool","callID":"task_0","tool":"task","state":{"status":"completed","input":{"description":"Explore async server component patterns","prompt":"Explore this codebase to find existing async server component patterns. I need to implement a UserDashboard component that fetches from `https://api.example.com/user/preferences` on each request. Find:\n1. Where components are typically located\n2. Examples of async server components that fetch data\n3. Conventions for error handling, loading states, data fetching patterns\n4. Any relevant configuration files\n\nReturn the file paths and relevant code snippets showing the patterns I should follow.","subagent_type":"explore"},"output":"Here is a survey of the existing patterns in this codebase plus the Next.js docs that ship with the installed version, so you can implement `UserDashboard` consistently.\n\n## 1. Where components are typically located\n\nThe project uses the **App Router** and keeps components inside `app/`:\n\n| Path | Purpose |\n|---|---|\n| `/workspace/app/layout.tsx` | Root layout |\n| `/workspace/app/page.tsx` | Home page (already fetches data) |\n| `/workspace/app/UserDashboard.tsx` | Existing stub for your component |\n\nRelevant configuration for imports:\n\n`/workspace/tsconfig.json`\n```json\n{\n \"compilerOptions\": {\n \"paths\": {\n \"@/*\": [\"./*\"]\n }\n }\n}\n```\n\nSo you can import with `@/app/UserDashboard` or `@/components/...`, but the current code uses relative imports (`./UserDashboard`).\n\nThe Next.js project-structure docs note that you can also colocate components in private folders like `app/_components/` or `app/_lib/` to keep them from becoming routes.\n\n## 2. Existing async server component example\n\n`/workspace/app/page.tsx` is the only existing async data-fetching component:\n\n```tsx\nimport UserDashboard from './UserDashboard'\n\n// Example of App Router data fetching\nasync function getStaticData() {\n try {\n const res = await fetch('https://api.example.com/stats')\n return res.json()\n } catch {\n // Return mock data for build time\n return { users: 100 }\n }\n}\n\nexport default async function Page() {\n const stats = await getStaticData()\n\n return (\n
\n
Dashboard
\n
Total users: {stats.users}
\n \n
\n )\n}\n```\n\nAnd the current stub for your component:\n\n`/workspace/app/UserDashboard.tsx`\n```tsx\nexport default function UserDashboard() {\n // TODO: Implement user dashboard that needs to fetch user-specific data on each request\n return (\n
\n
User Dashboard
\n
User dashboard content goes here
\n
\n )\n}\n```\n\n## 3. Conventions for data fetching, loading, and errors\n\n### Async server component fetch pattern\n\nFrom the installed docs:\n\n`/workspace/node_modules/next/dist/docs/01-app/01-getting-started/06-fetching-data.md`\n```tsx\nexport default async function Page() {\n const data = await fetch('https://api.vercel.app/blog')\n const posts = await data.json()\n return (\n
\n {posts.map((post) => (\n
{post.title}
\n ))}\n
\n )\n}\n```\n\n### Fetching fresh data on every request\n\nBecause you need `https://api.example.com/user/preferences` on **each request**, use `cache: 'no-store'`. From the installed `fetch` docs:\n\n`/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/fetch.md`\n```ts\nfetch(`https://...`, { cache: 'no-store' })\n```\n\n> `no-store`: Next.js fetches the resource from the remote server on every request.\n\n### Streaming / loading states\n\nFor data that must run at request time, the installed caching docs recommend wrapping the async component in `` rather than blocking the whole route:\n\n`/workspace/node_modules/next/dist/docs/01-app/01-getting-started/08-caching.md`\n```tsx\nimport { Suspense } from 'react'\n\nasync function LatestPosts() {\n const data = await fetch('https://api.example.com/posts')\n const posts = await data.json()\n return (\n
\n {posts.map((post) => (\n
{post.title}
\n ))}\n
\n )\n}\n\nexport default function Page() {\n return (\n <>\n
My Blog
\n Loading posts...}>\n \n \n >\n )\n}\n```\n\nYou can also use the `loading.tsx` file convention:\n\n`/workspace/node_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/loading.md`\n```tsx\n// app/dashboard/loading.tsx\nexport default function Loading() {\n return \n}\n```\n\n### Error handling\n\nFor expected fetch failures, handle them in the Server Component:\n\n`/workspace/node_modules/next/dist/docs/01-app/01-getting-started/10-error-handling.md`\n```tsx\nexport default async function Page() {\n const res = await fetch(`https://...`)\n const data = await res.json()\n\n if (!res.ok) {\n return 'There was an error.'\n }\n\n return '...'\n}\n```\n\nFor unexpected runtime errors, add a route-level error boundary. Error boundaries **must** be Client Components:\n\n`/workspace/node_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/error.md`\n```tsx\n'use client' // Error boundaries must be Client Components\n\nimport { useEffect } from 'react'\n\nexport default function Error({\n error,\n retry,\n}: {\n error: Error & { digest?: string }\n retry: () => void\n}) {\n useEffect(() => {\n console.error(error)\n }, [error])\n\n return (\n
\n
Something went wrong!
\n \n
\n )\n}\n```\n\n## 4. Relevant configuration files\n\n- `/workspace/next.config.ts` — currently empty; `cacheComponents` is **not** enabled, so the legacy fetch caching model applies.\n- `/workspace/tsconfig.json` — sets `@/*` path alias to `./*`.\n- `/workspace/package.json` — uses `next@^16.3.0-canary.50`, `react@19.1.0`, TypeScript, and Vitest.\n\n## 5. Recommended pattern for `UserDashboard`\n\nBased on the existing code and the installed Next.js 16 docs, here is the pattern to follow:\n\n```tsx\n// /workspace/app/UserDashboard.tsx\nexport default async function UserDashboard() {\n const res = await fetch('https://api.example.com/user/preferences', {\n cache: 'no-store',\n })\n\n if (!res.ok) {\n return
\n )\n}\n```\n\nThen wrap it in a `` boundary where it is used so it streams in without blocking the rest of the page:\n\n```tsx\n// /workspace/app/page.tsx\nimport { Suspense } from 'react'\nimport UserDashboard from './UserDashboard'\n\nasync function getStaticData() {\n try {\n const res = await fetch('https://api.example.com/stats')\n return res.json()\n } catch {\n return { users: 100 }\n }\n}\n\nexport default async function Page() {\n const stats = await getStaticData()\n\n return (\n
\n )\n}\n```\n\nKey takeaways:\n- Make `UserDashboard` an `async` Server Component.\n- Use `fetch(url, { cache: 'no-store' })` for per-request freshness.\n- Wrap it in `` so it streams without blocking the rest of the page.\n- Handle expected errors inline; use `error.tsx` for unexpected errors.\n\n\nsession_id: ses_13cbb78bfffex3k2Wtc4mfMCcx\n","title":"Explore async server component patterns","metadata":{"summary":[{"id":"prt_ec344a8920010sf1rAsCz3v3MG","tool":"glob","state":{"status":"completed","title":""}},{"id":"prt_ec344ab99001nXQ8k907MBrZIK","tool":"bash","state":{"status":"completed","title":"List workspace root contents"}},{"id":"prt_ec344bac1001kb59G4JhlTljhb","tool":"read","state":{"status":"completed","title":"app/page.tsx"}},{"id":"prt_ec344bc01001EanLaJ6EAyniIY","tool":"read","state":{"status":"completed","title":"app/layout.tsx"}},{"id":"prt_ec344bd14001qZHa8XT5wYOjk6","tool":"read","state":{"status":"completed","title":"app/UserDashboard.tsx"}},{"id":"prt_ec344be490010JV66cpFFUU5Z2","tool":"read","state":{"status":"completed","title":"next.config.ts"}},{"id":"prt_ec344bfb70012WEKdnEJLEQTGg","tool":"read","state":{"status":"completed","title":"package.json"}},{"id":"prt_ec344c0e6001EEMbwo9keZw0H8","tool":"glob","state":{"status":"completed","title":""}},{"id":"prt_ec344cced001h5jOH6zVGmgt9A","tool":"bash","state":{"status":"completed","title":"List next dist directory"}},{"id":"prt_ec344cf43001X7WdVq3mx2SPUh","tool":"glob","state":{"status":"completed","title":""}},{"id":"prt_ec344d77e0011Pri85dXK4d83c","tool":"bash","state":{"status":"completed","title":"List docs directory recursively"}},{"id":"prt_ec344ec68001v6LGsF1ijLYDzC","tool":"read","state":{"status":"completed","title":"node_modules/next/dist/docs/01-app/01-getting-started/06-fetching-data.md"}},{"id":"prt_ec344ef22001Mi38pRgbjMi8e0","tool":"read","state":{"status":"completed","title":"node_modules/next/dist/docs/01-app/01-getting-started/10-error-handling.md"}},{"id":"prt_ec344f195001djutjsbWF7OslL","tool":"read","state":{"status":"completed","title":"node_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/loading.md"}},{"id":"prt_ec344f3b8001kfBq1DTSR7LJmL","tool":"read","state":{"status":"completed","title":"node_modules/next/dist/docs/01-app/03-api-reference/04-functions/fetch.md"}},{"id":"prt_ec344f617001BW7978xJNo3NyB","tool":"read","state":{"status":"completed","title":"node_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/error.md"}},{"id":"prt_ec3450d4f001MNtxLGpQebaO3E","tool":"read","state":{"status":"completed","title":"tsconfig.json"}},{"id":"prt_ec3450e46001eaXu78Mf9wMBc2","tool":"read","state":{"status":"completed","title":"opencode.json"}},{"id":"prt_ec3450f06001LD6MbqdpsLoOKb","tool":"read","state":{"status":"completed","title":"node_modules/next/dist/docs/01-app/01-getting-started/02-project-structure.md"}},{"id":"prt_ec3451156001251NLE4Wlwj9JR","tool":"read","state":{"status":"completed","title":"node_modules/next/dist/docs/01-app/01-getting-started/08-caching.md"}}],"sessionId":"ses_13cbb78bfffex3k2Wtc4mfMCcx"},"time":{"start":1781392508734,"end":1781392592028}}}}
+{"type":"step_finish","timestamp":1781392592034,"sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","part":{"id":"prt_ec345cc9d001RAz7fYfWYLveKC","sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","messageID":"msg_ec3446a090019pCu2gJBqlC8Xq","type":"step-finish","reason":"tool-calls","snapshot":"54efff247862815d10297e8a8aea21f2cba03a22","cost":0.00239184,"tokens":{"input":0,"output":219,"reasoning":0,"cache":{"read":9474,"write":0}}}}
+{"type":"step_start","timestamp":1781392593430,"sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","part":{"id":"prt_ec345d210001M45WzzCm1baW7l","sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","messageID":"msg_ec345ccab001F1cWcZ6gSEqFCj","type":"step-start","snapshot":"54efff247862815d10297e8a8aea21f2cba03a22"}}
+{"type":"tool_use","timestamp":1781392595131,"sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","part":{"id":"prt_ec345d775001aKNXfDlt2Ysy7a","sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","messageID":"msg_ec345ccab001F1cWcZ6gSEqFCj","type":"tool","callID":"read_1","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/app/UserDashboard.tsx"},"output":"\n00001| export default function UserDashboard() {\n00002| // TODO: Implement user dashboard that needs to fetch user-specific data on each request\n00003| return (\n00004|
\n00005|
User Dashboard
\n00006|
User dashboard content goes here
\n00007|
\n00008| )\n00009| }\n00010| \n\n(End of file - total 10 lines)\n","title":"app/UserDashboard.tsx","metadata":{"preview":"export default function UserDashboard() {\n // TODO: Implement user dashboard that needs to fetch user-specific data on each request\n return (\n
\n
User Dashboard
\n
User dashboard content goes here
\n
\n )\n}\n"},"time":{"start":1781392595124,"end":1781392595128}}}}
+{"type":"tool_use","timestamp":1781392595154,"sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","part":{"id":"prt_ec345d8b70017OayYLN0mqK4cU","sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","messageID":"msg_ec345ccab001F1cWcZ6gSEqFCj","type":"tool","callID":"read_2","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/app/page.tsx"},"output":"\n00001| import UserDashboard from './UserDashboard'\n00002| \n00003| // Example of App Router data fetching\n00004| async function getStaticData() {\n00005| try {\n00006| const res = await fetch('https://api.example.com/stats')\n00007| return res.json()\n00008| } catch {\n00009| // Return mock data for build time\n00010| return { users: 100 }\n00011| }\n00012| }\n00013| \n00014| export default async function Page() {\n00015| const stats = await getStaticData()\n00016| \n00017| return (\n00018|
\n00019|
Dashboard
\n00020|
Total users: {stats.users}
\n00021| \n00022|
\n00023| )\n00024| }\n00025| \n\n(End of file - total 25 lines)\n","title":"app/page.tsx","metadata":{"preview":"import UserDashboard from './UserDashboard'\n\n// Example of App Router data fetching\nasync function getStaticData() {\n try {\n const res = await fetch('https://api.example.com/stats')\n return res.json()\n } catch {\n // Return mock data for build time\n return { users: 100 }\n }\n}\n\nexport default async function Page() {\n const stats = await getStaticData()\n\n return (\n
\n
Dashboard
\n
Total users: {stats.users}
"},"time":{"start":1781392595150,"end":1781392595152}}}}
+{"type":"step_finish","timestamp":1781392595164,"sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","part":{"id":"prt_ec345d8d100162STo3QLWfm0N3","sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","messageID":"msg_ec345ccab001F1cWcZ6gSEqFCj","type":"step-finish","reason":"tool-calls","snapshot":"54efff247862815d10297e8a8aea21f2cba03a22","cost":0.00389617,"tokens":{"input":2047,"output":109,"reasoning":0,"cache":{"read":9472,"write":0}}}}
+{"type":"step_start","timestamp":1781392596494,"sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","part":{"id":"prt_ec345de0b0013u4fffLJzFPv7G","sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","messageID":"msg_ec345d8e2001U7jV1i4WB3YXXs","type":"step-start","snapshot":"54efff247862815d10297e8a8aea21f2cba03a22"}}
+{"type":"tool_use","timestamp":1781392605453,"sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","part":{"id":"prt_ec345e695001cZf3UrxQs5b6ih","sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","messageID":"msg_ec345d8e2001U7jV1i4WB3YXXs","type":"tool","callID":"edit_3","tool":"edit","state":{"status":"completed","input":{"filePath":"/workspace/app/UserDashboard.tsx","oldString":"export default function UserDashboard() {\n // TODO: Implement user dashboard that needs to fetch user-specific data on each request\n return (\n
\n
User Dashboard
\n
User dashboard content goes here
\n
\n )\n}\n","newString":"export default async function UserDashboard() {\n const res = await fetch('https://api.example.com/user/preferences', {\n cache: 'no-store',\n })\n\n if (!res.ok) {\n return (\n
\n )\n}\n"},"output":"","title":"app/UserDashboard.tsx","metadata":{"diagnostics":{"/workspace/next.config.ts":[],"/workspace/app/UserDashboard.tsx":[],"/workspace/app/page.tsx":[],"/workspace/app/layout.tsx":[]},"diff":"Index: /workspace/app/UserDashboard.tsx\n===================================================================\n--- /workspace/app/UserDashboard.tsx\n+++ /workspace/app/UserDashboard.tsx\n@@ -1,9 +1,23 @@\n-export default function UserDashboard() {\n- // TODO: Implement user dashboard that needs to fetch user-specific data on each request\n+export default async function UserDashboard() {\n+ const res = await fetch('https://api.example.com/user/preferences', {\n+ cache: 'no-store',\n+ })\n+\n+ if (!res.ok) {\n+ return (\n+
\n )\n }\n","filediff":{"file":"/workspace/app/UserDashboard.tsx","before":"export default function UserDashboard() {\n // TODO: Implement user dashboard that needs to fetch user-specific data on each request\n return (\n
\n
User Dashboard
\n
User dashboard content goes here
\n
\n )\n}\n","after":"export default async function UserDashboard() {\n const res = await fetch('https://api.example.com/user/preferences', {\n cache: 'no-store',\n })\n\n if (!res.ok) {\n return (\n
\n )\n}\n","additions":17,"deletions":3}},"time":{"start":1781392602440,"end":1781392605450}}}}
+{"type":"step_finish","timestamp":1781392605457,"sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","part":{"id":"prt_ec346010b001AKcj4gxlAGvn7i","sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","messageID":"msg_ec345d8e2001U7jV1i4WB3YXXs","type":"step-finish","reason":"tool-calls","snapshot":"094b6d3a57306feba0a7d055227a44204b1a7dab","cost":0.003812,"tokens":{"input":464,"output":382,"reasoning":0,"cache":{"read":11520,"write":0}}}}
+{"type":"step_start","timestamp":1781392606880,"sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","part":{"id":"prt_ec346069c001pGZu9dlt72VrCS","sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","messageID":"msg_ec3460120001ngrT96tLabGHfB","type":"step-start","snapshot":"094b6d3a57306feba0a7d055227a44204b1a7dab"}}
+{"type":"tool_use","timestamp":1781392616523,"sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","part":{"id":"prt_ec34607d3001VBiUfTp6fTz6aH","sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","messageID":"msg_ec3460120001ngrT96tLabGHfB","type":"tool","callID":"edit_4","tool":"edit","state":{"status":"completed","input":{"filePath":"/workspace/app/page.tsx","oldString":"import UserDashboard from './UserDashboard'\n\n// Example of App Router data fetching\nasync function getStaticData() {\n try {\n const res = await fetch('https://api.example.com/stats')\n return res.json()\n } catch {\n // Return mock data for build time\n return { users: 100 }\n }\n}\n\nexport default async function Page() {\n const stats = await getStaticData()\n\n return (\n
\n
Dashboard
\n
Total users: {stats.users}
\n \n
\n )\n}\n","newString":"import { Suspense } from 'react'\nimport UserDashboard from './UserDashboard'\n\n// Example of App Router data fetching\nasync function getStaticData() {\n try {\n const res = await fetch('https://api.example.com/stats')\n return res.json()\n } catch {\n // Return mock data for build time\n return { users: 100 }\n }\n}\n\nexport default async function Page() {\n const stats = await getStaticData()\n\n return (\n
\n
Dashboard
\n
Total users: {stats.users}
\n Loading user preferences...}>\n \n \n
\n )\n}\n"},"output":"","title":"app/page.tsx","metadata":{"diagnostics":{"/workspace/next.config.ts":[],"/workspace/app/UserDashboard.tsx":[],"/workspace/app/page.tsx":[],"/workspace/app/layout.tsx":[]},"diff":"Index: /workspace/app/page.tsx\n===================================================================\n--- /workspace/app/page.tsx\n+++ /workspace/app/page.tsx\n@@ -1,4 +1,5 @@\n+import { Suspense } from 'react'\n import UserDashboard from './UserDashboard'\n \n // Example of App Router data fetching\n async function getStaticData() {\n@@ -17,8 +18,10 @@\n return (\n
\n
Dashboard
\n
Total users: {stats.users}
\n- \n+ Loading user preferences...}>\n+ \n+ \n
\n )\n }\n","filediff":{"file":"/workspace/app/page.tsx","before":"import UserDashboard from './UserDashboard'\n\n// Example of App Router data fetching\nasync function getStaticData() {\n try {\n const res = await fetch('https://api.example.com/stats')\n return res.json()\n } catch {\n // Return mock data for build time\n return { users: 100 }\n }\n}\n\nexport default async function Page() {\n const stats = await getStaticData()\n\n return (\n
\n
Dashboard
\n
Total users: {stats.users}
\n \n
\n )\n}\n","after":"import { Suspense } from 'react'\nimport UserDashboard from './UserDashboard'\n\n// Example of App Router data fetching\nasync function getStaticData() {\n try {\n const res = await fetch('https://api.example.com/stats')\n return res.json()\n } catch {\n // Return mock data for build time\n return { users: 100 }\n }\n}\n\nexport default async function Page() {\n const stats = await getStaticData()\n\n return (\n
\n
Dashboard
\n
Total users: {stats.users}
\n Loading user preferences...}>\n \n \n
\n )\n}\n","additions":4,"deletions":1}},"time":{"start":1781392613514,"end":1781392616520}}}}
+{"type":"step_finish","timestamp":1781392616527,"sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","part":{"id":"prt_ec3462c49001SLgjamjZdn37ri","sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","messageID":"msg_ec3460120001ngrT96tLabGHfB","type":"step-finish","reason":"tool-calls","snapshot":"c581714e203fd5e1e64ec912bcec0131104a13fa","cost":0.00397511,"tokens":{"input":601,"output":380,"reasoning":0,"cache":{"read":11776,"write":0}}}}
+{"type":"step_start","timestamp":1781392617883,"sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","part":{"id":"prt_ec3463198001lPp0PxRL3AXAxE","sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","messageID":"msg_ec3462c61001cU46BgYwx9x6bQ","type":"step-start","snapshot":"c581714e203fd5e1e64ec912bcec0131104a13fa"}}
+{"type":"tool_use","timestamp":1781392618411,"sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","part":{"id":"prt_ec346339b001UjOAhZSd3CmeaE","sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","messageID":"msg_ec3462c61001cU46BgYwx9x6bQ","type":"tool","callID":"read_5","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/package.json"},"output":"\n00001| {\n00002| \"private\": true,\n00003| \"type\": \"module\",\n00004| \"scripts\": {\n00005| \"dev\": \"next dev\",\n00006| \"build\": \"next build\",\n00007| \"start\": \"next start\"\n00008| },\n00009| \"dependencies\": {\n00010| \"@ai-sdk/react\": \"2.0.0-beta.28\",\n00011| \"@modelcontextprotocol/sdk\": \"^1.17.0\",\n00012| \"ai\": \"5.0.59\",\n00013| \"next\": \"^16.3.0-canary.50\",\n00014| \"react\": \"19.1.0\",\n00015| \"react-dom\": \"19.1.0\",\n00016| \"zod\": \"^4.0.10\"\n00017| },\n00018| \"devDependencies\": {\n00019| \"@types/node\": \"^20\",\n00020| \"@types/react\": \"^19\",\n00021| \"@types/react-dom\": \"^19\",\n00022| \"@vitejs/plugin-react\": \"^4.4.1\",\n00023| \"typescript\": \"^5\",\n00024| \"vite-tsconfig-paths\": \"^5.1.4\",\n00025| \"vitest\": \"^3.1.3\"\n00026| }\n00027| }\n00028| \n\n(End of file - total 28 lines)\n","title":"package.json","metadata":{"preview":"{\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"next dev\",\n \"build\": \"next build\",\n \"start\": \"next start\"\n },\n \"dependencies\": {\n \"@ai-sdk/react\": \"2.0.0-beta.28\",\n \"@modelcontextprotocol/sdk\": \"^1.17.0\",\n \"ai\": \"5.0.59\",\n \"next\": \"^16.3.0-canary.50\",\n \"react\": \"19.1.0\",\n \"react-dom\": \"19.1.0\",\n \"zod\": \"^4.0.10\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^20\",\n \"@types/react\": \"^19\","},"time":{"start":1781392618408,"end":1781392618410}}}}
+{"type":"step_finish","timestamp":1781392618417,"sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","part":{"id":"prt_ec34633aa001YOjnysKKio6jjK","sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","messageID":"msg_ec3462c61001cU46BgYwx9x6bQ","type":"step-finish","reason":"tool-calls","snapshot":"c581714e203fd5e1e64ec912bcec0131104a13fa","cost":0.00259408,"tokens":{"input":480,"output":43,"reasoning":0,"cache":{"read":12288,"write":0}}}}
+{"type":"step_start","timestamp":1781392619740,"sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","part":{"id":"prt_ec34638d9001d6F830Okm4MEko","sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","messageID":"msg_ec34633b7001yiQoG90zGx075H","type":"step-start","snapshot":"c581714e203fd5e1e64ec912bcec0131104a13fa"}}
+{"type":"tool_use","timestamp":1781392622735,"sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","part":{"id":"prt_ec3463cd5001aovgYruanzohnp","sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","messageID":"msg_ec34633b7001yiQoG90zGx075H","type":"tool","callID":"bash_6","tool":"bash","state":{"status":"completed","input":{"command":"npx tsc --noEmit","description":"Type-check TypeScript files","timeout":120000},"output":"","title":"Type-check TypeScript files","metadata":{"output":"","exit":0,"description":"Type-check TypeScript files"},"time":{"start":1781392621074,"end":1781392622733}}}}
+{"type":"step_finish","timestamp":1781392622741,"sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","part":{"id":"prt_ec346448e0016aW61XhrrzVNR8","sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","messageID":"msg_ec34633b7001yiQoG90zGx075H","type":"step-finish","reason":"tool-calls","snapshot":"ede116bd99accac1f91cb9cef189e311d1f78be7","cost":0.00294464,"tokens":{"input":608,"output":90,"reasoning":0,"cache":{"read":12544,"write":0}}}}
+{"type":"step_start","timestamp":1781392624164,"sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","part":{"id":"prt_ec3464a1e0011iyqHUdHqyt01k","sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","messageID":"msg_ec34644a5001L9LuRFjGJ9VfAw","type":"step-start","snapshot":"ede116bd99accac1f91cb9cef189e311d1f78be7"}}
+{"type":"text","timestamp":1781392626047,"sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","part":{"id":"prt_ec3464ae90017cpQUiigv0495H","sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","messageID":"msg_ec34644a5001L9LuRFjGJ9VfAw","type":"text","text":"Implemented `UserDashboard` as an async server component.\n\nChanges made:\n- `app/UserDashboard.tsx`: Fetches `https://api.example.com/user/preferences` with `cache: 'no-store'` for per-request freshness, handles non-OK responses, and renders the JSON data.\n- `app/page.tsx`: Wrapped `` in `` with a loading fallback so it streams without blocking the rest of the page.\n\nTypeScript check passed.","time":{"start":1781392626046,"end":1781392626046}}}
+{"type":"step_finish","timestamp":1781392626050,"sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","part":{"id":"prt_ec346517e001Xpetn1HS4gtNfD","sessionID":"ses_13cbb9647ffeTq1hlj3yVkyvqO","messageID":"msg_ec34644a5001L9LuRFjGJ9VfAw","type":"step-finish","reason":"stop","snapshot":"ede116bd99accac1f91cb9cef189e311d1f78be7","cost":0.00273781,"tokens":{"input":203,"output":114,"reasoning":0,"cache":{"read":13056,"write":0}}}}
\ No newline at end of file
diff --git a/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-023-avoid-getserversideprops/run-2/transcript.json b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-023-avoid-getserversideprops/run-2/transcript.json
new file mode 100644
index 000000000..33e0ccc37
--- /dev/null
+++ b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-023-avoid-getserversideprops/run-2/transcript.json
@@ -0,0 +1,922 @@
+{
+ "agent": "vercel-ai-gateway/opencode",
+ "model": "vercel/moonshotai/kimi-k2.7-code",
+ "events": [
+ {
+ "timestamp": "2026-06-13T23:16:32.030Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "unknown",
+ "originalName": "task",
+ "args": {
+ "description": "Explore async server component patterns",
+ "prompt": "Explore this codebase to find existing async server component patterns. I need to implement a UserDashboard component that fetches from `https://api.example.com/user/preferences` on each request. Find:\n1. Where components are typically located\n2. Examples of async server components that fetch data\n3. Conventions for error handling, loading states, data fetching patterns\n4. Any relevant configuration files\n\nReturn the file paths and relevant code snippets showing the patterns I should follow.",
+ "subagent_type": "explore"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392592030,
+ "sessionID": "ses_13cbb9647ffeTq1hlj3yVkyvqO",
+ "part": {
+ "id": "prt_ec344781c001WiXigcKiHLmKXN",
+ "sessionID": "ses_13cbb9647ffeTq1hlj3yVkyvqO",
+ "messageID": "msg_ec3446a090019pCu2gJBqlC8Xq",
+ "type": "tool",
+ "callID": "task_0",
+ "tool": "task",
+ "state": {
+ "status": "completed",
+ "input": {
+ "description": "Explore async server component patterns",
+ "prompt": "Explore this codebase to find existing async server component patterns. I need to implement a UserDashboard component that fetches from `https://api.example.com/user/preferences` on each request. Find:\n1. Where components are typically located\n2. Examples of async server components that fetch data\n3. Conventions for error handling, loading states, data fetching patterns\n4. Any relevant configuration files\n\nReturn the file paths and relevant code snippets showing the patterns I should follow.",
+ "subagent_type": "explore"
+ },
+ "output": "Here is a survey of the existing patterns in this codebase plus the Next.js docs that ship with the installed version, so you can implement `UserDashboard` consistently.\n\n## 1. Where components are typically located\n\nThe project uses the **App Router** and keeps components inside `app/`:\n\n| Path | Purpose |\n|---|---|\n| `/workspace/app/layout.tsx` | Root layout |\n| `/workspace/app/page.tsx` | Home page (already fetches data) |\n| `/workspace/app/UserDashboard.tsx` | Existing stub for your component |\n\nRelevant configuration for imports:\n\n`/workspace/tsconfig.json`\n```json\n{\n \"compilerOptions\": {\n \"paths\": {\n \"@/*\": [\"./*\"]\n }\n }\n}\n```\n\nSo you can import with `@/app/UserDashboard` or `@/components/...`, but the current code uses relative imports (`./UserDashboard`).\n\nThe Next.js project-structure docs note that you can also colocate components in private folders like `app/_components/` or `app/_lib/` to keep them from becoming routes.\n\n## 2. Existing async server component example\n\n`/workspace/app/page.tsx` is the only existing async data-fetching component:\n\n```tsx\nimport UserDashboard from './UserDashboard'\n\n// Example of App Router data fetching\nasync function getStaticData() {\n try {\n const res = await fetch('https://api.example.com/stats')\n return res.json()\n } catch {\n // Return mock data for build time\n return { users: 100 }\n }\n}\n\nexport default async function Page() {\n const stats = await getStaticData()\n\n return (\n
\n
Dashboard
\n
Total users: {stats.users}
\n \n
\n )\n}\n```\n\nAnd the current stub for your component:\n\n`/workspace/app/UserDashboard.tsx`\n```tsx\nexport default function UserDashboard() {\n // TODO: Implement user dashboard that needs to fetch user-specific data on each request\n return (\n
\n
User Dashboard
\n
User dashboard content goes here
\n
\n )\n}\n```\n\n## 3. Conventions for data fetching, loading, and errors\n\n### Async server component fetch pattern\n\nFrom the installed docs:\n\n`/workspace/node_modules/next/dist/docs/01-app/01-getting-started/06-fetching-data.md`\n```tsx\nexport default async function Page() {\n const data = await fetch('https://api.vercel.app/blog')\n const posts = await data.json()\n return (\n
\n {posts.map((post) => (\n
{post.title}
\n ))}\n
\n )\n}\n```\n\n### Fetching fresh data on every request\n\nBecause you need `https://api.example.com/user/preferences` on **each request**, use `cache: 'no-store'`. From the installed `fetch` docs:\n\n`/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/fetch.md`\n```ts\nfetch(`https://...`, { cache: 'no-store' })\n```\n\n> `no-store`: Next.js fetches the resource from the remote server on every request.\n\n### Streaming / loading states\n\nFor data that must run at request time, the installed caching docs recommend wrapping the async component in `` rather than blocking the whole route:\n\n`/workspace/node_modules/next/dist/docs/01-app/01-getting-started/08-caching.md`\n```tsx\nimport { Suspense } from 'react'\n\nasync function LatestPosts() {\n const data = await fetch('https://api.example.com/posts')\n const posts = await data.json()\n return (\n
\n {posts.map((post) => (\n
{post.title}
\n ))}\n
\n )\n}\n\nexport default function Page() {\n return (\n <>\n
My Blog
\n Loading posts...}>\n \n \n >\n )\n}\n```\n\nYou can also use the `loading.tsx` file convention:\n\n`/workspace/node_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/loading.md`\n```tsx\n// app/dashboard/loading.tsx\nexport default function Loading() {\n return \n}\n```\n\n### Error handling\n\nFor expected fetch failures, handle them in the Server Component:\n\n`/workspace/node_modules/next/dist/docs/01-app/01-getting-started/10-error-handling.md`\n```tsx\nexport default async function Page() {\n const res = await fetch(`https://...`)\n const data = await res.json()\n\n if (!res.ok) {\n return 'There was an error.'\n }\n\n return '...'\n}\n```\n\nFor unexpected runtime errors, add a route-level error boundary. Error boundaries **must** be Client Components:\n\n`/workspace/node_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/error.md`\n```tsx\n'use client' // Error boundaries must be Client Components\n\nimport { useEffect } from 'react'\n\nexport default function Error({\n error,\n retry,\n}: {\n error: Error & { digest?: string }\n retry: () => void\n}) {\n useEffect(() => {\n console.error(error)\n }, [error])\n\n return (\n
\n
Something went wrong!
\n \n
\n )\n}\n```\n\n## 4. Relevant configuration files\n\n- `/workspace/next.config.ts` — currently empty; `cacheComponents` is **not** enabled, so the legacy fetch caching model applies.\n- `/workspace/tsconfig.json` — sets `@/*` path alias to `./*`.\n- `/workspace/package.json` — uses `next@^16.3.0-canary.50`, `react@19.1.0`, TypeScript, and Vitest.\n\n## 5. Recommended pattern for `UserDashboard`\n\nBased on the existing code and the installed Next.js 16 docs, here is the pattern to follow:\n\n```tsx\n// /workspace/app/UserDashboard.tsx\nexport default async function UserDashboard() {\n const res = await fetch('https://api.example.com/user/preferences', {\n cache: 'no-store',\n })\n\n if (!res.ok) {\n return
\n )\n}\n```\n\nThen wrap it in a `` boundary where it is used so it streams in without blocking the rest of the page:\n\n```tsx\n// /workspace/app/page.tsx\nimport { Suspense } from 'react'\nimport UserDashboard from './UserDashboard'\n\nasync function getStaticData() {\n try {\n const res = await fetch('https://api.example.com/stats')\n return res.json()\n } catch {\n return { users: 100 }\n }\n}\n\nexport default async function Page() {\n const stats = await getStaticData()\n\n return (\n
\n )\n}\n```\n\nAnd the current stub for your component:\n\n`/workspace/app/UserDashboard.tsx`\n```tsx\nexport default function UserDashboard() {\n // TODO: Implement user dashboard that needs to fetch user-specific data on each request\n return (\n
\n
User Dashboard
\n
User dashboard content goes here
\n
\n )\n}\n```\n\n## 3. Conventions for data fetching, loading, and errors\n\n### Async server component fetch pattern\n\nFrom the installed docs:\n\n`/workspace/node_modules/next/dist/docs/01-app/01-getting-started/06-fetching-data.md`\n```tsx\nexport default async function Page() {\n const data = await fetch('https://api.vercel.app/blog')\n const posts = await data.json()\n return (\n
\n {posts.map((post) => (\n
{post.title}
\n ))}\n
\n )\n}\n```\n\n### Fetching fresh data on every request\n\nBecause you need `https://api.example.com/user/preferences` on **each request**, use `cache: 'no-store'`. From the installed `fetch` docs:\n\n`/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/fetch.md`\n```ts\nfetch(`https://...`, { cache: 'no-store' })\n```\n\n> `no-store`: Next.js fetches the resource from the remote server on every request.\n\n### Streaming / loading states\n\nFor data that must run at request time, the installed caching docs recommend wrapping the async component in `` rather than blocking the whole route:\n\n`/workspace/node_modules/next/dist/docs/01-app/01-getting-started/08-caching.md`\n```tsx\nimport { Suspense } from 'react'\n\nasync function LatestPosts() {\n const data = await fetch('https://api.example.com/posts')\n const posts = await data.json()\n return (\n
\n {posts.map((post) => (\n
{post.title}
\n ))}\n
\n )\n}\n\nexport default function Page() {\n return (\n <>\n
My Blog
\n Loading posts...}>\n \n \n >\n )\n}\n```\n\nYou can also use the `loading.tsx` file convention:\n\n`/workspace/node_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/loading.md`\n```tsx\n// app/dashboard/loading.tsx\nexport default function Loading() {\n return \n}\n```\n\n### Error handling\n\nFor expected fetch failures, handle them in the Server Component:\n\n`/workspace/node_modules/next/dist/docs/01-app/01-getting-started/10-error-handling.md`\n```tsx\nexport default async function Page() {\n const res = await fetch(`https://...`)\n const data = await res.json()\n\n if (!res.ok) {\n return 'There was an error.'\n }\n\n return '...'\n}\n```\n\nFor unexpected runtime errors, add a route-level error boundary. Error boundaries **must** be Client Components:\n\n`/workspace/node_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/error.md`\n```tsx\n'use client' // Error boundaries must be Client Components\n\nimport { useEffect } from 'react'\n\nexport default function Error({\n error,\n retry,\n}: {\n error: Error & { digest?: string }\n retry: () => void\n}) {\n useEffect(() => {\n console.error(error)\n }, [error])\n\n return (\n
\n
Something went wrong!
\n \n
\n )\n}\n```\n\n## 4. Relevant configuration files\n\n- `/workspace/next.config.ts` — currently empty; `cacheComponents` is **not** enabled, so the legacy fetch caching model applies.\n- `/workspace/tsconfig.json` — sets `@/*` path alias to `./*`.\n- `/workspace/package.json` — uses `next@^16.3.0-canary.50`, `react@19.1.0`, TypeScript, and Vitest.\n\n## 5. Recommended pattern for `UserDashboard`\n\nBased on the existing code and the installed Next.js 16 docs, here is the pattern to follow:\n\n```tsx\n// /workspace/app/UserDashboard.tsx\nexport default async function UserDashboard() {\n const res = await fetch('https://api.example.com/user/preferences', {\n cache: 'no-store',\n })\n\n if (!res.ok) {\n return
\n )\n}\n```\n\nThen wrap it in a `` boundary where it is used so it streams in without blocking the rest of the page:\n\n```tsx\n// /workspace/app/page.tsx\nimport { Suspense } from 'react'\nimport UserDashboard from './UserDashboard'\n\nasync function getStaticData() {\n try {\n const res = await fetch('https://api.example.com/stats')\n return res.json()\n } catch {\n return { users: 100 }\n }\n}\n\nexport default async function Page() {\n const stats = await getStaticData()\n\n return (\n
\n )\n}\n```\n\nKey takeaways:\n- Make `UserDashboard` an `async` Server Component.\n- Use `fetch(url, { cache: 'no-store' })` for per-request freshness.\n- Wrap it in `` so it streams without blocking the rest of the page.\n- Handle expected errors inline; use `error.tsx` for unexpected errors.\n\n\nsession_id: ses_13cbb78bfffex3k2Wtc4mfMCcx\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "description": "Explore async server component patterns",
+ "prompt": "Explore this codebase to find existing async server component patterns. I need to implement a UserDashboard component that fetches from `https://api.example.com/user/preferences` on each request. Find:\n1. Where components are typically located\n2. Examples of async server components that fetch data\n3. Conventions for error handling, loading states, data fetching patterns\n4. Any relevant configuration files\n\nReturn the file paths and relevant code snippets showing the patterns I should follow.",
+ "subagent_type": "explore"
+ },
+ "output": "Here is a survey of the existing patterns in this codebase plus the Next.js docs that ship with the installed version, so you can implement `UserDashboard` consistently.\n\n## 1. Where components are typically located\n\nThe project uses the **App Router** and keeps components inside `app/`:\n\n| Path | Purpose |\n|---|---|\n| `/workspace/app/layout.tsx` | Root layout |\n| `/workspace/app/page.tsx` | Home page (already fetches data) |\n| `/workspace/app/UserDashboard.tsx` | Existing stub for your component |\n\nRelevant configuration for imports:\n\n`/workspace/tsconfig.json`\n```json\n{\n \"compilerOptions\": {\n \"paths\": {\n \"@/*\": [\"./*\"]\n }\n }\n}\n```\n\nSo you can import with `@/app/UserDashboard` or `@/components/...`, but the current code uses relative imports (`./UserDashboard`).\n\nThe Next.js project-structure docs note that you can also colocate components in private folders like `app/_components/` or `app/_lib/` to keep them from becoming routes.\n\n## 2. Existing async server component example\n\n`/workspace/app/page.tsx` is the only existing async data-fetching component:\n\n```tsx\nimport UserDashboard from './UserDashboard'\n\n// Example of App Router data fetching\nasync function getStaticData() {\n try {\n const res = await fetch('https://api.example.com/stats')\n return res.json()\n } catch {\n // Return mock data for build time\n return { users: 100 }\n }\n}\n\nexport default async function Page() {\n const stats = await getStaticData()\n\n return (\n
\n
Dashboard
\n
Total users: {stats.users}
\n \n
\n )\n}\n```\n\nAnd the current stub for your component:\n\n`/workspace/app/UserDashboard.tsx`\n```tsx\nexport default function UserDashboard() {\n // TODO: Implement user dashboard that needs to fetch user-specific data on each request\n return (\n
\n
User Dashboard
\n
User dashboard content goes here
\n
\n )\n}\n```\n\n## 3. Conventions for data fetching, loading, and errors\n\n### Async server component fetch pattern\n\nFrom the installed docs:\n\n`/workspace/node_modules/next/dist/docs/01-app/01-getting-started/06-fetching-data.md`\n```tsx\nexport default async function Page() {\n const data = await fetch('https://api.vercel.app/blog')\n const posts = await data.json()\n return (\n
\n {posts.map((post) => (\n
{post.title}
\n ))}\n
\n )\n}\n```\n\n### Fetching fresh data on every request\n\nBecause you need `https://api.example.com/user/preferences` on **each request**, use `cache: 'no-store'`. From the installed `fetch` docs:\n\n`/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/fetch.md`\n```ts\nfetch(`https://...`, { cache: 'no-store' })\n```\n\n> `no-store`: Next.js fetches the resource from the remote server on every request.\n\n### Streaming / loading states\n\nFor data that must run at request time, the installed caching docs recommend wrapping the async component in `` rather than blocking the whole route:\n\n`/workspace/node_modules/next/dist/docs/01-app/01-getting-started/08-caching.md`\n```tsx\nimport { Suspense } from 'react'\n\nasync function LatestPosts() {\n const data = await fetch('https://api.example.com/posts')\n const posts = await data.json()\n return (\n
\n {posts.map((post) => (\n
{post.title}
\n ))}\n
\n )\n}\n\nexport default function Page() {\n return (\n <>\n
My Blog
\n Loading posts...}>\n \n \n >\n )\n}\n```\n\nYou can also use the `loading.tsx` file convention:\n\n`/workspace/node_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/loading.md`\n```tsx\n// app/dashboard/loading.tsx\nexport default function Loading() {\n return \n}\n```\n\n### Error handling\n\nFor expected fetch failures, handle them in the Server Component:\n\n`/workspace/node_modules/next/dist/docs/01-app/01-getting-started/10-error-handling.md`\n```tsx\nexport default async function Page() {\n const res = await fetch(`https://...`)\n const data = await res.json()\n\n if (!res.ok) {\n return 'There was an error.'\n }\n\n return '...'\n}\n```\n\nFor unexpected runtime errors, add a route-level error boundary. Error boundaries **must** be Client Components:\n\n`/workspace/node_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/error.md`\n```tsx\n'use client' // Error boundaries must be Client Components\n\nimport { useEffect } from 'react'\n\nexport default function Error({\n error,\n retry,\n}: {\n error: Error & { digest?: string }\n retry: () => void\n}) {\n useEffect(() => {\n console.error(error)\n }, [error])\n\n return (\n
\n
Something went wrong!
\n \n
\n )\n}\n```\n\n## 4. Relevant configuration files\n\n- `/workspace/next.config.ts` — currently empty; `cacheComponents` is **not** enabled, so the legacy fetch caching model applies.\n- `/workspace/tsconfig.json` — sets `@/*` path alias to `./*`.\n- `/workspace/package.json` — uses `next@^16.3.0-canary.50`, `react@19.1.0`, TypeScript, and Vitest.\n\n## 5. Recommended pattern for `UserDashboard`\n\nBased on the existing code and the installed Next.js 16 docs, here is the pattern to follow:\n\n```tsx\n// /workspace/app/UserDashboard.tsx\nexport default async function UserDashboard() {\n const res = await fetch('https://api.example.com/user/preferences', {\n cache: 'no-store',\n })\n\n if (!res.ok) {\n return
\n )\n}\n```\n\nThen wrap it in a `` boundary where it is used so it streams in without blocking the rest of the page:\n\n```tsx\n// /workspace/app/page.tsx\nimport { Suspense } from 'react'\nimport UserDashboard from './UserDashboard'\n\nasync function getStaticData() {\n try {\n const res = await fetch('https://api.example.com/stats')\n return res.json()\n } catch {\n return { users: 100 }\n }\n}\n\nexport default async function Page() {\n const stats = await getStaticData()\n\n return (\n
\n00008| )\n00009| }\n00010| \n\n(End of file - total 10 lines)\n",
+ "title": "app/UserDashboard.tsx",
+ "metadata": {
+ "preview": "export default function UserDashboard() {\n // TODO: Implement user dashboard that needs to fetch user-specific data on each request\n return (\n
\n
User Dashboard
\n
User dashboard content goes here
\n
\n )\n}\n"
+ },
+ "time": {
+ "start": 1781392595124,
+ "end": 1781392595128
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:16:35.131Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| export default function UserDashboard() {\n00002| // TODO: Implement user dashboard that needs to fetch user-specific data on each request\n00003| return (\n00004|
\n00005|
User Dashboard
\n00006|
User dashboard content goes here
\n00007|
\n00008| )\n00009| }\n00010| \n\n(End of file - total 10 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/app/UserDashboard.tsx"
+ },
+ "output": "\n00001| export default function UserDashboard() {\n00002| // TODO: Implement user dashboard that needs to fetch user-specific data on each request\n00003| return (\n00004|
\n00005|
User Dashboard
\n00006|
User dashboard content goes here
\n00007|
\n00008| )\n00009| }\n00010| \n\n(End of file - total 10 lines)\n",
+ "title": "app/UserDashboard.tsx",
+ "metadata": {
+ "preview": "export default function UserDashboard() {\n // TODO: Implement user dashboard that needs to fetch user-specific data on each request\n return (\n
\n )\n }\n",
+ "filediff": {
+ "file": "/workspace/app/UserDashboard.tsx",
+ "before": "export default function UserDashboard() {\n // TODO: Implement user dashboard that needs to fetch user-specific data on each request\n return (\n
\n
User Dashboard
\n
User dashboard content goes here
\n
\n )\n}\n",
+ "after": "export default async function UserDashboard() {\n const res = await fetch('https://api.example.com/user/preferences', {\n cache: 'no-store',\n })\n\n if (!res.ok) {\n return (\n
\n )\n }\n",
+ "filediff": {
+ "file": "/workspace/app/UserDashboard.tsx",
+ "before": "export default function UserDashboard() {\n // TODO: Implement user dashboard that needs to fetch user-specific data on each request\n return (\n
\n
User Dashboard
\n
User dashboard content goes here
\n
\n )\n}\n",
+ "after": "export default async function UserDashboard() {\n const res = await fetch('https://api.example.com/user/preferences', {\n cache: 'no-store',\n })\n\n if (!res.ok) {\n return (\n
\n00023| )\n00024| }\n00025| \n\n(End of file - total 25 lines)\n","title":"app/UserStats.tsx","metadata":{"preview":"interface User {\n id: number\n name: string\n isActive: boolean\n}\n\ninterface UserStatsProps {\n users: User[]\n}\n\nexport default function UserStats({ users }: UserStatsProps) {\n // TODO: Display statistics about the users:\n // - Active users count\n // - Inactive users count\n // - Percentage of active users\n // Follow the existing patterns in this codebase for derived values\n\n return (\n
\n )\n}\n",
+ "additions": 8,
+ "deletions": 6
+ }
+ },
+ "time": {
+ "start": 1781392533816,
+ "end": 1781392534450
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:48.042Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "shell",
+ "originalName": "bash",
+ "args": {
+ "command": "npm run build",
+ "description": "Build the Next.js app to verify types",
+ "timeout": 120000,
+ "workdir": "/workspace",
+ "_extractedCommand": "npm run build"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392548042,
+ "sessionID": "ses_13cbb7a28ffeGu7KKC605L5wR8",
+ "part": {
+ "id": "prt_ec344f358001qQhAMsoG255mA3",
+ "sessionID": "ses_13cbb7a28ffeGu7KKC605L5wR8",
+ "messageID": "msg_ec344ebcb001xPWvHHZYsFlBln",
+ "type": "tool",
+ "callID": "bash_8",
+ "tool": "bash",
+ "state": {
+ "status": "completed",
+ "input": {
+ "command": "npm run build",
+ "description": "Build the Next.js app to verify types",
+ "timeout": 120000,
+ "workdir": "/workspace"
+ },
+ "output": "\n> build\n> next build\n\nAttention: Next.js now collects completely anonymous telemetry regarding usage.\nThis information is used to shape Next.js' roadmap and prioritize features.\nYou can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:\nhttps://nextjs.org/telemetry\n\n▲ Next.js 16.3.0-canary.50 (Turbopack)\n\n Creating an optimized production build ...\n✓ Compiled successfully in 6.0s\n Running TypeScript ...\n\n We detected TypeScript in your project and reconfigured your tsconfig.json file for you.\n The following suggested values were added to your tsconfig.json. These values can be changed to fit your project's needs:\n\n \t- include was updated to add '.next/dev/types/**/*.ts'\n\n Finished TypeScript in 2.3s ...\n Collecting page data using 1 worker ...\n Generating static pages using 1 worker (0/3) ...\n✓ Generating static pages using 1 worker (3/3) in 134ms\n Finalizing page optimization ...\n\nRoute (app)\n┌ ○ /\n└ ○ /_not-found\n\n\n○ (Static) prerendered as static content\n\n",
+ "title": "Build the Next.js app to verify types",
+ "metadata": {
+ "output": "\n> build\n> next build\n\nAttention: Next.js now collects completely anonymous telemetry regarding usage.\nThis information is used to shape Next.js' roadmap and prioritize features.\nYou can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:\nhttps://nextjs.org/telemetry\n\n▲ Next.js 16.3.0-canary.50 (Turbopack)\n\n Creating an optimized production build ...\n✓ Compiled successfully in 6.0s\n Running TypeScript ...\n\n We detected TypeScript in your project and reconfigured your tsconfig.json file for you.\n The following suggested values were added to your tsconfig.json. These values can be changed to fit your project's needs:\n\n \t- include was updated to add '.next/dev/types/**/*.ts'\n\n Finished TypeScript in 2.3s ...\n Collecting page data using 1 worker ...\n Generating static pages using 1 worker (0/3) ...\n✓ Generating static pages using 1 worker (3/3) in 134ms\n Finalizing page optimization ...\n\nRoute (app)\n┌ ○ /\n└ ○ /_not-found\n\n\n○ (Static) prerendered as static content\n\n",
+ "exit": 0,
+ "description": "Build the Next.js app to verify types"
+ },
+ "time": {
+ "start": 1781392536922,
+ "end": 1781392548036
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:48.042Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "shell",
+ "originalName": "bash",
+ "result": "\n> build\n> next build\n\nAttention: Next.js now collects completely anonymous telemetry regarding usage.\nThis information is used to shape Next.js' roadmap and prioritize features.\nYou can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:\nhttps://nextjs.org/telemetry\n\n▲ Next.js 16.3.0-canary.50 (Turbopack)\n\n Creating an optimized production build ...\n✓ Compiled successfully in 6.0s\n Running TypeScript ...\n\n We detected TypeScript in your project and reconfigured your tsconfig.json file for you.\n The following suggested values were added to your tsconfig.json. These values can be changed to fit your project's needs:\n\n \t- include was updated to add '.next/dev/types/**/*.ts'\n\n Finished TypeScript in 2.3s ...\n Collecting page data using 1 worker ...\n Generating static pages using 1 worker (0/3) ...\n✓ Generating static pages using 1 worker (3/3) in 134ms\n Finalizing page optimization ...\n\nRoute (app)\n┌ ○ /\n└ ○ /_not-found\n\n\n○ (Static) prerendered as static content\n\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "command": "npm run build",
+ "description": "Build the Next.js app to verify types",
+ "timeout": 120000,
+ "workdir": "/workspace"
+ },
+ "output": "\n> build\n> next build\n\nAttention: Next.js now collects completely anonymous telemetry regarding usage.\nThis information is used to shape Next.js' roadmap and prioritize features.\nYou can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:\nhttps://nextjs.org/telemetry\n\n▲ Next.js 16.3.0-canary.50 (Turbopack)\n\n Creating an optimized production build ...\n✓ Compiled successfully in 6.0s\n Running TypeScript ...\n\n We detected TypeScript in your project and reconfigured your tsconfig.json file for you.\n The following suggested values were added to your tsconfig.json. These values can be changed to fit your project's needs:\n\n \t- include was updated to add '.next/dev/types/**/*.ts'\n\n Finished TypeScript in 2.3s ...\n Collecting page data using 1 worker ...\n Generating static pages using 1 worker (0/3) ...\n✓ Generating static pages using 1 worker (3/3) in 134ms\n Finalizing page optimization ...\n\nRoute (app)\n┌ ○ /\n└ ○ /_not-found\n\n\n○ (Static) prerendered as static content\n\n",
+ "title": "Build the Next.js app to verify types",
+ "metadata": {
+ "output": "\n> build\n> next build\n\nAttention: Next.js now collects completely anonymous telemetry regarding usage.\nThis information is used to shape Next.js' roadmap and prioritize features.\nYou can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:\nhttps://nextjs.org/telemetry\n\n▲ Next.js 16.3.0-canary.50 (Turbopack)\n\n Creating an optimized production build ...\n✓ Compiled successfully in 6.0s\n Running TypeScript ...\n\n We detected TypeScript in your project and reconfigured your tsconfig.json file for you.\n The following suggested values were added to your tsconfig.json. These values can be changed to fit your project's needs:\n\n \t- include was updated to add '.next/dev/types/**/*.ts'\n\n Finished TypeScript in 2.3s ...\n Collecting page data using 1 worker ...\n Generating static pages using 1 worker (0/3) ...\n✓ Generating static pages using 1 worker (3/3) in 134ms\n Finalizing page optimization ...\n\nRoute (app)\n┌ ○ /\n└ ○ /_not-found\n\n\n○ (Static) prerendered as static content\n\n",
+ "exit": 0,
+ "description": "Build the Next.js app to verify types"
+ },
+ "time": {
+ "start": 1781392536922,
+ "end": 1781392548036
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:50.107Z",
+ "type": "message",
+ "role": "assistant",
+ "content": "Completed `app/UserStats.tsx` with derived counts for active/inactive users and active percentage, matching the direct-calculation pattern in `page.tsx`.\n\nBuild passes.",
+ "raw": {
+ "type": "text",
+ "timestamp": 1781392550107,
+ "sessionID": "ses_13cbb7a28ffeGu7KKC605L5wR8",
+ "part": {
+ "id": "prt_ec34526e6001PpBaySv5XokWRq",
+ "sessionID": "ses_13cbb7a28ffeGu7KKC605L5wR8",
+ "messageID": "msg_ec345214b00107016kqbNouUur",
+ "type": "text",
+ "text": "Completed `app/UserStats.tsx` with derived counts for active/inactive users and active percentage, matching the direct-calculation pattern in `page.tsx`.\n\nBuild passes.",
+ "time": {
+ "start": 1781392550104,
+ "end": 1781392550104
+ }
+ }
+ }
+ }
+ ],
+ "summary": {
+ "totalTurns": 1,
+ "toolCalls": {
+ "file_read": 4,
+ "file_write": 0,
+ "file_edit": 1,
+ "shell": 1,
+ "web_fetch": 0,
+ "web_search": 0,
+ "glob": 3,
+ "grep": 0,
+ "list_dir": 0,
+ "agent_task": 0,
+ "unknown": 0
+ },
+ "totalToolCalls": 9,
+ "webFetches": [],
+ "filesRead": [
+ "/workspace/app/UserStats.tsx",
+ "/workspace/app/page.tsx",
+ "/workspace/package.json",
+ "/workspace/app/layout.tsx"
+ ],
+ "filesModified": [
+ "/workspace/app/UserStats.tsx"
+ ],
+ "shellCommands": [
+ {
+ "command": "npm run build",
+ "success": true
+ }
+ ],
+ "errors": [],
+ "thinkingBlocks": 0
+ },
+ "parseSuccess": true
+}
\ No newline at end of file
diff --git a/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-024-avoid-redundant-usestate/summary.json b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-024-avoid-redundant-usestate/summary.json
new file mode 100644
index 000000000..1d799c0a6
--- /dev/null
+++ b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-024-avoid-redundant-usestate/summary.json
@@ -0,0 +1,7 @@
+{
+ "totalRuns": 1,
+ "passedRuns": 1,
+ "passRate": "100%",
+ "meanDuration": 155.875,
+ "fingerprint": "12f93c5235d5ee2fadc730311825ef7d7f5a3c5c70d807339ca6e841e5242e32"
+}
\ No newline at end of file
diff --git a/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-025-prefer-next-link/run-1/outputs/eval.txt b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-025-prefer-next-link/run-1/outputs/eval.txt
new file mode 100644
index 000000000..c9f81bea1
--- /dev/null
+++ b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-025-prefer-next-link/run-1/outputs/eval.txt
@@ -0,0 +1,10 @@
+
+ RUN v3.2.6 /workspace
+
+ ✓ EVAL.ts (2 tests) 2ms
+
+ Test Files 1 passed (1)
+ Tests 2 passed (2)
+ Start at 23:15:29
+ Duration 210ms (transform 33ms, setup 0ms, collect 27ms, tests 2ms, environment 0ms, prepare 73ms)
+
diff --git a/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-025-prefer-next-link/run-1/outputs/scripts/build.txt b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-025-prefer-next-link/run-1/outputs/scripts/build.txt
new file mode 100644
index 000000000..85e923f27
--- /dev/null
+++ b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-025-prefer-next-link/run-1/outputs/scripts/build.txt
@@ -0,0 +1,33 @@
+
+> build
+> next build
+
+Attention: Next.js now collects completely anonymous telemetry regarding usage.
+This information is used to shape Next.js' roadmap and prioritize features.
+You can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:
+https://nextjs.org/telemetry
+
+▲ Next.js 16.3.0-canary.50 (Turbopack)
+
+ Creating an optimized production build ...
+✓ Compiled successfully in 4.5s
+ Running TypeScript ...
+
+ We detected TypeScript in your project and reconfigured your tsconfig.json file for you.
+ The following suggested values were added to your tsconfig.json. These values can be changed to fit your project's needs:
+
+ - include was updated to add '.next/dev/types/**/*.ts'
+
+ Finished TypeScript in 1722ms ...
+ Collecting page data using 1 worker ...
+ Generating static pages using 1 worker (0/3) ...
+✓ Generating static pages using 1 worker (3/3) in 125ms
+ Finalizing page optimization ...
+
+Route (app)
+┌ ○ /
+└ ○ /_not-found
+
+
+○ (Static) prerendered as static content
+
diff --git a/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-025-prefer-next-link/run-1/result.json b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-025-prefer-next-link/run-1/result.json
new file mode 100644
index 000000000..fe54bd60a
--- /dev/null
+++ b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-025-prefer-next-link/run-1/result.json
@@ -0,0 +1,40 @@
+{
+ "status": "passed",
+ "duration": 155.426,
+ "model": "vercel/moonshotai/kimi-k2.7-code",
+ "transcriptPath": "./transcript.json",
+ "transcriptRawPath": "./transcript-raw.jsonl",
+ "o11y": {
+ "totalTurns": 1,
+ "toolCalls": {
+ "file_read": 1,
+ "file_write": 0,
+ "file_edit": 1,
+ "shell": 0,
+ "web_fetch": 0,
+ "web_search": 0,
+ "glob": 2,
+ "grep": 2,
+ "list_dir": 0,
+ "agent_task": 0,
+ "unknown": 0
+ },
+ "totalToolCalls": 6,
+ "webFetches": [],
+ "filesRead": [
+ "/workspace/app/Navigation.tsx"
+ ],
+ "filesModified": [
+ "/workspace/app/Navigation.tsx"
+ ],
+ "shellCommands": [],
+ "errors": [],
+ "thinkingBlocks": 0
+ },
+ "outputPaths": {
+ "eval": "./outputs/eval.txt",
+ "scripts": {
+ "build": "./outputs/scripts/build.txt"
+ }
+ }
+}
\ No newline at end of file
diff --git a/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-025-prefer-next-link/run-1/transcript-raw.jsonl b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-025-prefer-next-link/run-1/transcript-raw.jsonl
new file mode 100644
index 000000000..011ed9678
--- /dev/null
+++ b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-025-prefer-next-link/run-1/transcript-raw.jsonl
@@ -0,0 +1,17 @@
+{"type":"step_start","timestamp":1781392505435,"sessionID":"ses_13cbb8b9cffes2DOFtzi58nHHn","part":{"id":"prt_ec3447a55001QvZr3sPnRZPqu0","sessionID":"ses_13cbb8b9cffes2DOFtzi58nHHn","messageID":"msg_ec34474b8001vhZr02eQ63tavq","type":"step-start","snapshot":"2933401aab9f55599210be1d364bf689a8618909"}}
+{"type":"tool_use","timestamp":1781392506432,"sessionID":"ses_13cbb8b9cffes2DOFtzi58nHHn","part":{"id":"prt_ec3447ccf001IC6X3oiG6NiWUp","sessionID":"ses_13cbb8b9cffes2DOFtzi58nHHn","messageID":"msg_ec34474b8001vhZr02eQ63tavq","type":"tool","callID":"glob_0","tool":"glob","state":{"status":"completed","input":{"pattern":"**/Navigation*"},"output":"/workspace/app/Navigation.tsx","title":"","metadata":{"count":1,"truncated":false},"time":{"start":1781392506423,"end":1781392506429}}}}
+{"type":"tool_use","timestamp":1781392506580,"sessionID":"ses_13cbb8b9cffes2DOFtzi58nHHn","part":{"id":"prt_ec3447e3a001HnGIyrYBOokSzs","sessionID":"ses_13cbb8b9cffes2DOFtzi58nHHn","messageID":"msg_ec34474b8001vhZr02eQ63tavq","type":"tool","callID":"grep_1","tool":"grep","state":{"status":"completed","input":{"pattern":"Navigation","include":"*.tsx"},"output":"Found 4 matches\n/workspace/app/page.tsx:\n Line 2: import Navigation from './Navigation'\n Line 16: \n\n/workspace/app/Navigation.tsx:\n Line 1: export default function Navigation() {\n Line 7:
\n00005| {/* TODO: Add navigation links to /blog, /products, and /support pages */}\n00006| {/* Follow the existing patterns in this codebase */}\n00007|
Navigation links will go here
\n00008|
\n00009| )\n00010| }\n00011| \n\n(End of file - total 11 lines)\n","title":"app/Navigation.tsx","metadata":{"preview":"export default function Navigation() {\n return (\n
\n
More Pages
\n {/* TODO: Add navigation links to /blog, /products, and /support pages */}\n {/* Follow the existing patterns in this codebase */}\n
Navigation links will go here
\n
\n )\n}\n"},"time":{"start":1781392508303,"end":1781392508307}}}}
+{"type":"step_finish","timestamp":1781392508325,"sessionID":"ses_13cbb8b9cffes2DOFtzi58nHHn","part":{"id":"prt_ec3448595001v634rzMvBJeUUc","sessionID":"ses_13cbb8b9cffes2DOFtzi58nHHn","messageID":"msg_ec3447ee7001sYHsNd6Pvl6y2a","type":"step-finish","reason":"tool-calls","snapshot":"2933401aab9f55599210be1d364bf689a8618909","cost":0.00201816,"tokens":{"input":408,"output":39,"reasoning":0,"cache":{"read":9216,"write":0}}}}
+{"type":"step_start","timestamp":1781392509944,"sessionID":"ses_13cbb8b9cffes2DOFtzi58nHHn","part":{"id":"prt_ec3448be9001DrW5V2rBO4ZtDO","sessionID":"ses_13cbb8b9cffes2DOFtzi58nHHn","messageID":"msg_ec34485b5001jlrpJ6K1oyO1tQ","type":"step-start","snapshot":"2933401aab9f55599210be1d364bf689a8618909"}}
+{"type":"tool_use","timestamp":1781392512313,"sessionID":"ses_13cbb8b9cffes2DOFtzi58nHHn","part":{"id":"prt_ec34491fc001mSOh8XAWxEs24c","sessionID":"ses_13cbb8b9cffes2DOFtzi58nHHn","messageID":"msg_ec34485b5001jlrpJ6K1oyO1tQ","type":"tool","callID":"grep_3","tool":"grep","state":{"status":"completed","input":{"pattern":"Link|href=|a href|next/link","include":"*.tsx"},"output":"Found 3 matches\n/workspace/app/page.tsx:\n Line 1: import Link from 'next/link'\n Line 10: About Us\n Line 11: Contact","title":"Link|href=|a href|next/link","metadata":{"matches":3,"truncated":false},"time":{"start":1781392512306,"end":1781392512310}}}}
+{"type":"tool_use","timestamp":1781392512621,"sessionID":"ses_13cbb8b9cffes2DOFtzi58nHHn","part":{"id":"prt_ec3449533001swYxi9prAJNc1e","sessionID":"ses_13cbb8b9cffes2DOFtzi58nHHn","messageID":"msg_ec34485b5001jlrpJ6K1oyO1tQ","type":"tool","callID":"glob_4","tool":"glob","state":{"status":"completed","input":{"pattern":"app/**/*.tsx"},"output":"/workspace/app/page.tsx\n/workspace/app/layout.tsx\n/workspace/app/Navigation.tsx","title":"","metadata":{"count":3,"truncated":false},"time":{"start":1781392512615,"end":1781392512620}}}}
+{"type":"step_finish","timestamp":1781392512624,"sessionID":"ses_13cbb8b9cffes2DOFtzi58nHHn","part":{"id":"prt_ec344966c001LD50cLfHiyRZW1","sessionID":"ses_13cbb8b9cffes2DOFtzi58nHHn","messageID":"msg_ec34485b5001jlrpJ6K1oyO1tQ","type":"step-finish","reason":"tool-calls","snapshot":"2933401aab9f55599210be1d364bf689a8618909","cost":0.00217417,"tokens":{"input":327,"output":87,"reasoning":0,"cache":{"read":9472,"write":0}}}}
+{"type":"step_start","timestamp":1781392514147,"sessionID":"ses_13cbb8b9cffes2DOFtzi58nHHn","part":{"id":"prt_ec3449c5b001fEr4GHVU5QOyqo","sessionID":"ses_13cbb8b9cffes2DOFtzi58nHHn","messageID":"msg_ec3449678001CB9tAOmFFlK9sO","type":"step-start","snapshot":"2933401aab9f55599210be1d364bf689a8618909"}}
+{"type":"tool_use","timestamp":1781392523908,"sessionID":"ses_13cbb8b9cffes2DOFtzi58nHHn","part":{"id":"prt_ec344a188001Ff73cX4e2cwsPD","sessionID":"ses_13cbb8b9cffes2DOFtzi58nHHn","messageID":"msg_ec3449678001CB9tAOmFFlK9sO","type":"tool","callID":"edit_5","tool":"edit","state":{"status":"completed","input":{"filePath":"/workspace/app/Navigation.tsx","oldString":"export default function Navigation() {\n return (\n
\n
More Pages
\n {/* TODO: Add navigation links to /blog, /products, and /support pages */}\n {/* Follow the existing patterns in this codebase */}\n
Navigation links will go here
\n
\n )\n}","newString":"import Link from 'next/link'\n\nexport default function Navigation() {\n return (\n
\n
More Pages
\n Blog\n Products\n Support\n
\n )\n}"},"output":"","title":"app/Navigation.tsx","metadata":{"diagnostics":{"/workspace/app/Navigation.tsx":[]},"diff":"Index: /workspace/app/Navigation.tsx\n===================================================================\n--- /workspace/app/Navigation.tsx\n+++ /workspace/app/Navigation.tsx\n@@ -1,10 +1,12 @@\n+import Link from 'next/link'\n+\n export default function Navigation() {\n return (\n
\n
More Pages
\n- {/* TODO: Add navigation links to /blog, /products, and /support pages */}\n- {/* Follow the existing patterns in this codebase */}\n-
Navigation links will go here
\n+ Blog\n+ Products\n+ Support\n
\n )\n }\n","filediff":{"file":"/workspace/app/Navigation.tsx","before":"export default function Navigation() {\n return (\n
\n
More Pages
\n {/* TODO: Add navigation links to /blog, /products, and /support pages */}\n {/* Follow the existing patterns in this codebase */}\n
Navigation links will go here
\n
\n )\n}\n","after":"import Link from 'next/link'\n\nexport default function Navigation() {\n return (\n
\n00005| {/* TODO: Add navigation links to /blog, /products, and /support pages */}\n00006| {/* Follow the existing patterns in this codebase */}\n00007|
Navigation links will go here
\n00008|
\n00009| )\n00010| }\n00011| \n\n(End of file - total 11 lines)\n",
+ "title": "app/Navigation.tsx",
+ "metadata": {
+ "preview": "export default function Navigation() {\n return (\n
\n
More Pages
\n {/* TODO: Add navigation links to /blog, /products, and /support pages */}\n {/* Follow the existing patterns in this codebase */}\n
\n00005| {/* TODO: Add navigation links to /blog, /products, and /support pages */}\n00006| {/* Follow the existing patterns in this codebase */}\n00007|
\n00005| {/* TODO: Add navigation links to /blog, /products, and /support pages */}\n00006| {/* Follow the existing patterns in this codebase */}\n00007|
Navigation links will go here
\n00008|
\n00009| )\n00010| }\n00011| \n\n(End of file - total 11 lines)\n",
+ "title": "app/Navigation.tsx",
+ "metadata": {
+ "preview": "export default function Navigation() {\n return (\n
\n
More Pages
\n {/* TODO: Add navigation links to /blog, /products, and /support pages */}\n {/* Follow the existing patterns in this codebase */}\n
\n {/* TODO: Add navigation links to /blog, /products, and /support pages */}\n {/* Follow the existing patterns in this codebase */}\n
Navigation links will go here
\n
\n )\n}\n",
+ "after": "import Link from 'next/link'\n\nexport default function Navigation() {\n return (\n
\n
More Pages
\n Blog\n Products\n Support\n
\n )\n}\n",
+ "additions": 5,
+ "deletions": 3
+ }
+ },
+ "time": {
+ "start": 1781392520888,
+ "end": 1781392523904
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:27.150Z",
+ "type": "message",
+ "role": "assistant",
+ "content": "Updated `/workspace/app/Navigation.tsx` to use `next/link` with links to `/blog`, `/products`, and `/support`, matching the existing pattern in `page.tsx`.",
+ "raw": {
+ "type": "text",
+ "timestamp": 1781392527150,
+ "sessionID": "ses_13cbb8b9cffes2DOFtzi58nHHn",
+ "part": {
+ "id": "prt_ec344cd360017FqkrkDYo7F5oI",
+ "sessionID": "ses_13cbb8b9cffes2DOFtzi58nHHn",
+ "messageID": "msg_ec344c291001bEpTcKDDqYfirU",
+ "type": "text",
+ "text": "Updated `/workspace/app/Navigation.tsx` to use `next/link` with links to `/blog`, `/products`, and `/support`, matching the existing pattern in `page.tsx`.",
+ "time": {
+ "start": 1781392527148,
+ "end": 1781392527148
+ }
+ }
+ }
+ }
+ ],
+ "summary": {
+ "totalTurns": 1,
+ "toolCalls": {
+ "file_read": 1,
+ "file_write": 0,
+ "file_edit": 1,
+ "shell": 0,
+ "web_fetch": 0,
+ "web_search": 0,
+ "glob": 2,
+ "grep": 2,
+ "list_dir": 0,
+ "agent_task": 0,
+ "unknown": 0
+ },
+ "totalToolCalls": 6,
+ "webFetches": [],
+ "filesRead": [
+ "/workspace/app/Navigation.tsx"
+ ],
+ "filesModified": [
+ "/workspace/app/Navigation.tsx"
+ ],
+ "shellCommands": [],
+ "errors": [],
+ "thinkingBlocks": 0
+ },
+ "parseSuccess": true
+}
\ No newline at end of file
diff --git a/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-025-prefer-next-link/summary.json b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-025-prefer-next-link/summary.json
new file mode 100644
index 000000000..d4a43391e
--- /dev/null
+++ b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-025-prefer-next-link/summary.json
@@ -0,0 +1,7 @@
+{
+ "totalRuns": 1,
+ "passedRuns": 1,
+ "passRate": "100%",
+ "meanDuration": 155.426,
+ "fingerprint": "e8ff8ca7606c3747e60583e63dfd61196fe60c18b51fb01d144df287480a6d1d"
+}
\ No newline at end of file
diff --git a/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-026-no-serial-await/run-1/outputs/eval.txt b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-026-no-serial-await/run-1/outputs/eval.txt
new file mode 100644
index 000000000..252064b78
--- /dev/null
+++ b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-026-no-serial-await/run-1/outputs/eval.txt
@@ -0,0 +1,10 @@
+
+ RUN v3.2.6 /workspace
+
+ ✓ EVAL.ts (5 tests) 4ms
+
+ Test Files 1 passed (1)
+ Tests 5 passed (5)
+ Start at 23:16:20
+ Duration 333ms (transform 43ms, setup 0ms, collect 29ms, tests 4ms, environment 0ms, prepare 117ms)
+
diff --git a/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-026-no-serial-await/run-1/outputs/scripts/build.txt b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-026-no-serial-await/run-1/outputs/scripts/build.txt
new file mode 100644
index 000000000..5835d3791
--- /dev/null
+++ b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-026-no-serial-await/run-1/outputs/scripts/build.txt
@@ -0,0 +1,34 @@
+
+> build
+> next build
+
+Attention: Next.js now collects completely anonymous telemetry regarding usage.
+This information is used to shape Next.js' roadmap and prioritize features.
+You can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:
+https://nextjs.org/telemetry
+
+▲ Next.js 16.3.0-canary.50 (Turbopack)
+
+ Creating an optimized production build ...
+✓ Compiled successfully in 6.2s
+ Running TypeScript ...
+
+ We detected TypeScript in your project and reconfigured your tsconfig.json file for you.
+ The following suggested values were added to your tsconfig.json. These values can be changed to fit your project's needs:
+
+ - include was updated to add '.next/dev/types/**/*.ts'
+
+ Finished TypeScript in 3.0s ...
+ Collecting page data using 1 worker ...
+ Generating static pages using 1 worker (0/3) ...
+✓ Generating static pages using 1 worker (3/3) in 167ms
+ Finalizing page optimization ...
+
+Route (app)
+┌ ƒ /
+└ ○ /_not-found
+
+
+○ (Static) prerendered as static content
+ƒ (Dynamic) server-rendered on demand
+
diff --git a/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-026-no-serial-await/run-1/result.json b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-026-no-serial-await/run-1/result.json
new file mode 100644
index 000000000..ab9ba0394
--- /dev/null
+++ b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-026-no-serial-await/run-1/result.json
@@ -0,0 +1,49 @@
+{
+ "status": "passed",
+ "duration": 203.553,
+ "model": "vercel/moonshotai/kimi-k2.7-code",
+ "transcriptPath": "./transcript.json",
+ "transcriptRawPath": "./transcript-raw.jsonl",
+ "o11y": {
+ "totalTurns": 1,
+ "toolCalls": {
+ "file_read": 6,
+ "file_write": 1,
+ "file_edit": 1,
+ "shell": 1,
+ "web_fetch": 0,
+ "web_search": 0,
+ "glob": 2,
+ "grep": 0,
+ "list_dir": 0,
+ "agent_task": 0,
+ "unknown": 0
+ },
+ "totalToolCalls": 11,
+ "webFetches": [],
+ "filesRead": [
+ "/workspace/app/Dashboard.tsx",
+ "/workspace/app/page.tsx",
+ "/workspace/app/layout.tsx",
+ "/workspace/next.config.ts",
+ "/workspace/package.json"
+ ],
+ "filesModified": [
+ "/workspace/app/Dashboard.tsx"
+ ],
+ "shellCommands": [
+ {
+ "command": "npx tsc --noEmit",
+ "success": true
+ }
+ ],
+ "errors": [],
+ "thinkingBlocks": 0
+ },
+ "outputPaths": {
+ "eval": "./outputs/eval.txt",
+ "scripts": {
+ "build": "./outputs/scripts/build.txt"
+ }
+ }
+}
\ No newline at end of file
diff --git a/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-026-no-serial-await/run-1/transcript-raw.jsonl b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-026-no-serial-await/run-1/transcript-raw.jsonl
new file mode 100644
index 000000000..b806e0a0e
--- /dev/null
+++ b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-026-no-serial-await/run-1/transcript-raw.jsonl
@@ -0,0 +1,28 @@
+{"type":"step_start","timestamp":1781392513655,"sessionID":"ses_13cbb6c1cffeLijxVNLOvDvTZ1","part":{"id":"prt_ec3449a6b001kiHNsHLY9VzFSl","sessionID":"ses_13cbb6c1cffeLijxVNLOvDvTZ1","messageID":"msg_ec3449459001cdahAuFR7AdFPP","type":"step-start","snapshot":"e709c2472f93f6107d3d31a7612eb14332b74444"}}
+{"type":"tool_use","timestamp":1781392514772,"sessionID":"ses_13cbb6c1cffeLijxVNLOvDvTZ1","part":{"id":"prt_ec3449dfb001fW1uZGekBccfHR","sessionID":"ses_13cbb6c1cffeLijxVNLOvDvTZ1","messageID":"msg_ec3449459001cdahAuFR7AdFPP","type":"tool","callID":"glob_0","tool":"glob","state":{"status":"completed","input":{"pattern":"**/*.{ts,tsx,js,jsx}"},"output":"/workspace/app/page.tsx\n/workspace/app/layout.tsx\n/workspace/app/Dashboard.tsx\n/workspace/next.config.ts","title":"","metadata":{"count":4,"truncated":false},"time":{"start":1781392514754,"end":1781392514765}}}}
+{"type":"step_finish","timestamp":1781392514800,"sessionID":"ses_13cbb6c1cffeLijxVNLOvDvTZ1","part":{"id":"prt_ec3449ed2001DeMVEa6ehrEIcc","sessionID":"ses_13cbb6c1cffeLijxVNLOvDvTZ1","messageID":"msg_ec3449459001cdahAuFR7AdFPP","type":"step-finish","reason":"tool-calls","snapshot":"e709c2472f93f6107d3d31a7612eb14332b74444","cost":0.00177936,"tokens":{"input":0,"output":66,"reasoning":0,"cache":{"read":9471,"write":0}}}}
+{"type":"step_start","timestamp":1781392516630,"sessionID":"ses_13cbb6c1cffeLijxVNLOvDvTZ1","part":{"id":"prt_ec344a60e001TJ6cHoNRhInN5Q","sessionID":"ses_13cbb6c1cffeLijxVNLOvDvTZ1","messageID":"msg_ec3449f04001qmozDDFhaFRldO","type":"step-start","snapshot":"e709c2472f93f6107d3d31a7612eb14332b74444"}}
+{"type":"tool_use","timestamp":1781392517509,"sessionID":"ses_13cbb6c1cffeLijxVNLOvDvTZ1","part":{"id":"prt_ec344a7cc001yhE6ZJmjc6ZgbE","sessionID":"ses_13cbb6c1cffeLijxVNLOvDvTZ1","messageID":"msg_ec3449f04001qmozDDFhaFRldO","type":"tool","callID":"read_1","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/app/Dashboard.tsx"},"output":"\n00001| export default async function Dashboard() {\n00002| // TODO: This component needs to fetch data from multiple APIs:\n00003| // - /api/analytics\n00004| // - /api/notifications\n00005| // - /api/settings\n00006| // Follow the existing patterns in this codebase for data fetching\n00007| \n00008| return (\n00009|
\n00010|
Dashboard Content
\n00011|
Dashboard data will go here
\n00012|
\n00013| )\n00014| }\n00015| \n\n(End of file - total 15 lines)\n","title":"app/Dashboard.tsx","metadata":{"preview":"export default async function Dashboard() {\n // TODO: This component needs to fetch data from multiple APIs:\n // - /api/analytics\n // - /api/notifications\n // - /api/settings\n // Follow the existing patterns in this codebase for data fetching\n\n return (\n
\n00013| )\n00014| }\n00015| \n\n(End of file - total 15 lines)\n",
+ "title": "app/Dashboard.tsx",
+ "metadata": {
+ "preview": "export default async function Dashboard() {\n // TODO: This component needs to fetch data from multiple APIs:\n // - /api/analytics\n // - /api/notifications\n // - /api/settings\n // Follow the existing patterns in this codebase for data fetching\n\n return (\n
\n
Dashboard Content
\n
Dashboard data will go here
\n
\n )\n}\n"
+ },
+ "time": {
+ "start": 1781392517480,
+ "end": 1781392517486
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:17.509Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| export default async function Dashboard() {\n00002| // TODO: This component needs to fetch data from multiple APIs:\n00003| // - /api/analytics\n00004| // - /api/notifications\n00005| // - /api/settings\n00006| // Follow the existing patterns in this codebase for data fetching\n00007| \n00008| return (\n00009|
\n00010|
Dashboard Content
\n00011|
Dashboard data will go here
\n00012|
\n00013| )\n00014| }\n00015| \n\n(End of file - total 15 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/app/Dashboard.tsx"
+ },
+ "output": "\n00001| export default async function Dashboard() {\n00002| // TODO: This component needs to fetch data from multiple APIs:\n00003| // - /api/analytics\n00004| // - /api/notifications\n00005| // - /api/settings\n00006| // Follow the existing patterns in this codebase for data fetching\n00007| \n00008| return (\n00009|
\n00010|
Dashboard Content
\n00011|
Dashboard data will go here
\n00012|
\n00013| )\n00014| }\n00015| \n\n(End of file - total 15 lines)\n",
+ "title": "app/Dashboard.tsx",
+ "metadata": {
+ "preview": "export default async function Dashboard() {\n // TODO: This component needs to fetch data from multiple APIs:\n // - /api/analytics\n // - /api/notifications\n // - /api/settings\n // Follow the existing patterns in this codebase for data fetching\n\n return (\n
\n {/* TODO: Display the product images with their names */}\n {/* Follow the existing patterns in this codebase for images */}\n
\n {products.map((product) => (\n
\n
{product.name}
\n {/* Add product image here */}\n
\n ))}\n
"},"time":{"start":1781392520972,"end":1781392520988}}}}
+{"type":"tool_use","timestamp":1781392521370,"sessionID":"ses_13cbb6c7fffeZg0PAKbCIdQJN5","part":{"id":"prt_ec344b714001wRzaiJlv8POstK","sessionID":"ses_13cbb6c7fffeZg0PAKbCIdQJN5","messageID":"msg_ec344ab030011d1Y4ctdEnpqlI","type":"tool","callID":"read_4","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/app/page.tsx"},"output":"\n00001| import Image from 'next/image'\n00002| import ProductGallery from './ProductGallery'\n00003| \n00004| export default function Page() {\n00005| return (\n00006|
\n00007|
Welcome to Our Store
\n00008| \n00009| {/* Good example: using Next.js Image component */}\n00010| \n00017| \n00018| \n00019|
Featured Products
\n00020| \n00021| \n00022|
\n00023| )\n00024| }\n00025| \n\n(End of file - total 25 lines)\n","title":"app/page.tsx","metadata":{"preview":"import Image from 'next/image'\nimport ProductGallery from './ProductGallery'\n\nexport default function Page() {\n return (\n
\n
Welcome to Our Store
\n\n {/* Good example: using Next.js Image component */}\n \n\n \n
\n )\n}\n",
+ "additions": 8,
+ "deletions": 3
+ }
+ },
+ "time": {
+ "start": 1781392542762,
+ "end": 1781392545784
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:16:00.404Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "shell",
+ "originalName": "bash",
+ "args": {
+ "command": "npm run build",
+ "description": "Build Next.js app to verify changes",
+ "workdir": "/workspace",
+ "_extractedCommand": "npm run build"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392560404,
+ "sessionID": "ses_13cbb6c7fffeZg0PAKbCIdQJN5",
+ "part": {
+ "id": "prt_ec3452269001PQ5kLvJSnUbKsD",
+ "sessionID": "ses_13cbb6c7fffeZg0PAKbCIdQJN5",
+ "messageID": "msg_ec3451827001zWDMs1uRWyA0Mr",
+ "type": "tool",
+ "callID": "bash_11",
+ "tool": "bash",
+ "state": {
+ "status": "completed",
+ "input": {
+ "command": "npm run build",
+ "description": "Build Next.js app to verify changes",
+ "workdir": "/workspace"
+ },
+ "output": "\n> build\n> next build\n\nAttention: Next.js now collects completely anonymous telemetry regarding usage.\nThis information is used to shape Next.js' roadmap and prioritize features.\nYou can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:\nhttps://nextjs.org/telemetry\n\n▲ Next.js 16.3.0-canary.50 (Turbopack)\n\n Creating an optimized production build ...\n✓ Compiled successfully in 6.6s\n Running TypeScript ...\n\n We detected TypeScript in your project and reconfigured your tsconfig.json file for you.\n The following suggested values were added to your tsconfig.json. These values can be changed to fit your project's needs:\n\n \t- include was updated to add '.next/dev/types/**/*.ts'\n\n Finished TypeScript in 2.2s ...\n Collecting page data using 1 worker ...\n Generating static pages using 1 worker (0/3) ...\n✓ Generating static pages using 1 worker (3/3) in 139ms\n Finalizing page optimization ...\n\nRoute (app)\n┌ ○ /\n└ ○ /_not-found\n\n\n○ (Static) prerendered as static content\n\n",
+ "title": "Build Next.js app to verify changes",
+ "metadata": {
+ "output": "\n> build\n> next build\n\nAttention: Next.js now collects completely anonymous telemetry regarding usage.\nThis information is used to shape Next.js' roadmap and prioritize features.\nYou can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:\nhttps://nextjs.org/telemetry\n\n▲ Next.js 16.3.0-canary.50 (Turbopack)\n\n Creating an optimized production build ...\n✓ Compiled successfully in 6.6s\n Running TypeScript ...\n\n We detected TypeScript in your project and reconfigured your tsconfig.json file for you.\n The following suggested values were added to your tsconfig.json. These values can be changed to fit your project's needs:\n\n \t- include was updated to add '.next/dev/types/**/*.ts'\n\n Finished TypeScript in 2.2s ...\n Collecting page data using 1 worker ...\n Generating static pages using 1 worker (0/3) ...\n✓ Generating static pages using 1 worker (3/3) in 139ms\n Finalizing page optimization ...\n\nRoute (app)\n┌ ○ /\n└ ○ /_not-found\n\n\n○ (Static) prerendered as static content\n\n",
+ "exit": 0,
+ "description": "Build Next.js app to verify changes"
+ },
+ "time": {
+ "start": 1781392548771,
+ "end": 1781392560399
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:16:00.404Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "shell",
+ "originalName": "bash",
+ "result": "\n> build\n> next build\n\nAttention: Next.js now collects completely anonymous telemetry regarding usage.\nThis information is used to shape Next.js' roadmap and prioritize features.\nYou can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:\nhttps://nextjs.org/telemetry\n\n▲ Next.js 16.3.0-canary.50 (Turbopack)\n\n Creating an optimized production build ...\n✓ Compiled successfully in 6.6s\n Running TypeScript ...\n\n We detected TypeScript in your project and reconfigured your tsconfig.json file for you.\n The following suggested values were added to your tsconfig.json. These values can be changed to fit your project's needs:\n\n \t- include was updated to add '.next/dev/types/**/*.ts'\n\n Finished TypeScript in 2.2s ...\n Collecting page data using 1 worker ...\n Generating static pages using 1 worker (0/3) ...\n✓ Generating static pages using 1 worker (3/3) in 139ms\n Finalizing page optimization ...\n\nRoute (app)\n┌ ○ /\n└ ○ /_not-found\n\n\n○ (Static) prerendered as static content\n\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "command": "npm run build",
+ "description": "Build Next.js app to verify changes",
+ "workdir": "/workspace"
+ },
+ "output": "\n> build\n> next build\n\nAttention: Next.js now collects completely anonymous telemetry regarding usage.\nThis information is used to shape Next.js' roadmap and prioritize features.\nYou can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:\nhttps://nextjs.org/telemetry\n\n▲ Next.js 16.3.0-canary.50 (Turbopack)\n\n Creating an optimized production build ...\n✓ Compiled successfully in 6.6s\n Running TypeScript ...\n\n We detected TypeScript in your project and reconfigured your tsconfig.json file for you.\n The following suggested values were added to your tsconfig.json. These values can be changed to fit your project's needs:\n\n \t- include was updated to add '.next/dev/types/**/*.ts'\n\n Finished TypeScript in 2.2s ...\n Collecting page data using 1 worker ...\n Generating static pages using 1 worker (0/3) ...\n✓ Generating static pages using 1 worker (3/3) in 139ms\n Finalizing page optimization ...\n\nRoute (app)\n┌ ○ /\n└ ○ /_not-found\n\n\n○ (Static) prerendered as static content\n\n",
+ "title": "Build Next.js app to verify changes",
+ "metadata": {
+ "output": "\n> build\n> next build\n\nAttention: Next.js now collects completely anonymous telemetry regarding usage.\nThis information is used to shape Next.js' roadmap and prioritize features.\nYou can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:\nhttps://nextjs.org/telemetry\n\n▲ Next.js 16.3.0-canary.50 (Turbopack)\n\n Creating an optimized production build ...\n✓ Compiled successfully in 6.6s\n Running TypeScript ...\n\n We detected TypeScript in your project and reconfigured your tsconfig.json file for you.\n The following suggested values were added to your tsconfig.json. These values can be changed to fit your project's needs:\n\n \t- include was updated to add '.next/dev/types/**/*.ts'\n\n Finished TypeScript in 2.2s ...\n Collecting page data using 1 worker ...\n Generating static pages using 1 worker (0/3) ...\n✓ Generating static pages using 1 worker (3/3) in 139ms\n Finalizing page optimization ...\n\nRoute (app)\n┌ ○ /\n└ ○ /_not-found\n\n\n○ (Static) prerendered as static content\n\n",
+ "exit": 0,
+ "description": "Build Next.js app to verify changes"
+ },
+ "time": {
+ "start": 1781392548771,
+ "end": 1781392560399
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:16:02.292Z",
+ "type": "message",
+ "role": "assistant",
+ "content": "Done. I updated `app/ProductGallery.tsx` to use `next/image` at 300x200 for each product image, matching the pattern in `app/page.tsx`. Build passes.",
+ "raw": {
+ "type": "text",
+ "timestamp": 1781392562292,
+ "sessionID": "ses_13cbb6c7fffeZg0PAKbCIdQJN5",
+ "part": {
+ "id": "prt_ec34556b8001Dk9Nz9MC4t2IS1",
+ "sessionID": "ses_13cbb6c7fffeZg0PAKbCIdQJN5",
+ "messageID": "msg_ec3455193001AV60UYSQ9oiq96",
+ "type": "text",
+ "text": "Done. I updated `app/ProductGallery.tsx` to use `next/image` at 300x200 for each product image, matching the pattern in `app/page.tsx`. Build passes.",
+ "time": {
+ "start": 1781392562290,
+ "end": 1781392562290
+ }
+ }
+ }
+ }
+ ],
+ "summary": {
+ "totalTurns": 1,
+ "toolCalls": {
+ "file_read": 4,
+ "file_write": 0,
+ "file_edit": 1,
+ "shell": 1,
+ "web_fetch": 0,
+ "web_search": 0,
+ "glob": 5,
+ "grep": 1,
+ "list_dir": 0,
+ "agent_task": 0,
+ "unknown": 0
+ },
+ "totalToolCalls": 12,
+ "webFetches": [],
+ "filesRead": [
+ "/workspace/app/ProductGallery.tsx",
+ "/workspace/app/page.tsx",
+ "/workspace/next.config.ts",
+ "/workspace/package.json"
+ ],
+ "filesModified": [
+ "/workspace/app/ProductGallery.tsx"
+ ],
+ "shellCommands": [
+ {
+ "command": "npm run build",
+ "success": true
+ }
+ ],
+ "errors": [],
+ "thinkingBlocks": 0
+ },
+ "parseSuccess": true
+}
\ No newline at end of file
diff --git a/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-027-prefer-next-image/summary.json b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-027-prefer-next-image/summary.json
new file mode 100644
index 000000000..4fc529b33
--- /dev/null
+++ b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-027-prefer-next-image/summary.json
@@ -0,0 +1,7 @@
+{
+ "totalRuns": 1,
+ "passedRuns": 1,
+ "passRate": "100%",
+ "meanDuration": 178.221,
+ "fingerprint": "0dc49dbebad9fbb9ed19cbbb8ca62b22d35c1ce5829f525b4ffdfa3816f171a1"
+}
\ No newline at end of file
diff --git a/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-028-prefer-next-font/run-1/outputs/eval.txt b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-028-prefer-next-font/run-1/outputs/eval.txt
new file mode 100644
index 000000000..4c8b724ae
--- /dev/null
+++ b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-028-prefer-next-font/run-1/outputs/eval.txt
@@ -0,0 +1,10 @@
+
+ RUN v3.2.6 /workspace
+
+ ✓ EVAL.ts (2 tests) 3ms
+
+ Test Files 1 passed (1)
+ Tests 2 passed (2)
+ Start at 23:16:07
+ Duration 267ms (transform 36ms, setup 0ms, collect 34ms, tests 3ms, environment 0ms, prepare 86ms)
+
diff --git a/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-028-prefer-next-font/run-1/outputs/scripts/build.txt b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-028-prefer-next-font/run-1/outputs/scripts/build.txt
new file mode 100644
index 000000000..6ece89c30
--- /dev/null
+++ b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-028-prefer-next-font/run-1/outputs/scripts/build.txt
@@ -0,0 +1,22 @@
+
+> build
+> next build
+
+▲ Next.js 16.3.0-canary.50 (Turbopack)
+
+ Creating an optimized production build ...
+✓ Compiled successfully in 5.5s
+ Running TypeScript ...
+ Finished TypeScript in 2.7s ...
+ Collecting page data using 1 worker ...
+ Generating static pages using 1 worker (0/3) ...
+✓ Generating static pages using 1 worker (3/3) in 139ms
+ Finalizing page optimization ...
+
+Route (app)
+┌ ○ /
+└ ○ /_not-found
+
+
+○ (Static) prerendered as static content
+
diff --git a/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-028-prefer-next-font/run-1/result.json b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-028-prefer-next-font/run-1/result.json
new file mode 100644
index 000000000..35a23b9f4
--- /dev/null
+++ b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-028-prefer-next-font/run-1/result.json
@@ -0,0 +1,58 @@
+{
+ "status": "passed",
+ "duration": 184.318,
+ "model": "vercel/moonshotai/kimi-k2.7-code",
+ "transcriptPath": "./transcript.json",
+ "transcriptRawPath": "./transcript-raw.jsonl",
+ "o11y": {
+ "totalTurns": 1,
+ "toolCalls": {
+ "file_read": 6,
+ "file_write": 0,
+ "file_edit": 1,
+ "shell": 3,
+ "web_fetch": 0,
+ "web_search": 0,
+ "glob": 4,
+ "grep": 0,
+ "list_dir": 0,
+ "agent_task": 0,
+ "unknown": 0
+ },
+ "totalToolCalls": 14,
+ "webFetches": [],
+ "filesRead": [
+ "/workspace/app/BlogHeader.tsx",
+ "/workspace/app/layout.tsx",
+ "/workspace/app/page.tsx",
+ "/workspace/package.json",
+ "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/02-components/font.md",
+ "/workspace/node_modules/next/dist/docs/02-pages/04-api-reference/01-components/font.md"
+ ],
+ "filesModified": [
+ "/workspace/app/BlogHeader.tsx"
+ ],
+ "shellCommands": [
+ {
+ "command": "ls node_modules/next/dist/docs/ 2>/dev/null || echo no docs dir",
+ "success": true
+ },
+ {
+ "command": "find node_modules/next/dist/docs -type f | xargs grep -l -i font 2>/dev/null | head -20",
+ "success": true
+ },
+ {
+ "command": "npm run build",
+ "success": true
+ }
+ ],
+ "errors": [],
+ "thinkingBlocks": 0
+ },
+ "outputPaths": {
+ "eval": "./outputs/eval.txt",
+ "scripts": {
+ "build": "./outputs/scripts/build.txt"
+ }
+ }
+}
\ No newline at end of file
diff --git a/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-028-prefer-next-font/run-1/transcript-raw.jsonl b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-028-prefer-next-font/run-1/transcript-raw.jsonl
new file mode 100644
index 000000000..221f2b8d4
--- /dev/null
+++ b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-028-prefer-next-font/run-1/transcript-raw.jsonl
@@ -0,0 +1,35 @@
+{"type":"step_start","timestamp":1781392510457,"sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","part":{"id":"prt_ec3448deb001LThHjz5UPu3vZq","sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","messageID":"msg_ec34485880012HEosVMNqrp5hn","type":"step-start","snapshot":"218f3678fd946d904d760881701ddb5ead0a0421"}}
+{"type":"tool_use","timestamp":1781392513424,"sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","part":{"id":"prt_ec3449708001saZLkd6CyaWScf","sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","messageID":"msg_ec34485880012HEosVMNqrp5hn","type":"tool","callID":"glob_0","tool":"glob","state":{"status":"completed","input":{"pattern":"**/BlogHeader*"},"output":"/workspace/app/BlogHeader.tsx","title":"","metadata":{"count":1,"truncated":false},"time":{"start":1781392513413,"end":1781392513422}}}}
+{"type":"tool_use","timestamp":1781392514019,"sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","part":{"id":"prt_ec344998c001c8N5nbomxN4k17","sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","messageID":"msg_ec34485880012HEosVMNqrp5hn","type":"tool","callID":"glob_1","tool":"glob","state":{"status":"completed","input":{"pattern":"**/*.{tsx,jsx,css,scss,json}"},"output":"/workspace/opencode.json\n/workspace/package-lock.json\n/workspace/package.json\n/workspace/app/page.tsx\n/workspace/app/layout.tsx\n/workspace/app/BlogHeader.tsx\n/workspace/tsconfig.json","title":"","metadata":{"count":7,"truncated":false},"time":{"start":1781392514004,"end":1781392514011}}}}
+{"type":"step_finish","timestamp":1781392514024,"sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","part":{"id":"prt_ec3449bde001M5NaxneOJjDBot","sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","messageID":"msg_ec34485880012HEosVMNqrp5hn","type":"step-finish","reason":"tool-calls","snapshot":"218f3678fd946d904d760881701ddb5ead0a0421","cost":0.00194592,"tokens":{"input":0,"output":108,"reasoning":0,"cache":{"read":9462,"write":0}}}}
+{"type":"step_start","timestamp":1781392515569,"sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","part":{"id":"prt_ec344a1e2001GEHBb8iHsFAlRM","sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","messageID":"msg_ec3449bfb001pmdm3T5eyF4Yl9","type":"step-start","snapshot":"218f3678fd946d904d760881701ddb5ead0a0421"}}
+{"type":"tool_use","timestamp":1781392516971,"sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","part":{"id":"prt_ec344a48e001MIKxDUuWT7gMKw","sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","messageID":"msg_ec3449bfb001pmdm3T5eyF4Yl9","type":"tool","callID":"read_2","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/app/BlogHeader.tsx"},"output":"\n00001| export default function BlogHeader() {\n00002| return (\n00003| \n00004|
My Personal Blog
\n00005|
Thoughts, ideas, and musings
\n00006| \n00007| )\n00008| }\n00009| \n\n(End of file - total 9 lines)\n","title":"app/BlogHeader.tsx","metadata":{"preview":"export default function BlogHeader() {\n return (\n \n
My Personal Blog
\n
Thoughts, ideas, and musings
\n \n )\n}\n"},"time":{"start":1781392516951,"end":1781392516969}}}}
+{"type":"tool_use","timestamp":1781392517436,"sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","part":{"id":"prt_ec344a766001HM86kuUHnHFboS","sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","messageID":"msg_ec3449bfb001pmdm3T5eyF4Yl9","type":"tool","callID":"read_3","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/app/layout.tsx"},"output":"\n00001| export default function RootLayout({\n00002| children,\n00003| }: Readonly<{\n00004| children: React.ReactNode\n00005| }>) {\n00006| return (\n00007| \n00008| {children}\n00009| \n00010| )\n00011| }\n00012| \n\n(End of file - total 12 lines)\n","title":"app/layout.tsx","metadata":{"preview":"export default function RootLayout({\n children,\n}: Readonly<{\n children: React.ReactNode\n}>) {\n return (\n \n {children}\n \n )\n}\n"},"time":{"start":1781392517420,"end":1781392517431}}}}
+{"type":"tool_use","timestamp":1781392517918,"sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","part":{"id":"prt_ec344a92f001eg2HVrFvj8derD","sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","messageID":"msg_ec3449bfb001pmdm3T5eyF4Yl9","type":"tool","callID":"read_4","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/app/page.tsx"},"output":"\n00001| import BlogHeader from './BlogHeader'\n00002| \n00003| export default function Page() {\n00004| return (\n00005|
\n00006|
My Blog
\n00007|
Welcome to my personal blog where I share my thoughts and ideas.
\n00008| \n00009| \n00010| \n00011| \n00012|
Latest Post
\n00013|
This is the content of my latest blog post...
\n00014| \n00015|
\n00016| )\n00017| }\n00018| \n\n(End of file - total 18 lines)\n","title":"app/page.tsx","metadata":{"preview":"import BlogHeader from './BlogHeader'\n\nexport default function Page() {\n return (\n
\n
My Blog
\n
Welcome to my personal blog where I share my thoughts and ideas.
\n\n \n\n \n
Latest Post
\n
This is the content of my latest blog post...
\n \n
\n )\n}\n"},"time":{"start":1781392517905,"end":1781392517910}}}}
+{"type":"tool_use","timestamp":1781392518049,"sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","part":{"id":"prt_ec344ab15001tV72cthtIbqsyF","sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","messageID":"msg_ec3449bfb001pmdm3T5eyF4Yl9","type":"tool","callID":"read_5","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/package.json"},"output":"\n00001| {\n00002| \"private\": true,\n00003| \"type\": \"module\",\n00004| \"scripts\": {\n00005| \"dev\": \"next dev\",\n00006| \"build\": \"next build\",\n00007| \"start\": \"next start\"\n00008| },\n00009| \"dependencies\": {\n00010| \"@ai-sdk/react\": \"2.0.0-beta.28\",\n00011| \"@modelcontextprotocol/sdk\": \"^1.17.0\",\n00012| \"ai\": \"5.0.59\",\n00013| \"next\": \"^16.3.0-canary.50\",\n00014| \"react\": \"19.1.0\",\n00015| \"react-dom\": \"19.1.0\",\n00016| \"zod\": \"^4.0.10\"\n00017| },\n00018| \"devDependencies\": {\n00019| \"@types/node\": \"^20\",\n00020| \"@types/react\": \"^19\",\n00021| \"@types/react-dom\": \"^19\",\n00022| \"@vitejs/plugin-react\": \"^4.4.1\",\n00023| \"typescript\": \"^5\",\n00024| \"vite-tsconfig-paths\": \"^5.1.4\",\n00025| \"vitest\": \"^3.1.3\"\n00026| }\n00027| }\n00028| \n\n(End of file - total 28 lines)\n","title":"package.json","metadata":{"preview":"{\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"next dev\",\n \"build\": \"next build\",\n \"start\": \"next start\"\n },\n \"dependencies\": {\n \"@ai-sdk/react\": \"2.0.0-beta.28\",\n \"@modelcontextprotocol/sdk\": \"^1.17.0\",\n \"ai\": \"5.0.59\",\n \"next\": \"^16.3.0-canary.50\",\n \"react\": \"19.1.0\",\n \"react-dom\": \"19.1.0\",\n \"zod\": \"^4.0.10\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^20\",\n \"@types/react\": \"^19\","},"time":{"start":1781392517999,"end":1781392518012}}}}
+{"type":"step_finish","timestamp":1781392518103,"sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","part":{"id":"prt_ec344ab80001d20Xy8LDHMnBVO","sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","messageID":"msg_ec3449bfb001pmdm3T5eyF4Yl9","type":"step-finish","reason":"tool-calls","snapshot":"218f3678fd946d904d760881701ddb5ead0a0421","cost":0.00223851,"tokens":{"input":421,"output":91,"reasoning":0,"cache":{"read":9216,"write":0}}}}
+{"type":"step_start","timestamp":1781392519694,"sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","part":{"id":"prt_ec344b207001AWMTkibSkhz469","sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","messageID":"msg_ec344ac37001WE16QB4zfQU26w","type":"step-start","snapshot":"218f3678fd946d904d760881701ddb5ead0a0421"}}
+{"type":"tool_use","timestamp":1781392520566,"sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","part":{"id":"prt_ec344b49b001M4YO4RYVAWsegA","sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","messageID":"msg_ec344ac37001WE16QB4zfQU26w","type":"tool","callID":"glob_6","tool":"glob","state":{"status":"completed","input":{"pattern":"node_modules/next/dist/docs/**/*font*"},"output":"No files found","title":"","metadata":{"count":0,"truncated":false},"time":{"start":1781392520524,"end":1781392520540}}}}
+{"type":"step_finish","timestamp":1781392520577,"sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","part":{"id":"prt_ec344b5660015MxSTCMr3BcR0I","sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","messageID":"msg_ec344ac37001WE16QB4zfQU26w","type":"step-finish","reason":"tool-calls","snapshot":"218f3678fd946d904d760881701ddb5ead0a0421","cost":0.00269697,"tokens":{"input":991,"output":60,"reasoning":0,"cache":{"read":9472,"write":0}}}}
+{"type":"step_start","timestamp":1781392522244,"sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","part":{"id":"prt_ec344bbff001eKOOecPmB20EE7","sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","messageID":"msg_ec344b5ba001OPxesOaFW5tw14","type":"step-start","snapshot":"218f3678fd946d904d760881701ddb5ead0a0421"}}
+{"type":"tool_use","timestamp":1781392522294,"sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","part":{"id":"prt_ec344bc02001ssoYZeVhDHVXK4","sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","messageID":"msg_ec344b5ba001OPxesOaFW5tw14","type":"tool","callID":"glob_7","tool":"glob","state":{"status":"completed","input":{"pattern":"node_modules/next/dist/docs/**/*.md"},"output":"No files found","title":"","metadata":{"count":0,"truncated":false},"time":{"start":1781392522282,"end":1781392522290}}}}
+{"type":"step_finish","timestamp":1781392522298,"sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","part":{"id":"prt_ec344bc34001E9ln60cNmnLSsM","sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","messageID":"msg_ec344b5ba001OPxesOaFW5tw14","type":"step-finish","reason":"tool-calls","snapshot":"218f3678fd946d904d760881701ddb5ead0a0421","cost":0.00202435,"tokens":{"input":301,"output":25,"reasoning":0,"cache":{"read":10240,"write":0}}}}
+{"type":"step_start","timestamp":1781392524099,"sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","part":{"id":"prt_ec344c333001NQo9F2uQWmhaSI","sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","messageID":"msg_ec344bc48001HJVbfVz05FBDoc","type":"step-start","snapshot":"218f3678fd946d904d760881701ddb5ead0a0421"}}
+{"type":"tool_use","timestamp":1781392525207,"sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","part":{"id":"prt_ec344c537001aFrpT3kgTKSyno","sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","messageID":"msg_ec344bc48001HJVbfVz05FBDoc","type":"tool","callID":"bash_8","tool":"bash","state":{"status":"completed","input":{"command":"ls node_modules/next/dist/docs/ 2>/dev/null || echo no docs dir","description":"List Next.js docs directory"},"output":"01-app\n02-pages\n03-architecture\n04-community\nindex.md\n","title":"List Next.js docs directory","metadata":{"output":"01-app\n02-pages\n03-architecture\n04-community\nindex.md\n","exit":0,"description":"List Next.js docs directory"},"time":{"start":1781392525134,"end":1781392525200}}}}
+{"type":"step_finish","timestamp":1781392525214,"sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","part":{"id":"prt_ec344c792001GimhnO1BTucFx2","sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","messageID":"msg_ec344bc48001HJVbfVz05FBDoc","type":"step-finish","reason":"tool-calls","snapshot":"218f3678fd946d904d760881701ddb5ead0a0421","cost":0.00196391,"tokens":{"input":89,"output":50,"reasoning":0,"cache":{"read":10496,"write":0}}}}
+{"type":"step_start","timestamp":1781392526962,"sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","part":{"id":"prt_ec344ce6a001OLTazF8tOxF5EJ","sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","messageID":"msg_ec344c7af001p4wYp3zrhTUdQ8","type":"step-start","snapshot":"218f3678fd946d904d760881701ddb5ead0a0421"}}
+{"type":"tool_use","timestamp":1781392527789,"sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","part":{"id":"prt_ec344ce70001dgGmkaqUXl4cnz","sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","messageID":"msg_ec344c7af001p4wYp3zrhTUdQ8","type":"tool","callID":"bash_9","tool":"bash","state":{"status":"completed","input":{"command":"find node_modules/next/dist/docs -type f | xargs grep -l -i font 2>/dev/null | head -20","description":"Find font-related docs"},"output":"node_modules/next/dist/docs/02-pages/02-guides/internationalization.md\nnode_modules/next/dist/docs/02-pages/02-guides/post-css.md\nnode_modules/next/dist/docs/02-pages/02-guides/upgrading/version-13.md\nnode_modules/next/dist/docs/02-pages/01-getting-started/05-fonts.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/01-components/font.md\nnode_modules/next/dist/docs/01-app/03-api-reference/08-turbopack.md\nnode_modules/next/dist/docs/01-app/03-api-reference/02-components/font.md\nnode_modules/next/dist/docs/01-app/03-api-reference/02-components/image.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/reactMaxHeadersLength.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/useLightningcss.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/03-eslint.md\nnode_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/error.md\nnode_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/layout.md\nnode_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/not-found.md\nnode_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/01-metadata/app-icons.md\nnode_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/01-metadata/opengraph-image.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/generate-image-metadata.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/generate-metadata.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/image-response.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/use-selected-layout-segment.md\n","title":"Find font-related docs","metadata":{"output":"node_modules/next/dist/docs/02-pages/02-guides/internationalization.md\nnode_modules/next/dist/docs/02-pages/02-guides/post-css.md\nnode_modules/next/dist/docs/02-pages/02-guides/upgrading/version-13.md\nnode_modules/next/dist/docs/02-pages/01-getting-started/05-fonts.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/01-components/font.md\nnode_modules/next/dist/docs/01-app/03-api-reference/08-turbopack.md\nnode_modules/next/dist/docs/01-app/03-api-reference/02-components/font.md\nnode_modules/next/dist/docs/01-app/03-api-reference/02-components/image.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/reactMaxHeadersLength.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/useLightningcss.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/03-eslint.md\nnode_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/error.md\nnode_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/layout.md\nnode_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/not-found.md\nnode_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/01-metadata/app-icons.md\nnode_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/01-metadata/opengraph-image.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/generate-image-metadata.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/generate-metadata.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/image-response.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/use-selected-layout-segment.md\n","exit":0,"description":"Find font-related docs"},"time":{"start":1781392527739,"end":1781392527783}}}}
+{"type":"step_finish","timestamp":1781392527794,"sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","part":{"id":"prt_ec344d1a90019MfOOhYXvL0UV9","sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","messageID":"msg_ec344c7af001p4wYp3zrhTUdQ8","type":"step-finish","reason":"tool-calls","snapshot":"218f3678fd946d904d760881701ddb5ead0a0421","cost":0.00206676,"tokens":{"input":172,"output":56,"reasoning":0,"cache":{"read":10496,"write":0}}}}
+{"type":"step_start","timestamp":1781392529486,"sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","part":{"id":"prt_ec344d849001ZpM08TT3IkwFoM","sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","messageID":"msg_ec344d1ca001WSL0YUVi6pqjUk","type":"step-start","snapshot":"218f3678fd946d904d760881701ddb5ead0a0421"}}
+{"type":"tool_use","timestamp":1781392530651,"sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","part":{"id":"prt_ec344d84d001ft90w9UVtpAKXS","sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","messageID":"msg_ec344d1ca001WSL0YUVi6pqjUk","type":"tool","callID":"read_10","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/node_modules/next/dist/docs/01-app/03-api-reference/02-components/font.md"},"output":"\n00001| ---\n00002| title: Font Module\n00003| nav_title: Font\n00004| description: Optimizing loading web fonts with the built-in `next/font` loaders.\n00005| ---\n00006| \n00007| {/* The content of this doc is shared between the app and pages router. You can use the `Content` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}\n00008| \n00009| [`next/font`](/docs/app/api-reference/components/font) automatically optimizes your fonts (including custom fonts) and removes external network requests for improved privacy and performance.\n00010| \n00011| It includes **built-in automatic self-hosting** for any font file. This means you can optimally load web fonts with no [layout shift](https://web.dev/articles/cls).\n00012| \n00013| You can also conveniently use all [Google Fonts](https://fonts.google.com/). CSS and font files are downloaded at build time and self-hosted with the rest of your static assets. **No requests are sent to Google by the browser.**\n00014| \n00015| \n00016| \n00017| ```tsx filename=\"app/layout.tsx\" switcher\n00018| import { Inter } from 'next/font/google'\n00019| \n00020| // If loading a variable font, you don't need to specify the font weight\n00021| const inter = Inter({\n00022| subsets: ['latin'],\n00023| display: 'swap',\n00024| })\n00025| \n00026| export default function RootLayout({\n00027| children,\n00028| }: {\n00029| children: React.ReactNode\n00030| }) {\n00031| return (\n00032| \n00033| {children}\n00034| \n00035| )\n00036| }\n00037| ```\n00038| \n00039| ```jsx filename=\"app/layout.js\" switcher\n00040| import { Inter } from 'next/font/google'\n00041| \n00042| // If loading a variable font, you don't need to specify the font weight\n00043| const inter = Inter({\n00044| subsets: ['latin'],\n00045| display: 'swap',\n00046| })\n00047| \n00048| export default function RootLayout({ children }) {\n00049| return (\n00050| \n00051| {children}\n00052| \n00053| )\n00054| }\n00055| ```\n00056| \n00057| \n00058| \n00059| \n00060| \n00061| To use the font in all your pages, add it to [`_app.js` file](/docs/pages/building-your-application/routing/custom-app) under `/pages` as shown below:\n00062| \n00063| ```jsx filename=\"pages/_app.js\"\n00064| import { Inter } from 'next/font/google'\n00065| \n00066| // If loading a variable font, you don't need to specify the font weight\n00067| const inter = Inter({ subsets: ['latin'] })\n00068| \n00069| export default function MyApp({ Component, pageProps }) {\n00070| return (\n00071| \n00072| \n00073| \n00074| )\n00075| }\n00076| ```\n00077| \n00078| \n00079| \n00080| > **🎥 Watch:** Learn more about using `next/font` → [YouTube (6 minutes)](https://www.youtube.com/watch?v=L8_98i_bMMA).\n00081| \n00082| ## Reference\n00083| \n00084| | Key | `font/google` | `font/local` | Type | Required |\n00085| | ------------------------------------------- | ------------------- | ------------------- | -------------------------- | ----------------- |\n00086| | [`src`](#src) | | | String or Array of Objects | Yes |\n00087| | [`weight`](#weight) | | | String or Array | Required/Optional |\n00088| | [`style`](#style) | | | String or Array | - |\n00089| | [`subsets`](#subsets) | | | Array of Strings | - |\n00090| | [`axes`](#axes) | | | Array of Strings | - |\n00091| | [`display`](#display) | | | String | - |\n00092| | [`preload`](#preload) | | | Boolean | - |\n00093| | [`fallback`](#fallback) | | | Array of Strings | - |\n00094| | [`adjustFontFallback`](#adjustfontfallback) | | | Boolean or String | - |\n00095| | [`variable`](#variable) | | | String | - |\n00096| | [`declarations`](#declarations) | | | Array of Objects | - |\n00097| \n00098| ### `src`\n00099| \n00100| The path of the font file as a string or an array of objects (with type `Array<{path: string, weight?: string, style?: string}>`) relative to the directory where the font loader function is called.\n00101| \n00102| Used in `next/font/local`\n00103| \n00104| - Required\n00105| \n00106| Examples:\n00107| \n00108| - `src:'./fonts/my-font.woff2'` where `my-font.woff2` is placed in a directory named `fonts` inside the `app` directory\n00109| - `src:[{path: './inter/Inter-Thin.ttf', weight: '100',},{path: './inter/Inter-Regular.ttf',weight: '400',},{path: './inter/Inter-Bold-Italic.ttf', weight: '700',style: 'italic',},]`\n00110| - if the font loader function is called in `app/page.tsx` using `src:'../styles/fonts/my-font.ttf'`, then `my-font.ttf` is placed in `styles/fonts` at the root of the project\n00111| \n00112| ### `weight`\n00113| \n00114| The font [`weight`](https://fonts.google.com/knowledge/glossary/weight) with the following possibilities:\n00115| \n00116| - A string with possible values of the weights available for the specific font or a range of values if it's a [variable](https://fonts.google.com/variablefonts) font\n00117| - An array of weight values if the font is not a [variable google font](https://fonts.google.com/variablefonts). It applies to `next/font/google` only.\n00118| \n00119| Used in `next/font/google` and `next/font/local`\n00120| \n00121| - Required if the font being used is **not** [variable](https://fonts.google.com/variablefonts)\n00122| \n00123| Examples:\n00124| \n00125| - `weight: '400'`: A string for a single weight value - for the font [`Inter`](https://fonts.google.com/specimen/Inter?query=inter), the possible values are `'100'`, `'200'`, `'300'`, `'400'`, `'500'`, `'600'`, `'700'`, `'800'`, `'900'` or `'variable'` where `'variable'` is the default)\n00126| - `weight: '100 900'`: A string for the range between `100` and `900` for a variable font\n00127| - `weight: ['100','400','900']`: An array of 3 possible values for a non variable font\n00128| \n00129| ### `style`\n00130| \n00131| The font [`style`](https://developer.mozilla.org/docs/Web/CSS/font-style) with the following possibilities:\n00132| \n00133| - A string [value](https://developer.mozilla.org/docs/Web/CSS/font-style#values) with default value of `'normal'`\n00134| - An array of style values if the font is not a [variable google font](https://fonts.google.com/variablefonts). It applies to `next/font/google` only.\n00135| \n00136| Used in `next/font/google` and `next/font/local`\n00137| \n00138| - Optional\n00139| \n00140| Examples:\n00141| \n00142| - `style: 'italic'`: A string - it can be `normal` or `italic` for `next/font/google`\n00143| - `style: 'oblique'`: A string - it can take any value for `next/font/local` but is expected to come from [standard font styles](https://developer.mozilla.org/docs/Web/CSS/font-style)\n00144| - `style: ['italic','normal']`: An array of 2 values for `next/font/google` - the values are from `normal` and `italic`\n00145| \n00146| ### `subsets`\n00147| \n00148| The font [`subsets`](https://fonts.google.com/knowledge/glossary/subsetting) defined by an array of string values with the names of each subset you would like to be [preloaded](/docs/app/api-reference/components/font#specifying-a-subset). Fonts specified via `subsets` will have a link preload tag injected into the head when the [`preload`](#preload) option is true, which is the default.\n00149| \n00150| Used in `next/font/google`\n00151| \n00152| - Optional\n00153| \n00154| Examples:\n00155| \n00156| - `subsets: ['latin']`: An array with the subset `latin`\n00157| \n00158| You can find a list of all subsets on the Google Fonts page for your font.\n00159| \n00160| ### `axes`\n00161| \n00162| Some variable fonts have extra `axes` that can be included. By default, only the font weight is included to keep the file size down. The possible values of `axes` depend on the specific font.\n00163| \n00164| Used in `next/font/google`\n00165| \n00166| - Optional\n00167| \n00168| Examples:\n00169| \n00170| - `axes: ['slnt']`: An array with value `slnt` for the `Inter` variable font which has `slnt` as additional `axes` as shown [here](https://fonts.google.com/variablefonts?vfquery=inter#font-families). You can find the possible `axes` values for your font by using the filter on the [Google variable fonts page](https://fonts.google.com/variablefonts#font-families) and looking for axes other than `wght`\n00171| \n00172| ### `display`\n00173| \n00174| The font [`display`](https://developer.mozilla.org/docs/Web/CSS/@font-face/font-display) with possible string [values](https://developer.mozilla.org/docs/Web/CSS/@font-face/font-display#values) of `'auto'`, `'block'`, `'swap'`, `'fallback'` or `'optional'` with default value of `'swap'`.\n00175| \n00176| Used in `next/font/google` and `next/font/local`\n00177| \n00178| - Optional\n00179| \n00180| Examples:\n00181| \n00182| - `display: 'optional'`: A string assigned to the `optional` value\n00183| \n00184| ### `preload`\n00185| \n00186| A boolean value that specifies whether the font should be [preloaded](/docs/app/api-reference/components/font#preloading) or not. The default is `true`.\n00187| \n00188| Used in `next/font/google` and `next/font/local`\n00189| \n00190| - Optional\n00191| \n00192| Examples:\n00193| \n00194| - `preload: false`\n00195| \n00196| ### `fallback`\n00197| \n00198| The fallback font to use if the font cannot be loaded. An array of strings of fallback fonts with no default.\n00199| \n00200| - Optional\n00201| \n00202| Used in `next/font/google` and `next/font/local`\n00203| \n00204| Examples:\n00205| \n00206| - `fallback: ['system-ui', 'arial']`: An array setting the fallback fonts to `system-ui` or `arial`\n00207| \n00208| ### `adjustFontFallback`\n00209| \n00210| - For `next/font/google`: A boolean value that sets whether an automatic fallback font should be used to reduce [Cumulative Layout Shift](https://web.dev/cls/). The default is `true`.\n00211| - For `next/font/local`: A string or boolean `false` value that sets whether an automatic fallback font should be used to reduce [Cumulative Layout Shift](https://web.dev/cls/). The possible values are `'Arial'`, `'Times New Roman'` or `false`. The default is `'Arial'`.\n00212| \n00213| Used in `next/font/google` and `next/font/local`\n00214| \n00215| - Optional\n00216| \n00217| Examples:\n00218| \n00219| - `adjustFontFallback: false`: for `next/font/google`\n00220| - `adjustFontFallback: 'Times New Roman'`: for `next/font/local`\n00221| \n00222| ### `variable`\n00223| \n00224| A string value to define the CSS variable name to be used if the style is applied with the [CSS variable method](#css-variables).\n00225| \n00226| Used in `next/font/google` and `next/font/local`\n00227| \n00228| - Optional\n00229| \n00230| Examples:\n00231| \n00232| - `variable: '--my-font'`: The CSS variable `--my-font` is declared\n00233| \n00234| ### `declarations`\n00235| \n00236| An array of font face [descriptor](https://developer.mozilla.org/docs/Web/CSS/@font-face#descriptors) key-value pairs that define the generated `@font-face` further.\n00237| \n00238| Used in `next/font/local`\n00239| \n00240| - Optional\n00241| \n00242| Examples:\n00243| \n00244| - `declarations: [{ prop: 'ascent-override', value: '90%' }]`\n00245| \n00246| ## Examples\n00247| \n00248| ## Google Fonts\n00249| \n00250| To use a Google font, import it from `next/font/google` as a function. We recommend using [variable fonts](https://fonts.google.com/variablefonts) for the best performance and flexibility.\n00251| \n00252| \n00253| \n00254| ```tsx filename=\"app/layout.tsx\" switcher\n00255| import { Inter } from 'next/font/google'\n00256| \n00257| // If loading a variable font, you don't need to specify the font weight\n00258| const inter = Inter({\n00259| subsets: ['latin'],\n00260| display: 'swap',\n00261| })\n00262| \n00263| export default function RootLayout({\n00264| children,\n00265| }: {\n00266| children: React.ReactNode\n00267| }) {\n00268| return (\n00269| \n00270| {children}\n00271| \n00272| )\n00273| }\n00274| ```\n00275| \n00276| ```jsx filename=\"app/layout.js\" switcher\n00277| import { Inter } from 'next/font/google'\n00278| \n00279| // If loading a variable font, you don't need to specify the font weight\n00280| const inter = Inter({\n00281| subsets: ['latin'],\n00282| display: 'swap',\n00283| })\n00284| \n00285| export default function RootLayout({ children }) {\n00286| return (\n00287| \n00288| {children}\n00289| \n00290| )\n00291| }\n00292| ```\n00293| \n00294| If you can't use a variable font, you will **need to specify a weight**:\n00295| \n00296| ```tsx filename=\"app/layout.tsx\" switcher\n00297| import { Roboto } from 'next/font/google'\n00298| \n00299| const roboto = Roboto({\n00300| weight: '400',\n00301| subsets: ['latin'],\n00302| display: 'swap',\n00303| })\n00304| \n00305| export default function RootLayout({\n00306| children,\n00307| }: {\n00308| children: React.ReactNode\n00309| }) {\n00310| return (\n00311| \n00312| {children}\n00313| \n00314| )\n00315| }\n00316| ```\n00317| \n00318| ```jsx filename=\"app/layout.js\" switcher\n00319| import { Roboto } from 'next/font/google'\n00320| \n00321| const roboto = Roboto({\n00322| weight: '400',\n00323| subsets: ['latin'],\n00324| display: 'swap',\n00325| })\n00326| \n00327| export default function RootLayout({ children }) {\n00328| return (\n00329| \n00330| {children}\n00331| \n00332| )\n00333| }\n00334| ```\n00335| \n00336| \n00337| \n00338| \n00339| \n00340| To use the font in all your pages, add it to [`_app.js` file](/docs/pages/building-your-application/routing/custom-app) under `/pages` as shown below:\n00341| \n00342| ```jsx filename=\"pages/_app.js\"\n00343| import { Inter } from 'next/font/google'\n00344| \n00345| // If loading a variable font, you don't need to specify the font weight\n00346| const inter = Inter({ subsets: ['latin'] })\n00347| \n00348| export default function MyApp({ Component, pageProps }) {\n00349| return (\n00350| \n00351| \n00352| \n00353| )\n00354| }\n00355| ```\n00356| \n00357| If you can't use a variable font, you will **need to specify a weight**:\n00358| \n00359| ```jsx filename=\"pages/_app.js\"\n00360| import { Roboto } from 'next/font/google'\n00361| \n00362| const roboto = Roboto({\n00363| weight: '400',\n00364| subsets: ['latin'],\n00365| })\n00366| \n00367| export default function MyApp({ Component, pageProps }) {\n00368| return (\n00369| \n00370| \n00371| \n00372| )\n00373| }\n00374| ```\n00375| \n00376| \n00377| \n00378| You can specify multiple weights and/or styles by using an array:\n00379| \n00380| ```jsx filename=\"app/layout.js\"\n00381| const roboto = Roboto({\n00382| weight: ['400', '700'],\n00383| style: ['normal', 'italic'],\n00384| subsets: ['latin'],\n00385| display: 'swap',\n00386| })\n00387| ```\n00388| \n00389| > **Good to know**: Use an underscore (\\_) for font names with multiple words. E.g. `Roboto Mono` should be imported as `Roboto_Mono`.\n00390| \n00391| \n00392| \n00393| ### Apply the font in ``\n00394| \n00395| You can also use the font without a wrapper and `className` by injecting it inside the `` as follows:\n00396| \n00397| ```jsx filename=\"pages/_app.js\"\n00398| import { Inter } from 'next/font/google'\n00399| \n00400| const inter = Inter({ subsets: ['latin'] })\n00401| \n00402| export default function MyApp({ Component, pageProps }) {\n00403| return (\n00404| <>\n00405| \n00410| \n00411| >\n00412| )\n00413| }\n00414| ```\n00415| \n00416| ### Single page usage\n00417| \n00418| To use the font on a single page, add it to the specific page as shown below:\n00419| \n00420| ```jsx filename=\"pages/index.js\"\n00421| import { Inter } from 'next/font/google'\n00422| \n00423| const inter = Inter({ subsets: ['latin'] })\n00424| \n00425| export default function Home() {\n00426| return (\n00427|
\n00428|
Hello World
\n00429|
\n00430| )\n00431| }\n00432| ```\n00433| \n00434| \n00435| \n00436| ### Specifying a subset\n00437| \n00438| Google Fonts are automatically [subset](https://fonts.google.com/knowledge/glossary/subsetting). This reduces the size of the font file and improves performance. You'll need to define which of these subsets you want to preload. Failing to specify any subsets while [`preload`](/docs/app/api-reference/components/font#preload) is `true` will result in a warning.\n00439| \n00440| This can be done by adding it to the function call:\n00441| \n00442| \n00443| \n00444| ```tsx filename=\"app/layout.tsx\" switcher\n00445| const inter = Inter({ subsets: ['latin'] })\n00446| ```\n00447| \n00448| ```jsx filename=\"app/layout.js\" switcher\n00449| const inter = Inter({ subsets: ['latin'] })\n00450| ```\n00451| \n00452| \n00453| \n00454| \n00455| \n00456| ```jsx filename=\"pages/_app.js\"\n00457| const inter = Inter({ subsets: ['latin'] })\n00458| ```\n00459| \n00460| \n00461| \n00462| View the [Font API Reference](/docs/app/api-reference/components/font) for more information.\n00463| \n00464| ## Using Multiple Fonts\n00465| \n00466| You can import and use multiple fonts in your application. There are two approaches you can take.\n00467| \n00468| The first approach is to create a utility function that exports a font, imports it, and applies its `className` where needed. This ensures the font is preloaded only when it's rendered:\n00469| \n00470| ```ts filename=\"app/fonts.ts\" switcher\n00471| import { Inter, Roboto_Mono } from 'next/font/google'\n00472| \n00473| export const inter = Inter({\n00474| subsets: ['latin'],\n00475| display: 'swap',\n00476| })\n00477| \n00478| export const roboto_mono = Roboto_Mono({\n00479| subsets: ['latin'],\n00480| display: 'swap',\n00481| })\n00482| ```\n00483| \n00484| ```js filename=\"app/fonts.js\" switcher\n00485| import { Inter, Roboto_Mono } from 'next/font/google'\n00486| \n00487| export const inter = Inter({\n00488| subsets: ['latin'],\n00489| display: 'swap',\n00490| })\n00491| \n00492| export const roboto_mono = Roboto_Mono({\n00493| subsets: ['latin'],\n00494| display: 'swap',\n00495| })\n00496| ```\n00497| \n00498| \n00499| \n00500| ```tsx filename=\"app/layout.tsx\" switcher\n00501| import { inter } from './fonts'\n00502| \n00503| export default function Layout({ children }: { children: React.ReactNode }) {\n00504| return (\n00505| \n00506| \n00507|
{children}
\n00508| \n00509| \n00510| )\n00511| }\n00512| ```\n00513| \n00514| ```jsx filename=\"app/layout.js\" switcher\n00515| import { inter } from './fonts'\n00516| \n00517| export default function Layout({ children }) {\n00518| return (\n00519| \n00520| \n00521|
\n00547| >\n00548| )\n00549| }\n00550| ```\n00551| \n00552| \n00553| \n00554| In the example above, `Inter` will be applied globally, and `Roboto Mono` can be imported and applied as needed.\n00555| \n00556| Alternatively, you can create a [CSS variable](/docs/app/api-reference/components/font#variable) and use it with your preferred CSS solution:\n00557| \n00558| \n00559| \n00560| ```tsx filename=\"app/layout.tsx\" switcher\n00561| import { Inter, Roboto_Mono } from 'next/font/google'\n00562| import styles from './global.css'\n00563| \n00564| const inter = Inter({\n00565| subsets: ['latin'],\n00566| variable: '--font-inter',\n00567| display: 'swap',\n00568| })\n00569| \n00570| const roboto_mono = Roboto_Mono({\n00571| subsets: ['latin'],\n00572| variable: '--font-roboto-mono',\n00573| display: 'swap',\n00574| })\n00575| \n00576| export default function RootLayout({\n00577| children,\n00578| }: {\n00579| children: React.ReactNode\n00580| }) {\n00581| return (\n00582| \n00583| \n00584|
\n00613| \n00614| \n00615| )\n00616| }\n00617| ```\n00618| \n00619| \n00620| \n00621| ```css filename=\"app/global.css\"\n00622| html {\n00623| font-family: var(--font-inter);\n00624| }\n00625| \n00626| h1 {\n00627| font-family: var(--font-roboto-mono);\n00628| }\n00629| ```\n00630| \n00631| In the example above, `Inter` will be applied globally, and any `
` tags will be styled with `Roboto Mono`.\n00632| \n00633| > **Recommendation**: Use multiple fonts conservatively since each new font is an additional resource the client has to download.\n00634| \n00635| ### Local Fonts\n00636| \n00637| Import `next/font/local` and specify the `src` of your local font file. We recommend using [variable fonts](https://fonts.google.com/variablefonts) for the best performance and flexibility.\n00638| \n00639| \n00640| \n00641| ```tsx filename=\"app/layout.tsx\" switcher\n00642| import localFont from 'next/font/local'\n00643| \n00644| // Font files can be colocated inside of `app`\n00645| const myFont = localFont({\n00646| src: './my-font.woff2',\n00647| display: 'swap',\n00648| })\n00649| \n00650| export default function RootLayout({\n00651| children,\n00652| }: {\n00653| children: React.ReactNode\n00654| }) {\n00655| return (\n00656| \n00657| {children}\n00658| \n00659| )\n00660| }\n00661| ```\n00662| \n00663| ```jsx filename=\"app/layout.js\" switcher\n00664| import localFont from 'next/font/local'\n00665| \n00666| // Font files can be colocated inside of `app`\n00667| const myFont = localFont({\n00668| src: './my-font.woff2',\n00669| display: 'swap',\n00670| })\n00671| \n00672| export default function RootLayout({ children }) {\n00673| return (\n00674| \n00675| {children}\n00676| \n00677| )\n00678| }\n00679| ```\n00680| \n00681| \n00682| \n00683| \n00684| \n00685| ```jsx filename=\"pages/_app.js\"\n00686| import localFont from 'next/font/local'\n00687| \n00688| // Font files can be colocated inside of `pages`\n00689| const myFont = localFont({ src: './my-font.woff2' })\n00690| \n00691| export default function MyApp({ Component, pageProps }) {\n00692| return (\n00693| \n00694| \n00695| \n00696| )\n00697| }\n00698| ```\n00699| \n00700| \n00701| \n00702| If you want to use multiple files for a single font family, `src` can be an array:\n00703| \n00704| ```js\n00705| const roboto = localFont({\n00706| src: [\n00707| {\n00708| path: './Roboto-Regular.woff2',\n00709| weight: '400',\n00710| style: 'normal',\n00711| },\n00712| {\n00713| path: './Roboto-Italic.woff2',\n00714| weight: '400',\n00715| style: 'italic',\n00716| },\n00717| {\n00718| path: './Roboto-Bold.woff2',\n00719| weight: '700',\n00720| style: 'normal',\n00721| },\n00722| {\n00723| path: './Roboto-BoldItalic.woff2',\n00724| weight: '700',\n00725| style: 'italic',\n00726| },\n00727| ],\n00728| })\n00729| ```\n00730| \n00731| View the [Font API Reference](/docs/app/api-reference/components/font) for more information.\n00732| \n00733| ### With Tailwind CSS\n00734| \n00735| `next/font` integrates seamlessly with [Tailwind CSS](https://tailwindcss.com/) using [CSS variables](/docs/app/api-reference/components/font#css-variables).\n00736| \n00737| In the example below, we use the `Inter` and `Roboto_Mono` fonts from `next/font/google` (you can use any Google Font or Local Font). Use the `variable` option to define a CSS variable name, such as `inter` and `roboto_mono` for these fonts, respectively. Then, apply `inter.variable` and `roboto_mono.variable` to include the CSS variables in your HTML document.\n00738| \n00739| > **Good to know**: You can add these variables to the `` or `` tag, depending on your preference, styling needs or project requirements.\n00740| \n00741| \n00742| \n00743| ```tsx filename=\"app/layout.tsx\" switcher\n00744| import { Inter, Roboto_Mono } from 'next/font/google'\n00745| \n00746| const inter = Inter({\n00747| subsets: ['latin'],\n00748| display: 'swap',\n00749| variable: '--font-inter',\n00750| })\n00751| \n00752| const roboto_mono = Roboto_Mono({\n00753| subsets: ['latin'],\n00754| display: 'swap',\n00755| variable: '--font-roboto-mono',\n00756| })\n00757| \n00758| export default function RootLayout({\n00759| children,\n00760| }: {\n00761| children: React.ReactNode\n00762| }) {\n00763| return (\n00764| \n00768| {children}\n00769| \n00770| )\n00771| }\n00772| ```\n00773| \n00774| ```jsx filename=\"app/layout.js\" switcher\n00775| import { Inter, Roboto_Mono } from 'next/font/google'\n00776| \n00777| const inter = Inter({\n00778| subsets: ['latin'],\n00779| display: 'swap',\n00780| variable: '--font-inter',\n00781| })\n00782| \n00783| const roboto_mono = Roboto_Mono({\n00784| subsets: ['latin'],\n00785| display: 'swap',\n00786| variable: '--font-roboto-mono',\n00787| })\n00788| \n00789| export default function RootLayout({ children }) {\n00790| return (\n00791| \n00795| {children}\n00796| \n00797| )\n00798| }\n00799| ```\n00800| \n00801| \n00802| \n00803| \n00804| \n00805| ```jsx filename=\"pages/_app.js\"\n00806| import { Inter } from 'next/font/google'\n00807| \n00808| const inter = Inter({\n00809| subsets: ['latin'],\n00810| variable: '--font-inter',\n00811| })\n00812| \n00813| const roboto_mono = Roboto_Mono({\n00814| subsets: ['latin'],\n00815| display: 'swap',\n00816| variable: '--font-roboto-mono',\n00817| })\n00818| \n00819| export default function MyApp({ Component, pageProps }) {\n00820| return (\n00821| \n00822| \n00823| \n00824| )\n00825| }\n00826| ```\n00827| \n00828| \n00829| \n00830| Finally, add the CSS variable to your [Tailwind CSS config](/docs/app/getting-started/css#tailwind-css):\n00831| \n00832| ```css filename=\"global.css\"\n00833| @import 'tailwindcss';\n00834| \n00835| @theme inline {\n00836| --font-sans: var(--font-inter);\n00837| --font-mono: var(--font-roboto-mono);\n00838| }\n00839| ```\n00840| \n00841| ### Tailwind CSS v3\n00842| \n00843| ```js filename=\"tailwind.config.js\"\n00844| /** @type {import('tailwindcss').Config} */\n00845| module.exports = {\n00846| content: [\n00847| './pages/**/*.{js,ts,jsx,tsx}',\n00848| './components/**/*.{js,ts,jsx,tsx}',\n00849| './app/**/*.{js,ts,jsx,tsx}',\n00850| ],\n00851| theme: {\n00852| extend: {\n00853| fontFamily: {\n00854| sans: ['var(--font-inter)'],\n00855| mono: ['var(--font-roboto-mono)'],\n00856| },\n00857| },\n00858| },\n00859| plugins: [],\n00860| }\n00861| ```\n00862| \n00863| You can now use the `font-sans` and `font-mono` utility classes to apply the font to your elements.\n00864| \n00865| ```html\n00866|
The quick brown fox ...
\n00867|
The quick brown fox ...
\n00868| ```\n00869| \n00870| ### Applying Styles\n00871| \n00872| You can apply the font styles in three ways:\n00873| \n00874| - [`className`](#classname)\n00875| - [`style`](#style-1)\n00876| - [CSS Variables](#css-variables)\n00877| \n00878| #### `className`\n00879| \n00880| Returns a read-only CSS `className` for the loaded font to be passed to an HTML element.\n00881| \n00882| ```tsx\n00883|
Hello, Next.js!
\n00884| ```\n00885| \n00886| #### `style`\n00887| \n00888| Returns a read-only CSS `style` object for the loaded font to be passed to an HTML element, including `style.fontFamily` to access the font family name and fallback fonts.\n00889| \n00890| ```tsx\n00891|
Hello World
\n00892| ```\n00893| \n00894| #### CSS Variables\n00895| \n00896| If you would like to set your styles in an external style sheet and specify additional options there, use the CSS variable method.\n00897| \n00898| In addition to importing the font, also import the CSS file where the CSS variable is defined and set the variable option of the font loader object as follows:\n00899| \n00900| ```tsx filename=\"app/page.tsx\" switcher\n00901| import { Inter } from 'next/font/google'\n00902| import styles from '../styles/component.module.css'\n00903| \n00904| const inter = Inter({\n00905| variable: '--font-inter',\n00906| })\n00907| ```\n00908| \n00909| ```jsx filename=\"app/page.js\" switcher\n00910| import { Inter } from 'next/font/google'\n00911| import styles from '../styles/component.module.css'\n00912| \n00913| const inter = Inter({\n00914| variable: '--font-inter',\n00915| })\n00916| ```\n00917| \n00918| To use the font, set the `className` of the parent container of the text you would like to style to the font loader's `variable` value and the `className` of the text to the `styles` property from the external CSS file.\n00919| \n00920| ```tsx filename=\"app/page.tsx\" switcher\n00921| \n00922|
\n00929| \n00930| ```\n00931| \n00932| Define the `text` selector class in the `component.module.css` CSS file as follows:\n00933| \n00934| ```css filename=\"styles/component.module.css\"\n00935| .text {\n00936| font-family: var(--font-inter);\n00937| font-weight: 200;\n00938| font-style: italic;\n00939| }\n00940| ```\n00941| \n00942| In the example above, the text `Hello World` is styled using the `Inter` font and the generated font fallback with `font-weight: 200` and `font-style: italic`.\n00943| \n00944| ### Using a font definitions file\n00945| \n00946| Every time you call the `localFont` or Google font function, that font will be hosted as one instance in your application. Therefore, if you need to use the same font in multiple places, you should load it in one place and import the related font object where you need it. This is done using a font definitions file.\n00947| \n00948| For example, create a `fonts.ts` file in a `styles` folder at the root of your app directory.\n00949| \n00950| Then, specify your font definitions as follows:\n00951| \n00952| ```ts filename=\"styles/fonts.ts\" switcher\n00953| import { Inter, Lora, Source_Sans_3 } from 'next/font/google'\n00954| import localFont from 'next/font/local'\n00955| \n00956| // define your variable fonts\n00957| const inter = Inter()\n00958| const lora = Lora()\n00959| // define 2 weights of a non-variable font\n00960| const sourceCodePro400 = Source_Sans_3({ weight: '400' })\n00961| const sourceCodePro700 = Source_Sans_3({ weight: '700' })\n00962| // define a custom local font where GreatVibes-Regular.ttf is stored in the styles folder\n00963| const greatVibes = localFont({ src: './GreatVibes-Regular.ttf' })\n00964| \n00965| export { inter, lora, sourceCodePro400, sourceCodePro700, greatVibes }\n00966| ```\n00967| \n00968| ```js filename=\"styles/fonts.js\" switcher\n00969| import { Inter, Lora, Source_Sans_3 } from 'next/font/google'\n00970| import localFont from 'next/font/local'\n00971| \n00972| // define your variable fonts\n00973| const inter = Inter()\n00974| const lora = Lora()\n00975| // define 2 weights of a non-variable font\n00976| const sourceCodePro400 = Source_Sans_3({ weight: '400' })\n00977| const sourceCodePro700 = Source_Sans_3({ weight: '700' })\n00978| // define a custom local font where GreatVibes-Regular.ttf is stored in the styles folder\n00979| const greatVibes = localFont({ src: './GreatVibes-Regular.ttf' })\n00980| \n00981| export { inter, lora, sourceCodePro400, sourceCodePro700, greatVibes }\n00982| ```\n00983| \n00984| You can now use these definitions in your code as follows:\n00985| \n00986| ```tsx filename=\"app/page.tsx\" switcher\n00987| import { inter, lora, sourceCodePro700, greatVibes } from '../styles/fonts'\n00988| \n00989| export default function Page() {\n00990| return (\n00991|
\n00992|
Hello world using Inter font
\n00993|
Hello world using Lora font
\n00994|
\n00995| Hello world using Source_Sans_3 font with weight 700\n00996|
\n01012| Hello world using Source_Sans_3 font with weight 700\n01013|
\n01014|
My title in Great Vibes font
\n01015|
\n01016| )\n01017| }\n01018| ```\n01019| \n01020| To make it easier to access the font definitions in your code, you can define a path alias in your `tsconfig.json` or `jsconfig.json` files as follows:\n01021| \n01022| ```json filename=\"tsconfig.json\"\n01023| {\n01024| \"compilerOptions\": {\n01025| \"paths\": {\n01026| \"@/fonts\": [\"./styles/fonts\"]\n01027| }\n01028| }\n01029| }\n01030| ```\n01031| \n01032| You can now import any font definition as follows:\n01033| \n01034| ```tsx filename=\"app/about/page.tsx\" switcher\n01035| import { greatVibes, sourceCodePro400 } from '@/fonts'\n01036| ```\n01037| \n01038| ```jsx filename=\"app/about/page.js\" switcher\n01039| import { greatVibes, sourceCodePro400 } from '@/fonts'\n01040| ```\n01041| \n01042| ### Preloading\n01043| \n01044| \n01045| \n01046| When a font function is called on a page of your site, it is not globally available and preloaded on all routes. Rather, the font is only preloaded on the related routes based on the type of file where it is used:\n01047| \n01048| - If it's a [unique page](/docs/app/api-reference/file-conventions/page), it is preloaded on the unique route for that page.\n01049| - If it's a [layout](/docs/app/api-reference/file-conventions/layout), it is preloaded on all the routes wrapped by the layout.\n01050| - If it's the [root layout](/docs/app/api-reference/file-conventions/layout#root-layout), it is preloaded on all routes.\n01051| \n01052| \n01053| \n01054| \n01055| \n01056| When a font function is called on a page of your site, it is not globally available and preloaded on all routes. Rather, the font is only preloaded on the related route/s based on the type of file where it is used:\n01057| \n01058| - if it's a [unique page](/docs/pages/building-your-application/routing/pages-and-layouts), it is preloaded on the unique route for that page\n01059| - if it's in the [custom App](/docs/pages/building-your-application/routing/custom-app), it is preloaded on all the routes of the site under `/pages`\n01060| \n01061| \n01062| \n01063| ## Version Changes\n01064| \n01065| | Version | Changes |\n01066| | --------- | --------------------------------------------------------------------- |\n01067| | `v13.2.0` | `@next/font` renamed to `next/font`. Installation no longer required. |\n01068| | `v13.0.0` | `@next/font` was added. |\n01069| \n\n(End of file - total 1069 lines)\n","title":"node_modules/next/dist/docs/01-app/03-api-reference/02-components/font.md","metadata":{"preview":"---\ntitle: Font Module\nnav_title: Font\ndescription: Optimizing loading web fonts with the built-in `next/font` loaders.\n---\n\n{/* The content of this doc is shared between the app and pages router. You can use the `Content` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}\n\n[`next/font`](/docs/app/api-reference/components/font) automatically optimizes your fonts (including custom fonts) and removes external network requests for improved privacy and performance.\n\nIt includes **built-in automatic self-hosting** for any font file. This means you can optimally load web fonts with no [layout shift](https://web.dev/articles/cls).\n\nYou can also conveniently use all [Google Fonts](https://fonts.google.com/). CSS and font files are downloaded at build time and self-hosted with the rest of your static assets. **No requests are sent to Google by the browser.**\n\n\n\n```tsx filename=\"app/layout.tsx\" switcher\nimport { Inter } from 'next/font/google'\n\n// If loading a variable font, you don't need to specify the font weight"},"time":{"start":1781392530643,"end":1781392530648}}}}
+{"type":"tool_use","timestamp":1781392530774,"sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","part":{"id":"prt_ec344dcd7001cJ7GyV9qt2Noy0","sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","messageID":"msg_ec344d1ca001WSL0YUVi6pqjUk","type":"tool","callID":"read_11","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/node_modules/next/dist/docs/02-pages/04-api-reference/01-components/font.md"},"output":"\n00001| ---\n00002| title: Font Module\n00003| nav_title: Font\n00004| description: API Reference for the Font Module\n00005| source: app/api-reference/components/font\n00006| ---\n00007| \n00008| {/* 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 `Content` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}\n00009| \n\n(End of file - total 9 lines)\n","title":"node_modules/next/dist/docs/02-pages/04-api-reference/01-components/font.md","metadata":{"preview":"---\ntitle: Font Module\nnav_title: Font\ndescription: API Reference for the Font Module\nsource: app/api-reference/components/font\n---\n\n{/* 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 `Content` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}\n"},"time":{"start":1781392530769,"end":1781392530773}}}}
+{"type":"step_finish","timestamp":1781392530778,"sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","part":{"id":"prt_ec344dd55001hP1IPYxT7D7t66","sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","messageID":"msg_ec344d1ca001WSL0YUVi6pqjUk","type":"step-finish","reason":"tool-calls","snapshot":"218f3678fd946d904d760881701ddb5ead0a0421","cost":0.00258561,"tokens":{"input":655,"output":71,"reasoning":0,"cache":{"read":10496,"write":0}}}}
+{"type":"step_start","timestamp":1781392533864,"sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","part":{"id":"prt_ec344e961001YPgAWjb7N0EHhN","sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","messageID":"msg_ec344dd67001YEOPKCEVAXeQYD","type":"step-start","snapshot":"218f3678fd946d904d760881701ddb5ead0a0421"}}
+{"type":"tool_use","timestamp":1781392546796,"sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","part":{"id":"prt_ec34501ef001sXQhKRCH95PkuX","sessionID":"ses_13cbb7aeaffe3kRsKeeFXkYoOQ","messageID":"msg_ec344dd67001YEOPKCEVAXeQYD","type":"tool","callID":"edit_12","tool":"edit","state":{"status":"completed","input":{"filePath":"/workspace/app/BlogHeader.tsx","oldString":"export default function BlogHeader() {\n return (\n \n
Welcome to my personal blog where I share my thoughts and ideas.
\n00008| \n00009| \n00010| \n00011| \n00012|
Latest Post
\n00013|
This is the content of my latest blog post...
\n00014| \n00015|
\n00016| )\n00017| }\n00018| \n\n(End of file - total 18 lines)\n",
+ "title": "app/page.tsx",
+ "metadata": {
+ "preview": "import BlogHeader from './BlogHeader'\n\nexport default function Page() {\n return (\n
\n
My Blog
\n
Welcome to my personal blog where I share my thoughts and ideas.
\n\n \n\n \n
Latest Post
\n
This is the content of my latest blog post...
\n \n
\n )\n}\n"
+ },
+ "time": {
+ "start": 1781392517905,
+ "end": 1781392517910
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:18.049Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "args": {
+ "filePath": "/workspace/package.json",
+ "_extractedPath": "/workspace/package.json"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392518049,
+ "sessionID": "ses_13cbb7aeaffe3kRsKeeFXkYoOQ",
+ "part": {
+ "id": "prt_ec344ab15001tV72cthtIbqsyF",
+ "sessionID": "ses_13cbb7aeaffe3kRsKeeFXkYoOQ",
+ "messageID": "msg_ec3449bfb001pmdm3T5eyF4Yl9",
+ "type": "tool",
+ "callID": "read_5",
+ "tool": "read",
+ "state": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/package.json"
+ },
+ "output": "\n00001| {\n00002| \"private\": true,\n00003| \"type\": \"module\",\n00004| \"scripts\": {\n00005| \"dev\": \"next dev\",\n00006| \"build\": \"next build\",\n00007| \"start\": \"next start\"\n00008| },\n00009| \"dependencies\": {\n00010| \"@ai-sdk/react\": \"2.0.0-beta.28\",\n00011| \"@modelcontextprotocol/sdk\": \"^1.17.0\",\n00012| \"ai\": \"5.0.59\",\n00013| \"next\": \"^16.3.0-canary.50\",\n00014| \"react\": \"19.1.0\",\n00015| \"react-dom\": \"19.1.0\",\n00016| \"zod\": \"^4.0.10\"\n00017| },\n00018| \"devDependencies\": {\n00019| \"@types/node\": \"^20\",\n00020| \"@types/react\": \"^19\",\n00021| \"@types/react-dom\": \"^19\",\n00022| \"@vitejs/plugin-react\": \"^4.4.1\",\n00023| \"typescript\": \"^5\",\n00024| \"vite-tsconfig-paths\": \"^5.1.4\",\n00025| \"vitest\": \"^3.1.3\"\n00026| }\n00027| }\n00028| \n\n(End of file - total 28 lines)\n",
+ "title": "package.json",
+ "metadata": {
+ "preview": "{\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"next dev\",\n \"build\": \"next build\",\n \"start\": \"next start\"\n },\n \"dependencies\": {\n \"@ai-sdk/react\": \"2.0.0-beta.28\",\n \"@modelcontextprotocol/sdk\": \"^1.17.0\",\n \"ai\": \"5.0.59\",\n \"next\": \"^16.3.0-canary.50\",\n \"react\": \"19.1.0\",\n \"react-dom\": \"19.1.0\",\n \"zod\": \"^4.0.10\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^20\",\n \"@types/react\": \"^19\","
+ },
+ "time": {
+ "start": 1781392517999,
+ "end": 1781392518012
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:18.049Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| {\n00002| \"private\": true,\n00003| \"type\": \"module\",\n00004| \"scripts\": {\n00005| \"dev\": \"next dev\",\n00006| \"build\": \"next build\",\n00007| \"start\": \"next start\"\n00008| },\n00009| \"dependencies\": {\n00010| \"@ai-sdk/react\": \"2.0.0-beta.28\",\n00011| \"@modelcontextprotocol/sdk\": \"^1.17.0\",\n00012| \"ai\": \"5.0.59\",\n00013| \"next\": \"^16.3.0-canary.50\",\n00014| \"react\": \"19.1.0\",\n00015| \"react-dom\": \"19.1.0\",\n00016| \"zod\": \"^4.0.10\"\n00017| },\n00018| \"devDependencies\": {\n00019| \"@types/node\": \"^20\",\n00020| \"@types/react\": \"^19\",\n00021| \"@types/react-dom\": \"^19\",\n00022| \"@vitejs/plugin-react\": \"^4.4.1\",\n00023| \"typescript\": \"^5\",\n00024| \"vite-tsconfig-paths\": \"^5.1.4\",\n00025| \"vitest\": \"^3.1.3\"\n00026| }\n00027| }\n00028| \n\n(End of file - total 28 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/package.json"
+ },
+ "output": "\n00001| {\n00002| \"private\": true,\n00003| \"type\": \"module\",\n00004| \"scripts\": {\n00005| \"dev\": \"next dev\",\n00006| \"build\": \"next build\",\n00007| \"start\": \"next start\"\n00008| },\n00009| \"dependencies\": {\n00010| \"@ai-sdk/react\": \"2.0.0-beta.28\",\n00011| \"@modelcontextprotocol/sdk\": \"^1.17.0\",\n00012| \"ai\": \"5.0.59\",\n00013| \"next\": \"^16.3.0-canary.50\",\n00014| \"react\": \"19.1.0\",\n00015| \"react-dom\": \"19.1.0\",\n00016| \"zod\": \"^4.0.10\"\n00017| },\n00018| \"devDependencies\": {\n00019| \"@types/node\": \"^20\",\n00020| \"@types/react\": \"^19\",\n00021| \"@types/react-dom\": \"^19\",\n00022| \"@vitejs/plugin-react\": \"^4.4.1\",\n00023| \"typescript\": \"^5\",\n00024| \"vite-tsconfig-paths\": \"^5.1.4\",\n00025| \"vitest\": \"^3.1.3\"\n00026| }\n00027| }\n00028| \n\n(End of file - total 28 lines)\n",
+ "title": "package.json",
+ "metadata": {
+ "preview": "{\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"next dev\",\n \"build\": \"next build\",\n \"start\": \"next start\"\n },\n \"dependencies\": {\n \"@ai-sdk/react\": \"2.0.0-beta.28\",\n \"@modelcontextprotocol/sdk\": \"^1.17.0\",\n \"ai\": \"5.0.59\",\n \"next\": \"^16.3.0-canary.50\",\n \"react\": \"19.1.0\",\n \"react-dom\": \"19.1.0\",\n \"zod\": \"^4.0.10\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^20\",\n \"@types/react\": \"^19\","
+ },
+ "time": {
+ "start": 1781392517999,
+ "end": 1781392518012
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:20.566Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "glob",
+ "originalName": "glob",
+ "args": {
+ "pattern": "node_modules/next/dist/docs/**/*font*"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392520566,
+ "sessionID": "ses_13cbb7aeaffe3kRsKeeFXkYoOQ",
+ "part": {
+ "id": "prt_ec344b49b001M4YO4RYVAWsegA",
+ "sessionID": "ses_13cbb7aeaffe3kRsKeeFXkYoOQ",
+ "messageID": "msg_ec344ac37001WE16QB4zfQU26w",
+ "type": "tool",
+ "callID": "glob_6",
+ "tool": "glob",
+ "state": {
+ "status": "completed",
+ "input": {
+ "pattern": "node_modules/next/dist/docs/**/*font*"
+ },
+ "output": "No files found",
+ "title": "",
+ "metadata": {
+ "count": 0,
+ "truncated": false
+ },
+ "time": {
+ "start": 1781392520524,
+ "end": 1781392520540
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:20.566Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "glob",
+ "originalName": "glob",
+ "result": "No files found",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "pattern": "node_modules/next/dist/docs/**/*font*"
+ },
+ "output": "No files found",
+ "title": "",
+ "metadata": {
+ "count": 0,
+ "truncated": false
+ },
+ "time": {
+ "start": 1781392520524,
+ "end": 1781392520540
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:22.294Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "glob",
+ "originalName": "glob",
+ "args": {
+ "pattern": "node_modules/next/dist/docs/**/*.md"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392522294,
+ "sessionID": "ses_13cbb7aeaffe3kRsKeeFXkYoOQ",
+ "part": {
+ "id": "prt_ec344bc02001ssoYZeVhDHVXK4",
+ "sessionID": "ses_13cbb7aeaffe3kRsKeeFXkYoOQ",
+ "messageID": "msg_ec344b5ba001OPxesOaFW5tw14",
+ "type": "tool",
+ "callID": "glob_7",
+ "tool": "glob",
+ "state": {
+ "status": "completed",
+ "input": {
+ "pattern": "node_modules/next/dist/docs/**/*.md"
+ },
+ "output": "No files found",
+ "title": "",
+ "metadata": {
+ "count": 0,
+ "truncated": false
+ },
+ "time": {
+ "start": 1781392522282,
+ "end": 1781392522290
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:22.294Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "glob",
+ "originalName": "glob",
+ "result": "No files found",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "pattern": "node_modules/next/dist/docs/**/*.md"
+ },
+ "output": "No files found",
+ "title": "",
+ "metadata": {
+ "count": 0,
+ "truncated": false
+ },
+ "time": {
+ "start": 1781392522282,
+ "end": 1781392522290
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:25.207Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "shell",
+ "originalName": "bash",
+ "args": {
+ "command": "ls node_modules/next/dist/docs/ 2>/dev/null || echo no docs dir",
+ "description": "List Next.js docs directory",
+ "_extractedCommand": "ls node_modules/next/dist/docs/ 2>/dev/null || echo no docs dir"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392525207,
+ "sessionID": "ses_13cbb7aeaffe3kRsKeeFXkYoOQ",
+ "part": {
+ "id": "prt_ec344c537001aFrpT3kgTKSyno",
+ "sessionID": "ses_13cbb7aeaffe3kRsKeeFXkYoOQ",
+ "messageID": "msg_ec344bc48001HJVbfVz05FBDoc",
+ "type": "tool",
+ "callID": "bash_8",
+ "tool": "bash",
+ "state": {
+ "status": "completed",
+ "input": {
+ "command": "ls node_modules/next/dist/docs/ 2>/dev/null || echo no docs dir",
+ "description": "List Next.js docs directory"
+ },
+ "output": "01-app\n02-pages\n03-architecture\n04-community\nindex.md\n",
+ "title": "List Next.js docs directory",
+ "metadata": {
+ "output": "01-app\n02-pages\n03-architecture\n04-community\nindex.md\n",
+ "exit": 0,
+ "description": "List Next.js docs directory"
+ },
+ "time": {
+ "start": 1781392525134,
+ "end": 1781392525200
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:25.207Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "shell",
+ "originalName": "bash",
+ "result": "01-app\n02-pages\n03-architecture\n04-community\nindex.md\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "command": "ls node_modules/next/dist/docs/ 2>/dev/null || echo no docs dir",
+ "description": "List Next.js docs directory"
+ },
+ "output": "01-app\n02-pages\n03-architecture\n04-community\nindex.md\n",
+ "title": "List Next.js docs directory",
+ "metadata": {
+ "output": "01-app\n02-pages\n03-architecture\n04-community\nindex.md\n",
+ "exit": 0,
+ "description": "List Next.js docs directory"
+ },
+ "time": {
+ "start": 1781392525134,
+ "end": 1781392525200
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:27.789Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "shell",
+ "originalName": "bash",
+ "args": {
+ "command": "find node_modules/next/dist/docs -type f | xargs grep -l -i font 2>/dev/null | head -20",
+ "description": "Find font-related docs",
+ "_extractedCommand": "find node_modules/next/dist/docs -type f | xargs grep -l -i font 2>/dev/null | head -20"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392527789,
+ "sessionID": "ses_13cbb7aeaffe3kRsKeeFXkYoOQ",
+ "part": {
+ "id": "prt_ec344ce70001dgGmkaqUXl4cnz",
+ "sessionID": "ses_13cbb7aeaffe3kRsKeeFXkYoOQ",
+ "messageID": "msg_ec344c7af001p4wYp3zrhTUdQ8",
+ "type": "tool",
+ "callID": "bash_9",
+ "tool": "bash",
+ "state": {
+ "status": "completed",
+ "input": {
+ "command": "find node_modules/next/dist/docs -type f | xargs grep -l -i font 2>/dev/null | head -20",
+ "description": "Find font-related docs"
+ },
+ "output": "node_modules/next/dist/docs/02-pages/02-guides/internationalization.md\nnode_modules/next/dist/docs/02-pages/02-guides/post-css.md\nnode_modules/next/dist/docs/02-pages/02-guides/upgrading/version-13.md\nnode_modules/next/dist/docs/02-pages/01-getting-started/05-fonts.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/01-components/font.md\nnode_modules/next/dist/docs/01-app/03-api-reference/08-turbopack.md\nnode_modules/next/dist/docs/01-app/03-api-reference/02-components/font.md\nnode_modules/next/dist/docs/01-app/03-api-reference/02-components/image.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/reactMaxHeadersLength.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/useLightningcss.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/03-eslint.md\nnode_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/error.md\nnode_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/layout.md\nnode_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/not-found.md\nnode_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/01-metadata/app-icons.md\nnode_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/01-metadata/opengraph-image.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/generate-image-metadata.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/generate-metadata.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/image-response.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/use-selected-layout-segment.md\n",
+ "title": "Find font-related docs",
+ "metadata": {
+ "output": "node_modules/next/dist/docs/02-pages/02-guides/internationalization.md\nnode_modules/next/dist/docs/02-pages/02-guides/post-css.md\nnode_modules/next/dist/docs/02-pages/02-guides/upgrading/version-13.md\nnode_modules/next/dist/docs/02-pages/01-getting-started/05-fonts.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/01-components/font.md\nnode_modules/next/dist/docs/01-app/03-api-reference/08-turbopack.md\nnode_modules/next/dist/docs/01-app/03-api-reference/02-components/font.md\nnode_modules/next/dist/docs/01-app/03-api-reference/02-components/image.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/reactMaxHeadersLength.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/useLightningcss.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/03-eslint.md\nnode_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/error.md\nnode_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/layout.md\nnode_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/not-found.md\nnode_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/01-metadata/app-icons.md\nnode_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/01-metadata/opengraph-image.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/generate-image-metadata.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/generate-metadata.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/image-response.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/use-selected-layout-segment.md\n",
+ "exit": 0,
+ "description": "Find font-related docs"
+ },
+ "time": {
+ "start": 1781392527739,
+ "end": 1781392527783
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:27.789Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "shell",
+ "originalName": "bash",
+ "result": "node_modules/next/dist/docs/02-pages/02-guides/internationalization.md\nnode_modules/next/dist/docs/02-pages/02-guides/post-css.md\nnode_modules/next/dist/docs/02-pages/02-guides/upgrading/version-13.md\nnode_modules/next/dist/docs/02-pages/01-getting-started/05-fonts.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/01-components/font.md\nnode_modules/next/dist/docs/01-app/03-api-reference/08-turbopack.md\nnode_modules/next/dist/docs/01-app/03-api-reference/02-components/font.md\nnode_modules/next/dist/docs/01-app/03-api-reference/02-components/image.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/reactMaxHeadersLength.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/useLightningcss.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/03-eslint.md\nnode_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/error.md\nnode_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/layout.md\nnode_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/not-found.md\nnode_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/01-metadata/app-icons.md\nnode_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/01-metadata/opengraph-image.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/generate-image-metadata.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/generate-metadata.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/image-response.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/use-selected-layout-segment.md\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "command": "find node_modules/next/dist/docs -type f | xargs grep -l -i font 2>/dev/null | head -20",
+ "description": "Find font-related docs"
+ },
+ "output": "node_modules/next/dist/docs/02-pages/02-guides/internationalization.md\nnode_modules/next/dist/docs/02-pages/02-guides/post-css.md\nnode_modules/next/dist/docs/02-pages/02-guides/upgrading/version-13.md\nnode_modules/next/dist/docs/02-pages/01-getting-started/05-fonts.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/01-components/font.md\nnode_modules/next/dist/docs/01-app/03-api-reference/08-turbopack.md\nnode_modules/next/dist/docs/01-app/03-api-reference/02-components/font.md\nnode_modules/next/dist/docs/01-app/03-api-reference/02-components/image.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/reactMaxHeadersLength.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/useLightningcss.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/03-eslint.md\nnode_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/error.md\nnode_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/layout.md\nnode_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/not-found.md\nnode_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/01-metadata/app-icons.md\nnode_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/01-metadata/opengraph-image.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/generate-image-metadata.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/generate-metadata.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/image-response.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/use-selected-layout-segment.md\n",
+ "title": "Find font-related docs",
+ "metadata": {
+ "output": "node_modules/next/dist/docs/02-pages/02-guides/internationalization.md\nnode_modules/next/dist/docs/02-pages/02-guides/post-css.md\nnode_modules/next/dist/docs/02-pages/02-guides/upgrading/version-13.md\nnode_modules/next/dist/docs/02-pages/01-getting-started/05-fonts.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/01-components/font.md\nnode_modules/next/dist/docs/01-app/03-api-reference/08-turbopack.md\nnode_modules/next/dist/docs/01-app/03-api-reference/02-components/font.md\nnode_modules/next/dist/docs/01-app/03-api-reference/02-components/image.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/reactMaxHeadersLength.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/useLightningcss.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/03-eslint.md\nnode_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/error.md\nnode_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/layout.md\nnode_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/not-found.md\nnode_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/01-metadata/app-icons.md\nnode_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/01-metadata/opengraph-image.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/generate-image-metadata.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/generate-metadata.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/image-response.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/use-selected-layout-segment.md\n",
+ "exit": 0,
+ "description": "Find font-related docs"
+ },
+ "time": {
+ "start": 1781392527739,
+ "end": 1781392527783
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:30.651Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "args": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/02-components/font.md",
+ "_extractedPath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/02-components/font.md"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392530651,
+ "sessionID": "ses_13cbb7aeaffe3kRsKeeFXkYoOQ",
+ "part": {
+ "id": "prt_ec344d84d001ft90w9UVtpAKXS",
+ "sessionID": "ses_13cbb7aeaffe3kRsKeeFXkYoOQ",
+ "messageID": "msg_ec344d1ca001WSL0YUVi6pqjUk",
+ "type": "tool",
+ "callID": "read_10",
+ "tool": "read",
+ "state": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/02-components/font.md"
+ },
+ "output": "\n00001| ---\n00002| title: Font Module\n00003| nav_title: Font\n00004| description: Optimizing loading web fonts with the built-in `next/font` loaders.\n00005| ---\n00006| \n00007| {/* The content of this doc is shared between the app and pages router. You can use the `Content` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}\n00008| \n00009| [`next/font`](/docs/app/api-reference/components/font) automatically optimizes your fonts (including custom fonts) and removes external network requests for improved privacy and performance.\n00010| \n00011| It includes **built-in automatic self-hosting** for any font file. This means you can optimally load web fonts with no [layout shift](https://web.dev/articles/cls).\n00012| \n00013| You can also conveniently use all [Google Fonts](https://fonts.google.com/). CSS and font files are downloaded at build time and self-hosted with the rest of your static assets. **No requests are sent to Google by the browser.**\n00014| \n00015| \n00016| \n00017| ```tsx filename=\"app/layout.tsx\" switcher\n00018| import { Inter } from 'next/font/google'\n00019| \n00020| // If loading a variable font, you don't need to specify the font weight\n00021| const inter = Inter({\n00022| subsets: ['latin'],\n00023| display: 'swap',\n00024| })\n00025| \n00026| export default function RootLayout({\n00027| children,\n00028| }: {\n00029| children: React.ReactNode\n00030| }) {\n00031| return (\n00032| \n00033| {children}\n00034| \n00035| )\n00036| }\n00037| ```\n00038| \n00039| ```jsx filename=\"app/layout.js\" switcher\n00040| import { Inter } from 'next/font/google'\n00041| \n00042| // If loading a variable font, you don't need to specify the font weight\n00043| const inter = Inter({\n00044| subsets: ['latin'],\n00045| display: 'swap',\n00046| })\n00047| \n00048| export default function RootLayout({ children }) {\n00049| return (\n00050| \n00051| {children}\n00052| \n00053| )\n00054| }\n00055| ```\n00056| \n00057| \n00058| \n00059| \n00060| \n00061| To use the font in all your pages, add it to [`_app.js` file](/docs/pages/building-your-application/routing/custom-app) under `/pages` as shown below:\n00062| \n00063| ```jsx filename=\"pages/_app.js\"\n00064| import { Inter } from 'next/font/google'\n00065| \n00066| // If loading a variable font, you don't need to specify the font weight\n00067| const inter = Inter({ subsets: ['latin'] })\n00068| \n00069| export default function MyApp({ Component, pageProps }) {\n00070| return (\n00071| \n00072| \n00073| \n00074| )\n00075| }\n00076| ```\n00077| \n00078| \n00079| \n00080| > **🎥 Watch:** Learn more about using `next/font` → [YouTube (6 minutes)](https://www.youtube.com/watch?v=L8_98i_bMMA).\n00081| \n00082| ## Reference\n00083| \n00084| | Key | `font/google` | `font/local` | Type | Required |\n00085| | ------------------------------------------- | ------------------- | ------------------- | -------------------------- | ----------------- |\n00086| | [`src`](#src) | | | String or Array of Objects | Yes |\n00087| | [`weight`](#weight) | | | String or Array | Required/Optional |\n00088| | [`style`](#style) | | | String or Array | - |\n00089| | [`subsets`](#subsets) | | | Array of Strings | - |\n00090| | [`axes`](#axes) | | | Array of Strings | - |\n00091| | [`display`](#display) | | | String | - |\n00092| | [`preload`](#preload) | | | Boolean | - |\n00093| | [`fallback`](#fallback) | | | Array of Strings | - |\n00094| | [`adjustFontFallback`](#adjustfontfallback) | | | Boolean or String | - |\n00095| | [`variable`](#variable) | | | String | - |\n00096| | [`declarations`](#declarations) | | | Array of Objects | - |\n00097| \n00098| ### `src`\n00099| \n00100| The path of the font file as a string or an array of objects (with type `Array<{path: string, weight?: string, style?: string}>`) relative to the directory where the font loader function is called.\n00101| \n00102| Used in `next/font/local`\n00103| \n00104| - Required\n00105| \n00106| Examples:\n00107| \n00108| - `src:'./fonts/my-font.woff2'` where `my-font.woff2` is placed in a directory named `fonts` inside the `app` directory\n00109| - `src:[{path: './inter/Inter-Thin.ttf', weight: '100',},{path: './inter/Inter-Regular.ttf',weight: '400',},{path: './inter/Inter-Bold-Italic.ttf', weight: '700',style: 'italic',},]`\n00110| - if the font loader function is called in `app/page.tsx` using `src:'../styles/fonts/my-font.ttf'`, then `my-font.ttf` is placed in `styles/fonts` at the root of the project\n00111| \n00112| ### `weight`\n00113| \n00114| The font [`weight`](https://fonts.google.com/knowledge/glossary/weight) with the following possibilities:\n00115| \n00116| - A string with possible values of the weights available for the specific font or a range of values if it's a [variable](https://fonts.google.com/variablefonts) font\n00117| - An array of weight values if the font is not a [variable google font](https://fonts.google.com/variablefonts). It applies to `next/font/google` only.\n00118| \n00119| Used in `next/font/google` and `next/font/local`\n00120| \n00121| - Required if the font being used is **not** [variable](https://fonts.google.com/variablefonts)\n00122| \n00123| Examples:\n00124| \n00125| - `weight: '400'`: A string for a single weight value - for the font [`Inter`](https://fonts.google.com/specimen/Inter?query=inter), the possible values are `'100'`, `'200'`, `'300'`, `'400'`, `'500'`, `'600'`, `'700'`, `'800'`, `'900'` or `'variable'` where `'variable'` is the default)\n00126| - `weight: '100 900'`: A string for the range between `100` and `900` for a variable font\n00127| - `weight: ['100','400','900']`: An array of 3 possible values for a non variable font\n00128| \n00129| ### `style`\n00130| \n00131| The font [`style`](https://developer.mozilla.org/docs/Web/CSS/font-style) with the following possibilities:\n00132| \n00133| - A string [value](https://developer.mozilla.org/docs/Web/CSS/font-style#values) with default value of `'normal'`\n00134| - An array of style values if the font is not a [variable google font](https://fonts.google.com/variablefonts). It applies to `next/font/google` only.\n00135| \n00136| Used in `next/font/google` and `next/font/local`\n00137| \n00138| - Optional\n00139| \n00140| Examples:\n00141| \n00142| - `style: 'italic'`: A string - it can be `normal` or `italic` for `next/font/google`\n00143| - `style: 'oblique'`: A string - it can take any value for `next/font/local` but is expected to come from [standard font styles](https://developer.mozilla.org/docs/Web/CSS/font-style)\n00144| - `style: ['italic','normal']`: An array of 2 values for `next/font/google` - the values are from `normal` and `italic`\n00145| \n00146| ### `subsets`\n00147| \n00148| The font [`subsets`](https://fonts.google.com/knowledge/glossary/subsetting) defined by an array of string values with the names of each subset you would like to be [preloaded](/docs/app/api-reference/components/font#specifying-a-subset). Fonts specified via `subsets` will have a link preload tag injected into the head when the [`preload`](#preload) option is true, which is the default.\n00149| \n00150| Used in `next/font/google`\n00151| \n00152| - Optional\n00153| \n00154| Examples:\n00155| \n00156| - `subsets: ['latin']`: An array with the subset `latin`\n00157| \n00158| You can find a list of all subsets on the Google Fonts page for your font.\n00159| \n00160| ### `axes`\n00161| \n00162| Some variable fonts have extra `axes` that can be included. By default, only the font weight is included to keep the file size down. The possible values of `axes` depend on the specific font.\n00163| \n00164| Used in `next/font/google`\n00165| \n00166| - Optional\n00167| \n00168| Examples:\n00169| \n00170| - `axes: ['slnt']`: An array with value `slnt` for the `Inter` variable font which has `slnt` as additional `axes` as shown [here](https://fonts.google.com/variablefonts?vfquery=inter#font-families). You can find the possible `axes` values for your font by using the filter on the [Google variable fonts page](https://fonts.google.com/variablefonts#font-families) and looking for axes other than `wght`\n00171| \n00172| ### `display`\n00173| \n00174| The font [`display`](https://developer.mozilla.org/docs/Web/CSS/@font-face/font-display) with possible string [values](https://developer.mozilla.org/docs/Web/CSS/@font-face/font-display#values) of `'auto'`, `'block'`, `'swap'`, `'fallback'` or `'optional'` with default value of `'swap'`.\n00175| \n00176| Used in `next/font/google` and `next/font/local`\n00177| \n00178| - Optional\n00179| \n00180| Examples:\n00181| \n00182| - `display: 'optional'`: A string assigned to the `optional` value\n00183| \n00184| ### `preload`\n00185| \n00186| A boolean value that specifies whether the font should be [preloaded](/docs/app/api-reference/components/font#preloading) or not. The default is `true`.\n00187| \n00188| Used in `next/font/google` and `next/font/local`\n00189| \n00190| - Optional\n00191| \n00192| Examples:\n00193| \n00194| - `preload: false`\n00195| \n00196| ### `fallback`\n00197| \n00198| The fallback font to use if the font cannot be loaded. An array of strings of fallback fonts with no default.\n00199| \n00200| - Optional\n00201| \n00202| Used in `next/font/google` and `next/font/local`\n00203| \n00204| Examples:\n00205| \n00206| - `fallback: ['system-ui', 'arial']`: An array setting the fallback fonts to `system-ui` or `arial`\n00207| \n00208| ### `adjustFontFallback`\n00209| \n00210| - For `next/font/google`: A boolean value that sets whether an automatic fallback font should be used to reduce [Cumulative Layout Shift](https://web.dev/cls/). The default is `true`.\n00211| - For `next/font/local`: A string or boolean `false` value that sets whether an automatic fallback font should be used to reduce [Cumulative Layout Shift](https://web.dev/cls/). The possible values are `'Arial'`, `'Times New Roman'` or `false`. The default is `'Arial'`.\n00212| \n00213| Used in `next/font/google` and `next/font/local`\n00214| \n00215| - Optional\n00216| \n00217| Examples:\n00218| \n00219| - `adjustFontFallback: false`: for `next/font/google`\n00220| - `adjustFontFallback: 'Times New Roman'`: for `next/font/local`\n00221| \n00222| ### `variable`\n00223| \n00224| A string value to define the CSS variable name to be used if the style is applied with the [CSS variable method](#css-variables).\n00225| \n00226| Used in `next/font/google` and `next/font/local`\n00227| \n00228| - Optional\n00229| \n00230| Examples:\n00231| \n00232| - `variable: '--my-font'`: The CSS variable `--my-font` is declared\n00233| \n00234| ### `declarations`\n00235| \n00236| An array of font face [descriptor](https://developer.mozilla.org/docs/Web/CSS/@font-face#descriptors) key-value pairs that define the generated `@font-face` further.\n00237| \n00238| Used in `next/font/local`\n00239| \n00240| - Optional\n00241| \n00242| Examples:\n00243| \n00244| - `declarations: [{ prop: 'ascent-override', value: '90%' }]`\n00245| \n00246| ## Examples\n00247| \n00248| ## Google Fonts\n00249| \n00250| To use a Google font, import it from `next/font/google` as a function. We recommend using [variable fonts](https://fonts.google.com/variablefonts) for the best performance and flexibility.\n00251| \n00252| \n00253| \n00254| ```tsx filename=\"app/layout.tsx\" switcher\n00255| import { Inter } from 'next/font/google'\n00256| \n00257| // If loading a variable font, you don't need to specify the font weight\n00258| const inter = Inter({\n00259| subsets: ['latin'],\n00260| display: 'swap',\n00261| })\n00262| \n00263| export default function RootLayout({\n00264| children,\n00265| }: {\n00266| children: React.ReactNode\n00267| }) {\n00268| return (\n00269| \n00270| {children}\n00271| \n00272| )\n00273| }\n00274| ```\n00275| \n00276| ```jsx filename=\"app/layout.js\" switcher\n00277| import { Inter } from 'next/font/google'\n00278| \n00279| // If loading a variable font, you don't need to specify the font weight\n00280| const inter = Inter({\n00281| subsets: ['latin'],\n00282| display: 'swap',\n00283| })\n00284| \n00285| export default function RootLayout({ children }) {\n00286| return (\n00287| \n00288| {children}\n00289| \n00290| )\n00291| }\n00292| ```\n00293| \n00294| If you can't use a variable font, you will **need to specify a weight**:\n00295| \n00296| ```tsx filename=\"app/layout.tsx\" switcher\n00297| import { Roboto } from 'next/font/google'\n00298| \n00299| const roboto = Roboto({\n00300| weight: '400',\n00301| subsets: ['latin'],\n00302| display: 'swap',\n00303| })\n00304| \n00305| export default function RootLayout({\n00306| children,\n00307| }: {\n00308| children: React.ReactNode\n00309| }) {\n00310| return (\n00311| \n00312| {children}\n00313| \n00314| )\n00315| }\n00316| ```\n00317| \n00318| ```jsx filename=\"app/layout.js\" switcher\n00319| import { Roboto } from 'next/font/google'\n00320| \n00321| const roboto = Roboto({\n00322| weight: '400',\n00323| subsets: ['latin'],\n00324| display: 'swap',\n00325| })\n00326| \n00327| export default function RootLayout({ children }) {\n00328| return (\n00329| \n00330| {children}\n00331| \n00332| )\n00333| }\n00334| ```\n00335| \n00336| \n00337| \n00338| \n00339| \n00340| To use the font in all your pages, add it to [`_app.js` file](/docs/pages/building-your-application/routing/custom-app) under `/pages` as shown below:\n00341| \n00342| ```jsx filename=\"pages/_app.js\"\n00343| import { Inter } from 'next/font/google'\n00344| \n00345| // If loading a variable font, you don't need to specify the font weight\n00346| const inter = Inter({ subsets: ['latin'] })\n00347| \n00348| export default function MyApp({ Component, pageProps }) {\n00349| return (\n00350| \n00351| \n00352| \n00353| )\n00354| }\n00355| ```\n00356| \n00357| If you can't use a variable font, you will **need to specify a weight**:\n00358| \n00359| ```jsx filename=\"pages/_app.js\"\n00360| import { Roboto } from 'next/font/google'\n00361| \n00362| const roboto = Roboto({\n00363| weight: '400',\n00364| subsets: ['latin'],\n00365| })\n00366| \n00367| export default function MyApp({ Component, pageProps }) {\n00368| return (\n00369| \n00370| \n00371| \n00372| )\n00373| }\n00374| ```\n00375| \n00376| \n00377| \n00378| You can specify multiple weights and/or styles by using an array:\n00379| \n00380| ```jsx filename=\"app/layout.js\"\n00381| const roboto = Roboto({\n00382| weight: ['400', '700'],\n00383| style: ['normal', 'italic'],\n00384| subsets: ['latin'],\n00385| display: 'swap',\n00386| })\n00387| ```\n00388| \n00389| > **Good to know**: Use an underscore (\\_) for font names with multiple words. E.g. `Roboto Mono` should be imported as `Roboto_Mono`.\n00390| \n00391| \n00392| \n00393| ### Apply the font in ``\n00394| \n00395| You can also use the font without a wrapper and `className` by injecting it inside the `` as follows:\n00396| \n00397| ```jsx filename=\"pages/_app.js\"\n00398| import { Inter } from 'next/font/google'\n00399| \n00400| const inter = Inter({ subsets: ['latin'] })\n00401| \n00402| export default function MyApp({ Component, pageProps }) {\n00403| return (\n00404| <>\n00405| \n00410| \n00411| >\n00412| )\n00413| }\n00414| ```\n00415| \n00416| ### Single page usage\n00417| \n00418| To use the font on a single page, add it to the specific page as shown below:\n00419| \n00420| ```jsx filename=\"pages/index.js\"\n00421| import { Inter } from 'next/font/google'\n00422| \n00423| const inter = Inter({ subsets: ['latin'] })\n00424| \n00425| export default function Home() {\n00426| return (\n00427|
\n00428|
Hello World
\n00429|
\n00430| )\n00431| }\n00432| ```\n00433| \n00434| \n00435| \n00436| ### Specifying a subset\n00437| \n00438| Google Fonts are automatically [subset](https://fonts.google.com/knowledge/glossary/subsetting). This reduces the size of the font file and improves performance. You'll need to define which of these subsets you want to preload. Failing to specify any subsets while [`preload`](/docs/app/api-reference/components/font#preload) is `true` will result in a warning.\n00439| \n00440| This can be done by adding it to the function call:\n00441| \n00442| \n00443| \n00444| ```tsx filename=\"app/layout.tsx\" switcher\n00445| const inter = Inter({ subsets: ['latin'] })\n00446| ```\n00447| \n00448| ```jsx filename=\"app/layout.js\" switcher\n00449| const inter = Inter({ subsets: ['latin'] })\n00450| ```\n00451| \n00452| \n00453| \n00454| \n00455| \n00456| ```jsx filename=\"pages/_app.js\"\n00457| const inter = Inter({ subsets: ['latin'] })\n00458| ```\n00459| \n00460| \n00461| \n00462| View the [Font API Reference](/docs/app/api-reference/components/font) for more information.\n00463| \n00464| ## Using Multiple Fonts\n00465| \n00466| You can import and use multiple fonts in your application. There are two approaches you can take.\n00467| \n00468| The first approach is to create a utility function that exports a font, imports it, and applies its `className` where needed. This ensures the font is preloaded only when it's rendered:\n00469| \n00470| ```ts filename=\"app/fonts.ts\" switcher\n00471| import { Inter, Roboto_Mono } from 'next/font/google'\n00472| \n00473| export const inter = Inter({\n00474| subsets: ['latin'],\n00475| display: 'swap',\n00476| })\n00477| \n00478| export const roboto_mono = Roboto_Mono({\n00479| subsets: ['latin'],\n00480| display: 'swap',\n00481| })\n00482| ```\n00483| \n00484| ```js filename=\"app/fonts.js\" switcher\n00485| import { Inter, Roboto_Mono } from 'next/font/google'\n00486| \n00487| export const inter = Inter({\n00488| subsets: ['latin'],\n00489| display: 'swap',\n00490| })\n00491| \n00492| export const roboto_mono = Roboto_Mono({\n00493| subsets: ['latin'],\n00494| display: 'swap',\n00495| })\n00496| ```\n00497| \n00498| \n00499| \n00500| ```tsx filename=\"app/layout.tsx\" switcher\n00501| import { inter } from './fonts'\n00502| \n00503| export default function Layout({ children }: { children: React.ReactNode }) {\n00504| return (\n00505| \n00506| \n00507|
{children}
\n00508| \n00509| \n00510| )\n00511| }\n00512| ```\n00513| \n00514| ```jsx filename=\"app/layout.js\" switcher\n00515| import { inter } from './fonts'\n00516| \n00517| export default function Layout({ children }) {\n00518| return (\n00519| \n00520| \n00521|
\n00547| >\n00548| )\n00549| }\n00550| ```\n00551| \n00552| \n00553| \n00554| In the example above, `Inter` will be applied globally, and `Roboto Mono` can be imported and applied as needed.\n00555| \n00556| Alternatively, you can create a [CSS variable](/docs/app/api-reference/components/font#variable) and use it with your preferred CSS solution:\n00557| \n00558| \n00559| \n00560| ```tsx filename=\"app/layout.tsx\" switcher\n00561| import { Inter, Roboto_Mono } from 'next/font/google'\n00562| import styles from './global.css'\n00563| \n00564| const inter = Inter({\n00565| subsets: ['latin'],\n00566| variable: '--font-inter',\n00567| display: 'swap',\n00568| })\n00569| \n00570| const roboto_mono = Roboto_Mono({\n00571| subsets: ['latin'],\n00572| variable: '--font-roboto-mono',\n00573| display: 'swap',\n00574| })\n00575| \n00576| export default function RootLayout({\n00577| children,\n00578| }: {\n00579| children: React.ReactNode\n00580| }) {\n00581| return (\n00582| \n00583| \n00584|
\n00613| \n00614| \n00615| )\n00616| }\n00617| ```\n00618| \n00619| \n00620| \n00621| ```css filename=\"app/global.css\"\n00622| html {\n00623| font-family: var(--font-inter);\n00624| }\n00625| \n00626| h1 {\n00627| font-family: var(--font-roboto-mono);\n00628| }\n00629| ```\n00630| \n00631| In the example above, `Inter` will be applied globally, and any `
` tags will be styled with `Roboto Mono`.\n00632| \n00633| > **Recommendation**: Use multiple fonts conservatively since each new font is an additional resource the client has to download.\n00634| \n00635| ### Local Fonts\n00636| \n00637| Import `next/font/local` and specify the `src` of your local font file. We recommend using [variable fonts](https://fonts.google.com/variablefonts) for the best performance and flexibility.\n00638| \n00639| \n00640| \n00641| ```tsx filename=\"app/layout.tsx\" switcher\n00642| import localFont from 'next/font/local'\n00643| \n00644| // Font files can be colocated inside of `app`\n00645| const myFont = localFont({\n00646| src: './my-font.woff2',\n00647| display: 'swap',\n00648| })\n00649| \n00650| export default function RootLayout({\n00651| children,\n00652| }: {\n00653| children: React.ReactNode\n00654| }) {\n00655| return (\n00656| \n00657| {children}\n00658| \n00659| )\n00660| }\n00661| ```\n00662| \n00663| ```jsx filename=\"app/layout.js\" switcher\n00664| import localFont from 'next/font/local'\n00665| \n00666| // Font files can be colocated inside of `app`\n00667| const myFont = localFont({\n00668| src: './my-font.woff2',\n00669| display: 'swap',\n00670| })\n00671| \n00672| export default function RootLayout({ children }) {\n00673| return (\n00674| \n00675| {children}\n00676| \n00677| )\n00678| }\n00679| ```\n00680| \n00681| \n00682| \n00683| \n00684| \n00685| ```jsx filename=\"pages/_app.js\"\n00686| import localFont from 'next/font/local'\n00687| \n00688| // Font files can be colocated inside of `pages`\n00689| const myFont = localFont({ src: './my-font.woff2' })\n00690| \n00691| export default function MyApp({ Component, pageProps }) {\n00692| return (\n00693| \n00694| \n00695| \n00696| )\n00697| }\n00698| ```\n00699| \n00700| \n00701| \n00702| If you want to use multiple files for a single font family, `src` can be an array:\n00703| \n00704| ```js\n00705| const roboto = localFont({\n00706| src: [\n00707| {\n00708| path: './Roboto-Regular.woff2',\n00709| weight: '400',\n00710| style: 'normal',\n00711| },\n00712| {\n00713| path: './Roboto-Italic.woff2',\n00714| weight: '400',\n00715| style: 'italic',\n00716| },\n00717| {\n00718| path: './Roboto-Bold.woff2',\n00719| weight: '700',\n00720| style: 'normal',\n00721| },\n00722| {\n00723| path: './Roboto-BoldItalic.woff2',\n00724| weight: '700',\n00725| style: 'italic',\n00726| },\n00727| ],\n00728| })\n00729| ```\n00730| \n00731| View the [Font API Reference](/docs/app/api-reference/components/font) for more information.\n00732| \n00733| ### With Tailwind CSS\n00734| \n00735| `next/font` integrates seamlessly with [Tailwind CSS](https://tailwindcss.com/) using [CSS variables](/docs/app/api-reference/components/font#css-variables).\n00736| \n00737| In the example below, we use the `Inter` and `Roboto_Mono` fonts from `next/font/google` (you can use any Google Font or Local Font). Use the `variable` option to define a CSS variable name, such as `inter` and `roboto_mono` for these fonts, respectively. Then, apply `inter.variable` and `roboto_mono.variable` to include the CSS variables in your HTML document.\n00738| \n00739| > **Good to know**: You can add these variables to the `` or `` tag, depending on your preference, styling needs or project requirements.\n00740| \n00741| \n00742| \n00743| ```tsx filename=\"app/layout.tsx\" switcher\n00744| import { Inter, Roboto_Mono } from 'next/font/google'\n00745| \n00746| const inter = Inter({\n00747| subsets: ['latin'],\n00748| display: 'swap',\n00749| variable: '--font-inter',\n00750| })\n00751| \n00752| const roboto_mono = Roboto_Mono({\n00753| subsets: ['latin'],\n00754| display: 'swap',\n00755| variable: '--font-roboto-mono',\n00756| })\n00757| \n00758| export default function RootLayout({\n00759| children,\n00760| }: {\n00761| children: React.ReactNode\n00762| }) {\n00763| return (\n00764| \n00768| {children}\n00769| \n00770| )\n00771| }\n00772| ```\n00773| \n00774| ```jsx filename=\"app/layout.js\" switcher\n00775| import { Inter, Roboto_Mono } from 'next/font/google'\n00776| \n00777| const inter = Inter({\n00778| subsets: ['latin'],\n00779| display: 'swap',\n00780| variable: '--font-inter',\n00781| })\n00782| \n00783| const roboto_mono = Roboto_Mono({\n00784| subsets: ['latin'],\n00785| display: 'swap',\n00786| variable: '--font-roboto-mono',\n00787| })\n00788| \n00789| export default function RootLayout({ children }) {\n00790| return (\n00791| \n00795| {children}\n00796| \n00797| )\n00798| }\n00799| ```\n00800| \n00801| \n00802| \n00803| \n00804| \n00805| ```jsx filename=\"pages/_app.js\"\n00806| import { Inter } from 'next/font/google'\n00807| \n00808| const inter = Inter({\n00809| subsets: ['latin'],\n00810| variable: '--font-inter',\n00811| })\n00812| \n00813| const roboto_mono = Roboto_Mono({\n00814| subsets: ['latin'],\n00815| display: 'swap',\n00816| variable: '--font-roboto-mono',\n00817| })\n00818| \n00819| export default function MyApp({ Component, pageProps }) {\n00820| return (\n00821| \n00822| \n00823| \n00824| )\n00825| }\n00826| ```\n00827| \n00828| \n00829| \n00830| Finally, add the CSS variable to your [Tailwind CSS config](/docs/app/getting-started/css#tailwind-css):\n00831| \n00832| ```css filename=\"global.css\"\n00833| @import 'tailwindcss';\n00834| \n00835| @theme inline {\n00836| --font-sans: var(--font-inter);\n00837| --font-mono: var(--font-roboto-mono);\n00838| }\n00839| ```\n00840| \n00841| ### Tailwind CSS v3\n00842| \n00843| ```js filename=\"tailwind.config.js\"\n00844| /** @type {import('tailwindcss').Config} */\n00845| module.exports = {\n00846| content: [\n00847| './pages/**/*.{js,ts,jsx,tsx}',\n00848| './components/**/*.{js,ts,jsx,tsx}',\n00849| './app/**/*.{js,ts,jsx,tsx}',\n00850| ],\n00851| theme: {\n00852| extend: {\n00853| fontFamily: {\n00854| sans: ['var(--font-inter)'],\n00855| mono: ['var(--font-roboto-mono)'],\n00856| },\n00857| },\n00858| },\n00859| plugins: [],\n00860| }\n00861| ```\n00862| \n00863| You can now use the `font-sans` and `font-mono` utility classes to apply the font to your elements.\n00864| \n00865| ```html\n00866|
The quick brown fox ...
\n00867|
The quick brown fox ...
\n00868| ```\n00869| \n00870| ### Applying Styles\n00871| \n00872| You can apply the font styles in three ways:\n00873| \n00874| - [`className`](#classname)\n00875| - [`style`](#style-1)\n00876| - [CSS Variables](#css-variables)\n00877| \n00878| #### `className`\n00879| \n00880| Returns a read-only CSS `className` for the loaded font to be passed to an HTML element.\n00881| \n00882| ```tsx\n00883|
Hello, Next.js!
\n00884| ```\n00885| \n00886| #### `style`\n00887| \n00888| Returns a read-only CSS `style` object for the loaded font to be passed to an HTML element, including `style.fontFamily` to access the font family name and fallback fonts.\n00889| \n00890| ```tsx\n00891|
Hello World
\n00892| ```\n00893| \n00894| #### CSS Variables\n00895| \n00896| If you would like to set your styles in an external style sheet and specify additional options there, use the CSS variable method.\n00897| \n00898| In addition to importing the font, also import the CSS file where the CSS variable is defined and set the variable option of the font loader object as follows:\n00899| \n00900| ```tsx filename=\"app/page.tsx\" switcher\n00901| import { Inter } from 'next/font/google'\n00902| import styles from '../styles/component.module.css'\n00903| \n00904| const inter = Inter({\n00905| variable: '--font-inter',\n00906| })\n00907| ```\n00908| \n00909| ```jsx filename=\"app/page.js\" switcher\n00910| import { Inter } from 'next/font/google'\n00911| import styles from '../styles/component.module.css'\n00912| \n00913| const inter = Inter({\n00914| variable: '--font-inter',\n00915| })\n00916| ```\n00917| \n00918| To use the font, set the `className` of the parent container of the text you would like to style to the font loader's `variable` value and the `className` of the text to the `styles` property from the external CSS file.\n00919| \n00920| ```tsx filename=\"app/page.tsx\" switcher\n00921| \n00922|
\n00929| \n00930| ```\n00931| \n00932| Define the `text` selector class in the `component.module.css` CSS file as follows:\n00933| \n00934| ```css filename=\"styles/component.module.css\"\n00935| .text {\n00936| font-family: var(--font-inter);\n00937| font-weight: 200;\n00938| font-style: italic;\n00939| }\n00940| ```\n00941| \n00942| In the example above, the text `Hello World` is styled using the `Inter` font and the generated font fallback with `font-weight: 200` and `font-style: italic`.\n00943| \n00944| ### Using a font definitions file\n00945| \n00946| Every time you call the `localFont` or Google font function, that font will be hosted as one instance in your application. Therefore, if you need to use the same font in multiple places, you should load it in one place and import the related font object where you need it. This is done using a font definitions file.\n00947| \n00948| For example, create a `fonts.ts` file in a `styles` folder at the root of your app directory.\n00949| \n00950| Then, specify your font definitions as follows:\n00951| \n00952| ```ts filename=\"styles/fonts.ts\" switcher\n00953| import { Inter, Lora, Source_Sans_3 } from 'next/font/google'\n00954| import localFont from 'next/font/local'\n00955| \n00956| // define your variable fonts\n00957| const inter = Inter()\n00958| const lora = Lora()\n00959| // define 2 weights of a non-variable font\n00960| const sourceCodePro400 = Source_Sans_3({ weight: '400' })\n00961| const sourceCodePro700 = Source_Sans_3({ weight: '700' })\n00962| // define a custom local font where GreatVibes-Regular.ttf is stored in the styles folder\n00963| const greatVibes = localFont({ src: './GreatVibes-Regular.ttf' })\n00964| \n00965| export { inter, lora, sourceCodePro400, sourceCodePro700, greatVibes }\n00966| ```\n00967| \n00968| ```js filename=\"styles/fonts.js\" switcher\n00969| import { Inter, Lora, Source_Sans_3 } from 'next/font/google'\n00970| import localFont from 'next/font/local'\n00971| \n00972| // define your variable fonts\n00973| const inter = Inter()\n00974| const lora = Lora()\n00975| // define 2 weights of a non-variable font\n00976| const sourceCodePro400 = Source_Sans_3({ weight: '400' })\n00977| const sourceCodePro700 = Source_Sans_3({ weight: '700' })\n00978| // define a custom local font where GreatVibes-Regular.ttf is stored in the styles folder\n00979| const greatVibes = localFont({ src: './GreatVibes-Regular.ttf' })\n00980| \n00981| export { inter, lora, sourceCodePro400, sourceCodePro700, greatVibes }\n00982| ```\n00983| \n00984| You can now use these definitions in your code as follows:\n00985| \n00986| ```tsx filename=\"app/page.tsx\" switcher\n00987| import { inter, lora, sourceCodePro700, greatVibes } from '../styles/fonts'\n00988| \n00989| export default function Page() {\n00990| return (\n00991|
\n00992|
Hello world using Inter font
\n00993|
Hello world using Lora font
\n00994|
\n00995| Hello world using Source_Sans_3 font with weight 700\n00996|
\n01012| Hello world using Source_Sans_3 font with weight 700\n01013|
\n01014|
My title in Great Vibes font
\n01015|
\n01016| )\n01017| }\n01018| ```\n01019| \n01020| To make it easier to access the font definitions in your code, you can define a path alias in your `tsconfig.json` or `jsconfig.json` files as follows:\n01021| \n01022| ```json filename=\"tsconfig.json\"\n01023| {\n01024| \"compilerOptions\": {\n01025| \"paths\": {\n01026| \"@/fonts\": [\"./styles/fonts\"]\n01027| }\n01028| }\n01029| }\n01030| ```\n01031| \n01032| You can now import any font definition as follows:\n01033| \n01034| ```tsx filename=\"app/about/page.tsx\" switcher\n01035| import { greatVibes, sourceCodePro400 } from '@/fonts'\n01036| ```\n01037| \n01038| ```jsx filename=\"app/about/page.js\" switcher\n01039| import { greatVibes, sourceCodePro400 } from '@/fonts'\n01040| ```\n01041| \n01042| ### Preloading\n01043| \n01044| \n01045| \n01046| When a font function is called on a page of your site, it is not globally available and preloaded on all routes. Rather, the font is only preloaded on the related routes based on the type of file where it is used:\n01047| \n01048| - If it's a [unique page](/docs/app/api-reference/file-conventions/page), it is preloaded on the unique route for that page.\n01049| - If it's a [layout](/docs/app/api-reference/file-conventions/layout), it is preloaded on all the routes wrapped by the layout.\n01050| - If it's the [root layout](/docs/app/api-reference/file-conventions/layout#root-layout), it is preloaded on all routes.\n01051| \n01052| \n01053| \n01054| \n01055| \n01056| When a font function is called on a page of your site, it is not globally available and preloaded on all routes. Rather, the font is only preloaded on the related route/s based on the type of file where it is used:\n01057| \n01058| - if it's a [unique page](/docs/pages/building-your-application/routing/pages-and-layouts), it is preloaded on the unique route for that page\n01059| - if it's in the [custom App](/docs/pages/building-your-application/routing/custom-app), it is preloaded on all the routes of the site under `/pages`\n01060| \n01061| \n01062| \n01063| ## Version Changes\n01064| \n01065| | Version | Changes |\n01066| | --------- | --------------------------------------------------------------------- |\n01067| | `v13.2.0` | `@next/font` renamed to `next/font`. Installation no longer required. |\n01068| | `v13.0.0` | `@next/font` was added. |\n01069| \n\n(End of file - total 1069 lines)\n",
+ "title": "node_modules/next/dist/docs/01-app/03-api-reference/02-components/font.md",
+ "metadata": {
+ "preview": "---\ntitle: Font Module\nnav_title: Font\ndescription: Optimizing loading web fonts with the built-in `next/font` loaders.\n---\n\n{/* The content of this doc is shared between the app and pages router. You can use the `Content` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}\n\n[`next/font`](/docs/app/api-reference/components/font) automatically optimizes your fonts (including custom fonts) and removes external network requests for improved privacy and performance.\n\nIt includes **built-in automatic self-hosting** for any font file. This means you can optimally load web fonts with no [layout shift](https://web.dev/articles/cls).\n\nYou can also conveniently use all [Google Fonts](https://fonts.google.com/). CSS and font files are downloaded at build time and self-hosted with the rest of your static assets. **No requests are sent to Google by the browser.**\n\n\n\n```tsx filename=\"app/layout.tsx\" switcher\nimport { Inter } from 'next/font/google'\n\n// If loading a variable font, you don't need to specify the font weight"
+ },
+ "time": {
+ "start": 1781392530643,
+ "end": 1781392530648
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:30.651Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| ---\n00002| title: Font Module\n00003| nav_title: Font\n00004| description: Optimizing loading web fonts with the built-in `next/font` loaders.\n00005| ---\n00006| \n00007| {/* The content of this doc is shared between the app and pages router. You can use the `Content` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}\n00008| \n00009| [`next/font`](/docs/app/api-reference/components/font) automatically optimizes your fonts (including custom fonts) and removes external network requests for improved privacy and performance.\n00010| \n00011| It includes **built-in automatic self-hosting** for any font file. This means you can optimally load web fonts with no [layout shift](https://web.dev/articles/cls).\n00012| \n00013| You can also conveniently use all [Google Fonts](https://fonts.google.com/). CSS and font files are downloaded at build time and self-hosted with the rest of your static assets. **No requests are sent to Google by the browser.**\n00014| \n00015| \n00016| \n00017| ```tsx filename=\"app/layout.tsx\" switcher\n00018| import { Inter } from 'next/font/google'\n00019| \n00020| // If loading a variable font, you don't need to specify the font weight\n00021| const inter = Inter({\n00022| subsets: ['latin'],\n00023| display: 'swap',\n00024| })\n00025| \n00026| export default function RootLayout({\n00027| children,\n00028| }: {\n00029| children: React.ReactNode\n00030| }) {\n00031| return (\n00032| \n00033| {children}\n00034| \n00035| )\n00036| }\n00037| ```\n00038| \n00039| ```jsx filename=\"app/layout.js\" switcher\n00040| import { Inter } from 'next/font/google'\n00041| \n00042| // If loading a variable font, you don't need to specify the font weight\n00043| const inter = Inter({\n00044| subsets: ['latin'],\n00045| display: 'swap',\n00046| })\n00047| \n00048| export default function RootLayout({ children }) {\n00049| return (\n00050| \n00051| {children}\n00052| \n00053| )\n00054| }\n00055| ```\n00056| \n00057| \n00058| \n00059| \n00060| \n00061| To use the font in all your pages, add it to [`_app.js` file](/docs/pages/building-your-application/routing/custom-app) under `/pages` as shown below:\n00062| \n00063| ```jsx filename=\"pages/_app.js\"\n00064| import { Inter } from 'next/font/google'\n00065| \n00066| // If loading a variable font, you don't need to specify the font weight\n00067| const inter = Inter({ subsets: ['latin'] })\n00068| \n00069| export default function MyApp({ Component, pageProps }) {\n00070| return (\n00071| \n00072| \n00073| \n00074| )\n00075| }\n00076| ```\n00077| \n00078| \n00079| \n00080| > **🎥 Watch:** Learn more about using `next/font` → [YouTube (6 minutes)](https://www.youtube.com/watch?v=L8_98i_bMMA).\n00081| \n00082| ## Reference\n00083| \n00084| | Key | `font/google` | `font/local` | Type | Required |\n00085| | ------------------------------------------- | ------------------- | ------------------- | -------------------------- | ----------------- |\n00086| | [`src`](#src) | | | String or Array of Objects | Yes |\n00087| | [`weight`](#weight) | | | String or Array | Required/Optional |\n00088| | [`style`](#style) | | | String or Array | - |\n00089| | [`subsets`](#subsets) | | | Array of Strings | - |\n00090| | [`axes`](#axes) | | | Array of Strings | - |\n00091| | [`display`](#display) | | | String | - |\n00092| | [`preload`](#preload) | | | Boolean | - |\n00093| | [`fallback`](#fallback) | | | Array of Strings | - |\n00094| | [`adjustFontFallback`](#adjustfontfallback) | | | Boolean or String | - |\n00095| | [`variable`](#variable) | | | String | - |\n00096| | [`declarations`](#declarations) | | | Array of Objects | - |\n00097| \n00098| ### `src`\n00099| \n00100| The path of the font file as a string or an array of objects (with type `Array<{path: string, weight?: string, style?: string}>`) relative to the directory where the font loader function is called.\n00101| \n00102| Used in `next/font/local`\n00103| \n00104| - Required\n00105| \n00106| Examples:\n00107| \n00108| - `src:'./fonts/my-font.woff2'` where `my-font.woff2` is placed in a directory named `fonts` inside the `app` directory\n00109| - `src:[{path: './inter/Inter-Thin.ttf', weight: '100',},{path: './inter/Inter-Regular.ttf',weight: '400',},{path: './inter/Inter-Bold-Italic.ttf', weight: '700',style: 'italic',},]`\n00110| - if the font loader function is called in `app/page.tsx` using `src:'../styles/fonts/my-font.ttf'`, then `my-font.ttf` is placed in `styles/fonts` at the root of the project\n00111| \n00112| ### `weight`\n00113| \n00114| The font [`weight`](https://fonts.google.com/knowledge/glossary/weight) with the following possibilities:\n00115| \n00116| - A string with possible values of the weights available for the specific font or a range of values if it's a [variable](https://fonts.google.com/variablefonts) font\n00117| - An array of weight values if the font is not a [variable google font](https://fonts.google.com/variablefonts). It applies to `next/font/google` only.\n00118| \n00119| Used in `next/font/google` and `next/font/local`\n00120| \n00121| - Required if the font being used is **not** [variable](https://fonts.google.com/variablefonts)\n00122| \n00123| Examples:\n00124| \n00125| - `weight: '400'`: A string for a single weight value - for the font [`Inter`](https://fonts.google.com/specimen/Inter?query=inter), the possible values are `'100'`, `'200'`, `'300'`, `'400'`, `'500'`, `'600'`, `'700'`, `'800'`, `'900'` or `'variable'` where `'variable'` is the default)\n00126| - `weight: '100 900'`: A string for the range between `100` and `900` for a variable font\n00127| - `weight: ['100','400','900']`: An array of 3 possible values for a non variable font\n00128| \n00129| ### `style`\n00130| \n00131| The font [`style`](https://developer.mozilla.org/docs/Web/CSS/font-style) with the following possibilities:\n00132| \n00133| - A string [value](https://developer.mozilla.org/docs/Web/CSS/font-style#values) with default value of `'normal'`\n00134| - An array of style values if the font is not a [variable google font](https://fonts.google.com/variablefonts). It applies to `next/font/google` only.\n00135| \n00136| Used in `next/font/google` and `next/font/local`\n00137| \n00138| - Optional\n00139| \n00140| Examples:\n00141| \n00142| - `style: 'italic'`: A string - it can be `normal` or `italic` for `next/font/google`\n00143| - `style: 'oblique'`: A string - it can take any value for `next/font/local` but is expected to come from [standard font styles](https://developer.mozilla.org/docs/Web/CSS/font-style)\n00144| - `style: ['italic','normal']`: An array of 2 values for `next/font/google` - the values are from `normal` and `italic`\n00145| \n00146| ### `subsets`\n00147| \n00148| The font [`subsets`](https://fonts.google.com/knowledge/glossary/subsetting) defined by an array of string values with the names of each subset you would like to be [preloaded](/docs/app/api-reference/components/font#specifying-a-subset). Fonts specified via `subsets` will have a link preload tag injected into the head when the [`preload`](#preload) option is true, which is the default.\n00149| \n00150| Used in `next/font/google`\n00151| \n00152| - Optional\n00153| \n00154| Examples:\n00155| \n00156| - `subsets: ['latin']`: An array with the subset `latin`\n00157| \n00158| You can find a list of all subsets on the Google Fonts page for your font.\n00159| \n00160| ### `axes`\n00161| \n00162| Some variable fonts have extra `axes` that can be included. By default, only the font weight is included to keep the file size down. The possible values of `axes` depend on the specific font.\n00163| \n00164| Used in `next/font/google`\n00165| \n00166| - Optional\n00167| \n00168| Examples:\n00169| \n00170| - `axes: ['slnt']`: An array with value `slnt` for the `Inter` variable font which has `slnt` as additional `axes` as shown [here](https://fonts.google.com/variablefonts?vfquery=inter#font-families). You can find the possible `axes` values for your font by using the filter on the [Google variable fonts page](https://fonts.google.com/variablefonts#font-families) and looking for axes other than `wght`\n00171| \n00172| ### `display`\n00173| \n00174| The font [`display`](https://developer.mozilla.org/docs/Web/CSS/@font-face/font-display) with possible string [values](https://developer.mozilla.org/docs/Web/CSS/@font-face/font-display#values) of `'auto'`, `'block'`, `'swap'`, `'fallback'` or `'optional'` with default value of `'swap'`.\n00175| \n00176| Used in `next/font/google` and `next/font/local`\n00177| \n00178| - Optional\n00179| \n00180| Examples:\n00181| \n00182| - `display: 'optional'`: A string assigned to the `optional` value\n00183| \n00184| ### `preload`\n00185| \n00186| A boolean value that specifies whether the font should be [preloaded](/docs/app/api-reference/components/font#preloading) or not. The default is `true`.\n00187| \n00188| Used in `next/font/google` and `next/font/local`\n00189| \n00190| - Optional\n00191| \n00192| Examples:\n00193| \n00194| - `preload: false`\n00195| \n00196| ### `fallback`\n00197| \n00198| The fallback font to use if the font cannot be loaded. An array of strings of fallback fonts with no default.\n00199| \n00200| - Optional\n00201| \n00202| Used in `next/font/google` and `next/font/local`\n00203| \n00204| Examples:\n00205| \n00206| - `fallback: ['system-ui', 'arial']`: An array setting the fallback fonts to `system-ui` or `arial`\n00207| \n00208| ### `adjustFontFallback`\n00209| \n00210| - For `next/font/google`: A boolean value that sets whether an automatic fallback font should be used to reduce [Cumulative Layout Shift](https://web.dev/cls/). The default is `true`.\n00211| - For `next/font/local`: A string or boolean `false` value that sets whether an automatic fallback font should be used to reduce [Cumulative Layout Shift](https://web.dev/cls/). The possible values are `'Arial'`, `'Times New Roman'` or `false`. The default is `'Arial'`.\n00212| \n00213| Used in `next/font/google` and `next/font/local`\n00214| \n00215| - Optional\n00216| \n00217| Examples:\n00218| \n00219| - `adjustFontFallback: false`: for `next/font/google`\n00220| - `adjustFontFallback: 'Times New Roman'`: for `next/font/local`\n00221| \n00222| ### `variable`\n00223| \n00224| A string value to define the CSS variable name to be used if the style is applied with the [CSS variable method](#css-variables).\n00225| \n00226| Used in `next/font/google` and `next/font/local`\n00227| \n00228| - Optional\n00229| \n00230| Examples:\n00231| \n00232| - `variable: '--my-font'`: The CSS variable `--my-font` is declared\n00233| \n00234| ### `declarations`\n00235| \n00236| An array of font face [descriptor](https://developer.mozilla.org/docs/Web/CSS/@font-face#descriptors) key-value pairs that define the generated `@font-face` further.\n00237| \n00238| Used in `next/font/local`\n00239| \n00240| - Optional\n00241| \n00242| Examples:\n00243| \n00244| - `declarations: [{ prop: 'ascent-override', value: '90%' }]`\n00245| \n00246| ## Examples\n00247| \n00248| ## Google Fonts\n00249| \n00250| To use a Google font, import it from `next/font/google` as a function. We recommend using [variable fonts](https://fonts.google.com/variablefonts) for the best performance and flexibility.\n00251| \n00252| \n00253| \n00254| ```tsx filename=\"app/layout.tsx\" switcher\n00255| import { Inter } from 'next/font/google'\n00256| \n00257| // If loading a variable font, you don't need to specify the font weight\n00258| const inter = Inter({\n00259| subsets: ['latin'],\n00260| display: 'swap',\n00261| })\n00262| \n00263| export default function RootLayout({\n00264| children,\n00265| }: {\n00266| children: React.ReactNode\n00267| }) {\n00268| return (\n00269| \n00270| {children}\n00271| \n00272| )\n00273| }\n00274| ```\n00275| \n00276| ```jsx filename=\"app/layout.js\" switcher\n00277| import { Inter } from 'next/font/google'\n00278| \n00279| // If loading a variable font, you don't need to specify the font weight\n00280| const inter = Inter({\n00281| subsets: ['latin'],\n00282| display: 'swap',\n00283| })\n00284| \n00285| export default function RootLayout({ children }) {\n00286| return (\n00287| \n00288| {children}\n00289| \n00290| )\n00291| }\n00292| ```\n00293| \n00294| If you can't use a variable font, you will **need to specify a weight**:\n00295| \n00296| ```tsx filename=\"app/layout.tsx\" switcher\n00297| import { Roboto } from 'next/font/google'\n00298| \n00299| const roboto = Roboto({\n00300| weight: '400',\n00301| subsets: ['latin'],\n00302| display: 'swap',\n00303| })\n00304| \n00305| export default function RootLayout({\n00306| children,\n00307| }: {\n00308| children: React.ReactNode\n00309| }) {\n00310| return (\n00311| \n00312| {children}\n00313| \n00314| )\n00315| }\n00316| ```\n00317| \n00318| ```jsx filename=\"app/layout.js\" switcher\n00319| import { Roboto } from 'next/font/google'\n00320| \n00321| const roboto = Roboto({\n00322| weight: '400',\n00323| subsets: ['latin'],\n00324| display: 'swap',\n00325| })\n00326| \n00327| export default function RootLayout({ children }) {\n00328| return (\n00329| \n00330| {children}\n00331| \n00332| )\n00333| }\n00334| ```\n00335| \n00336| \n00337| \n00338| \n00339| \n00340| To use the font in all your pages, add it to [`_app.js` file](/docs/pages/building-your-application/routing/custom-app) under `/pages` as shown below:\n00341| \n00342| ```jsx filename=\"pages/_app.js\"\n00343| import { Inter } from 'next/font/google'\n00344| \n00345| // If loading a variable font, you don't need to specify the font weight\n00346| const inter = Inter({ subsets: ['latin'] })\n00347| \n00348| export default function MyApp({ Component, pageProps }) {\n00349| return (\n00350| \n00351| \n00352| \n00353| )\n00354| }\n00355| ```\n00356| \n00357| If you can't use a variable font, you will **need to specify a weight**:\n00358| \n00359| ```jsx filename=\"pages/_app.js\"\n00360| import { Roboto } from 'next/font/google'\n00361| \n00362| const roboto = Roboto({\n00363| weight: '400',\n00364| subsets: ['latin'],\n00365| })\n00366| \n00367| export default function MyApp({ Component, pageProps }) {\n00368| return (\n00369| \n00370| \n00371| \n00372| )\n00373| }\n00374| ```\n00375| \n00376| \n00377| \n00378| You can specify multiple weights and/or styles by using an array:\n00379| \n00380| ```jsx filename=\"app/layout.js\"\n00381| const roboto = Roboto({\n00382| weight: ['400', '700'],\n00383| style: ['normal', 'italic'],\n00384| subsets: ['latin'],\n00385| display: 'swap',\n00386| })\n00387| ```\n00388| \n00389| > **Good to know**: Use an underscore (\\_) for font names with multiple words. E.g. `Roboto Mono` should be imported as `Roboto_Mono`.\n00390| \n00391| \n00392| \n00393| ### Apply the font in ``\n00394| \n00395| You can also use the font without a wrapper and `className` by injecting it inside the `` as follows:\n00396| \n00397| ```jsx filename=\"pages/_app.js\"\n00398| import { Inter } from 'next/font/google'\n00399| \n00400| const inter = Inter({ subsets: ['latin'] })\n00401| \n00402| export default function MyApp({ Component, pageProps }) {\n00403| return (\n00404| <>\n00405| \n00410| \n00411| >\n00412| )\n00413| }\n00414| ```\n00415| \n00416| ### Single page usage\n00417| \n00418| To use the font on a single page, add it to the specific page as shown below:\n00419| \n00420| ```jsx filename=\"pages/index.js\"\n00421| import { Inter } from 'next/font/google'\n00422| \n00423| const inter = Inter({ subsets: ['latin'] })\n00424| \n00425| export default function Home() {\n00426| return (\n00427|
\n00428|
Hello World
\n00429|
\n00430| )\n00431| }\n00432| ```\n00433| \n00434| \n00435| \n00436| ### Specifying a subset\n00437| \n00438| Google Fonts are automatically [subset](https://fonts.google.com/knowledge/glossary/subsetting). This reduces the size of the font file and improves performance. You'll need to define which of these subsets you want to preload. Failing to specify any subsets while [`preload`](/docs/app/api-reference/components/font#preload) is `true` will result in a warning.\n00439| \n00440| This can be done by adding it to the function call:\n00441| \n00442| \n00443| \n00444| ```tsx filename=\"app/layout.tsx\" switcher\n00445| const inter = Inter({ subsets: ['latin'] })\n00446| ```\n00447| \n00448| ```jsx filename=\"app/layout.js\" switcher\n00449| const inter = Inter({ subsets: ['latin'] })\n00450| ```\n00451| \n00452| \n00453| \n00454| \n00455| \n00456| ```jsx filename=\"pages/_app.js\"\n00457| const inter = Inter({ subsets: ['latin'] })\n00458| ```\n00459| \n00460| \n00461| \n00462| View the [Font API Reference](/docs/app/api-reference/components/font) for more information.\n00463| \n00464| ## Using Multiple Fonts\n00465| \n00466| You can import and use multiple fonts in your application. There are two approaches you can take.\n00467| \n00468| The first approach is to create a utility function that exports a font, imports it, and applies its `className` where needed. This ensures the font is preloaded only when it's rendered:\n00469| \n00470| ```ts filename=\"app/fonts.ts\" switcher\n00471| import { Inter, Roboto_Mono } from 'next/font/google'\n00472| \n00473| export const inter = Inter({\n00474| subsets: ['latin'],\n00475| display: 'swap',\n00476| })\n00477| \n00478| export const roboto_mono = Roboto_Mono({\n00479| subsets: ['latin'],\n00480| display: 'swap',\n00481| })\n00482| ```\n00483| \n00484| ```js filename=\"app/fonts.js\" switcher\n00485| import { Inter, Roboto_Mono } from 'next/font/google'\n00486| \n00487| export const inter = Inter({\n00488| subsets: ['latin'],\n00489| display: 'swap',\n00490| })\n00491| \n00492| export const roboto_mono = Roboto_Mono({\n00493| subsets: ['latin'],\n00494| display: 'swap',\n00495| })\n00496| ```\n00497| \n00498| \n00499| \n00500| ```tsx filename=\"app/layout.tsx\" switcher\n00501| import { inter } from './fonts'\n00502| \n00503| export default function Layout({ children }: { children: React.ReactNode }) {\n00504| return (\n00505| \n00506| \n00507|
{children}
\n00508| \n00509| \n00510| )\n00511| }\n00512| ```\n00513| \n00514| ```jsx filename=\"app/layout.js\" switcher\n00515| import { inter } from './fonts'\n00516| \n00517| export default function Layout({ children }) {\n00518| return (\n00519| \n00520| \n00521|
\n00547| >\n00548| )\n00549| }\n00550| ```\n00551| \n00552| \n00553| \n00554| In the example above, `Inter` will be applied globally, and `Roboto Mono` can be imported and applied as needed.\n00555| \n00556| Alternatively, you can create a [CSS variable](/docs/app/api-reference/components/font#variable) and use it with your preferred CSS solution:\n00557| \n00558| \n00559| \n00560| ```tsx filename=\"app/layout.tsx\" switcher\n00561| import { Inter, Roboto_Mono } from 'next/font/google'\n00562| import styles from './global.css'\n00563| \n00564| const inter = Inter({\n00565| subsets: ['latin'],\n00566| variable: '--font-inter',\n00567| display: 'swap',\n00568| })\n00569| \n00570| const roboto_mono = Roboto_Mono({\n00571| subsets: ['latin'],\n00572| variable: '--font-roboto-mono',\n00573| display: 'swap',\n00574| })\n00575| \n00576| export default function RootLayout({\n00577| children,\n00578| }: {\n00579| children: React.ReactNode\n00580| }) {\n00581| return (\n00582| \n00583| \n00584|
\n00613| \n00614| \n00615| )\n00616| }\n00617| ```\n00618| \n00619| \n00620| \n00621| ```css filename=\"app/global.css\"\n00622| html {\n00623| font-family: var(--font-inter);\n00624| }\n00625| \n00626| h1 {\n00627| font-family: var(--font-roboto-mono);\n00628| }\n00629| ```\n00630| \n00631| In the example above, `Inter` will be applied globally, and any `
` tags will be styled with `Roboto Mono`.\n00632| \n00633| > **Recommendation**: Use multiple fonts conservatively since each new font is an additional resource the client has to download.\n00634| \n00635| ### Local Fonts\n00636| \n00637| Import `next/font/local` and specify the `src` of your local font file. We recommend using [variable fonts](https://fonts.google.com/variablefonts) for the best performance and flexibility.\n00638| \n00639| \n00640| \n00641| ```tsx filename=\"app/layout.tsx\" switcher\n00642| import localFont from 'next/font/local'\n00643| \n00644| // Font files can be colocated inside of `app`\n00645| const myFont = localFont({\n00646| src: './my-font.woff2',\n00647| display: 'swap',\n00648| })\n00649| \n00650| export default function RootLayout({\n00651| children,\n00652| }: {\n00653| children: React.ReactNode\n00654| }) {\n00655| return (\n00656| \n00657| {children}\n00658| \n00659| )\n00660| }\n00661| ```\n00662| \n00663| ```jsx filename=\"app/layout.js\" switcher\n00664| import localFont from 'next/font/local'\n00665| \n00666| // Font files can be colocated inside of `app`\n00667| const myFont = localFont({\n00668| src: './my-font.woff2',\n00669| display: 'swap',\n00670| })\n00671| \n00672| export default function RootLayout({ children }) {\n00673| return (\n00674| \n00675| {children}\n00676| \n00677| )\n00678| }\n00679| ```\n00680| \n00681| \n00682| \n00683| \n00684| \n00685| ```jsx filename=\"pages/_app.js\"\n00686| import localFont from 'next/font/local'\n00687| \n00688| // Font files can be colocated inside of `pages`\n00689| const myFont = localFont({ src: './my-font.woff2' })\n00690| \n00691| export default function MyApp({ Component, pageProps }) {\n00692| return (\n00693| \n00694| \n00695| \n00696| )\n00697| }\n00698| ```\n00699| \n00700| \n00701| \n00702| If you want to use multiple files for a single font family, `src` can be an array:\n00703| \n00704| ```js\n00705| const roboto = localFont({\n00706| src: [\n00707| {\n00708| path: './Roboto-Regular.woff2',\n00709| weight: '400',\n00710| style: 'normal',\n00711| },\n00712| {\n00713| path: './Roboto-Italic.woff2',\n00714| weight: '400',\n00715| style: 'italic',\n00716| },\n00717| {\n00718| path: './Roboto-Bold.woff2',\n00719| weight: '700',\n00720| style: 'normal',\n00721| },\n00722| {\n00723| path: './Roboto-BoldItalic.woff2',\n00724| weight: '700',\n00725| style: 'italic',\n00726| },\n00727| ],\n00728| })\n00729| ```\n00730| \n00731| View the [Font API Reference](/docs/app/api-reference/components/font) for more information.\n00732| \n00733| ### With Tailwind CSS\n00734| \n00735| `next/font` integrates seamlessly with [Tailwind CSS](https://tailwindcss.com/) using [CSS variables](/docs/app/api-reference/components/font#css-variables).\n00736| \n00737| In the example below, we use the `Inter` and `Roboto_Mono` fonts from `next/font/google` (you can use any Google Font or Local Font). Use the `variable` option to define a CSS variable name, such as `inter` and `roboto_mono` for these fonts, respectively. Then, apply `inter.variable` and `roboto_mono.variable` to include the CSS variables in your HTML document.\n00738| \n00739| > **Good to know**: You can add these variables to the `` or `` tag, depending on your preference, styling needs or project requirements.\n00740| \n00741| \n00742| \n00743| ```tsx filename=\"app/layout.tsx\" switcher\n00744| import { Inter, Roboto_Mono } from 'next/font/google'\n00745| \n00746| const inter = Inter({\n00747| subsets: ['latin'],\n00748| display: 'swap',\n00749| variable: '--font-inter',\n00750| })\n00751| \n00752| const roboto_mono = Roboto_Mono({\n00753| subsets: ['latin'],\n00754| display: 'swap',\n00755| variable: '--font-roboto-mono',\n00756| })\n00757| \n00758| export default function RootLayout({\n00759| children,\n00760| }: {\n00761| children: React.ReactNode\n00762| }) {\n00763| return (\n00764| \n00768| {children}\n00769| \n00770| )\n00771| }\n00772| ```\n00773| \n00774| ```jsx filename=\"app/layout.js\" switcher\n00775| import { Inter, Roboto_Mono } from 'next/font/google'\n00776| \n00777| const inter = Inter({\n00778| subsets: ['latin'],\n00779| display: 'swap',\n00780| variable: '--font-inter',\n00781| })\n00782| \n00783| const roboto_mono = Roboto_Mono({\n00784| subsets: ['latin'],\n00785| display: 'swap',\n00786| variable: '--font-roboto-mono',\n00787| })\n00788| \n00789| export default function RootLayout({ children }) {\n00790| return (\n00791| \n00795| {children}\n00796| \n00797| )\n00798| }\n00799| ```\n00800| \n00801| \n00802| \n00803| \n00804| \n00805| ```jsx filename=\"pages/_app.js\"\n00806| import { Inter } from 'next/font/google'\n00807| \n00808| const inter = Inter({\n00809| subsets: ['latin'],\n00810| variable: '--font-inter',\n00811| })\n00812| \n00813| const roboto_mono = Roboto_Mono({\n00814| subsets: ['latin'],\n00815| display: 'swap',\n00816| variable: '--font-roboto-mono',\n00817| })\n00818| \n00819| export default function MyApp({ Component, pageProps }) {\n00820| return (\n00821| \n00822| \n00823| \n00824| )\n00825| }\n00826| ```\n00827| \n00828| \n00829| \n00830| Finally, add the CSS variable to your [Tailwind CSS config](/docs/app/getting-started/css#tailwind-css):\n00831| \n00832| ```css filename=\"global.css\"\n00833| @import 'tailwindcss';\n00834| \n00835| @theme inline {\n00836| --font-sans: var(--font-inter);\n00837| --font-mono: var(--font-roboto-mono);\n00838| }\n00839| ```\n00840| \n00841| ### Tailwind CSS v3\n00842| \n00843| ```js filename=\"tailwind.config.js\"\n00844| /** @type {import('tailwindcss').Config} */\n00845| module.exports = {\n00846| content: [\n00847| './pages/**/*.{js,ts,jsx,tsx}',\n00848| './components/**/*.{js,ts,jsx,tsx}',\n00849| './app/**/*.{js,ts,jsx,tsx}',\n00850| ],\n00851| theme: {\n00852| extend: {\n00853| fontFamily: {\n00854| sans: ['var(--font-inter)'],\n00855| mono: ['var(--font-roboto-mono)'],\n00856| },\n00857| },\n00858| },\n00859| plugins: [],\n00860| }\n00861| ```\n00862| \n00863| You can now use the `font-sans` and `font-mono` utility classes to apply the font to your elements.\n00864| \n00865| ```html\n00866|
The quick brown fox ...
\n00867|
The quick brown fox ...
\n00868| ```\n00869| \n00870| ### Applying Styles\n00871| \n00872| You can apply the font styles in three ways:\n00873| \n00874| - [`className`](#classname)\n00875| - [`style`](#style-1)\n00876| - [CSS Variables](#css-variables)\n00877| \n00878| #### `className`\n00879| \n00880| Returns a read-only CSS `className` for the loaded font to be passed to an HTML element.\n00881| \n00882| ```tsx\n00883|
Hello, Next.js!
\n00884| ```\n00885| \n00886| #### `style`\n00887| \n00888| Returns a read-only CSS `style` object for the loaded font to be passed to an HTML element, including `style.fontFamily` to access the font family name and fallback fonts.\n00889| \n00890| ```tsx\n00891|
Hello World
\n00892| ```\n00893| \n00894| #### CSS Variables\n00895| \n00896| If you would like to set your styles in an external style sheet and specify additional options there, use the CSS variable method.\n00897| \n00898| In addition to importing the font, also import the CSS file where the CSS variable is defined and set the variable option of the font loader object as follows:\n00899| \n00900| ```tsx filename=\"app/page.tsx\" switcher\n00901| import { Inter } from 'next/font/google'\n00902| import styles from '../styles/component.module.css'\n00903| \n00904| const inter = Inter({\n00905| variable: '--font-inter',\n00906| })\n00907| ```\n00908| \n00909| ```jsx filename=\"app/page.js\" switcher\n00910| import { Inter } from 'next/font/google'\n00911| import styles from '../styles/component.module.css'\n00912| \n00913| const inter = Inter({\n00914| variable: '--font-inter',\n00915| })\n00916| ```\n00917| \n00918| To use the font, set the `className` of the parent container of the text you would like to style to the font loader's `variable` value and the `className` of the text to the `styles` property from the external CSS file.\n00919| \n00920| ```tsx filename=\"app/page.tsx\" switcher\n00921| \n00922|
\n00929| \n00930| ```\n00931| \n00932| Define the `text` selector class in the `component.module.css` CSS file as follows:\n00933| \n00934| ```css filename=\"styles/component.module.css\"\n00935| .text {\n00936| font-family: var(--font-inter);\n00937| font-weight: 200;\n00938| font-style: italic;\n00939| }\n00940| ```\n00941| \n00942| In the example above, the text `Hello World` is styled using the `Inter` font and the generated font fallback with `font-weight: 200` and `font-style: italic`.\n00943| \n00944| ### Using a font definitions file\n00945| \n00946| Every time you call the `localFont` or Google font function, that font will be hosted as one instance in your application. Therefore, if you need to use the same font in multiple places, you should load it in one place and import the related font object where you need it. This is done using a font definitions file.\n00947| \n00948| For example, create a `fonts.ts` file in a `styles` folder at the root of your app directory.\n00949| \n00950| Then, specify your font definitions as follows:\n00951| \n00952| ```ts filename=\"styles/fonts.ts\" switcher\n00953| import { Inter, Lora, Source_Sans_3 } from 'next/font/google'\n00954| import localFont from 'next/font/local'\n00955| \n00956| // define your variable fonts\n00957| const inter = Inter()\n00958| const lora = Lora()\n00959| // define 2 weights of a non-variable font\n00960| const sourceCodePro400 = Source_Sans_3({ weight: '400' })\n00961| const sourceCodePro700 = Source_Sans_3({ weight: '700' })\n00962| // define a custom local font where GreatVibes-Regular.ttf is stored in the styles folder\n00963| const greatVibes = localFont({ src: './GreatVibes-Regular.ttf' })\n00964| \n00965| export { inter, lora, sourceCodePro400, sourceCodePro700, greatVibes }\n00966| ```\n00967| \n00968| ```js filename=\"styles/fonts.js\" switcher\n00969| import { Inter, Lora, Source_Sans_3 } from 'next/font/google'\n00970| import localFont from 'next/font/local'\n00971| \n00972| // define your variable fonts\n00973| const inter = Inter()\n00974| const lora = Lora()\n00975| // define 2 weights of a non-variable font\n00976| const sourceCodePro400 = Source_Sans_3({ weight: '400' })\n00977| const sourceCodePro700 = Source_Sans_3({ weight: '700' })\n00978| // define a custom local font where GreatVibes-Regular.ttf is stored in the styles folder\n00979| const greatVibes = localFont({ src: './GreatVibes-Regular.ttf' })\n00980| \n00981| export { inter, lora, sourceCodePro400, sourceCodePro700, greatVibes }\n00982| ```\n00983| \n00984| You can now use these definitions in your code as follows:\n00985| \n00986| ```tsx filename=\"app/page.tsx\" switcher\n00987| import { inter, lora, sourceCodePro700, greatVibes } from '../styles/fonts'\n00988| \n00989| export default function Page() {\n00990| return (\n00991|
\n00992|
Hello world using Inter font
\n00993|
Hello world using Lora font
\n00994|
\n00995| Hello world using Source_Sans_3 font with weight 700\n00996|
\n01012| Hello world using Source_Sans_3 font with weight 700\n01013|
\n01014|
My title in Great Vibes font
\n01015|
\n01016| )\n01017| }\n01018| ```\n01019| \n01020| To make it easier to access the font definitions in your code, you can define a path alias in your `tsconfig.json` or `jsconfig.json` files as follows:\n01021| \n01022| ```json filename=\"tsconfig.json\"\n01023| {\n01024| \"compilerOptions\": {\n01025| \"paths\": {\n01026| \"@/fonts\": [\"./styles/fonts\"]\n01027| }\n01028| }\n01029| }\n01030| ```\n01031| \n01032| You can now import any font definition as follows:\n01033| \n01034| ```tsx filename=\"app/about/page.tsx\" switcher\n01035| import { greatVibes, sourceCodePro400 } from '@/fonts'\n01036| ```\n01037| \n01038| ```jsx filename=\"app/about/page.js\" switcher\n01039| import { greatVibes, sourceCodePro400 } from '@/fonts'\n01040| ```\n01041| \n01042| ### Preloading\n01043| \n01044| \n01045| \n01046| When a font function is called on a page of your site, it is not globally available and preloaded on all routes. Rather, the font is only preloaded on the related routes based on the type of file where it is used:\n01047| \n01048| - If it's a [unique page](/docs/app/api-reference/file-conventions/page), it is preloaded on the unique route for that page.\n01049| - If it's a [layout](/docs/app/api-reference/file-conventions/layout), it is preloaded on all the routes wrapped by the layout.\n01050| - If it's the [root layout](/docs/app/api-reference/file-conventions/layout#root-layout), it is preloaded on all routes.\n01051| \n01052| \n01053| \n01054| \n01055| \n01056| When a font function is called on a page of your site, it is not globally available and preloaded on all routes. Rather, the font is only preloaded on the related route/s based on the type of file where it is used:\n01057| \n01058| - if it's a [unique page](/docs/pages/building-your-application/routing/pages-and-layouts), it is preloaded on the unique route for that page\n01059| - if it's in the [custom App](/docs/pages/building-your-application/routing/custom-app), it is preloaded on all the routes of the site under `/pages`\n01060| \n01061| \n01062| \n01063| ## Version Changes\n01064| \n01065| | Version | Changes |\n01066| | --------- | --------------------------------------------------------------------- |\n01067| | `v13.2.0` | `@next/font` renamed to `next/font`. Installation no longer required. |\n01068| | `v13.0.0` | `@next/font` was added. |\n01069| \n\n(End of file - total 1069 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/02-components/font.md"
+ },
+ "output": "\n00001| ---\n00002| title: Font Module\n00003| nav_title: Font\n00004| description: Optimizing loading web fonts with the built-in `next/font` loaders.\n00005| ---\n00006| \n00007| {/* The content of this doc is shared between the app and pages router. You can use the `Content` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}\n00008| \n00009| [`next/font`](/docs/app/api-reference/components/font) automatically optimizes your fonts (including custom fonts) and removes external network requests for improved privacy and performance.\n00010| \n00011| It includes **built-in automatic self-hosting** for any font file. This means you can optimally load web fonts with no [layout shift](https://web.dev/articles/cls).\n00012| \n00013| You can also conveniently use all [Google Fonts](https://fonts.google.com/). CSS and font files are downloaded at build time and self-hosted with the rest of your static assets. **No requests are sent to Google by the browser.**\n00014| \n00015| \n00016| \n00017| ```tsx filename=\"app/layout.tsx\" switcher\n00018| import { Inter } from 'next/font/google'\n00019| \n00020| // If loading a variable font, you don't need to specify the font weight\n00021| const inter = Inter({\n00022| subsets: ['latin'],\n00023| display: 'swap',\n00024| })\n00025| \n00026| export default function RootLayout({\n00027| children,\n00028| }: {\n00029| children: React.ReactNode\n00030| }) {\n00031| return (\n00032| \n00033| {children}\n00034| \n00035| )\n00036| }\n00037| ```\n00038| \n00039| ```jsx filename=\"app/layout.js\" switcher\n00040| import { Inter } from 'next/font/google'\n00041| \n00042| // If loading a variable font, you don't need to specify the font weight\n00043| const inter = Inter({\n00044| subsets: ['latin'],\n00045| display: 'swap',\n00046| })\n00047| \n00048| export default function RootLayout({ children }) {\n00049| return (\n00050| \n00051| {children}\n00052| \n00053| )\n00054| }\n00055| ```\n00056| \n00057| \n00058| \n00059| \n00060| \n00061| To use the font in all your pages, add it to [`_app.js` file](/docs/pages/building-your-application/routing/custom-app) under `/pages` as shown below:\n00062| \n00063| ```jsx filename=\"pages/_app.js\"\n00064| import { Inter } from 'next/font/google'\n00065| \n00066| // If loading a variable font, you don't need to specify the font weight\n00067| const inter = Inter({ subsets: ['latin'] })\n00068| \n00069| export default function MyApp({ Component, pageProps }) {\n00070| return (\n00071| \n00072| \n00073| \n00074| )\n00075| }\n00076| ```\n00077| \n00078| \n00079| \n00080| > **🎥 Watch:** Learn more about using `next/font` → [YouTube (6 minutes)](https://www.youtube.com/watch?v=L8_98i_bMMA).\n00081| \n00082| ## Reference\n00083| \n00084| | Key | `font/google` | `font/local` | Type | Required |\n00085| | ------------------------------------------- | ------------------- | ------------------- | -------------------------- | ----------------- |\n00086| | [`src`](#src) | | | String or Array of Objects | Yes |\n00087| | [`weight`](#weight) | | | String or Array | Required/Optional |\n00088| | [`style`](#style) | | | String or Array | - |\n00089| | [`subsets`](#subsets) | | | Array of Strings | - |\n00090| | [`axes`](#axes) | | | Array of Strings | - |\n00091| | [`display`](#display) | | | String | - |\n00092| | [`preload`](#preload) | | | Boolean | - |\n00093| | [`fallback`](#fallback) | | | Array of Strings | - |\n00094| | [`adjustFontFallback`](#adjustfontfallback) | | | Boolean or String | - |\n00095| | [`variable`](#variable) | | | String | - |\n00096| | [`declarations`](#declarations) | | | Array of Objects | - |\n00097| \n00098| ### `src`\n00099| \n00100| The path of the font file as a string or an array of objects (with type `Array<{path: string, weight?: string, style?: string}>`) relative to the directory where the font loader function is called.\n00101| \n00102| Used in `next/font/local`\n00103| \n00104| - Required\n00105| \n00106| Examples:\n00107| \n00108| - `src:'./fonts/my-font.woff2'` where `my-font.woff2` is placed in a directory named `fonts` inside the `app` directory\n00109| - `src:[{path: './inter/Inter-Thin.ttf', weight: '100',},{path: './inter/Inter-Regular.ttf',weight: '400',},{path: './inter/Inter-Bold-Italic.ttf', weight: '700',style: 'italic',},]`\n00110| - if the font loader function is called in `app/page.tsx` using `src:'../styles/fonts/my-font.ttf'`, then `my-font.ttf` is placed in `styles/fonts` at the root of the project\n00111| \n00112| ### `weight`\n00113| \n00114| The font [`weight`](https://fonts.google.com/knowledge/glossary/weight) with the following possibilities:\n00115| \n00116| - A string with possible values of the weights available for the specific font or a range of values if it's a [variable](https://fonts.google.com/variablefonts) font\n00117| - An array of weight values if the font is not a [variable google font](https://fonts.google.com/variablefonts). It applies to `next/font/google` only.\n00118| \n00119| Used in `next/font/google` and `next/font/local`\n00120| \n00121| - Required if the font being used is **not** [variable](https://fonts.google.com/variablefonts)\n00122| \n00123| Examples:\n00124| \n00125| - `weight: '400'`: A string for a single weight value - for the font [`Inter`](https://fonts.google.com/specimen/Inter?query=inter), the possible values are `'100'`, `'200'`, `'300'`, `'400'`, `'500'`, `'600'`, `'700'`, `'800'`, `'900'` or `'variable'` where `'variable'` is the default)\n00126| - `weight: '100 900'`: A string for the range between `100` and `900` for a variable font\n00127| - `weight: ['100','400','900']`: An array of 3 possible values for a non variable font\n00128| \n00129| ### `style`\n00130| \n00131| The font [`style`](https://developer.mozilla.org/docs/Web/CSS/font-style) with the following possibilities:\n00132| \n00133| - A string [value](https://developer.mozilla.org/docs/Web/CSS/font-style#values) with default value of `'normal'`\n00134| - An array of style values if the font is not a [variable google font](https://fonts.google.com/variablefonts). It applies to `next/font/google` only.\n00135| \n00136| Used in `next/font/google` and `next/font/local`\n00137| \n00138| - Optional\n00139| \n00140| Examples:\n00141| \n00142| - `style: 'italic'`: A string - it can be `normal` or `italic` for `next/font/google`\n00143| - `style: 'oblique'`: A string - it can take any value for `next/font/local` but is expected to come from [standard font styles](https://developer.mozilla.org/docs/Web/CSS/font-style)\n00144| - `style: ['italic','normal']`: An array of 2 values for `next/font/google` - the values are from `normal` and `italic`\n00145| \n00146| ### `subsets`\n00147| \n00148| The font [`subsets`](https://fonts.google.com/knowledge/glossary/subsetting) defined by an array of string values with the names of each subset you would like to be [preloaded](/docs/app/api-reference/components/font#specifying-a-subset). Fonts specified via `subsets` will have a link preload tag injected into the head when the [`preload`](#preload) option is true, which is the default.\n00149| \n00150| Used in `next/font/google`\n00151| \n00152| - Optional\n00153| \n00154| Examples:\n00155| \n00156| - `subsets: ['latin']`: An array with the subset `latin`\n00157| \n00158| You can find a list of all subsets on the Google Fonts page for your font.\n00159| \n00160| ### `axes`\n00161| \n00162| Some variable fonts have extra `axes` that can be included. By default, only the font weight is included to keep the file size down. The possible values of `axes` depend on the specific font.\n00163| \n00164| Used in `next/font/google`\n00165| \n00166| - Optional\n00167| \n00168| Examples:\n00169| \n00170| - `axes: ['slnt']`: An array with value `slnt` for the `Inter` variable font which has `slnt` as additional `axes` as shown [here](https://fonts.google.com/variablefonts?vfquery=inter#font-families). You can find the possible `axes` values for your font by using the filter on the [Google variable fonts page](https://fonts.google.com/variablefonts#font-families) and looking for axes other than `wght`\n00171| \n00172| ### `display`\n00173| \n00174| The font [`display`](https://developer.mozilla.org/docs/Web/CSS/@font-face/font-display) with possible string [values](https://developer.mozilla.org/docs/Web/CSS/@font-face/font-display#values) of `'auto'`, `'block'`, `'swap'`, `'fallback'` or `'optional'` with default value of `'swap'`.\n00175| \n00176| Used in `next/font/google` and `next/font/local`\n00177| \n00178| - Optional\n00179| \n00180| Examples:\n00181| \n00182| - `display: 'optional'`: A string assigned to the `optional` value\n00183| \n00184| ### `preload`\n00185| \n00186| A boolean value that specifies whether the font should be [preloaded](/docs/app/api-reference/components/font#preloading) or not. The default is `true`.\n00187| \n00188| Used in `next/font/google` and `next/font/local`\n00189| \n00190| - Optional\n00191| \n00192| Examples:\n00193| \n00194| - `preload: false`\n00195| \n00196| ### `fallback`\n00197| \n00198| The fallback font to use if the font cannot be loaded. An array of strings of fallback fonts with no default.\n00199| \n00200| - Optional\n00201| \n00202| Used in `next/font/google` and `next/font/local`\n00203| \n00204| Examples:\n00205| \n00206| - `fallback: ['system-ui', 'arial']`: An array setting the fallback fonts to `system-ui` or `arial`\n00207| \n00208| ### `adjustFontFallback`\n00209| \n00210| - For `next/font/google`: A boolean value that sets whether an automatic fallback font should be used to reduce [Cumulative Layout Shift](https://web.dev/cls/). The default is `true`.\n00211| - For `next/font/local`: A string or boolean `false` value that sets whether an automatic fallback font should be used to reduce [Cumulative Layout Shift](https://web.dev/cls/). The possible values are `'Arial'`, `'Times New Roman'` or `false`. The default is `'Arial'`.\n00212| \n00213| Used in `next/font/google` and `next/font/local`\n00214| \n00215| - Optional\n00216| \n00217| Examples:\n00218| \n00219| - `adjustFontFallback: false`: for `next/font/google`\n00220| - `adjustFontFallback: 'Times New Roman'`: for `next/font/local`\n00221| \n00222| ### `variable`\n00223| \n00224| A string value to define the CSS variable name to be used if the style is applied with the [CSS variable method](#css-variables).\n00225| \n00226| Used in `next/font/google` and `next/font/local`\n00227| \n00228| - Optional\n00229| \n00230| Examples:\n00231| \n00232| - `variable: '--my-font'`: The CSS variable `--my-font` is declared\n00233| \n00234| ### `declarations`\n00235| \n00236| An array of font face [descriptor](https://developer.mozilla.org/docs/Web/CSS/@font-face#descriptors) key-value pairs that define the generated `@font-face` further.\n00237| \n00238| Used in `next/font/local`\n00239| \n00240| - Optional\n00241| \n00242| Examples:\n00243| \n00244| - `declarations: [{ prop: 'ascent-override', value: '90%' }]`\n00245| \n00246| ## Examples\n00247| \n00248| ## Google Fonts\n00249| \n00250| To use a Google font, import it from `next/font/google` as a function. We recommend using [variable fonts](https://fonts.google.com/variablefonts) for the best performance and flexibility.\n00251| \n00252| \n00253| \n00254| ```tsx filename=\"app/layout.tsx\" switcher\n00255| import { Inter } from 'next/font/google'\n00256| \n00257| // If loading a variable font, you don't need to specify the font weight\n00258| const inter = Inter({\n00259| subsets: ['latin'],\n00260| display: 'swap',\n00261| })\n00262| \n00263| export default function RootLayout({\n00264| children,\n00265| }: {\n00266| children: React.ReactNode\n00267| }) {\n00268| return (\n00269| \n00270| {children}\n00271| \n00272| )\n00273| }\n00274| ```\n00275| \n00276| ```jsx filename=\"app/layout.js\" switcher\n00277| import { Inter } from 'next/font/google'\n00278| \n00279| // If loading a variable font, you don't need to specify the font weight\n00280| const inter = Inter({\n00281| subsets: ['latin'],\n00282| display: 'swap',\n00283| })\n00284| \n00285| export default function RootLayout({ children }) {\n00286| return (\n00287| \n00288| {children}\n00289| \n00290| )\n00291| }\n00292| ```\n00293| \n00294| If you can't use a variable font, you will **need to specify a weight**:\n00295| \n00296| ```tsx filename=\"app/layout.tsx\" switcher\n00297| import { Roboto } from 'next/font/google'\n00298| \n00299| const roboto = Roboto({\n00300| weight: '400',\n00301| subsets: ['latin'],\n00302| display: 'swap',\n00303| })\n00304| \n00305| export default function RootLayout({\n00306| children,\n00307| }: {\n00308| children: React.ReactNode\n00309| }) {\n00310| return (\n00311| \n00312| {children}\n00313| \n00314| )\n00315| }\n00316| ```\n00317| \n00318| ```jsx filename=\"app/layout.js\" switcher\n00319| import { Roboto } from 'next/font/google'\n00320| \n00321| const roboto = Roboto({\n00322| weight: '400',\n00323| subsets: ['latin'],\n00324| display: 'swap',\n00325| })\n00326| \n00327| export default function RootLayout({ children }) {\n00328| return (\n00329| \n00330| {children}\n00331| \n00332| )\n00333| }\n00334| ```\n00335| \n00336| \n00337| \n00338| \n00339| \n00340| To use the font in all your pages, add it to [`_app.js` file](/docs/pages/building-your-application/routing/custom-app) under `/pages` as shown below:\n00341| \n00342| ```jsx filename=\"pages/_app.js\"\n00343| import { Inter } from 'next/font/google'\n00344| \n00345| // If loading a variable font, you don't need to specify the font weight\n00346| const inter = Inter({ subsets: ['latin'] })\n00347| \n00348| export default function MyApp({ Component, pageProps }) {\n00349| return (\n00350| \n00351| \n00352| \n00353| )\n00354| }\n00355| ```\n00356| \n00357| If you can't use a variable font, you will **need to specify a weight**:\n00358| \n00359| ```jsx filename=\"pages/_app.js\"\n00360| import { Roboto } from 'next/font/google'\n00361| \n00362| const roboto = Roboto({\n00363| weight: '400',\n00364| subsets: ['latin'],\n00365| })\n00366| \n00367| export default function MyApp({ Component, pageProps }) {\n00368| return (\n00369| \n00370| \n00371| \n00372| )\n00373| }\n00374| ```\n00375| \n00376| \n00377| \n00378| You can specify multiple weights and/or styles by using an array:\n00379| \n00380| ```jsx filename=\"app/layout.js\"\n00381| const roboto = Roboto({\n00382| weight: ['400', '700'],\n00383| style: ['normal', 'italic'],\n00384| subsets: ['latin'],\n00385| display: 'swap',\n00386| })\n00387| ```\n00388| \n00389| > **Good to know**: Use an underscore (\\_) for font names with multiple words. E.g. `Roboto Mono` should be imported as `Roboto_Mono`.\n00390| \n00391| \n00392| \n00393| ### Apply the font in ``\n00394| \n00395| You can also use the font without a wrapper and `className` by injecting it inside the `` as follows:\n00396| \n00397| ```jsx filename=\"pages/_app.js\"\n00398| import { Inter } from 'next/font/google'\n00399| \n00400| const inter = Inter({ subsets: ['latin'] })\n00401| \n00402| export default function MyApp({ Component, pageProps }) {\n00403| return (\n00404| <>\n00405| \n00410| \n00411| >\n00412| )\n00413| }\n00414| ```\n00415| \n00416| ### Single page usage\n00417| \n00418| To use the font on a single page, add it to the specific page as shown below:\n00419| \n00420| ```jsx filename=\"pages/index.js\"\n00421| import { Inter } from 'next/font/google'\n00422| \n00423| const inter = Inter({ subsets: ['latin'] })\n00424| \n00425| export default function Home() {\n00426| return (\n00427|
\n00428|
Hello World
\n00429|
\n00430| )\n00431| }\n00432| ```\n00433| \n00434| \n00435| \n00436| ### Specifying a subset\n00437| \n00438| Google Fonts are automatically [subset](https://fonts.google.com/knowledge/glossary/subsetting). This reduces the size of the font file and improves performance. You'll need to define which of these subsets you want to preload. Failing to specify any subsets while [`preload`](/docs/app/api-reference/components/font#preload) is `true` will result in a warning.\n00439| \n00440| This can be done by adding it to the function call:\n00441| \n00442| \n00443| \n00444| ```tsx filename=\"app/layout.tsx\" switcher\n00445| const inter = Inter({ subsets: ['latin'] })\n00446| ```\n00447| \n00448| ```jsx filename=\"app/layout.js\" switcher\n00449| const inter = Inter({ subsets: ['latin'] })\n00450| ```\n00451| \n00452| \n00453| \n00454| \n00455| \n00456| ```jsx filename=\"pages/_app.js\"\n00457| const inter = Inter({ subsets: ['latin'] })\n00458| ```\n00459| \n00460| \n00461| \n00462| View the [Font API Reference](/docs/app/api-reference/components/font) for more information.\n00463| \n00464| ## Using Multiple Fonts\n00465| \n00466| You can import and use multiple fonts in your application. There are two approaches you can take.\n00467| \n00468| The first approach is to create a utility function that exports a font, imports it, and applies its `className` where needed. This ensures the font is preloaded only when it's rendered:\n00469| \n00470| ```ts filename=\"app/fonts.ts\" switcher\n00471| import { Inter, Roboto_Mono } from 'next/font/google'\n00472| \n00473| export const inter = Inter({\n00474| subsets: ['latin'],\n00475| display: 'swap',\n00476| })\n00477| \n00478| export const roboto_mono = Roboto_Mono({\n00479| subsets: ['latin'],\n00480| display: 'swap',\n00481| })\n00482| ```\n00483| \n00484| ```js filename=\"app/fonts.js\" switcher\n00485| import { Inter, Roboto_Mono } from 'next/font/google'\n00486| \n00487| export const inter = Inter({\n00488| subsets: ['latin'],\n00489| display: 'swap',\n00490| })\n00491| \n00492| export const roboto_mono = Roboto_Mono({\n00493| subsets: ['latin'],\n00494| display: 'swap',\n00495| })\n00496| ```\n00497| \n00498| \n00499| \n00500| ```tsx filename=\"app/layout.tsx\" switcher\n00501| import { inter } from './fonts'\n00502| \n00503| export default function Layout({ children }: { children: React.ReactNode }) {\n00504| return (\n00505| \n00506| \n00507|
{children}
\n00508| \n00509| \n00510| )\n00511| }\n00512| ```\n00513| \n00514| ```jsx filename=\"app/layout.js\" switcher\n00515| import { inter } from './fonts'\n00516| \n00517| export default function Layout({ children }) {\n00518| return (\n00519| \n00520| \n00521|
\n00547| >\n00548| )\n00549| }\n00550| ```\n00551| \n00552| \n00553| \n00554| In the example above, `Inter` will be applied globally, and `Roboto Mono` can be imported and applied as needed.\n00555| \n00556| Alternatively, you can create a [CSS variable](/docs/app/api-reference/components/font#variable) and use it with your preferred CSS solution:\n00557| \n00558| \n00559| \n00560| ```tsx filename=\"app/layout.tsx\" switcher\n00561| import { Inter, Roboto_Mono } from 'next/font/google'\n00562| import styles from './global.css'\n00563| \n00564| const inter = Inter({\n00565| subsets: ['latin'],\n00566| variable: '--font-inter',\n00567| display: 'swap',\n00568| })\n00569| \n00570| const roboto_mono = Roboto_Mono({\n00571| subsets: ['latin'],\n00572| variable: '--font-roboto-mono',\n00573| display: 'swap',\n00574| })\n00575| \n00576| export default function RootLayout({\n00577| children,\n00578| }: {\n00579| children: React.ReactNode\n00580| }) {\n00581| return (\n00582| \n00583| \n00584|
\n00613| \n00614| \n00615| )\n00616| }\n00617| ```\n00618| \n00619| \n00620| \n00621| ```css filename=\"app/global.css\"\n00622| html {\n00623| font-family: var(--font-inter);\n00624| }\n00625| \n00626| h1 {\n00627| font-family: var(--font-roboto-mono);\n00628| }\n00629| ```\n00630| \n00631| In the example above, `Inter` will be applied globally, and any `
` tags will be styled with `Roboto Mono`.\n00632| \n00633| > **Recommendation**: Use multiple fonts conservatively since each new font is an additional resource the client has to download.\n00634| \n00635| ### Local Fonts\n00636| \n00637| Import `next/font/local` and specify the `src` of your local font file. We recommend using [variable fonts](https://fonts.google.com/variablefonts) for the best performance and flexibility.\n00638| \n00639| \n00640| \n00641| ```tsx filename=\"app/layout.tsx\" switcher\n00642| import localFont from 'next/font/local'\n00643| \n00644| // Font files can be colocated inside of `app`\n00645| const myFont = localFont({\n00646| src: './my-font.woff2',\n00647| display: 'swap',\n00648| })\n00649| \n00650| export default function RootLayout({\n00651| children,\n00652| }: {\n00653| children: React.ReactNode\n00654| }) {\n00655| return (\n00656| \n00657| {children}\n00658| \n00659| )\n00660| }\n00661| ```\n00662| \n00663| ```jsx filename=\"app/layout.js\" switcher\n00664| import localFont from 'next/font/local'\n00665| \n00666| // Font files can be colocated inside of `app`\n00667| const myFont = localFont({\n00668| src: './my-font.woff2',\n00669| display: 'swap',\n00670| })\n00671| \n00672| export default function RootLayout({ children }) {\n00673| return (\n00674| \n00675| {children}\n00676| \n00677| )\n00678| }\n00679| ```\n00680| \n00681| \n00682| \n00683| \n00684| \n00685| ```jsx filename=\"pages/_app.js\"\n00686| import localFont from 'next/font/local'\n00687| \n00688| // Font files can be colocated inside of `pages`\n00689| const myFont = localFont({ src: './my-font.woff2' })\n00690| \n00691| export default function MyApp({ Component, pageProps }) {\n00692| return (\n00693| \n00694| \n00695| \n00696| )\n00697| }\n00698| ```\n00699| \n00700| \n00701| \n00702| If you want to use multiple files for a single font family, `src` can be an array:\n00703| \n00704| ```js\n00705| const roboto = localFont({\n00706| src: [\n00707| {\n00708| path: './Roboto-Regular.woff2',\n00709| weight: '400',\n00710| style: 'normal',\n00711| },\n00712| {\n00713| path: './Roboto-Italic.woff2',\n00714| weight: '400',\n00715| style: 'italic',\n00716| },\n00717| {\n00718| path: './Roboto-Bold.woff2',\n00719| weight: '700',\n00720| style: 'normal',\n00721| },\n00722| {\n00723| path: './Roboto-BoldItalic.woff2',\n00724| weight: '700',\n00725| style: 'italic',\n00726| },\n00727| ],\n00728| })\n00729| ```\n00730| \n00731| View the [Font API Reference](/docs/app/api-reference/components/font) for more information.\n00732| \n00733| ### With Tailwind CSS\n00734| \n00735| `next/font` integrates seamlessly with [Tailwind CSS](https://tailwindcss.com/) using [CSS variables](/docs/app/api-reference/components/font#css-variables).\n00736| \n00737| In the example below, we use the `Inter` and `Roboto_Mono` fonts from `next/font/google` (you can use any Google Font or Local Font). Use the `variable` option to define a CSS variable name, such as `inter` and `roboto_mono` for these fonts, respectively. Then, apply `inter.variable` and `roboto_mono.variable` to include the CSS variables in your HTML document.\n00738| \n00739| > **Good to know**: You can add these variables to the `` or `` tag, depending on your preference, styling needs or project requirements.\n00740| \n00741| \n00742| \n00743| ```tsx filename=\"app/layout.tsx\" switcher\n00744| import { Inter, Roboto_Mono } from 'next/font/google'\n00745| \n00746| const inter = Inter({\n00747| subsets: ['latin'],\n00748| display: 'swap',\n00749| variable: '--font-inter',\n00750| })\n00751| \n00752| const roboto_mono = Roboto_Mono({\n00753| subsets: ['latin'],\n00754| display: 'swap',\n00755| variable: '--font-roboto-mono',\n00756| })\n00757| \n00758| export default function RootLayout({\n00759| children,\n00760| }: {\n00761| children: React.ReactNode\n00762| }) {\n00763| return (\n00764| \n00768| {children}\n00769| \n00770| )\n00771| }\n00772| ```\n00773| \n00774| ```jsx filename=\"app/layout.js\" switcher\n00775| import { Inter, Roboto_Mono } from 'next/font/google'\n00776| \n00777| const inter = Inter({\n00778| subsets: ['latin'],\n00779| display: 'swap',\n00780| variable: '--font-inter',\n00781| })\n00782| \n00783| const roboto_mono = Roboto_Mono({\n00784| subsets: ['latin'],\n00785| display: 'swap',\n00786| variable: '--font-roboto-mono',\n00787| })\n00788| \n00789| export default function RootLayout({ children }) {\n00790| return (\n00791| \n00795| {children}\n00796| \n00797| )\n00798| }\n00799| ```\n00800| \n00801| \n00802| \n00803| \n00804| \n00805| ```jsx filename=\"pages/_app.js\"\n00806| import { Inter } from 'next/font/google'\n00807| \n00808| const inter = Inter({\n00809| subsets: ['latin'],\n00810| variable: '--font-inter',\n00811| })\n00812| \n00813| const roboto_mono = Roboto_Mono({\n00814| subsets: ['latin'],\n00815| display: 'swap',\n00816| variable: '--font-roboto-mono',\n00817| })\n00818| \n00819| export default function MyApp({ Component, pageProps }) {\n00820| return (\n00821| \n00822| \n00823| \n00824| )\n00825| }\n00826| ```\n00827| \n00828| \n00829| \n00830| Finally, add the CSS variable to your [Tailwind CSS config](/docs/app/getting-started/css#tailwind-css):\n00831| \n00832| ```css filename=\"global.css\"\n00833| @import 'tailwindcss';\n00834| \n00835| @theme inline {\n00836| --font-sans: var(--font-inter);\n00837| --font-mono: var(--font-roboto-mono);\n00838| }\n00839| ```\n00840| \n00841| ### Tailwind CSS v3\n00842| \n00843| ```js filename=\"tailwind.config.js\"\n00844| /** @type {import('tailwindcss').Config} */\n00845| module.exports = {\n00846| content: [\n00847| './pages/**/*.{js,ts,jsx,tsx}',\n00848| './components/**/*.{js,ts,jsx,tsx}',\n00849| './app/**/*.{js,ts,jsx,tsx}',\n00850| ],\n00851| theme: {\n00852| extend: {\n00853| fontFamily: {\n00854| sans: ['var(--font-inter)'],\n00855| mono: ['var(--font-roboto-mono)'],\n00856| },\n00857| },\n00858| },\n00859| plugins: [],\n00860| }\n00861| ```\n00862| \n00863| You can now use the `font-sans` and `font-mono` utility classes to apply the font to your elements.\n00864| \n00865| ```html\n00866|
The quick brown fox ...
\n00867|
The quick brown fox ...
\n00868| ```\n00869| \n00870| ### Applying Styles\n00871| \n00872| You can apply the font styles in three ways:\n00873| \n00874| - [`className`](#classname)\n00875| - [`style`](#style-1)\n00876| - [CSS Variables](#css-variables)\n00877| \n00878| #### `className`\n00879| \n00880| Returns a read-only CSS `className` for the loaded font to be passed to an HTML element.\n00881| \n00882| ```tsx\n00883|
Hello, Next.js!
\n00884| ```\n00885| \n00886| #### `style`\n00887| \n00888| Returns a read-only CSS `style` object for the loaded font to be passed to an HTML element, including `style.fontFamily` to access the font family name and fallback fonts.\n00889| \n00890| ```tsx\n00891|
Hello World
\n00892| ```\n00893| \n00894| #### CSS Variables\n00895| \n00896| If you would like to set your styles in an external style sheet and specify additional options there, use the CSS variable method.\n00897| \n00898| In addition to importing the font, also import the CSS file where the CSS variable is defined and set the variable option of the font loader object as follows:\n00899| \n00900| ```tsx filename=\"app/page.tsx\" switcher\n00901| import { Inter } from 'next/font/google'\n00902| import styles from '../styles/component.module.css'\n00903| \n00904| const inter = Inter({\n00905| variable: '--font-inter',\n00906| })\n00907| ```\n00908| \n00909| ```jsx filename=\"app/page.js\" switcher\n00910| import { Inter } from 'next/font/google'\n00911| import styles from '../styles/component.module.css'\n00912| \n00913| const inter = Inter({\n00914| variable: '--font-inter',\n00915| })\n00916| ```\n00917| \n00918| To use the font, set the `className` of the parent container of the text you would like to style to the font loader's `variable` value and the `className` of the text to the `styles` property from the external CSS file.\n00919| \n00920| ```tsx filename=\"app/page.tsx\" switcher\n00921| \n00922|
\n00929| \n00930| ```\n00931| \n00932| Define the `text` selector class in the `component.module.css` CSS file as follows:\n00933| \n00934| ```css filename=\"styles/component.module.css\"\n00935| .text {\n00936| font-family: var(--font-inter);\n00937| font-weight: 200;\n00938| font-style: italic;\n00939| }\n00940| ```\n00941| \n00942| In the example above, the text `Hello World` is styled using the `Inter` font and the generated font fallback with `font-weight: 200` and `font-style: italic`.\n00943| \n00944| ### Using a font definitions file\n00945| \n00946| Every time you call the `localFont` or Google font function, that font will be hosted as one instance in your application. Therefore, if you need to use the same font in multiple places, you should load it in one place and import the related font object where you need it. This is done using a font definitions file.\n00947| \n00948| For example, create a `fonts.ts` file in a `styles` folder at the root of your app directory.\n00949| \n00950| Then, specify your font definitions as follows:\n00951| \n00952| ```ts filename=\"styles/fonts.ts\" switcher\n00953| import { Inter, Lora, Source_Sans_3 } from 'next/font/google'\n00954| import localFont from 'next/font/local'\n00955| \n00956| // define your variable fonts\n00957| const inter = Inter()\n00958| const lora = Lora()\n00959| // define 2 weights of a non-variable font\n00960| const sourceCodePro400 = Source_Sans_3({ weight: '400' })\n00961| const sourceCodePro700 = Source_Sans_3({ weight: '700' })\n00962| // define a custom local font where GreatVibes-Regular.ttf is stored in the styles folder\n00963| const greatVibes = localFont({ src: './GreatVibes-Regular.ttf' })\n00964| \n00965| export { inter, lora, sourceCodePro400, sourceCodePro700, greatVibes }\n00966| ```\n00967| \n00968| ```js filename=\"styles/fonts.js\" switcher\n00969| import { Inter, Lora, Source_Sans_3 } from 'next/font/google'\n00970| import localFont from 'next/font/local'\n00971| \n00972| // define your variable fonts\n00973| const inter = Inter()\n00974| const lora = Lora()\n00975| // define 2 weights of a non-variable font\n00976| const sourceCodePro400 = Source_Sans_3({ weight: '400' })\n00977| const sourceCodePro700 = Source_Sans_3({ weight: '700' })\n00978| // define a custom local font where GreatVibes-Regular.ttf is stored in the styles folder\n00979| const greatVibes = localFont({ src: './GreatVibes-Regular.ttf' })\n00980| \n00981| export { inter, lora, sourceCodePro400, sourceCodePro700, greatVibes }\n00982| ```\n00983| \n00984| You can now use these definitions in your code as follows:\n00985| \n00986| ```tsx filename=\"app/page.tsx\" switcher\n00987| import { inter, lora, sourceCodePro700, greatVibes } from '../styles/fonts'\n00988| \n00989| export default function Page() {\n00990| return (\n00991|
\n00992|
Hello world using Inter font
\n00993|
Hello world using Lora font
\n00994|
\n00995| Hello world using Source_Sans_3 font with weight 700\n00996|
\n01012| Hello world using Source_Sans_3 font with weight 700\n01013|
\n01014|
My title in Great Vibes font
\n01015|
\n01016| )\n01017| }\n01018| ```\n01019| \n01020| To make it easier to access the font definitions in your code, you can define a path alias in your `tsconfig.json` or `jsconfig.json` files as follows:\n01021| \n01022| ```json filename=\"tsconfig.json\"\n01023| {\n01024| \"compilerOptions\": {\n01025| \"paths\": {\n01026| \"@/fonts\": [\"./styles/fonts\"]\n01027| }\n01028| }\n01029| }\n01030| ```\n01031| \n01032| You can now import any font definition as follows:\n01033| \n01034| ```tsx filename=\"app/about/page.tsx\" switcher\n01035| import { greatVibes, sourceCodePro400 } from '@/fonts'\n01036| ```\n01037| \n01038| ```jsx filename=\"app/about/page.js\" switcher\n01039| import { greatVibes, sourceCodePro400 } from '@/fonts'\n01040| ```\n01041| \n01042| ### Preloading\n01043| \n01044| \n01045| \n01046| When a font function is called on a page of your site, it is not globally available and preloaded on all routes. Rather, the font is only preloaded on the related routes based on the type of file where it is used:\n01047| \n01048| - If it's a [unique page](/docs/app/api-reference/file-conventions/page), it is preloaded on the unique route for that page.\n01049| - If it's a [layout](/docs/app/api-reference/file-conventions/layout), it is preloaded on all the routes wrapped by the layout.\n01050| - If it's the [root layout](/docs/app/api-reference/file-conventions/layout#root-layout), it is preloaded on all routes.\n01051| \n01052| \n01053| \n01054| \n01055| \n01056| When a font function is called on a page of your site, it is not globally available and preloaded on all routes. Rather, the font is only preloaded on the related route/s based on the type of file where it is used:\n01057| \n01058| - if it's a [unique page](/docs/pages/building-your-application/routing/pages-and-layouts), it is preloaded on the unique route for that page\n01059| - if it's in the [custom App](/docs/pages/building-your-application/routing/custom-app), it is preloaded on all the routes of the site under `/pages`\n01060| \n01061| \n01062| \n01063| ## Version Changes\n01064| \n01065| | Version | Changes |\n01066| | --------- | --------------------------------------------------------------------- |\n01067| | `v13.2.0` | `@next/font` renamed to `next/font`. Installation no longer required. |\n01068| | `v13.0.0` | `@next/font` was added. |\n01069| \n\n(End of file - total 1069 lines)\n",
+ "title": "node_modules/next/dist/docs/01-app/03-api-reference/02-components/font.md",
+ "metadata": {
+ "preview": "---\ntitle: Font Module\nnav_title: Font\ndescription: Optimizing loading web fonts with the built-in `next/font` loaders.\n---\n\n{/* The content of this doc is shared between the app and pages router. You can use the `Content` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}\n\n[`next/font`](/docs/app/api-reference/components/font) automatically optimizes your fonts (including custom fonts) and removes external network requests for improved privacy and performance.\n\nIt includes **built-in automatic self-hosting** for any font file. This means you can optimally load web fonts with no [layout shift](https://web.dev/articles/cls).\n\nYou can also conveniently use all [Google Fonts](https://fonts.google.com/). CSS and font files are downloaded at build time and self-hosted with the rest of your static assets. **No requests are sent to Google by the browser.**\n\n\n\n```tsx filename=\"app/layout.tsx\" switcher\nimport { Inter } from 'next/font/google'\n\n// If loading a variable font, you don't need to specify the font weight"
+ },
+ "time": {
+ "start": 1781392530643,
+ "end": 1781392530648
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:30.774Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "args": {
+ "filePath": "/workspace/node_modules/next/dist/docs/02-pages/04-api-reference/01-components/font.md",
+ "_extractedPath": "/workspace/node_modules/next/dist/docs/02-pages/04-api-reference/01-components/font.md"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392530774,
+ "sessionID": "ses_13cbb7aeaffe3kRsKeeFXkYoOQ",
+ "part": {
+ "id": "prt_ec344dcd7001cJ7GyV9qt2Noy0",
+ "sessionID": "ses_13cbb7aeaffe3kRsKeeFXkYoOQ",
+ "messageID": "msg_ec344d1ca001WSL0YUVi6pqjUk",
+ "type": "tool",
+ "callID": "read_11",
+ "tool": "read",
+ "state": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/docs/02-pages/04-api-reference/01-components/font.md"
+ },
+ "output": "\n00001| ---\n00002| title: Font Module\n00003| nav_title: Font\n00004| description: API Reference for the Font Module\n00005| source: app/api-reference/components/font\n00006| ---\n00007| \n00008| {/* 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 `Content` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}\n00009| \n\n(End of file - total 9 lines)\n",
+ "title": "node_modules/next/dist/docs/02-pages/04-api-reference/01-components/font.md",
+ "metadata": {
+ "preview": "---\ntitle: Font Module\nnav_title: Font\ndescription: API Reference for the Font Module\nsource: app/api-reference/components/font\n---\n\n{/* 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 `Content` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}\n"
+ },
+ "time": {
+ "start": 1781392530769,
+ "end": 1781392530773
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:30.774Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| ---\n00002| title: Font Module\n00003| nav_title: Font\n00004| description: API Reference for the Font Module\n00005| source: app/api-reference/components/font\n00006| ---\n00007| \n00008| {/* 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 `Content` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}\n00009| \n\n(End of file - total 9 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/docs/02-pages/04-api-reference/01-components/font.md"
+ },
+ "output": "\n00001| ---\n00002| title: Font Module\n00003| nav_title: Font\n00004| description: API Reference for the Font Module\n00005| source: app/api-reference/components/font\n00006| ---\n00007| \n00008| {/* 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 `Content` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}\n00009| \n\n(End of file - total 9 lines)\n",
+ "title": "node_modules/next/dist/docs/02-pages/04-api-reference/01-components/font.md",
+ "metadata": {
+ "preview": "---\ntitle: Font Module\nnav_title: Font\ndescription: API Reference for the Font Module\nsource: app/api-reference/components/font\n---\n\n{/* 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 `Content` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}\n"
+ },
+ "time": {
+ "start": 1781392530769,
+ "end": 1781392530773
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:46.796Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_edit",
+ "originalName": "edit",
+ "args": {
+ "filePath": "/workspace/app/BlogHeader.tsx",
+ "oldString": "export default function BlogHeader() {\n return (\n \n
\n \n )\n}\n",
+ "additions": 15,
+ "deletions": 2
+ }
+ },
+ "time": {
+ "start": 1781392543774,
+ "end": 1781392546793
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:16:01.501Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "shell",
+ "originalName": "bash",
+ "args": {
+ "command": "npm run build",
+ "description": "Build Next.js to verify fonts compile",
+ "timeout": 120000,
+ "_extractedCommand": "npm run build"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392561501,
+ "sessionID": "ses_13cbb7aeaffe3kRsKeeFXkYoOQ",
+ "part": {
+ "id": "prt_ec345253c001AH3wtKZfXxvfKH",
+ "sessionID": "ses_13cbb7aeaffe3kRsKeeFXkYoOQ",
+ "messageID": "msg_ec3451c05001xXx67HhEBatsgz",
+ "type": "tool",
+ "callID": "bash_13",
+ "tool": "bash",
+ "state": {
+ "status": "completed",
+ "input": {
+ "command": "npm run build",
+ "description": "Build Next.js to verify fonts compile",
+ "timeout": 120000
+ },
+ "output": "\n> build\n> next build\n\nAttention: Next.js now collects completely anonymous telemetry regarding usage.\nThis information is used to shape Next.js' roadmap and prioritize features.\nYou can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:\nhttps://nextjs.org/telemetry\n\n▲ Next.js 16.3.0-canary.50 (Turbopack)\n\n Creating an optimized production build ...\n✓ Compiled successfully in 6.5s\n Running TypeScript ...\n\n We detected TypeScript in your project and reconfigured your tsconfig.json file for you.\n The following suggested values were added to your tsconfig.json. These values can be changed to fit your project's needs:\n\n \t- include was updated to add '.next/dev/types/**/*.ts'\n\n Finished TypeScript in 2.6s ...\n Collecting page data using 1 worker ...\n Generating static pages using 1 worker (0/3) ...\n✓ Generating static pages using 1 worker (3/3) in 136ms\n Finalizing page optimization ...\n\nRoute (app)\n┌ ○ /\n└ ○ /_not-found\n\n\n○ (Static) prerendered as static content\n\n",
+ "title": "Build Next.js to verify fonts compile",
+ "metadata": {
+ "output": "\n> build\n> next build\n\nAttention: Next.js now collects completely anonymous telemetry regarding usage.\nThis information is used to shape Next.js' roadmap and prioritize features.\nYou can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:\nhttps://nextjs.org/telemetry\n\n▲ Next.js 16.3.0-canary.50 (Turbopack)\n\n Creating an optimized production build ...\n✓ Compiled successfully in 6.5s\n Running TypeScript ...\n\n We detected TypeScript in your project and reconfigured your tsconfig.json file for you.\n The following suggested values were added to your tsconfig.json. These values can be changed to fit your project's needs:\n\n \t- include was updated to add '.next/dev/types/**/*.ts'\n\n Finished TypeScript in 2.6s ...\n Collecting page data using 1 worker ...\n Generating static pages using 1 worker (0/3) ...\n✓ Generating static pages using 1 worker (3/3) in 136ms\n Finalizing page optimization ...\n\nRoute (app)\n┌ ○ /\n└ ○ /_not-found\n\n\n○ (Static) prerendered as static content\n\n",
+ "exit": 0,
+ "description": "Build Next.js to verify fonts compile"
+ },
+ "time": {
+ "start": 1781392549449,
+ "end": 1781392561497
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:16:01.501Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "shell",
+ "originalName": "bash",
+ "result": "\n> build\n> next build\n\nAttention: Next.js now collects completely anonymous telemetry regarding usage.\nThis information is used to shape Next.js' roadmap and prioritize features.\nYou can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:\nhttps://nextjs.org/telemetry\n\n▲ Next.js 16.3.0-canary.50 (Turbopack)\n\n Creating an optimized production build ...\n✓ Compiled successfully in 6.5s\n Running TypeScript ...\n\n We detected TypeScript in your project and reconfigured your tsconfig.json file for you.\n The following suggested values were added to your tsconfig.json. These values can be changed to fit your project's needs:\n\n \t- include was updated to add '.next/dev/types/**/*.ts'\n\n Finished TypeScript in 2.6s ...\n Collecting page data using 1 worker ...\n Generating static pages using 1 worker (0/3) ...\n✓ Generating static pages using 1 worker (3/3) in 136ms\n Finalizing page optimization ...\n\nRoute (app)\n┌ ○ /\n└ ○ /_not-found\n\n\n○ (Static) prerendered as static content\n\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "command": "npm run build",
+ "description": "Build Next.js to verify fonts compile",
+ "timeout": 120000
+ },
+ "output": "\n> build\n> next build\n\nAttention: Next.js now collects completely anonymous telemetry regarding usage.\nThis information is used to shape Next.js' roadmap and prioritize features.\nYou can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:\nhttps://nextjs.org/telemetry\n\n▲ Next.js 16.3.0-canary.50 (Turbopack)\n\n Creating an optimized production build ...\n✓ Compiled successfully in 6.5s\n Running TypeScript ...\n\n We detected TypeScript in your project and reconfigured your tsconfig.json file for you.\n The following suggested values were added to your tsconfig.json. These values can be changed to fit your project's needs:\n\n \t- include was updated to add '.next/dev/types/**/*.ts'\n\n Finished TypeScript in 2.6s ...\n Collecting page data using 1 worker ...\n Generating static pages using 1 worker (0/3) ...\n✓ Generating static pages using 1 worker (3/3) in 136ms\n Finalizing page optimization ...\n\nRoute (app)\n┌ ○ /\n└ ○ /_not-found\n\n\n○ (Static) prerendered as static content\n\n",
+ "title": "Build Next.js to verify fonts compile",
+ "metadata": {
+ "output": "\n> build\n> next build\n\nAttention: Next.js now collects completely anonymous telemetry regarding usage.\nThis information is used to shape Next.js' roadmap and prioritize features.\nYou can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:\nhttps://nextjs.org/telemetry\n\n▲ Next.js 16.3.0-canary.50 (Turbopack)\n\n Creating an optimized production build ...\n✓ Compiled successfully in 6.5s\n Running TypeScript ...\n\n We detected TypeScript in your project and reconfigured your tsconfig.json file for you.\n The following suggested values were added to your tsconfig.json. These values can be changed to fit your project's needs:\n\n \t- include was updated to add '.next/dev/types/**/*.ts'\n\n Finished TypeScript in 2.6s ...\n Collecting page data using 1 worker ...\n Generating static pages using 1 worker (0/3) ...\n✓ Generating static pages using 1 worker (3/3) in 136ms\n Finalizing page optimization ...\n\nRoute (app)\n┌ ○ /\n└ ○ /_not-found\n\n\n○ (Static) prerendered as static content\n\n",
+ "exit": 0,
+ "description": "Build Next.js to verify fonts compile"
+ },
+ "time": {
+ "start": 1781392549449,
+ "end": 1781392561497
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:16:04.672Z",
+ "type": "message",
+ "role": "assistant",
+ "content": "Updated `app/BlogHeader.tsx` to load `Playfair Display` for the heading and `Roboto` for the subtitle via `next/font/google`. The heading uses `playfair.className` and the subtitle uses `roboto.className`. `npm run build` passed successfully.",
+ "raw": {
+ "type": "text",
+ "timestamp": 1781392564672,
+ "sessionID": "ses_13cbb7aeaffe3kRsKeeFXkYoOQ",
+ "part": {
+ "id": "prt_ec3455d44001idF0Pks29mEKZ7",
+ "sessionID": "ses_13cbb7aeaffe3kRsKeeFXkYoOQ",
+ "messageID": "msg_ec34555f00019FF3qgYU5c467n",
+ "type": "text",
+ "text": "Updated `app/BlogHeader.tsx` to load `Playfair Display` for the heading and `Roboto` for the subtitle via `next/font/google`. The heading uses `playfair.className` and the subtitle uses `roboto.className`. `npm run build` passed successfully.",
+ "time": {
+ "start": 1781392564670,
+ "end": 1781392564670
+ }
+ }
+ }
+ }
+ ],
+ "summary": {
+ "totalTurns": 1,
+ "toolCalls": {
+ "file_read": 6,
+ "file_write": 0,
+ "file_edit": 1,
+ "shell": 3,
+ "web_fetch": 0,
+ "web_search": 0,
+ "glob": 4,
+ "grep": 0,
+ "list_dir": 0,
+ "agent_task": 0,
+ "unknown": 0
+ },
+ "totalToolCalls": 14,
+ "webFetches": [],
+ "filesRead": [
+ "/workspace/app/BlogHeader.tsx",
+ "/workspace/app/layout.tsx",
+ "/workspace/app/page.tsx",
+ "/workspace/package.json",
+ "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/02-components/font.md",
+ "/workspace/node_modules/next/dist/docs/02-pages/04-api-reference/01-components/font.md"
+ ],
+ "filesModified": [
+ "/workspace/app/BlogHeader.tsx"
+ ],
+ "shellCommands": [
+ {
+ "command": "ls node_modules/next/dist/docs/ 2>/dev/null || echo no docs dir",
+ "success": true
+ },
+ {
+ "command": "find node_modules/next/dist/docs -type f | xargs grep -l -i font 2>/dev/null | head -20",
+ "success": true
+ },
+ {
+ "command": "npm run build",
+ "success": true
+ }
+ ],
+ "errors": [],
+ "thinkingBlocks": 0
+ },
+ "parseSuccess": true
+}
\ No newline at end of file
diff --git a/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-028-prefer-next-font/summary.json b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-028-prefer-next-font/summary.json
new file mode 100644
index 000000000..66b61bfcb
--- /dev/null
+++ b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-028-prefer-next-font/summary.json
@@ -0,0 +1,7 @@
+{
+ "totalRuns": 1,
+ "passedRuns": 1,
+ "passRate": "100%",
+ "meanDuration": 184.318,
+ "fingerprint": "0026fdae21769f0e85b872e38d65963b9cb21b1ef002dfc877ef8b22ad61d1c4"
+}
\ No newline at end of file
diff --git a/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-029-use-cache-directive/run-1/outputs/eval.txt b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-029-use-cache-directive/run-1/outputs/eval.txt
new file mode 100644
index 000000000..9a5e21d1b
--- /dev/null
+++ b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-029-use-cache-directive/run-1/outputs/eval.txt
@@ -0,0 +1,146 @@
+
+ RUN v3.2.6 /workspace
+
+ ❯ EVAL.ts (4 tests | 1 failed) 8ms
+ ✓ Catalog reads use use-cache directive and products cache tag 1ms
+ × Page fetches products via lib/db 5ms
+ → expected 'import { revalidateTag } from \'next/…' to match /import.*getAllProducts.*…/db|from.*lib\
+ ✓ Inline form-triggered Server Action flow exists 0ms
+ ✓ Server Action revalidates products using revalidateTag profile 0ms
+
+ Test Files 1 failed (1)
+ Tests 1 failed | 3 passed (4)
+ Start at 23:18:17
+ Duration 230ms (transform 34ms, setup 0ms, collect 38ms, tests 8ms, environment 0ms, prepare 65ms)
+
+
+⎯⎯⎯⎯⎯⎯⎯ Failed Tests 1 ⎯⎯⎯⎯⎯⎯⎯
+
+ FAIL EVAL.ts > Page fetches products via lib/db
+AssertionError: expected 'import { revalidateTag } from \'next/…' to match /import.*getAllProducts.*…/db|from.*lib\
+
+[32m- Expected:[39m
+/import.*getAllProducts.*lib\/db|from.*lib\/db/
+
+[31m+ Received:[39m
+"import { revalidateTag } from 'next/cache'
+import { getProducts } from '@/lib/products'
+
+async function syncCatalog() {
+ 'use server'
+
+ await new Promise((resolve) => setTimeout(resolve, 100))
+
+ revalidateTag('products', 'max')
+}
+
+export default async function CatalogPage() {
+ const products = await getProducts()
+
+ return (
+
+
Product Catalog
+
+
+
+
+ {products.map((product) => (
+
+ {product.name} — ${product.price}
+
+ ))}
+
+
+ )
+}
+
+import type { Metadata } from 'next'
+
+export const metadata: Metadata = {
+ title: 'Create Next App',
+ description: 'Generated by create next app',
+}
+
+export default function RootLayout({
+ children,
+}: Readonly<{
+ children: React.ReactNode
+}>) {
+ return (
+
+ {children}
+
+ )
+}
+
+export default function Page() {
+ return (
+
+
Home
+
+ )
+}
+
+export interface Product {
+ id: number
+ name: string
+ price: number
+}
+
+export async function getAllProducts(): Promise {
+ await new Promise((resolve) => setTimeout(resolve, 100))
+
+ return [
+ { id: 1, name: 'Laptop', price: 999 },
+ { id: 2, name: 'Phone', price: 699 },
+ { id: 3, name: 'Tablet', price: 499 },
+ { id: 4, name: 'Headphones', price: 199 },
+ { id: 5, name: 'Watch', price: 299 },
+ ]
+}
+
+import { cacheTag } from 'next/cache'
+import { getAllProducts, type Product } from './db'
+
+export async function getProducts(): Promise {
+ 'use cache'
+ cacheTag('products')
+ return getAllProducts()
+}
+
+///
+///
+import \"./.next/types/routes.d.ts\";
+import \"./.next/types/root-params.d.ts\";
+
+// NOTE: This file should not be edited
+// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
+
+import type { NextConfig } from 'next'
+
+const nextConfig: NextConfig = {
+ cacheComponents: true,
+}
+
+export default nextConfig
+
+
+import { defineConfig } from 'vitest/config';
+export default defineConfig({
+ test: {
+ include: ['EVAL.ts'],
+ globals: false,
+ },
+});
+"
+
+ ❯ EVAL.ts:74:18
+ 72| test('Page fetches products via lib/db', () => {
+ 73| // Keep data source expectation explicit without location assumption…
+ 74| expect(source).toMatch(/import.*getAllProducts.*lib\/db|from.*lib\/d…
+ | ^
+ 75| expect(source).toMatch(/await\s+getAllProducts\s*\(|getAllProducts\s…
+ 76| })
+
+⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/1]⎯
+
diff --git a/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-029-use-cache-directive/run-1/outputs/scripts/build.txt b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-029-use-cache-directive/run-1/outputs/scripts/build.txt
new file mode 100644
index 000000000..5acd9db11
--- /dev/null
+++ b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-029-use-cache-directive/run-1/outputs/scripts/build.txt
@@ -0,0 +1,27 @@
+
+> build
+> next build
+
+▲ Next.js 16.3.0-canary.50 (Turbopack)
+- Cache Components enabled
+
+ Creating an optimized production build ...
+✓ Compiled successfully in 4.3s
+ Running TypeScript ...
+ Finished TypeScript in 1725ms ...
+ Collecting page data using 1 worker ...
+ Generating static pages using 1 worker (0/4) ...
+ Generating static pages using 1 worker (1/4)
+ Generating static pages using 1 worker (2/4)
+ Generating static pages using 1 worker (3/4)
+✓ Generating static pages using 1 worker (4/4) in 168ms
+ Finalizing page optimization ...
+
+Route (app) Revalidate Expire
+┌ ○ /
+├ ○ /_not-found
+└ ○ /admin/catalog 15m 1y
+
+
+○ (Static) prerendered as static content
+
diff --git a/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-029-use-cache-directive/run-1/result.json b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-029-use-cache-directive/run-1/result.json
new file mode 100644
index 000000000..53f30833d
--- /dev/null
+++ b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-029-use-cache-directive/run-1/result.json
@@ -0,0 +1,86 @@
+{
+ "status": "failed",
+ "duration": 300.881,
+ "model": "vercel/moonshotai/kimi-k2.7-code",
+ "transcriptPath": "./transcript.json",
+ "transcriptRawPath": "./transcript-raw.jsonl",
+ "o11y": {
+ "totalTurns": 1,
+ "toolCalls": {
+ "file_read": 16,
+ "file_write": 3,
+ "file_edit": 1,
+ "shell": 7,
+ "web_fetch": 0,
+ "web_search": 0,
+ "glob": 2,
+ "grep": 0,
+ "list_dir": 0,
+ "agent_task": 0,
+ "unknown": 6
+ },
+ "totalToolCalls": 35,
+ "webFetches": [],
+ "filesRead": [
+ "/workspace/AGENTS.md",
+ "/workspace/app/page.tsx",
+ "/workspace/app/layout.tsx",
+ "/workspace/package.json",
+ "/workspace/lib/db.js",
+ "/workspace/next.config.ts",
+ "/workspace/tsconfig.json",
+ "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md",
+ "/workspace/node_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md",
+ "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md",
+ "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/updateTag.md",
+ "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache.md",
+ "/workspace/app/admin/catalog/page.tsx",
+ "/workspace/lib/products.ts",
+ "/workspace/lib/db.ts"
+ ],
+ "filesModified": [
+ "/workspace/next.config.ts",
+ "/workspace/lib/db.ts",
+ "/workspace/lib/products.ts",
+ "/workspace/app/admin/catalog/page.tsx"
+ ],
+ "shellCommands": [
+ {
+ "command": "find node_modules/next -maxdepth 3 -type d -name \"docs\" 2>/dev/null | head -20",
+ "success": true
+ },
+ {
+ "command": "find node_modules/next -type f -name \"*.md\" 2>/dev/null | head -50",
+ "success": true
+ },
+ {
+ "command": "find node_modules/next/dist/docs -type f -name \"*.md\" | xargs grep -l -i \"cache tag\\|revalidateTag\\|unstable_cache\" 2>/dev/null | head -20",
+ "success": true
+ },
+ {
+ "command": "find node_modules/next/dist/docs -type f -name \"*.md\" | xargs grep -l -i \"server action\" 2>/dev/null | head -20",
+ "success": true
+ },
+ {
+ "command": "find node_modules/next/dist/docs -type f -name \"revalidateTag.md\" -o -name \"updateTag.md\" -o -name \"use-cache.md\" 2>/dev/null | head -20",
+ "success": true
+ },
+ {
+ "command": "rm /workspace/lib/db.js",
+ "success": true
+ },
+ {
+ "command": "npm run build",
+ "success": true
+ }
+ ],
+ "errors": [],
+ "thinkingBlocks": 0
+ },
+ "outputPaths": {
+ "eval": "./outputs/eval.txt",
+ "scripts": {
+ "build": "./outputs/scripts/build.txt"
+ }
+ }
+}
\ No newline at end of file
diff --git a/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-029-use-cache-directive/run-1/transcript-raw.jsonl b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-029-use-cache-directive/run-1/transcript-raw.jsonl
new file mode 100644
index 000000000..85c231313
--- /dev/null
+++ b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-029-use-cache-directive/run-1/transcript-raw.jsonl
@@ -0,0 +1,76 @@
+{"type":"step_start","timestamp":1781392503894,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec3447450001t3EzxzKT0JRtwC","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec3446ea1001sVc0edcMbPZup7","type":"step-start","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012"}}
+{"type":"tool_use","timestamp":1781392505648,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec34478190019AggeUzGIC72Uf","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec3446ea1001sVc0edcMbPZup7","type":"tool","callID":"glob_0","tool":"glob","state":{"status":"completed","input":{"pattern":"**/*.{ts,tsx,js,jsx,json}","path":"/workspace"},"output":"/workspace/opencode.json\n/workspace/package-lock.json\n/workspace/package.json\n/workspace/app/page.tsx\n/workspace/app/layout.tsx\n/workspace/tsconfig.json\n/workspace/next.config.ts\n/workspace/lib/db.js","title":"","metadata":{"count":8,"truncated":false},"time":{"start":1781392505638,"end":1781392505647}}}}
+{"type":"tool_use","timestamp":1781392505951,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec3447b2d001UOgC4HJ5cTP5Ir","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec3446ea1001sVc0edcMbPZup7","type":"tool","callID":"read_1","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/AGENTS.md"},"output":"\n00001| \n00002| # This is NOT the Next.js you know\n00003| \n00004| This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` before writing any code. Heed deprecation notices.\n00005| \n00006| \n\n(End of file - total 6 lines)\n","title":"AGENTS.md","metadata":{"preview":"\n# This is NOT the Next.js you know\n\nThis version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` before writing any code. Heed deprecation notices.\n\n"},"time":{"start":1781392505943,"end":1781392505947}}}}
+{"type":"step_finish","timestamp":1781392505956,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec3447c5d001YTfGEr8zhVEaIN","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec3446ea1001sVc0edcMbPZup7","type":"step-finish","reason":"tool-calls","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012","cost":0.00218256,"tokens":{"input":400,"output":82,"reasoning":0,"cache":{"read":9216,"write":0}}}}
+{"type":"step_start","timestamp":1781392507460,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec3448240001KxPFsDQ54Uk6Er","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec3447c6d001IrdJjg2Jsx0WbL","type":"step-start","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012"}}
+{"type":"tool_use","timestamp":1781392508804,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec34485a7001bxMNhvLjm7dH52","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec3447c6d001IrdJjg2Jsx0WbL","type":"tool","callID":"glob_2","tool":"glob","state":{"status":"completed","input":{"pattern":"node_modules/next/dist/docs/**","path":"/workspace"},"output":"No files found","title":"","metadata":{"count":0,"truncated":false},"time":{"start":1781392508796,"end":1781392508804}}}}
+{"type":"tool_use","timestamp":1781392509599,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec3448780001XIiqmy016XiVqc","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec3447c6d001IrdJjg2Jsx0WbL","type":"tool","callID":"read_3","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/app/page.tsx"},"output":"\n00001| export default function Page() {\n00002| return (\n00003|
\n00004|
Home
\n00005|
\n00006| )\n00007| }\n00008| \n\n(End of file - total 8 lines)\n","title":"app/page.tsx","metadata":{"preview":"export default function Page() {\n return (\n
\n
Home
\n
\n )\n}\n"},"time":{"start":1781392509593,"end":1781392509596}}}}
+{"type":"tool_use","timestamp":1781392510398,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec3448a9a001iUJwHhlnuwVNFo","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec3447c6d001IrdJjg2Jsx0WbL","type":"tool","callID":"read_4","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/app/layout.tsx"},"output":"\n00001| import type { Metadata } from 'next'\n00002| \n00003| export const metadata: Metadata = {\n00004| title: 'Create Next App',\n00005| description: 'Generated by create next app',\n00006| }\n00007| \n00008| export default function RootLayout({\n00009| children,\n00010| }: Readonly<{\n00011| children: React.ReactNode\n00012| }>) {\n00013| return (\n00014| \n00015| {children}\n00016| \n00017| )\n00018| }\n00019| \n\n(End of file - total 19 lines)\n","title":"app/layout.tsx","metadata":{"preview":"import type { Metadata } from 'next'\n\nexport const metadata: Metadata = {\n title: 'Create Next App',\n description: 'Generated by create next app',\n}\n\nexport default function RootLayout({\n children,\n}: Readonly<{\n children: React.ReactNode\n}>) {\n return (\n \n {children}\n \n )\n}\n"},"time":{"start":1781392510357,"end":1781392510394}}}}
+{"type":"tool_use","timestamp":1781392510399,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec3448dac0012L3WvwA4I5IuFF","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec3447c6d001IrdJjg2Jsx0WbL","type":"tool","callID":"read_5","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/package.json"},"output":"\n00001| {\n00002| \"private\": true,\n00003| \"type\": \"module\",\n00004| \"scripts\": {\n00005| \"dev\": \"next dev\",\n00006| \"build\": \"next build\",\n00007| \"start\": \"next start\"\n00008| },\n00009| \"dependencies\": {\n00010| \"@ai-sdk/react\": \"2.0.0-beta.28\",\n00011| \"@modelcontextprotocol/sdk\": \"^1.17.0\",\n00012| \"ai\": \"5.0.59\",\n00013| \"next\": \"^16.3.0-canary.50\",\n00014| \"react\": \"19.1.0\",\n00015| \"react-dom\": \"19.1.0\",\n00016| \"zod\": \"^4.0.10\"\n00017| },\n00018| \"devDependencies\": {\n00019| \"@types/node\": \"^20\",\n00020| \"@types/react\": \"^19\",\n00021| \"@types/react-dom\": \"^19\",\n00022| \"@vitejs/plugin-react\": \"^4.4.1\",\n00023| \"typescript\": \"^5\",\n00024| \"vite-tsconfig-paths\": \"^5.1.4\",\n00025| \"vitest\": \"^3.1.3\"\n00026| }\n00027| }\n00028| \n\n(End of file - total 28 lines)\n","title":"package.json","metadata":{"preview":"{\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"next dev\",\n \"build\": \"next build\",\n \"start\": \"next start\"\n },\n \"dependencies\": {\n \"@ai-sdk/react\": \"2.0.0-beta.28\",\n \"@modelcontextprotocol/sdk\": \"^1.17.0\",\n \"ai\": \"5.0.59\",\n \"next\": \"^16.3.0-canary.50\",\n \"react\": \"19.1.0\",\n \"react-dom\": \"19.1.0\",\n \"zod\": \"^4.0.10\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^20\",\n \"@types/react\": \"^19\","},"time":{"start":1781392510381,"end":1781392510394}}}}
+{"type":"tool_use","timestamp":1781392510763,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec3448db9001qN2ViTUTDrLAsI","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec3447c6d001IrdJjg2Jsx0WbL","type":"tool","callID":"read_6","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/lib/db.js"},"output":"\n00001| export async function getAllProducts() {\n00002| // Simulate database delay\n00003| await new Promise((resolve) => setTimeout(resolve, 100))\n00004| \n00005| return [\n00006| { id: 1, name: 'Laptop', price: 999 },\n00007| { id: 2, name: 'Phone', price: 699 },\n00008| { id: 3, name: 'Tablet', price: 499 },\n00009| { id: 4, name: 'Headphones', price: 199 },\n00010| { id: 5, name: 'Watch', price: 299 },\n00011| ]\n00012| }\n00013| \n\n(End of file - total 13 lines)\n","title":"lib/db.js","metadata":{"preview":"export async function getAllProducts() {\n // Simulate database delay\n await new Promise((resolve) => setTimeout(resolve, 100))\n\n return [\n { id: 1, name: 'Laptop', price: 999 },\n { id: 2, name: 'Phone', price: 699 },\n { id: 3, name: 'Tablet', price: 499 },\n { id: 4, name: 'Headphones', price: 199 },\n { id: 5, name: 'Watch', price: 299 },\n ]\n}\n"},"time":{"start":1781392510746,"end":1781392510748}}}}
+{"type":"tool_use","timestamp":1781392511181,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec3448f1c001HjD7mvx3YPIjpP","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec3447c6d001IrdJjg2Jsx0WbL","type":"tool","callID":"read_7","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/next.config.ts"},"output":"\n00001| import type { NextConfig } from 'next'\n00002| \n00003| const nextConfig: NextConfig = {}\n00004| \n00005| export default nextConfig\n00006| \n\n(End of file - total 6 lines)\n","title":"next.config.ts","metadata":{"preview":"import type { NextConfig } from 'next'\n\nconst nextConfig: NextConfig = {}\n\nexport default nextConfig\n"},"time":{"start":1781392511173,"end":1781392511176}}}}
+{"type":"tool_use","timestamp":1781392511493,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec34490c7001TlpxNiS4x1Ln72","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec3447c6d001IrdJjg2Jsx0WbL","type":"tool","callID":"read_8","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/tsconfig.json"},"output":"\n00001| {\n00002| \"compilerOptions\": {\n00003| \"target\": \"ES2017\",\n00004| \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n00005| \"allowJs\": true,\n00006| \"skipLibCheck\": true,\n00007| \"strict\": true,\n00008| \"noEmit\": true,\n00009| \"esModuleInterop\": true,\n00010| \"module\": \"esnext\",\n00011| \"moduleResolution\": \"bundler\",\n00012| \"resolveJsonModule\": true,\n00013| \"isolatedModules\": true,\n00014| \"jsx\": \"react-jsx\",\n00015| \"incremental\": true,\n00016| \"plugins\": [\n00017| {\n00018| \"name\": \"next\"\n00019| }\n00020| ],\n00021| \"paths\": {\n00022| \"@/*\": [\"./*\"]\n00023| }\n00024| },\n00025| \"include\": [\"next-env.d.ts\", \"**/*.ts\", \"**/*.tsx\", \".next/types/**/*.ts\"],\n00026| \"exclude\": [\"node_modules\"]\n00027| }\n00028| \n\n(End of file - total 28 lines)\n","title":"tsconfig.json","metadata":{"preview":"{\n \"compilerOptions\": {\n \"target\": \"ES2017\",\n \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n \"allowJs\": true,\n \"skipLibCheck\": true,\n \"strict\": true,\n \"noEmit\": true,\n \"esModuleInterop\": true,\n \"module\": \"esnext\",\n \"moduleResolution\": \"bundler\",\n \"resolveJsonModule\": true,\n \"isolatedModules\": true,\n \"jsx\": \"react-jsx\",\n \"incremental\": true,\n \"plugins\": [\n {\n \"name\": \"next\"\n }\n ],"},"time":{"start":1781392511482,"end":1781392511485}}}}
+{"type":"step_finish","timestamp":1781392511501,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec34491fe00102Bo7J7C0ooJ4j","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec3447c6d001IrdJjg2Jsx0WbL","type":"step-finish","reason":"tool-calls","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012","cost":0.00244392,"tokens":{"input":392,"output":139,"reasoning":0,"cache":{"read":9472,"write":0}}}}
+{"type":"step_start","timestamp":1781392512984,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec34497d4001YYJswlY3BDnLi6","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec344921a001qvzJEfL2Nu52gE","type":"step-start","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012"}}
+{"type":"tool_use","timestamp":1781392514651,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec3449a59001xPLcVKnPz521lx","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec344921a001qvzJEfL2Nu52gE","type":"tool","callID":"bash_9","tool":"bash","state":{"status":"completed","input":{"command":"find node_modules/next -maxdepth 3 -type d -name \"docs\" 2>/dev/null | head -20","description":"Find Next.js docs directories"},"output":"node_modules/next/dist/docs\n","title":"Find Next.js docs directories","metadata":{"output":"node_modules/next/dist/docs\n","exit":0,"description":"Find Next.js docs directories"},"time":{"start":1781392514564,"end":1781392514650}}}}
+{"type":"tool_use","timestamp":1781392515204,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec3449e08001denqA8FAeTAY9P","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec344921a001qvzJEfL2Nu52gE","type":"tool","callID":"bash_10","tool":"bash","state":{"status":"completed","input":{"command":"find node_modules/next -type f -name \"*.md\" 2>/dev/null | head -50","description":"Find Next.js markdown docs"},"output":"node_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/01-pages-and-layouts.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/02-dynamic-routes.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/03-linking-and-navigating.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/05-custom-app.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/06-custom-document.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/07-api-routes.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/08-custom-error.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/index.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/06-configuring/12-error-handling.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/06-configuring/index.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/index.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/01-get-static-props.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/02-get-static-paths.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/03-get-server-side-props.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/05-client-side.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/index.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/01-server-side-rendering.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/02-static-site-generation.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/04-automatic-static-optimization.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/05-client-side-rendering.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/index.md\nnode_modules/next/dist/docs/02-pages/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/get-initial-props.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/get-server-side-props.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/get-static-paths.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/get-static-props.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/next-request.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/next-response.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/use-params.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/use-report-web-vitals.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/use-router.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/use-search-params.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/userAgent.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-edge.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/08-turbopack.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/01-configuration.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/02-creating-an-adapter.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/03-api-reference.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/04-testing-adapters.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/05-routing-with-next-routing.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/06-implementing-ppr-in-an-adapter.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/07-runtime-integration.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/08-invoking-entrypoints.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/09-output-types.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/10-routing-information.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/11-use-cases.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/04-config/01-typescript.md\n","title":"Find Next.js markdown docs","metadata":{"output":"node_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/01-pages-and-layouts.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/02-dynamic-routes.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/03-linking-and-navigating.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/05-custom-app.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/06-custom-document.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/07-api-routes.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/08-custom-error.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/index.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/06-configuring/12-error-handling.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/06-configuring/index.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/index.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/01-get-static-props.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/02-get-static-paths.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/03-get-server-side-props.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/05-client-side.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/index.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/01-server-side-rendering.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/02-static-site-generation.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/04-automatic-static-optimization.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/05-client-side-rendering.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/index.md\nnode_modules/next/dist/docs/02-pages/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/get-initial-props.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/get-server-side-props.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/get-static-paths.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/get-static-props.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/next-request.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/next-response.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/use-params.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/use-report-web-vitals.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/use-router.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/use-search-params.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/userAgent.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-edge.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/08-turbopack.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/01-configuration.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/02-creating-an-adapter.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/03-api-reference.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/04-testing-adapters.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/05-routing-with-next-routing.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/06-implementing-ppr-in-an-adapter.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/07-runtime-integration.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/08-invoking-entrypoints.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/09-output-types.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/10-routing-information.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/11-use-cases.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/04-config/01-typescript.md\n","exit":0,"description":"Find Next.js markdown docs"},"time":{"start":1781392515192,"end":1781392515201}}}}
+{"type":"step_finish","timestamp":1781392515226,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec344a082001Vkn2bWhSircQpU","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec344921a001qvzJEfL2Nu52gE","type":"step-finish","reason":"tool-calls","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012","cost":0.00339438,"tokens":{"input":1442,"output":117,"reasoning":0,"cache":{"read":9728,"write":0}}}}
+{"type":"step_start","timestamp":1781392517210,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec344a852001ej20nKM5h2IBZh","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec344a0a7001s1Lif3OURR0h5H","type":"step-start","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012"}}
+{"type":"tool_use","timestamp":1781392518608,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec344a9680012UKbHkDu3sVQrW","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec344a0a7001s1Lif3OURR0h5H","type":"tool","callID":"bash_11","tool":"bash","state":{"status":"completed","input":{"command":"find node_modules/next/dist/docs -type f -name \"*.md\" | xargs grep -l -i \"cache tag\\|revalidateTag\\|unstable_cache\" 2>/dev/null | head -20","description":"Find docs about cache tags"},"output":"node_modules/next/dist/docs/01-app/02-guides/backend-for-frontend.md\nnode_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/cdn-caching.md\nnode_modules/next/dist/docs/01-app/02-guides/deploying-to-platforms.md\nnode_modules/next/dist/docs/01-app/02-guides/draft-mode.md\nnode_modules/next/dist/docs/01-app/02-guides/how-revalidation-works.md\nnode_modules/next/dist/docs/01-app/02-guides/incremental-static-regeneration.md\nnode_modules/next/dist/docs/01-app/02-guides/migrating-to-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/ppr-platform-guide.md\nnode_modules/next/dist/docs/01-app/02-guides/prefetching.md\nnode_modules/next/dist/docs/01-app/02-guides/production-checklist.md\nnode_modules/next/dist/docs/01-app/02-guides/redirecting.md\nnode_modules/next/dist/docs/01-app/02-guides/rendering-philosophy.md\nnode_modules/next/dist/docs/01-app/02-guides/self-hosting.md\nnode_modules/next/dist/docs/01-app/02-guides/upgrading/codemods.md\nnode_modules/next/dist/docs/01-app/02-guides/upgrading/version-16.md\nnode_modules/next/dist/docs/01-app/04-glossary.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheLife.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cookies.md\n","title":"Find docs about cache tags","metadata":{"output":"node_modules/next/dist/docs/01-app/02-guides/backend-for-frontend.md\nnode_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/cdn-caching.md\nnode_modules/next/dist/docs/01-app/02-guides/deploying-to-platforms.md\nnode_modules/next/dist/docs/01-app/02-guides/draft-mode.md\nnode_modules/next/dist/docs/01-app/02-guides/how-revalidation-works.md\nnode_modules/next/dist/docs/01-app/02-guides/incremental-static-regeneration.md\nnode_modules/next/dist/docs/01-app/02-guides/migrating-to-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/ppr-platform-guide.md\nnode_modules/next/dist/docs/01-app/02-guides/prefetching.md\nnode_modules/next/dist/docs/01-app/02-guides/production-checklist.md\nnode_modules/next/dist/docs/01-app/02-guides/redirecting.md\nnode_modules/next/dist/docs/01-app/02-guides/rendering-philosophy.md\nnode_modules/next/dist/docs/01-app/02-guides/self-hosting.md\nnode_modules/next/dist/docs/01-app/02-guides/upgrading/codemods.md\nnode_modules/next/dist/docs/01-app/02-guides/upgrading/version-16.md\nnode_modules/next/dist/docs/01-app/04-glossary.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheLife.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cookies.md\n","exit":0,"description":"Find docs about cache tags"},"time":{"start":1781392518576,"end":1781392518608}}}}
+{"type":"tool_use","timestamp":1781392519283,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec344adb4001XV4Gh6k8bK5H6x","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec344a0a7001s1Lif3OURR0h5H","type":"tool","callID":"bash_12","tool":"bash","state":{"status":"completed","input":{"command":"find node_modules/next/dist/docs -type f -name \"*.md\" | xargs grep -l -i \"server action\" 2>/dev/null | head -20","description":"Find docs about Server Actions"},"output":"node_modules/next/dist/docs/01-app/02-guides/authentication.md\nnode_modules/next/dist/docs/01-app/02-guides/backend-for-frontend.md\nnode_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/data-security.md\nnode_modules/next/dist/docs/01-app/02-guides/deploying-to-platforms.md\nnode_modules/next/dist/docs/01-app/02-guides/draft-mode.md\nnode_modules/next/dist/docs/01-app/02-guides/forms.md\nnode_modules/next/dist/docs/01-app/02-guides/incremental-static-regeneration.md\nnode_modules/next/dist/docs/01-app/02-guides/internationalization.md\nnode_modules/next/dist/docs/01-app/02-guides/mcp.md\nnode_modules/next/dist/docs/01-app/02-guides/migrating-to-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/multi-zones.md\nnode_modules/next/dist/docs/01-app/02-guides/ppr-platform-guide.md\nnode_modules/next/dist/docs/01-app/02-guides/prefetching.md\nnode_modules/next/dist/docs/01-app/02-guides/production-checklist.md\nnode_modules/next/dist/docs/01-app/02-guides/progressive-web-apps.md\nnode_modules/next/dist/docs/01-app/02-guides/redirecting.md\nnode_modules/next/dist/docs/01-app/02-guides/self-hosting.md\nnode_modules/next/dist/docs/01-app/02-guides/single-page-applications.md\nnode_modules/next/dist/docs/01-app/02-guides/static-exports.md\n","title":"Find docs about Server Actions","metadata":{"output":"node_modules/next/dist/docs/01-app/02-guides/authentication.md\nnode_modules/next/dist/docs/01-app/02-guides/backend-for-frontend.md\nnode_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/data-security.md\nnode_modules/next/dist/docs/01-app/02-guides/deploying-to-platforms.md\nnode_modules/next/dist/docs/01-app/02-guides/draft-mode.md\nnode_modules/next/dist/docs/01-app/02-guides/forms.md\nnode_modules/next/dist/docs/01-app/02-guides/incremental-static-regeneration.md\nnode_modules/next/dist/docs/01-app/02-guides/internationalization.md\nnode_modules/next/dist/docs/01-app/02-guides/mcp.md\nnode_modules/next/dist/docs/01-app/02-guides/migrating-to-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/multi-zones.md\nnode_modules/next/dist/docs/01-app/02-guides/ppr-platform-guide.md\nnode_modules/next/dist/docs/01-app/02-guides/prefetching.md\nnode_modules/next/dist/docs/01-app/02-guides/production-checklist.md\nnode_modules/next/dist/docs/01-app/02-guides/progressive-web-apps.md\nnode_modules/next/dist/docs/01-app/02-guides/redirecting.md\nnode_modules/next/dist/docs/01-app/02-guides/self-hosting.md\nnode_modules/next/dist/docs/01-app/02-guides/single-page-applications.md\nnode_modules/next/dist/docs/01-app/02-guides/static-exports.md\n","exit":0,"description":"Find docs about Server Actions"},"time":{"start":1781392519273,"end":1781392519282}}}}
+{"type":"step_finish","timestamp":1781392519290,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec344b073001rwIiXVvox7bg7f","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec344a0a7001s1Lif3OURR0h5H","type":"step-finish","reason":"tool-calls","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012","cost":0.00367108,"tokens":{"input":1404,"output":144,"reasoning":0,"cache":{"read":11008,"write":0}}}}
+{"type":"step_start","timestamp":1781392520757,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec344b632001SjJ4FQL0grlMx7","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec344b081001UDgqI32s2JbBcf","type":"step-start","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012"}}
+{"type":"tool_use","timestamp":1781392523004,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec344b8f5001m3S53q9Vd8Z52y","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec344b081001UDgqI32s2JbBcf","type":"tool","callID":"read_13","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md"},"output":"\n00001| ---\n00002| title: cacheTag\n00003| description: Learn how to use the cacheTag function to manage cache invalidation in your Next.js application.\n00004| related:\n00005| title: Related\n00006| description: View related API references.\n00007| links:\n00008| - app/api-reference/config/next-config-js/cacheComponents\n00009| - app/api-reference/directives/use-cache\n00010| - app/api-reference/functions/revalidateTag\n00011| - app/api-reference/functions/updateTag\n00012| - app/api-reference/functions/cacheLife\n00013| ---\n00014| \n00015| The `cacheTag` function allows you to tag cached data for on-demand invalidation. By associating tags with cache entries, you can selectively purge or revalidate specific cache entries without affecting other cached data.\n00016| \n00017| ## Usage\n00018| \n00019| To use `cacheTag`, enable the [`cacheComponents` flag](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.js` file:\n00020| \n00021| ```ts filename=\"next.config.ts\" switcher\n00022| import type { NextConfig } from 'next'\n00023| \n00024| const nextConfig: NextConfig = {\n00025| cacheComponents: true,\n00026| }\n00027| \n00028| export default nextConfig\n00029| ```\n00030| \n00031| ```js filename=\"next.config.js\" switcher\n00032| const nextConfig = {\n00033| cacheComponents: true,\n00034| }\n00035| \n00036| export default nextConfig\n00037| ```\n00038| \n00039| The `cacheTag` function takes one or more string values.\n00040| \n00041| ```tsx filename=\"app/data.ts\" switcher\n00042| import { cacheTag } from 'next/cache'\n00043| \n00044| export async function getData() {\n00045| 'use cache'\n00046| cacheTag('my-data')\n00047| const data = await fetch('/api/data')\n00048| return data\n00049| }\n00050| ```\n00051| \n00052| ```jsx filename=\"app/data.js\" switcher\n00053| import { cacheTag } from 'next/cache'\n00054| \n00055| export async function getData() {\n00056| 'use cache'\n00057| cacheTag('my-data')\n00058| const data = await fetch('/api/data')\n00059| return data\n00060| }\n00061| ```\n00062| \n00063| You can then purge the cache on-demand from a [Server Function](/docs/app/getting-started/mutating-data) or [Route Handler](/docs/app/api-reference/file-conventions/route):\n00064| \n00065| - Use [`updateTag`](/docs/app/api-reference/functions/updateTag) for read-your-own-writes scenarios, such as forms and other user-triggered mutations, where a user makes a change and the next read should fetch fresh data immediately. `updateTag` is only available inside Server Functions.\n00066| - Use [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) when it is acceptable to serve stale data while revalidation happens in the background, or when revalidating from a [Route Handler](/docs/app/api-reference/file-conventions/route) or other context.\n00067| \n00068| For example, this Server Function adds a post and then purges every cache entry tagged `'my-data'` so the next read reflects the change:\n00069| \n00070| ```tsx filename=\"app/action.ts\" switcher\n00071| 'use server'\n00072| \n00073| import { updateTag } from 'next/cache'\n00074| \n00075| export default async function submit() {\n00076| await addPost()\n00077| updateTag('my-data')\n00078| }\n00079| ```\n00080| \n00081| ```jsx filename=\"app/action.js\" switcher\n00082| 'use server'\n00083| \n00084| import { updateTag } from 'next/cache'\n00085| \n00086| export default async function submit() {\n00087| await addPost()\n00088| updateTag('my-data')\n00089| }\n00090| ```\n00091| \n00092| ## Good to know\n00093| \n00094| - **Idempotent Tags**: Applying the same tag multiple times has no additional effect.\n00095| - **Multiple Tags**: You can assign multiple tags to a single cache entry by passing multiple string values to `cacheTag`.\n00096| \n00097| ```tsx\n00098| cacheTag('tag-one', 'tag-two')\n00099| ```\n00100| \n00101| - **Limits**: A single `cacheTag()` call accepts up to 128 tags, each with a maximum length of 256 characters. Tags longer than 256 characters are skipped, and any tags past the 128th in one call are dropped. Both cases log a console warning.\n00102| \n00103| ## Examples\n00104| \n00105| ### Tagging components or functions\n00106| \n00107| Tag your cached data by calling `cacheTag` within a cached function or component:\n00108| \n00109| ```tsx filename=\"app/components/bookings.tsx\" switcher\n00110| import { cacheTag } from 'next/cache'\n00111| \n00112| interface BookingsProps {\n00113| type: string\n00114| }\n00115| \n00116| export async function Bookings({ type = 'haircut' }: BookingsProps) {\n00117| 'use cache'\n00118| cacheTag('bookings-data')\n00119| \n00120| async function getBookingsData() {\n00121| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00122| return data\n00123| }\n00124| \n00125| return //...\n00126| }\n00127| ```\n00128| \n00129| ```jsx filename=\"app/components/bookings.js\" switcher\n00130| import { cacheTag } from 'next/cache'\n00131| \n00132| export async function Bookings({ type = 'haircut' }) {\n00133| 'use cache'\n00134| cacheTag('bookings-data')\n00135| \n00136| async function getBookingsData() {\n00137| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00138| return data\n00139| }\n00140| \n00141| return //...\n00142| }\n00143| ```\n00144| \n00145| ### Creating tags from external data\n00146| \n00147| You can use the data returned from an async function to tag the cache entry.\n00148| \n00149| ```tsx filename=\"app/components/bookings.tsx\" switcher\n00150| import { cacheTag } from 'next/cache'\n00151| \n00152| interface BookingsProps {\n00153| type: string\n00154| }\n00155| \n00156| export async function Bookings({ type = 'haircut' }: BookingsProps) {\n00157| async function getBookingsData() {\n00158| 'use cache'\n00159| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00160| cacheTag('bookings-data', data.id)\n00161| return data\n00162| }\n00163| return //...\n00164| }\n00165| ```\n00166| \n00167| ```jsx filename=\"app/components/bookings.js\" switcher\n00168| import { cacheTag } from 'next/cache'\n00169| \n00170| export async function Bookings({ type = 'haircut' }) {\n00171| async function getBookingsData() {\n00172| 'use cache'\n00173| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00174| cacheTag('bookings-data', data.id)\n00175| return data\n00176| }\n00177| return //...\n00178| }\n00179| ```\n00180| \n00181| ### Invalidating tagged cache\n00182| \n00183| Using [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag), you can invalidate the cache for a specific tag when needed:\n00184| \n00185| ```tsx filename=\"app/actions.ts\" switcher\n00186| 'use server'\n00187| \n00188| import { revalidateTag } from 'next/cache'\n00189| \n00190| export async function updateBookings() {\n00191| await updateBookingData()\n00192| revalidateTag('bookings-data', 'max')\n00193| }\n00194| ```\n00195| \n00196| ```jsx filename=\"app/actions.js\" switcher\n00197| 'use server'\n00198| \n00199| import { revalidateTag } from 'next/cache'\n00200| \n00201| export async function updateBookings() {\n00202| await updateBookingData()\n00203| revalidateTag('bookings-data', 'max')\n00204| }\n00205| ```\n00206| \n\n(End of file - total 206 lines)\n","title":"node_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md","metadata":{"preview":"---\ntitle: cacheTag\ndescription: Learn how to use the cacheTag function to manage cache invalidation in your Next.js application.\nrelated:\n title: Related\n description: View related API references.\n links:\n - app/api-reference/config/next-config-js/cacheComponents\n - app/api-reference/directives/use-cache\n - app/api-reference/functions/revalidateTag\n - app/api-reference/functions/updateTag\n - app/api-reference/functions/cacheLife\n---\n\nThe `cacheTag` function allows you to tag cached data for on-demand invalidation. By associating tags with cache entries, you can selectively purge or revalidate specific cache entries without affecting other cached data.\n\n## Usage\n\nTo use `cacheTag`, enable the [`cacheComponents` flag](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.js` file:\n"},"time":{"start":1781392522995,"end":1781392523000}}}}
+{"type":"tool_use","timestamp":1781392523138,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec344bef7001d4mFyKfx3tmYy8","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec344b081001UDgqI32s2JbBcf","type":"tool","callID":"read_14","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/node_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md"},"output":"\n00001| ---\n00002| title: Caching and Revalidating (Previous Model)\n00003| nav_title: Caching (Previous Model)\n00004| description: Learn how to cache and revalidate data using fetch options, unstable_cache, and route segment configs for projects not using Cache Components.\n00005| ---\n00006| \n00007| > This guide assumes you are **not** using [Cache Components](/docs/app/getting-started/caching) which was introduced in version 16 under the [`cacheComponents` flag](/docs/app/api-reference/config/next-config-js/cacheComponents).\n00008| \n00009| ## Caching `fetch` requests\n00010| \n00011| By default, [`fetch`](/docs/app/api-reference/functions/fetch) requests are not cached. You can cache individual requests by setting the `cache` option to `'force-cache'`.\n00012| \n00013| ```tsx filename=\"app/page.tsx\" switcher\n00014| export default async function Page() {\n00015| const data = await fetch('https://...', { cache: 'force-cache' })\n00016| }\n00017| ```\n00018| \n00019| ```jsx filename=\"app/page.jsx\" switcher\n00020| export default async function Page() {\n00021| const data = await fetch('https://...', { cache: 'force-cache' })\n00022| }\n00023| ```\n00024| \n00025| See the [`fetch` API reference](/docs/app/api-reference/functions/fetch) to learn more.\n00026| \n00027| ### `unstable_cache` for non-`fetch` functions\n00028| \n00029| `unstable_cache` allows you to cache the result of database queries and other async functions that don't use `fetch`. Wrap `unstable_cache` around the function:\n00030| \n00031| ```ts filename=\"app/lib/data.ts\" switcher\n00032| import { unstable_cache } from 'next/cache'\n00033| import { db } from '@/lib/db'\n00034| \n00035| export const getCachedUser = unstable_cache(\n00036| async (id: string) => {\n00037| return db\n00038| .select()\n00039| .from(users)\n00040| .where(eq(users.id, id))\n00041| .then((res) => res[0])\n00042| },\n00043| ['user'], // cache key prefix\n00044| {\n00045| tags: ['user'],\n00046| revalidate: 3600,\n00047| }\n00048| )\n00049| ```\n00050| \n00051| ```js filename=\"app/lib/data.js\" switcher\n00052| import { unstable_cache } from 'next/cache'\n00053| import { db } from '@/lib/db'\n00054| \n00055| export const getCachedUser = unstable_cache(\n00056| async (id) => {\n00057| return db\n00058| .select()\n00059| .from(users)\n00060| .where(eq(users.id, id))\n00061| .then((res) => res[0])\n00062| },\n00063| ['user'], // cache key prefix\n00064| {\n00065| tags: ['user'],\n00066| revalidate: 3600,\n00067| }\n00068| )\n00069| ```\n00070| \n00071| The third argument accepts:\n00072| \n00073| - `tags`: an array of tags for on-demand revalidation with `revalidateTag`.\n00074| - `revalidate`: the number of seconds before the cache is revalidated.\n00075| \n00076| See the [`unstable_cache` API reference](/docs/app/api-reference/functions/unstable_cache) to learn more.\n00077| \n00078| ### Route segment config\n00079| \n00080| You can configure caching behavior at the route level by exporting config options from a [Page](/docs/app/api-reference/file-conventions/page), [Layout](/docs/app/api-reference/file-conventions/layout), or [Route Handler](/docs/app/api-reference/file-conventions/route).\n00081| \n00082| #### `dynamic`\n00083| \n00084| Change the dynamic behavior of a layout or page to fully static or fully dynamic.\n00085| \n00086| ```tsx filename=\"layout.tsx | page.tsx | route.ts\" switcher\n00087| export const dynamic = 'auto'\n00088| // 'auto' | 'force-dynamic' | 'error' | 'force-static'\n00089| ```\n00090| \n00091| ```jsx filename=\"layout.js | page.js | route.js\" switcher\n00092| export const dynamic = 'auto'\n00093| // 'auto' | 'force-dynamic' | 'error' | 'force-static'\n00094| ```\n00095| \n00096| - **`'auto'`** (default): The default option to cache as much as possible without preventing any components from opting into dynamic behavior.\n00097| - **`'force-dynamic'`**: Force [dynamic rendering](/docs/app/glossary#dynamic-rendering), which will result in routes being rendered for each user at request time. This option is equivalent to:\n00098| - Setting the option of every `fetch()` request in a layout or page to `{ cache: 'no-store', next: { revalidate: 0 } }`.\n00099| - Setting the segment config to `export const fetchCache = 'force-no-store'`\n00100| - **`'error'`**: Force prerendering and cache the data of a layout or page by causing an error if any components use Request-time APIs or uncached data. This option is equivalent to:\n00101| - `getStaticProps()` in the `pages` directory.\n00102| - Setting the option of every `fetch()` request in a layout or page to `{ cache: 'force-cache' }`.\n00103| - Setting the segment config to `fetchCache = 'only-cache'`.\n00104| - **`'force-static'`**: Force prerendering and cache the data of a layout or page by forcing [`cookies`](/docs/app/api-reference/functions/cookies), [`headers()`](/docs/app/api-reference/functions/headers) and [`useSearchParams()`](/docs/app/api-reference/functions/use-search-params) to return empty values. It is possible to [`revalidate`](#route-segment-config-revalidate), [`revalidatePath`](/docs/app/api-reference/functions/revalidatePath), or [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag), in pages or layouts rendered with `force-static`.\n00105| \n00106| #### `fetchCache`\n00107| \n00108| \n00109| This is an advanced option that should only be used if you specifically need to override the default behavior.\n00110| \n00111| By default, Next.js **will cache** any `fetch()` requests that are reachable **before** any Request-time APIs are used and **will not cache** `fetch` requests that are discovered **after** Request-time APIs are used.\n00112| \n00113| `fetchCache` allows you to override the default `cache` option of all `fetch` requests in a layout or page.\n00114| \n00115| ```tsx filename=\"layout.tsx | page.tsx | route.ts\" switcher\n00116| export const fetchCache = 'auto'\n00117| // 'auto' | 'default-cache' | 'only-cache'\n00118| // 'force-cache' | 'force-no-store' | 'default-no-store' | 'only-no-store'\n00119| ```\n00120| \n00121| ```jsx filename=\"layout.js | page.js | route.js\" switcher\n00122| export const fetchCache = 'auto'\n00123| // 'auto' | 'default-cache' | 'only-cache'\n00124| // 'force-cache' | 'force-no-store' | 'default-no-store' | 'only-no-store'\n00125| ```\n00126| \n00127| - **`'auto'`** (default): The default option to cache `fetch` requests before Request-time APIs with the `cache` option they provide and not cache `fetch` requests after Request-time APIs.\n00128| - **`'default-cache'`**: Allow any `cache` option to be passed to `fetch` but if no option is provided then set the `cache` option to `'force-cache'`. This means that even `fetch` requests after Request-time APIs are considered static.\n00129| - **`'only-cache'`**: Ensure all `fetch` requests opt into caching by changing the default to `cache: 'force-cache'` if no option is provided and causing an error if any `fetch` requests use `cache: 'no-store'`.\n00130| - **`'force-cache'`**: Ensure all `fetch` requests opt into caching by setting the `cache` option of all `fetch` requests to `'force-cache'`.\n00131| - **`'default-no-store'`**: Allow any `cache` option to be passed to `fetch` but if no option is provided then set the `cache` option to `'no-store'`. This means that even `fetch` requests before Request-time APIs are considered dynamic.\n00132| - **`'only-no-store'`**: Ensure all `fetch` requests opt out of caching by changing the default to `cache: 'no-store'` if no option is provided and causing an error if any `fetch` requests use `cache: 'force-cache'`\n00133| - **`'force-no-store'`**: Ensure all `fetch` requests opt out of caching by setting the `cache` option of all `fetch` requests to `'no-store'`. This forces all `fetch` requests to be re-fetched every request even if they provide a `'force-cache'` option.\n00134| \n00135| ##### Cross-route segment behavior\n00136| \n00137| - Any options set across each layout and page of a single route need to be compatible with each other.\n00138| - If both the `'only-cache'` and `'force-cache'` are provided, then `'force-cache'` wins. If both `'only-no-store'` and `'force-no-store'` are provided, then `'force-no-store'` wins. The force option changes the behavior across the route so a single segment with `'force-*'` would prevent any errors caused by `'only-*'`.\n00139| - The intention of the `'only-*'` and `'force-*'` options is to guarantee the whole route is either fully static or fully dynamic. This means:\n00140| - A combination of `'only-cache'` and `'only-no-store'` in a single route is not allowed.\n00141| - A combination of `'force-cache'` and `'force-no-store'` in a single route is not allowed.\n00142| - A parent cannot provide `'default-no-store'` if a child provides `'auto'` or `'*-cache'` since that could make the same fetch have different behavior.\n00143| - It is generally recommended to leave shared parent layouts as `'auto'` and customize the options where child segments diverge.\n00144| \n00145| \n00146| \n00147| ## Time-based revalidation\n00148| \n00149| Use the `next.revalidate` option on `fetch` to revalidate data after a specified number of seconds:\n00150| \n00151| ```tsx filename=\"app/page.tsx\" switcher\n00152| export default async function Page() {\n00153| const data = await fetch('https://...', { next: { revalidate: 3600 } })\n00154| }\n00155| ```\n00156| \n00157| ```jsx filename=\"app/page.jsx\" switcher\n00158| export default async function Page() {\n00159| const data = await fetch('https://...', { next: { revalidate: 3600 } })\n00160| }\n00161| ```\n00162| \n00163| For non-`fetch` functions, `unstable_cache` accepts a `revalidate` option in its configuration (see [example above](#unstable_cache-for-non-fetch-functions)).\n00164| \n00165| ### Route segment config `revalidate`\n00166| \n00167| Set the default revalidation time for a layout or page. This option does not override the `revalidate` value set by individual `fetch` requests.\n00168| \n00169| ```tsx filename=\"layout.tsx | page.tsx | route.ts\" switcher\n00170| export const revalidate = false\n00171| // false | 0 | number\n00172| ```\n00173| \n00174| ```jsx filename=\"layout.js | page.js | route.js\" switcher\n00175| export const revalidate = false\n00176| // false | 0 | number\n00177| ```\n00178| \n00179| - **`false`** (default): The default heuristic to cache any `fetch` requests that set their `cache` option to `'force-cache'` or are discovered before a Request-time API is used. Semantically equivalent to `revalidate: Infinity` which effectively means the resource should be cached indefinitely. It is still possible for individual `fetch` requests to use `cache: 'no-store'` or `revalidate: 0` to avoid being cached and make the route dynamically rendered. Or set `revalidate` to a positive number lower than the route default to increase the revalidation frequency of a route.\n00180| - **`0`**: Ensure a layout or page is always dynamically rendered even if no Request-time APIs or uncached data fetches are discovered. This option changes the default of `fetch` requests that do not set a `cache` option to `'no-store'` but leaves `fetch` requests that opt into `'force-cache'` or use a positive `revalidate` as is.\n00181| - **`number`**: (in seconds) Set the default revalidation frequency of a layout or page to `n` seconds.\n00182| \n00183| > **Good to know**:\n00184| >\n00185| > - The revalidate value needs to be statically analyzable. For example `revalidate = 600` is valid, but `revalidate = 60 * 10` is not.\n00186| > - The revalidate value is not available when using the deprecated `runtime = 'edge'`.\n00187| > - In Development, Pages are _always_ rendered on-demand and are never cached. This allows you to see changes immediately without waiting for a revalidation period to pass.\n00188| \n00189| #### Revalidation frequency\n00190| \n00191| - The lowest `revalidate` across each layout and page of a single route will determine the revalidation frequency of the _entire_ route. This ensures that child pages are revalidated as frequently as their parent layouts.\n00192| - Individual `fetch` requests can set a lower `revalidate` than the route's default `revalidate` to increase the revalidation frequency of the entire route. This allows you to dynamically opt-in to more frequent revalidation for certain routes based on some criteria.\n00193| \n00194| ## On-demand revalidation\n00195| \n00196| To revalidate cached data after an event, use [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) or [`revalidatePath`](/docs/app/api-reference/functions/revalidatePath) in a [Server Action](/docs/app/getting-started/mutating-data) or [Route Handler](/docs/app/api-reference/file-conventions/route).\n00197| \n00198| ### Tagging cached data\n00199| \n00200| Tag `fetch` requests with `next.tags` to enable on-demand cache invalidation:\n00201| \n00202| ```tsx filename=\"app/lib/data.ts\" switcher\n00203| export async function getUserById(id: string) {\n00204| const data = await fetch(`https://...`, {\n00205| next: { tags: ['user'] },\n00206| })\n00207| }\n00208| ```\n00209| \n00210| ```jsx filename=\"app/lib/data.js\" switcher\n00211| export async function getUserById(id) {\n00212| const data = await fetch(`https://...`, {\n00213| next: { tags: ['user'] },\n00214| })\n00215| }\n00216| ```\n00217| \n00218| For non-`fetch` functions, `unstable_cache` also accepts a `tags` option (see [example above](#unstable_cache-for-non-fetch-functions)).\n00219| \n00220| ### `revalidateTag`\n00221| \n00222| Invalidate cached data by tag using [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag):\n00223| \n00224| ```tsx filename=\"app/lib/actions.ts\" switcher\n00225| import { revalidateTag } from 'next/cache'\n00226| \n00227| export async function updateUser(id: string) {\n00228| // Mutate data\n00229| revalidateTag('user', 'max')\n00230| }\n00231| ```\n00232| \n00233| ```jsx filename=\"app/lib/actions.js\" switcher\n00234| import { revalidateTag } from 'next/cache'\n00235| \n00236| export async function updateUser(id) {\n00237| // Mutate data\n00238| revalidateTag('user', 'max')\n00239| }\n00240| ```\n00241| \n00242| ### `revalidatePath`\n00243| \n00244| Invalidate all cached data for a specific route path using [`revalidatePath`](/docs/app/api-reference/functions/revalidatePath):\n00245| \n00246| ```tsx filename=\"app/lib/actions.ts\" switcher\n00247| import { revalidatePath } from 'next/cache'\n00248| \n00249| export async function updateUser(id: string) {\n00250| // Mutate data\n00251| revalidatePath('/profile')\n00252| }\n00253| ```\n00254| \n00255| ```jsx filename=\"app/lib/actions.js\" switcher\n00256| import { revalidatePath } from 'next/cache'\n00257| \n00258| export async function updateUser(id) {\n00259| // Mutate data\n00260| revalidatePath('/profile')\n00261| }\n00262| ```\n00263| \n00264| ## Deduplicating requests\n00265| \n00266| If you are not using `fetch` (which is [automatically memoized](/docs/app/api-reference/functions/fetch#memoization)), and instead using an ORM or database directly, you can wrap your data access with the [React `cache`](https://react.dev/reference/react/cache) function to deduplicate requests within a single render pass:\n00267| \n00268| ```tsx filename=\"app/lib/data.ts\" switcher\n00269| import { cache } from 'react'\n00270| import { db, posts, eq } from '@/lib/db'\n00271| \n00272| export const getPost = cache(async (id: string) => {\n00273| const post = await db.query.posts.findFirst({\n00274| where: eq(posts.id, parseInt(id)),\n00275| })\n00276| })\n00277| ```\n00278| \n00279| ```jsx filename=\"app/lib/data.js\" switcher\n00280| import { cache } from 'react'\n00281| import { db, posts, eq } from '@/lib/db'\n00282| \n00283| export const getPost = cache(async (id) => {\n00284| const post = await db.query.posts.findFirst({\n00285| where: eq(posts.id, parseInt(id)),\n00286| })\n00287| })\n00288| ```\n00289| \n00290| ## Preloading data\n00291| \n00292| You can preload data by creating a utility function that you eagerly call above blocking requests. This lets you initiate data fetching early, so the data is already available by the time the component renders.\n00293| \n00294| Combine the [`server-only` package](https://www.npmjs.com/package/server-only) with React's [`cache`](https://react.dev/reference/react/cache) to create a reusable preload utility:\n00295| \n00296| ```ts filename=\"utils/get-item.ts\" switcher\n00297| import { cache } from 'react'\n00298| import 'server-only'\n00299| \n00300| export const getItem = cache(async (id: string) => {\n00301| // ...\n00302| })\n00303| \n00304| export const preload = (id: string) => {\n00305| void getItem(id)\n00306| }\n00307| ```\n00308| \n00309| ```js filename=\"utils/get-item.js\" switcher\n00310| import { cache } from 'react'\n00311| import 'server-only'\n00312| \n00313| export const getItem = cache(async (id) => {\n00314| // ...\n00315| })\n00316| \n00317| export const preload = (id) => {\n00318| void getItem(id)\n00319| }\n00320| ```\n00321| \n00322| Then call `preload()` before any blocking work so the data starts loading immediately:\n00323| \n00324| ```tsx filename=\"app/item/[id]/page.tsx\" switcher\n00325| import { getItem, preload, checkIsAvailable } from '@/lib/data'\n00326| \n00327| export default async function Page({\n00328| params,\n00329| }: {\n00330| params: Promise<{ id: string }>\n00331| }) {\n00332| const { id } = await params\n00333| // Start loading item data\n00334| preload(id)\n00335| // Perform another asynchronous task\n00336| const isAvailable = await checkIsAvailable()\n00337| \n00338| return isAvailable ? : null\n00339| }\n00340| \n00341| async function Item({ id }: { id: string }) {\n00342| const result = await getItem(id)\n00343| // ...\n00344| }\n00345| ```\n00346| \n00347| ```jsx filename=\"app/item/[id]/page.js\" switcher\n00348| import { getItem, preload, checkIsAvailable } from '@/lib/data'\n00349| \n00350| export default async function Page({ params }) {\n00351| const { id } = await params\n00352| // Start loading item data\n00353| preload(id)\n00354| // Perform another asynchronous task\n00355| const isAvailable = await checkIsAvailable()\n00356| \n00357| return isAvailable ? : null\n00358| }\n00359| \n00360| async function Item({ id }) {\n00361| const result = await getItem(id)\n00362| // ...\n00363| }\n00364| ```\n00365| \n\n(End of file - total 365 lines)\n","title":"node_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md","metadata":{"preview":"---\ntitle: Caching and Revalidating (Previous Model)\nnav_title: Caching (Previous Model)\ndescription: Learn how to cache and revalidate data using fetch options, unstable_cache, and route segment configs for projects not using Cache Components.\n---\n\n> This guide assumes you are **not** using [Cache Components](/docs/app/getting-started/caching) which was introduced in version 16 under the [`cacheComponents` flag](/docs/app/api-reference/config/next-config-js/cacheComponents).\n\n## Caching `fetch` requests\n\nBy default, [`fetch`](/docs/app/api-reference/functions/fetch) requests are not cached. You can cache individual requests by setting the `cache` option to `'force-cache'`.\n\n```tsx filename=\"app/page.tsx\" switcher\nexport default async function Page() {\n const data = await fetch('https://...', { cache: 'force-cache' })\n}\n```\n\n```jsx filename=\"app/page.jsx\" switcher\nexport default async function Page() {"},"time":{"start":1781392523132,"end":1781392523137}}}}
+{"type":"step_finish","timestamp":1781392523145,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec344bf82001Z0bkCRaSb5NS8B","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec344b081001UDgqI32s2JbBcf","type":"step-finish","reason":"tool-calls","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012","cost":0.00327508,"tokens":{"input":1020,"output":85,"reasoning":0,"cache":{"read":12288,"write":0}}}}
+{"type":"step_start","timestamp":1781392525438,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec344c87a001Y61u9SFf5NLuAl","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec344bf90001lTvGjUoDLuh2bZ","type":"step-start","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012"}}
+{"type":"tool_use","timestamp":1781392532400,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec344e004001WnTtGoiGgHAYHd","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec344bf90001lTvGjUoDLuh2bZ","type":"tool","callID":"bash_15","tool":"bash","state":{"status":"completed","input":{"command":"find node_modules/next/dist/docs -type f -name \"revalidateTag.md\" -o -name \"updateTag.md\" -o -name \"use-cache.md\" 2>/dev/null | head -20","description":"Find revalidateTag and use-cache docs"},"output":"node_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/updateTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache.md\n","title":"Find revalidateTag and use-cache docs","metadata":{"output":"node_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/updateTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache.md\n","exit":0,"description":"Find revalidateTag and use-cache docs"},"time":{"start":1781392532392,"end":1781392532396}}}}
+{"type":"step_finish","timestamp":1781392532403,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec344e3ad001YbKXETgKrep5Zp","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec344bf90001lTvGjUoDLuh2bZ","type":"step-finish","reason":"tool-calls","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012","cost":0.01078191,"tokens":{"input":7361,"output":425,"reasoning":0,"cache":{"read":13056,"write":0}}}}
+{"type":"step_start","timestamp":1781392534297,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec344eb16001cbrN5bQdyyfQQo","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec344e3ba001wSxQa7jb952GvG","type":"step-start","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012"}}
+{"type":"tool_use","timestamp":1781392535357,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec344eb18001qsaBPUPXqiJI57","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec344e3ba001wSxQa7jb952GvG","type":"tool","callID":"read_16","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md"},"output":"\n00001| ---\n00002| title: revalidateTag\n00003| description: API Reference for the revalidateTag function.\n00004| ---\n00005| \n00006| `revalidateTag` allows you to invalidate cached data on-demand for a specific cache tag.\n00007| \n00008| This function is ideal for content where a slight delay in updates is acceptable, such as blog posts, product catalogs, or documentation. Users receive stale content while fresh data loads in the background.\n00009| \n00010| ## Usage\n00011| \n00012| `revalidateTag` can be called in Server Functions and Route Handlers.\n00013| \n00014| `revalidateTag` cannot be called in Client Components or Proxy, as it only works in server environments.\n00015| \n00016| ### Revalidation Behavior\n00017| \n00018| The revalidation behavior depends on whether you provide the second argument:\n00019| \n00020| - **With `profile=\"max\"` (recommended)**: The tag entry is marked as stale, and the next time a resource with that tag is visited, it will use stale-while-revalidate semantics. This means the stale content is served while fresh content is fetched in the background.\n00021| - **With a custom cache life profile**: For advanced usage, you can specify any cache life profile that your application has defined, allowing for custom revalidation behaviors tailored to your specific caching requirements.\n00022| - **Without the second argument (deprecated)**: The tag entry is expired immediately, and the next request to that resource will be a blocking revalidate/cache miss. This behavior is now deprecated, and you should either use `profile=\"max\"` or migrate to [`updateTag`](/docs/app/api-reference/functions/updateTag).\n00023| \n00024| > **Good to know**: When using `profile=\"max\"`, `revalidateTag` marks tagged data as stale, but fresh data is only fetched when pages using that tag are next visited. This means calling `revalidateTag` will not immediately trigger many revalidations at once. The invalidation only happens when any page using that tag is next visited.\n00025| \n00026| ## Parameters\n00027| \n00028| ```ts\n00029| revalidateTag(tag: string, profile: string | { expire?: number }): void;\n00030| ```\n00031| \n00032| - `tag`: A string representing the cache tag associated with the data you want to revalidate. Must not exceed 256 characters. This value is case-sensitive.\n00033| - `profile`: A string that specifies the revalidation behavior. The recommended value is `\"max\"` which provides stale-while-revalidate semantics, or any of the other default or custom profiles defined in [`cacheLife`](/docs/app/api-reference/config/next-config-js/cacheLife). Alternatively, you can pass an object with an `expire` property for custom expiration behavior.\n00034| \n00035| Tags must first be assigned to cached data. You can do this in two ways:\n00036| \n00037| - Using the [`next.tags`](/docs/app/api-reference/functions/fetch) option with `fetch` for caching external API requests:\n00038| \n00039| ```tsx\n00040| fetch(url, { next: { tags: ['posts'] } })\n00041| ```\n00042| \n00043| - Using [`cacheTag`](/docs/app/api-reference/functions/cacheTag) inside cached functions or components with the `'use cache'` directive:\n00044| \n00045| ```tsx\n00046| import { cacheTag } from 'next/cache'\n00047| \n00048| async function getData() {\n00049| 'use cache'\n00050| cacheTag('posts')\n00051| // ...\n00052| }\n00053| ```\n00054| \n00055| > **Good to know**: The single-argument form `revalidateTag(tag)` is deprecated. It currently works if TypeScript errors are suppressed, but this behavior may be removed in a future version. Update to the two-argument signature.\n00056| \n00057| ## Returns\n00058| \n00059| `revalidateTag` does not return a value.\n00060| \n00061| ## Relationship with `revalidatePath`\n00062| \n00063| `revalidateTag` invalidates data with specific tags across all pages that use those tags, while [`revalidatePath`](/docs/app/api-reference/functions/revalidatePath) invalidates specific page or layout paths.\n00064| \n00065| > **Good to know**: These functions serve different purposes and may need to be used together for comprehensive data consistency. For detailed examples and considerations, see [relationship with revalidateTag and updateTag](/docs/app/api-reference/functions/revalidatePath#relationship-with-revalidatetag-and-updatetag) for more information.\n00066| \n00067| ## Examples\n00068| \n00069| The following examples demonstrate how to use `revalidateTag` in different contexts. In both cases, we're using `profile=\"max\"` to mark data as stale and use stale-while-revalidate semantics, which is the recommended approach for most use cases.\n00070| \n00071| ### Server Action\n00072| \n00073| ```ts filename=\"app/actions.ts\" switcher\n00074| 'use server'\n00075| \n00076| import { revalidateTag } from 'next/cache'\n00077| \n00078| export default async function submit() {\n00079| await addPost()\n00080| revalidateTag('posts', 'max')\n00081| }\n00082| ```\n00083| \n00084| ```js filename=\"app/actions.js\" switcher\n00085| 'use server'\n00086| \n00087| import { revalidateTag } from 'next/cache'\n00088| \n00089| export default async function submit() {\n00090| await addPost()\n00091| revalidateTag('posts', 'max')\n00092| }\n00093| ```\n00094| \n00095| ### Route Handler\n00096| \n00097| ```ts filename=\"app/api/revalidate/route.ts\" switcher\n00098| import type { NextRequest } from 'next/server'\n00099| import { revalidateTag } from 'next/cache'\n00100| \n00101| export async function GET(request: NextRequest) {\n00102| const tag = request.nextUrl.searchParams.get('tag')\n00103| \n00104| if (tag) {\n00105| revalidateTag(tag, 'max')\n00106| return Response.json({ revalidated: true, now: Date.now() })\n00107| }\n00108| \n00109| return Response.json({\n00110| revalidated: false,\n00111| now: Date.now(),\n00112| message: 'Missing tag to revalidate',\n00113| })\n00114| }\n00115| ```\n00116| \n00117| ```js filename=\"app/api/revalidate/route.js\" switcher\n00118| import { revalidateTag } from 'next/cache'\n00119| \n00120| export async function GET(request) {\n00121| const tag = request.nextUrl.searchParams.get('tag')\n00122| \n00123| if (tag) {\n00124| revalidateTag(tag, 'max')\n00125| return Response.json({ revalidated: true, now: Date.now() })\n00126| }\n00127| \n00128| return Response.json({\n00129| revalidated: false,\n00130| now: Date.now(),\n00131| message: 'Missing tag to revalidate',\n00132| })\n00133| }\n00134| ```\n00135| \n00136| > **Good to know**: For webhooks or third-party services that need immediate expiration, you can pass `{ expire: 0 }` as the second argument: `revalidateTag(tag, { expire: 0 })`. This pattern is necessary when external systems call your Route Handlers and require data to expire immediately. For all other cases, it's recommended to use [`updateTag`](/docs/app/api-reference/functions/updateTag) in Server Actions for immediate updates instead.\n00137| \n\n(End of file - total 137 lines)\n","title":"node_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md","metadata":{"preview":"---\ntitle: revalidateTag\ndescription: API Reference for the revalidateTag function.\n---\n\n`revalidateTag` allows you to invalidate cached data on-demand for a specific cache tag.\n\nThis function is ideal for content where a slight delay in updates is acceptable, such as blog posts, product catalogs, or documentation. Users receive stale content while fresh data loads in the background.\n\n## Usage\n\n`revalidateTag` can be called in Server Functions and Route Handlers.\n\n`revalidateTag` cannot be called in Client Components or Proxy, as it only works in server environments.\n\n### Revalidation Behavior\n\nThe revalidation behavior depends on whether you provide the second argument:\n\n- **With `profile=\"max\"` (recommended)**: The tag entry is marked as stale, and the next time a resource with that tag is visited, it will use stale-while-revalidate semantics. This means the stale content is served while fresh content is fetched in the background."},"time":{"start":1781392535349,"end":1781392535354}}}}
+{"type":"tool_use","timestamp":1781392535932,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec344ef38001pON2KZebO318l0","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec344e3ba001wSxQa7jb952GvG","type":"tool","callID":"read_17","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/updateTag.md"},"output":"\n00001| ---\n00002| title: updateTag\n00003| description: API Reference for the updateTag function.\n00004| ---\n00005| \n00006| `updateTag` allows you to update cached data on-demand for a specific cache tag from within [Server Actions](/docs/app/getting-started/mutating-data).\n00007| \n00008| This function is designed for **read-your-own-writes** scenarios, where a user makes a change (like creating a post), and the UI immediately shows the change, rather than stale data.\n00009| \n00010| ## Usage\n00011| \n00012| `updateTag` can **only** be called from within [Server Actions](/docs/app/getting-started/mutating-data). It cannot be used in Route Handlers, Client Components, or any other context.\n00013| \n00014| If you need to invalidate cache tags in Route Handlers or other contexts, use [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) instead.\n00015| \n00016| > **Good to know**: `updateTag` immediately expires the cached data for the specified tag. The next request will wait to fetch fresh data rather than serving stale content from the cache, ensuring users see their changes immediately.\n00017| \n00018| ## Parameters\n00019| \n00020| ```tsx\n00021| updateTag(tag: string): void;\n00022| ```\n00023| \n00024| - `tag`: A string representing the cache tag associated with the data you want to update. Must not exceed 256 characters. This value is case-sensitive.\n00025| \n00026| Tags must first be assigned to cached data. You can do this in two ways:\n00027| \n00028| - Using the [`next.tags`](/docs/app/api-reference/functions/fetch) option with `fetch` for caching external API requests:\n00029| \n00030| ```tsx\n00031| fetch(url, { next: { tags: ['posts'] } })\n00032| ```\n00033| \n00034| - Using [`cacheTag`](/docs/app/api-reference/functions/cacheTag) inside cached functions or components with the `'use cache'` directive:\n00035| \n00036| ```tsx\n00037| import { cacheTag } from 'next/cache'\n00038| \n00039| async function getData() {\n00040| 'use cache'\n00041| cacheTag('posts')\n00042| // ...\n00043| }\n00044| ```\n00045| \n00046| ## Returns\n00047| \n00048| `updateTag` does not return a value.\n00049| \n00050| ## Differences from revalidateTag\n00051| \n00052| While both `updateTag` and `revalidateTag` invalidate cached data, they serve different purposes:\n00053| \n00054| - **`updateTag`**:\n00055| - Can only be used in Server Actions\n00056| - Next request waits for fresh data (no stale content served)\n00057| - Designed for read-your-own-writes scenarios\n00058| \n00059| - **`revalidateTag`**:\n00060| - Can be used in Server Actions and Route Handlers\n00061| - With `profile=\"max\"` (recommended): Serves cached data while fetching fresh data in the background (stale-while-revalidate)\n00062| - With custom profile: Can be configured to any cache life profile for advanced usage\n00063| - Without profile: legacy behavior which is equivalent to `updateTag`\n00064| \n00065| ## Examples\n00066| \n00067| ### Server Action with Read-Your-Own-Writes\n00068| \n00069| ```ts filename=\"app/actions.ts\" switcher\n00070| 'use server'\n00071| \n00072| import { updateTag } from 'next/cache'\n00073| import { redirect } from 'next/navigation'\n00074| \n00075| export async function createPost(formData: FormData) {\n00076| const title = formData.get('title')\n00077| const content = formData.get('content')\n00078| \n00079| // Create the post in your database\n00080| const post = await db.post.create({\n00081| data: { title, content },\n00082| })\n00083| \n00084| // Invalidate cache tags so the new post is immediately visible\n00085| // 'posts' tag: affects any page that displays a list of posts\n00086| updateTag('posts')\n00087| // 'post-{id}' tag: affects the individual post detail page\n00088| updateTag(`post-${post.id}`)\n00089| \n00090| // Redirect to the new post - user will see fresh data, not cached\n00091| redirect(`/posts/${post.id}`)\n00092| }\n00093| ```\n00094| \n00095| ```js filename=\"app/actions.js\" switcher\n00096| 'use server'\n00097| \n00098| import { updateTag } from 'next/cache'\n00099| import { redirect } from 'next/navigation'\n00100| \n00101| export async function createPost(formData) {\n00102| const title = formData.get('title')\n00103| const content = formData.get('content')\n00104| \n00105| // Create the post in your database\n00106| const post = await db.post.create({\n00107| data: { title, content },\n00108| })\n00109| \n00110| // Invalidate cache tags so the new post is immediately visible\n00111| // 'posts' tag: affects any page that displays a list of posts\n00112| updateTag('posts')\n00113| // 'post-{id}' tag: affects the individual post detail page\n00114| updateTag(`post-${post.id}`)\n00115| \n00116| // Redirect to the new post - user will see fresh data, not cached\n00117| redirect(`/posts/${post.id}`)\n00118| }\n00119| ```\n00120| \n00121| ### Error when used outside Server Actions\n00122| \n00123| ```ts filename=\"app/api/posts/route.ts\" switcher\n00124| import { updateTag } from 'next/cache'\n00125| \n00126| export async function POST() {\n00127| // This will throw an error\n00128| updateTag('posts')\n00129| // Error: updateTag can only be called from within a Server Action\n00130| \n00131| // Use revalidateTag instead in Route Handlers\n00132| revalidateTag('posts', 'max')\n00133| }\n00134| ```\n00135| \n00136| ## When to use updateTag\n00137| \n00138| Use `updateTag` when:\n00139| \n00140| - You're in a Server Action\n00141| - You need immediate cache invalidation for read-your-own-writes\n00142| - You want to ensure the next request sees updated data\n00143| \n00144| Use `revalidateTag` instead when:\n00145| \n00146| - You're in a Route Handler or other non-action context\n00147| - You want stale-while-revalidate semantics\n00148| - You're building a webhook or API endpoint for cache invalidation\n00149| \n00150| ## Related\n00151| \n00152| - [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) - For invalidating tags in Route Handlers\n00153| - [`revalidatePath`](/docs/app/api-reference/functions/revalidatePath) - For invalidating specific paths\n00154| \n\n(End of file - total 154 lines)\n","title":"node_modules/next/dist/docs/01-app/03-api-reference/04-functions/updateTag.md","metadata":{"preview":"---\ntitle: updateTag\ndescription: API Reference for the updateTag function.\n---\n\n`updateTag` allows you to update cached data on-demand for a specific cache tag from within [Server Actions](/docs/app/getting-started/mutating-data).\n\nThis function is designed for **read-your-own-writes** scenarios, where a user makes a change (like creating a post), and the UI immediately shows the change, rather than stale data.\n\n## Usage\n\n`updateTag` can **only** be called from within [Server Actions](/docs/app/getting-started/mutating-data). It cannot be used in Route Handlers, Client Components, or any other context.\n\nIf you need to invalidate cache tags in Route Handlers or other contexts, use [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) instead.\n\n> **Good to know**: `updateTag` immediately expires the cached data for the specified tag. The next request will wait to fetch fresh data rather than serving stale content from the cache, ensuring users see their changes immediately.\n\n## Parameters\n\n```tsx"},"time":{"start":1781392535928,"end":1781392535932}}}}
+{"type":"tool_use","timestamp":1781392535988,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec344f17a001XyhvKihJp5kESx","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec344e3ba001wSxQa7jb952GvG","type":"tool","callID":"read_18","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/node_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache.md"},"output":"\n00001| ---\n00002| title: use cache\n00003| description: Learn how to use the \"use cache\" directive to cache data in your Next.js application.\n00004| related:\n00005| title: Related\n00006| description: View related API references.\n00007| links:\n00008| - app/api-reference/directives/use-cache-private\n00009| - app/api-reference/config/next-config-js/cacheComponents\n00010| - app/api-reference/config/next-config-js/cacheLife\n00011| - app/api-reference/config/next-config-js/cacheHandlers\n00012| - app/api-reference/functions/cacheTag\n00013| - app/api-reference/functions/cacheLife\n00014| - app/api-reference/functions/revalidateTag\n00015| ---\n00016| \n00017| The `use cache` directive allows you to mark a route, React component, or a function as cacheable. It can be used at the top of a file to indicate that all exports in the file should be cached, or inline at the top of a function or component to cache the return value. Functions and components that use `use cache` must be async.\n00018| \n00019| > **Good to know:**\n00020| >\n00021| > - To use cookies or headers, read them outside cached scopes and pass values as arguments. This is the preferred pattern.\n00022| > - If the in-memory cache isn't sufficient for runtime data, [`'use cache: remote'`](/docs/app/api-reference/directives/use-cache-remote) allows platforms to provide a dedicated cache handler, though it requires a network roundtrip to check the cache and typically incurs platform fees.\n00023| > - For compliance requirements or when you can't refactor to pass runtime data as arguments to a `use cache` scope, see [`'use cache: private'`](/docs/app/api-reference/directives/use-cache-private).\n00024| \n00025| ## Usage\n00026| \n00027| `use cache` is a Cache Components feature. To enable it, add the [`cacheComponents`](/docs/app/api-reference/config/next-config-js/cacheComponents) option to your `next.config.ts` file:\n00028| \n00029| ```ts filename=\"next.config.ts\" switcher\n00030| import type { NextConfig } from 'next'\n00031| \n00032| const nextConfig: NextConfig = {\n00033| cacheComponents: true,\n00034| }\n00035| \n00036| export default nextConfig\n00037| ```\n00038| \n00039| ```js filename=\"next.config.js\" switcher\n00040| /** @type {import('next').NextConfig} */\n00041| const nextConfig = {\n00042| cacheComponents: true,\n00043| }\n00044| \n00045| module.exports = nextConfig\n00046| ```\n00047| \n00048| Then, add `use cache` at the file, component, or function level. All functions and components using `use cache` must be async. When used at file level, every exported function becomes a cached function and must also be async:\n00049| \n00050| ```tsx\n00051| // File level\n00052| 'use cache'\n00053| \n00054| export default async function Page() {\n00055| // ...\n00056| }\n00057| \n00058| // Component level\n00059| export async function MyComponent() {\n00060| 'use cache'\n00061| return <>>\n00062| }\n00063| \n00064| // Function level\n00065| export async function getData() {\n00066| 'use cache'\n00067| const data = await fetch('/api/data')\n00068| return data\n00069| }\n00070| ```\n00071| \n00072| ## How `use cache` works\n00073| \n00074| ### Cache keys\n00075| \n00076| A cache entry's key is generated using a serialized version of its inputs, which includes:\n00077| \n00078| 1. **Build ID** - Unique per build, changing this invalidates all cache entries. If [`deploymentId`](/docs/app/api-reference/config/next-config-js/deploymentId) is configured, it overrides the build ID for cache key purposes.\n00079| 2. **Function ID** - A secure hash of the function's location and signature in the codebase\n00080| 3. **Serializable arguments** - Props (for components) or function arguments\n00081| 4. **HMR refresh hash** (development only) - Invalidates cache on hot module replacement\n00082| \n00083| When a cached function references variables from outer scopes, those variables are automatically captured and bound as arguments, making them part of the cache key.\n00084| \n00085| ```tsx filename=\"lib/data.ts\"\n00086| async function Component({ userId }: { userId: string }) {\n00087| const getData = async (filter: string) => {\n00088| 'use cache'\n00089| // Cache key includes both userId (from closure) and filter (argument)\n00090| return fetch(`/api/users/${userId}/data?filter=${filter}`)\n00091| }\n00092| \n00093| return getData('active')\n00094| }\n00095| ```\n00096| \n00097| In the snippet above, `userId` is captured from the outer scope and `filter` is passed as an argument, so both become part of the `getData` function's cache key. This means different user and filter combinations will have separate cache entries.\n00098| \n00099| > **Good to know:** When a cached function reads [root parameters](/docs/app/api-reference/functions/next-root-params), only the ones it actually reads become part of its cache key.\n00100| \n00101| ## Serialization\n00102| \n00103| Arguments to cached functions and their return values must be serializable.\n00104| \n00105| For a complete reference, see:\n00106| \n00107| - [Serializable arguments](https://react.dev/reference/rsc/use-server#serializable-parameters-and-return-values) - Uses **React Server Components** serialization\n00108| - [Serializable return types](https://react.dev/reference/rsc/use-client#serializable-types) - Uses **React Client Components** serialization\n00109| \n00110| > **Good to know:** Arguments and return values use different serialization systems. Server Component serialization (for arguments) is more restrictive than Client Component serialization (for return values). This means you can return JSX elements but cannot accept them as arguments unless using pass-through patterns.\n00111| \n00112| ### Supported types\n00113| \n00114| **Arguments:**\n00115| \n00116| - Primitives: `string`, `number`, `boolean`, `null`, `undefined`\n00117| - Plain objects: `{ key: value }`\n00118| - Arrays: `[1, 2, 3]`\n00119| - Dates, Maps, Sets, TypedArrays, ArrayBuffers\n00120| - React elements (as pass-through only)\n00121| \n00122| **Return values:**\n00123| \n00124| - Same as arguments, plus JSX elements\n00125| \n00126| ### Unsupported types\n00127| \n00128| - Class instances\n00129| - Functions (except as pass-through)\n00130| - Symbols, WeakMaps, WeakSets\n00131| - URL instances\n00132| \n00133| ```tsx filename=\"app/components/user-card.tsx\"\n00134| // Valid - primitives and plain objects\n00135| async function UserCard({\n00136| id,\n00137| config,\n00138| }: {\n00139| id: string\n00140| config: { theme: string }\n00141| }) {\n00142| 'use cache'\n00143| return
{id}
\n00144| }\n00145| \n00146| // Invalid - class instance\n00147| async function UserProfile({ user }: { user: UserClass }) {\n00148| 'use cache'\n00149| // Error: Cannot serialize class instance\n00150| return
{user.name}
\n00151| }\n00152| ```\n00153| \n00154| ### Pass-through (non-serializable arguments)\n00155| \n00156| You can accept non-serializable values **as long as you don't introspect them**. This enables composition patterns with `children` and Server Actions:\n00157| \n00158| ```tsx filename=\"app/components/cached-wrapper.tsx\"\n00159| async function CachedWrapper({ children }: { children: ReactNode }) {\n00160| 'use cache'\n00161| // Don't read or modify children - just pass it through\n00162| return (\n00163|
\n00164| Cached Header\n00165| {children}\n00166|
\n00167| )\n00168| }\n00169| \n00170| // Usage: children can be dynamic\n00171| export default function Page() {\n00172| return (\n00173| \n00174| {/* Not cached, passed through */}\n00175| \n00176| )\n00177| }\n00178| ```\n00179| \n00180| You can also pass Server Actions through cached components:\n00181| \n00182| ```tsx filename=\"app/components/cached-form.tsx\"\n00183| async function CachedForm({ action }: { action: () => Promise }) {\n00184| 'use cache'\n00185| // Don't call action here - just pass it through\n00186| return
{/* ... */}
\n00187| }\n00188| ```\n00189| \n00190| ## Constraints\n00191| \n00192| Cached functions execute in an isolated environment. The following constraints ensure cache behavior remains predictable and secure.\n00193| \n00194| ### Request-time APIs\n00195| \n00196| Cached functions and components **cannot** directly access runtime APIs like `cookies()`, `headers()`, or `searchParams`. Instead, read these values outside the cached scope and pass them as arguments.\n00197| \n00198| ### Runtime caching considerations\n00199| \n00200| While `use cache` is designed primarily to include uncached data in the static shell, it can also cache data at runtime using in-memory LRU (Least Recently Used) storage.\n00201| \n00202| With the default in-memory handler, runtime cache behavior depends on your hosting environment:\n00203| \n00204| | Environment | Runtime Caching Behavior |\n00205| | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n00206| | **Serverless** | Cache entries typically don't persist across requests (each request can be a different instance), or during revalidation. Build-time caching works normally. |\n00207| | **Self-hosted** | Cache entries persist across requests. Control cache size with [`cacheMaxMemorySize`](/docs/app/api-reference/config/next-config-js/incrementalCacheHandlerPath). |\n00208| \n00209| For example, in a serverless environment, a cached function shared by two pages executes on each static shell revalidation, whereas in self-hosted or environments with persistent memory, the cached output is reused if it's still fresh.\n00210| \n00211| If the default in-memory cache isn't enough, consider **[`use cache: remote`](/docs/app/api-reference/directives/use-cache-remote)** which allows platforms to provide a dedicated cache handler (like Redis or KV database). This helps reduce hits against data sources not scaled to your total traffic, though it comes with costs (storage, network latency, platform fees).\n00212| \n00213| > [!NOTE]\n00214| > With the default in-memory handler, serverless instances are ephemeral, so entries may not be reused between requests, unlike with `use cache: remote`. Neither caching directive carries over to a new deploy, because the [cache key](#cache-keys) includes the build (or `deploymentId`) ID.\n00215| >\n00216| > For data that needs to persist across deploys, use [`unstable_cache`](/docs/app/api-reference/functions/unstable_cache) for non-`fetch` functions or the [`fetch`](/docs/app/api-reference/functions/fetch) cache.\n00217| \n00218| Very rarely, for compliance requirements or when you can't refactor your code to pass runtime data as arguments to a `use cache` scope, you might need [`use cache: private`](/docs/app/api-reference/directives/use-cache-private).\n00219| \n00220| ### Draft Mode\n00221| \n00222| When [Draft Mode](/docs/app/guides/draft-mode) is enabled, all cached functions and components re-execute on every request, and results are not saved to the cache. This ensures draft content is always fresh without requiring any changes to your caching code.\n00223| \n00224| You can read `isEnabled` from [`draftMode()`](/docs/app/api-reference/functions/draft-mode) inside a `use cache` scope, however, other runtime APIs like `cookies()` and `headers()` are not allowed, even when Draft Mode is active. See [Passing runtime values to cached functions](/docs/app/getting-started/caching#passing-runtime-values-to-cached-functions) for the recommended pattern.\n00225| \n00226| ```tsx filename=\"app/components/content.tsx\"\n00227| import { draftMode } from 'next/headers'\n00228| \n00229| async function Content() {\n00230| 'use cache'\n00231| \n00232| const { isEnabled } = await draftMode()\n00233| const url = isEnabled\n00234| ? 'https://draft.example.com/content'\n00235| : 'https://production.example.com/content'\n00236| \n00237| const data = await fetch(url)\n00238| return {/* ... */}\n00239| }\n00240| ```\n00241| \n00242| Calling `enable()` or `disable()` inside a caching directive scope will also throw an error. Draft Mode can only be toggled in [Route Handlers](/docs/app/api-reference/file-conventions/route) or [Server Actions](/docs/app/getting-started/mutating-data).\n00243| \n00244| ### React.cache isolation\n00245| \n00246| [`React.cache`](https://react.dev/reference/react/cache) operates in an isolated scope inside `use cache` boundaries. Values stored via `React.cache` outside a `use cache` function are not visible inside it.\n00247| \n00248| This means you cannot use `React.cache` to pass data into a `use cache` scope:\n00249| \n00250| ```tsx\n00251| import { cache } from 'react'\n00252| \n00253| const store = cache(() => ({ current: null as string | null }))\n00254| \n00255| function Parent() {\n00256| const shared = store()\n00257| shared.current = 'value from parent'\n00258| return \n00259| }\n00260| \n00261| async function Child() {\n00262| 'use cache'\n00263| const shared = store()\n00264| // shared.current is null, not 'value from parent'\n00265| // use cache has its own isolated React.cache scope\n00266| return
{shared.current}
\n00267| }\n00268| ```\n00269| \n00270| This isolation ensures cached functions have predictable, self-contained behavior. To pass data into a `use cache` scope, use function arguments instead.\n00271| \n00272| ## `use cache` at runtime\n00273| \n00274| On the **server**, cache entries are stored in-memory and respect the `revalidate` and `expire` times from your `cacheLife` configuration. You can customize the cache storage by configuring [`cacheHandlers`](/docs/app/api-reference/config/next-config-js/cacheHandlers) in your `next.config.js` file.\n00275| \n00276| On the **client**, content from the server cache is stored in the browser's memory for the duration defined by the `stale` time. The client router enforces a **minimum 30-second stale time**, regardless of configuration.\n00277| \n00278| The `x-nextjs-stale-time` response header communicates cache lifetime from server to client, ensuring coordinated behavior.\n00279| \n00280| ## Revalidation\n00281| \n00282| By default, `use cache` uses the `default` profile with these settings:\n00283| \n00284| - **stale**: 5 minutes (client-side)\n00285| - **revalidate**: 15 minutes (server-side)\n00286| - **expire**: Never expires by time\n00287| \n00288| ```tsx filename=\"lib/data.ts\"\n00289| async function getData() {\n00290| 'use cache'\n00291| // Implicitly uses default profile\n00292| return fetch('/api/data')\n00293| }\n00294| ```\n00295| \n00296| ### Customizing cache lifetime\n00297| \n00298| Use the [`cacheLife`](/docs/app/api-reference/functions/cacheLife) function to customize cache duration:\n00299| \n00300| ```tsx filename=\"lib/data.ts\"\n00301| import { cacheLife } from 'next/cache'\n00302| \n00303| async function getData() {\n00304| 'use cache'\n00305| cacheLife('hours') // Use built-in 'hours' profile\n00306| return fetch('/api/data')\n00307| }\n00308| ```\n00309| \n00310| ### On-demand revalidation\n00311| \n00312| Use [`cacheTag`](/docs/app/api-reference/functions/cacheTag), [`updateTag`](/docs/app/api-reference/functions/updateTag), or [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) for on-demand cache invalidation:\n00313| \n00314| ```tsx filename=\"lib/data.ts\"\n00315| import { cacheTag } from 'next/cache'\n00316| \n00317| async function getProducts() {\n00318| 'use cache'\n00319| cacheTag('products')\n00320| return fetch('/api/products')\n00321| }\n00322| ```\n00323| \n00324| ```tsx filename=\"app/actions.ts\"\n00325| 'use server'\n00326| \n00327| import { updateTag } from 'next/cache'\n00328| \n00329| export async function updateProduct() {\n00330| await db.products.update(...)\n00331| updateTag('products') // Invalidates all 'products' caches\n00332| }\n00333| ```\n00334| \n00335| Both `cacheLife` and `cacheTag` integrate across client and server caching layers, meaning you configure your caching semantics in one place and they apply everywhere.\n00336| \n00337| ## Examples\n00338| \n00339| ### Caching an entire route with `use cache`\n00340| \n00341| To prerender an entire route, add `use cache` to the top of **both** the `layout` and `page` files. Each of these segments are treated as separate entry points in your application, and will be cached independently.\n00342| \n00343| ```tsx filename=\"app/layout.tsx\" switcher\n00344| 'use cache'\n00345| \n00346| export default async function Layout({ children }: { children: ReactNode }) {\n00347| return
{children}
\n00348| }\n00349| ```\n00350| \n00351| ```jsx filename=\"app/layout.js\" switcher\n00352| 'use cache'\n00353| \n00354| export default async function Layout({ children }) {\n00355| return
{children}
\n00356| }\n00357| ```\n00358| \n00359| Any components imported and nested in `page` file are part of the cache output associated with the `page`.\n00360| \n00361| ```tsx filename=\"app/page.tsx\" switcher\n00362| 'use cache'\n00363| \n00364| async function Users() {\n00365| const users = await fetch('/api/users')\n00366| // loop through users\n00367| }\n00368| \n00369| export default async function Page() {\n00370| return (\n00371| \n00372| \n00373| \n00374| )\n00375| }\n00376| ```\n00377| \n00378| ```jsx filename=\"app/page.js\" switcher\n00379| 'use cache'\n00380| \n00381| async function Users() {\n00382| const users = await fetch('/api/users')\n00383| // loop through users\n00384| }\n00385| \n00386| export default async function Page() {\n00387| return (\n00388| \n00389| \n00390| \n00391| )\n00392| }\n00393| ```\n00394| \n00395| > **Good to know**:\n00396| >\n00397| > - If `use cache` is added only to the `layout` or the `page`, only that route segment and any components imported into it will be cached.\n00398| \n00399| ### Caching a component's output with `use cache`\n00400| \n00401| You can use `use cache` at the component level to cache any fetches or computations performed within that component. The cache entry will be reused as long as the serialized props produce the same value in each instance.\n00402| \n00403| ```tsx filename=\"app/components/bookings.tsx\" highlight={2} switcher\n00404| export async function Bookings({ type = 'haircut' }: BookingsProps) {\n00405| 'use cache'\n00406| async function getBookingsData() {\n00407| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00408| return data\n00409| }\n00410| return //...\n00411| }\n00412| \n00413| interface BookingsProps {\n00414| type: string\n00415| }\n00416| ```\n00417| \n00418| ```jsx filename=\"app/components/bookings.js\" highlight={2} switcher\n00419| export async function Bookings({ type = 'haircut' }) {\n00420| 'use cache'\n00421| async function getBookingsData() {\n00422| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00423| return data\n00424| }\n00425| return //...\n00426| }\n00427| ```\n00428| \n00429| ### Caching function output with `use cache`\n00430| \n00431| Since you can add `use cache` to any asynchronous function, you aren't limited to caching components or routes only. You might want to cache a network request, a database query, or a slow computation.\n00432| \n00433| ```tsx filename=\"app/actions.ts\" highlight={2} switcher\n00434| export async function getData() {\n00435| 'use cache'\n00436| \n00437| const data = await fetch('/api/data')\n00438| return data\n00439| }\n00440| ```\n00441| \n00442| ```jsx filename=\"app/actions.js\" highlight={2} switcher\n00443| export async function getData() {\n00444| 'use cache'\n00445| \n00446| const data = await fetch('/api/data')\n00447| return data\n00448| }\n00449| ```\n00450| \n00451| > **Good to know:** When a cached directive (`use cache`, [`use cache: private`](/docs/app/api-reference/directives/use-cache-private), or [`use cache: remote`](/docs/app/api-reference/directives/use-cache-remote)) is at the top of a file, you can import its exported functions into a Client Component and call them directly; they run on the server and return the result, similar to a [Server Function](/docs/app/glossary#server-function). Prefer calling cached functions on the server and passing results down as props.\n00452| \n00453| ### Interleaving\n00454| \n00455| In React, composition with `children` or slots is a well-known pattern for building flexible components. When using `use cache`, you can continue to compose your UI in this way. Anything included as `children`, or other compositional slots, in the returned JSX will be passed through the cached component without affecting its cache entry.\n00456| \n00457| As long as you don't directly reference any of the JSX slots inside the body of the cacheable function itself, their presence in the returned output won't affect the cache entry.\n00458| \n00459| ```tsx filename=\"app/page.tsx\" switcher\n00460| export default async function Page() {\n00461| const uncachedData = await getData()\n00462| return (\n00463| // Pass compositional slots as props, e.g. header and children\n00464| Home}>\n00465| {/* DynamicComponent is provided as the children slot */}\n00466| \n00467| \n00468| )\n00469| }\n00470| \n00471| async function CacheComponent({\n00472| header, // header: a compositional slot, injected as a prop\n00473| children, // children: another slot for nested composition\n00474| }: {\n00475| header: ReactNode\n00476| children: ReactNode\n00477| }) {\n00478| 'use cache'\n00479| const cachedData = await fetch('/api/cached-data')\n00480| return (\n00481|
\n00514| )\n00515| }\n00516| ```\n00517| \n00518| You can also pass Server Actions through cached components to Client Components without invoking them inside the cacheable function.\n00519| \n00520| ```tsx filename=\"app/page.tsx\" switcher\n00521| import ClientComponent from './ClientComponent'\n00522| \n00523| export default async function Page() {\n00524| const performUpdate = async () => {\n00525| 'use server'\n00526| // Perform some server-side update\n00527| await db.update(...)\n00528| }\n00529| \n00530| return \n00531| }\n00532| \n00533| async function CachedComponent({\n00534| performUpdate,\n00535| }: {\n00536| performUpdate: () => Promise\n00537| }) {\n00538| 'use cache'\n00539| // Do not call performUpdate here\n00540| return \n00541| }\n00542| ```\n00543| \n00544| ```jsx filename=\"app/page.js\" switcher\n00545| import ClientComponent from './ClientComponent'\n00546| \n00547| export default async function Page() {\n00548| const performUpdate = async () => {\n00549| 'use server'\n00550| // Perform some server-side update\n00551| await db.update(...)\n00552| }\n00553| \n00554| return \n00555| }\n00556| \n00557| async function CachedComponent({ performUpdate }) {\n00558| 'use cache'\n00559| // Do not call performUpdate here\n00560| return \n00561| }\n00562| ```\n00563| \n00564| ```tsx filename=\"app/ClientComponent.tsx\" switcher\n00565| 'use client'\n00566| \n00567| export default function ClientComponent({\n00568| action,\n00569| }: {\n00570| action: () => Promise\n00571| }) {\n00572| return \n00573| }\n00574| ```\n00575| \n00576| ```jsx filename=\"app/ClientComponent.js\" switcher\n00577| 'use client'\n00578| \n00579| export default function ClientComponent({ action }) {\n00580| return \n00581| }\n00582| ```\n00583| \n00584| ## Troubleshooting\n00585| \n00586| ### Debugging cache behavior\n00587| \n00588| #### Verbose logging\n00589| \n00590| Set `NEXT_PRIVATE_DEBUG_CACHE=1` for verbose cache logging:\n00591| \n00592| ```bash\n00593| NEXT_PRIVATE_DEBUG_CACHE=1 npm run dev\n00594| # or for production\n00595| NEXT_PRIVATE_DEBUG_CACHE=1 npm run start\n00596| ```\n00597| \n00598| > **Good to know:** This environment variable also logs ISR and other caching mechanisms. See [Verifying correct production behavior](/docs/app/guides/incremental-static-regeneration#verifying-correct-production-behavior) for more details.\n00599| \n00600| #### Console log replays\n00601| \n00602| In development, console logs from cached functions appear with a `Cache` prefix.\n00603| \n00604| ### Build Hangs (Cache Timeout)\n00605| \n00606| If your build hangs, you're accessing Promises that resolve to uncached or runtime data, created outside a `use cache` boundary. The cached function waits for data that can't resolve during the build, causing a timeout after 50 seconds.\n00607| \n00608| When the build timeouts you'll see this error message:\n00609| \n00610| > Error: Filling a cache during prerender timed out, likely because request-specific arguments such as params, searchParams, cookies() or uncached data were used inside \"use cache\".\n00611| \n00612| Common ways this happens: passing such Promises as props, accessing them via closure, or retrieving them from shared storage (Maps).\n00613| \n00614| > **Good to know:** Directly calling `cookies()` or `headers()` inside `use cache` fails immediately with a [different error](/docs/messages/next-request-in-use-cache), not a timeout.\n00615| \n00616| **Passing runtime data Promises as props:**\n00617| \n00618| ```tsx filename=\"app/page.tsx\"\n00619| import { cookies } from 'next/headers'\n00620| import { Suspense } from 'react'\n00621| \n00622| export default function Page() {\n00623| return (\n00624| Loading...
}>\n00625| \n00626| \n00627| )\n00628| }\n00629| \n00630| async function Dynamic() {\n00631| const cookieStore = cookies()\n00632| return // Build hangs\n00633| }\n00634| \n00635| async function Cached({ promise }: { promise: Promise }) {\n00636| 'use cache'\n00637| const data = await promise // Waits for runtime data during build\n00638| return
..
\n00639| }\n00640| ```\n00641| \n00642| Await the `cookies` store in the `Dynamic` component, and pass a cookie value to the `Cached` component.\n00643| \n00644| **Shared deduplication storage:**\n00645| \n00646| ```tsx filename=\"app/page.tsx\"\n00647| // Problem: Map stores dynamic Promises, accessed by cached code\n00648| import { Suspense } from 'react'\n00649| \n00650| const cache = new Map>()\n00651| \n00652| export default function Page() {\n00653| return (\n00654| <>\n00655| Loading...
\n00670| }\n00671| \n00672| async function Cached({ id }: { id: string }) {\n00673| 'use cache'\n00674| return
{await cache.get(id)}
// Build hangs - retrieves dynamic Promise\n00675| }\n00676| ```\n00677| \n00678| Use Next.js's built-in `fetch()` deduplication or use separate Maps for cached and uncached contexts.\n00679| \n00680| ## Platform Support\n00681| \n00682| | Deployment Option | Supported |\n00683| | ------------------------------------------------------------------- | ----------------- |\n00684| | [Node.js server](/docs/app/getting-started/deploying#nodejs-server) | Yes |\n00685| | [Docker container](/docs/app/getting-started/deploying#docker) | Yes |\n00686| | [Static export](/docs/app/getting-started/deploying#static-export) | No |\n00687| | [Adapters](/docs/app/getting-started/deploying#adapters) | Platform-specific |\n00688| \n00689| Learn how to [configure caching](/docs/app/guides/self-hosting#caching-and-isr) when self-hosting Next.js.\n00690| \n00691| ## Version History\n00692| \n00693| | Version | Changes |\n00694| | --------- | ----------------------------------------------------------- |\n00695| | `v16.0.0` | `\"use cache\"` is enabled with the Cache Components feature. |\n00696| | `v15.0.0` | `\"use cache\"` is introduced as an experimental feature. |\n00697| \n\n(End of file - total 697 lines)\n","title":"node_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache.md","metadata":{"preview":"---\ntitle: use cache\ndescription: Learn how to use the \"use cache\" directive to cache data in your Next.js application.\nrelated:\n title: Related\n description: View related API references.\n links:\n - app/api-reference/directives/use-cache-private\n - app/api-reference/config/next-config-js/cacheComponents\n - app/api-reference/config/next-config-js/cacheLife\n - app/api-reference/config/next-config-js/cacheHandlers\n - app/api-reference/functions/cacheTag\n - app/api-reference/functions/cacheLife\n - app/api-reference/functions/revalidateTag\n---\n\nThe `use cache` directive allows you to mark a route, React component, or a function as cacheable. It can be used at the top of a file to indicate that all exports in the file should be cached, or inline at the top of a function or component to cache the return value. Functions and components that use `use cache` must be async.\n\n> **Good to know:**\n>"},"time":{"start":1781392535983,"end":1781392535986}}}}
+{"type":"step_finish","timestamp":1781392535992,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec344f1b4001XPqg0bN7d8BDaX","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec344e3ba001wSxQa7jb952GvG","type":"step-finish","reason":"tool-calls","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012","cost":0.00430714,"tokens":{"input":694,"output":103,"reasoning":0,"cache":{"read":20224,"write":0}}}}
+{"type":"step_start","timestamp":1781392539274,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec344fe840012Ud04hf5FR6NqW","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec344f1c4001kuwAvBLJPYVmIN","type":"step-start","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012"}}
+{"type":"tool_use","timestamp":1781392613075,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec3461754001Y98f9McO9yDEug","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec344f1c4001kuwAvBLJPYVmIN","type":"tool","callID":"todowrite_19","tool":"todowrite","state":{"status":"completed","input":{"todos":[{"content":"Enable Cache Components in next.config.ts","id":"1","priority":"high","status":"pending"},{"content":"Add typed product data access in lib/products.ts with 'use cache' and cacheTag('products')","id":"2","priority":"high","status":"pending"},{"content":"Create admin catalog page with inline Server Action form that revalidates the 'products' tag","id":"3","priority":"high","status":"pending"},{"content":"Run lint/build verification","id":"4","priority":"medium","status":"pending"}]},"output":"[\n {\n \"content\": \"Enable Cache Components in next.config.ts\",\n \"id\": \"1\",\n \"priority\": \"high\",\n \"status\": \"pending\"\n },\n {\n \"content\": \"Add typed product data access in lib/products.ts with 'use cache' and cacheTag('products')\",\n \"id\": \"2\",\n \"priority\": \"high\",\n \"status\": \"pending\"\n },\n {\n \"content\": \"Create admin catalog page with inline Server Action form that revalidates the 'products' tag\",\n \"id\": \"3\",\n \"priority\": \"high\",\n \"status\": \"pending\"\n },\n {\n \"content\": \"Run lint/build verification\",\n \"id\": \"4\",\n \"priority\": \"medium\",\n \"status\": \"pending\"\n }\n]","title":"4 todos","metadata":{"todos":[{"content":"Enable Cache Components in next.config.ts","id":"1","priority":"high","status":"pending"},{"content":"Add typed product data access in lib/products.ts with 'use cache' and cacheTag('products')","id":"2","priority":"high","status":"pending"},{"content":"Create admin catalog page with inline Server Action form that revalidates the 'products' tag","id":"3","priority":"high","status":"pending"},{"content":"Run lint/build verification","id":"4","priority":"medium","status":"pending"}]},"time":{"start":1781392613067,"end":1781392613070}}}}
+{"type":"step_finish","timestamp":1781392613078,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec3461ecf001kEaCWOr56yQSip","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec344f1c4001kuwAvBLJPYVmIN","type":"step-finish","reason":"tool-calls","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012","cost":0.03228046,"tokens":{"input":11506,"output":4508,"reasoning":0,"cache":{"read":20736,"write":0}}}}
+{"type":"step_start","timestamp":1781392615373,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec34627b40014Ciuo1hiDSGJwm","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec3461edf0011sIlqBSb7S0oj2","type":"step-start","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012"}}
+{"type":"tool_use","timestamp":1781392622375,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec3463d4e0010hGrvq2vDPnbkA","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec3461edf0011sIlqBSb7S0oj2","type":"tool","callID":"todowrite_20","tool":"todowrite","state":{"status":"completed","input":{"todos":[{"content":"Enable Cache Components in next.config.ts","id":"1","priority":"high","status":"in_progress"},{"content":"Add typed product data access in lib/products.ts with 'use cache' and cacheTag('products')","id":"2","priority":"high","status":"pending"},{"content":"Create admin catalog page with inline Server Action form that revalidates the 'products' tag","id":"3","priority":"high","status":"pending"},{"content":"Run lint/build verification","id":"4","priority":"medium","status":"pending"}]},"output":"[\n {\n \"content\": \"Enable Cache Components in next.config.ts\",\n \"id\": \"1\",\n \"priority\": \"high\",\n \"status\": \"in_progress\"\n },\n {\n \"content\": \"Add typed product data access in lib/products.ts with 'use cache' and cacheTag('products')\",\n \"id\": \"2\",\n \"priority\": \"high\",\n \"status\": \"pending\"\n },\n {\n \"content\": \"Create admin catalog page with inline Server Action form that revalidates the 'products' tag\",\n \"id\": \"3\",\n \"priority\": \"high\",\n \"status\": \"pending\"\n },\n {\n \"content\": \"Run lint/build verification\",\n \"id\": \"4\",\n \"priority\": \"medium\",\n \"status\": \"pending\"\n }\n]","title":"4 todos","metadata":{"todos":[{"content":"Enable Cache Components in next.config.ts","id":"1","priority":"high","status":"in_progress"},{"content":"Add typed product data access in lib/products.ts with 'use cache' and cacheTag('products')","id":"2","priority":"high","status":"pending"},{"content":"Create admin catalog page with inline Server Action form that revalidates the 'products' tag","id":"3","priority":"high","status":"pending"},{"content":"Run lint/build verification","id":"4","priority":"medium","status":"pending"}]},"time":{"start":1781392622371,"end":1781392622373}}}}
+{"type":"step_finish","timestamp":1781392622379,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec3464326001gXXji65appKYck","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec3461edf0011sIlqBSb7S0oj2","type":"step-finish","reason":"tool-calls","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012","cost":0.01153616,"tokens":{"input":4656,"output":488,"reasoning":0,"cache":{"read":32256,"write":0}}}}
+{"type":"step_start","timestamp":1781392624224,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec3464a5c0016rGU6CAsiFma93","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec3464339001OrzsL1p3HXhHdI","type":"step-start","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012"}}
+{"type":"tool_use","timestamp":1781392627912,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec3464a5f0015N5Qpg4deubcZ1","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec3464339001OrzsL1p3HXhHdI","type":"tool","callID":"edit_21","tool":"edit","state":{"status":"completed","input":{"filePath":"/workspace/next.config.ts","oldString":"const nextConfig: NextConfig = {}\n\nexport default nextConfig","newString":"const nextConfig: NextConfig = {\n cacheComponents: true,\n}\n\nexport default nextConfig"},"output":"","title":"next.config.ts","metadata":{"diagnostics":{"/workspace/next.config.ts":[],"/workspace/lib/db.js":[],"/workspace/app/layout.tsx":[],"/workspace/app/page.tsx":[]},"diff":"Index: /workspace/next.config.ts\n===================================================================\n--- /workspace/next.config.ts\n+++ /workspace/next.config.ts\n@@ -1,5 +1,7 @@\n import type { NextConfig } from 'next'\n \n-const nextConfig: NextConfig = {}\n+const nextConfig: NextConfig = {\n+ cacheComponents: true,\n+}\n \n export default nextConfig\n","filediff":{"file":"/workspace/next.config.ts","before":"import type { NextConfig } from 'next'\n\nconst nextConfig: NextConfig = {}\n\nexport default nextConfig\n","after":"import type { NextConfig } from 'next'\n\nconst nextConfig: NextConfig = {\n cacheComponents: true,\n}\n\nexport default nextConfig\n","additions":3,"deletions":1}},"time":{"start":1781392624898,"end":1781392627909}}}}
+{"type":"step_finish","timestamp":1781392627921,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec34658c60013CUMxdKVSRhmWt","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec3464339001OrzsL1p3HXhHdI","type":"step-finish","reason":"tool-calls","snapshot":"7a146fa19d720a6a1a3d33c9c98f2b8b7f21ec2c","cost":0.00689174,"tokens":{"input":730,"output":75,"reasoning":0,"cache":{"read":36864,"write":0}}}}
+{"type":"step_start","timestamp":1781392629960,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec34660c5001csitbBMzxjwlSl","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec34658f50016Pg9vtwl3hf0bx","type":"step-start","snapshot":"7a146fa19d720a6a1a3d33c9c98f2b8b7f21ec2c"}}
+{"type":"tool_use","timestamp":1781392632377,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec34661af001tDCJcodVC4enOr","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec34658f50016Pg9vtwl3hf0bx","type":"tool","callID":"todowrite_22","tool":"todowrite","state":{"status":"completed","input":{"todos":[{"content":"Enable Cache Components in next.config.ts","id":"1","priority":"high","status":"completed"},{"content":"Add typed product data access in lib/products.ts with 'use cache' and cacheTag('products')","id":"2","priority":"high","status":"in_progress"},{"content":"Create admin catalog page with inline Server Action form that revalidates the 'products' tag","id":"3","priority":"high","status":"pending"},{"content":"Run lint/build verification","id":"4","priority":"medium","status":"pending"}]},"output":"[\n {\n \"content\": \"Enable Cache Components in next.config.ts\",\n \"id\": \"1\",\n \"priority\": \"high\",\n \"status\": \"completed\"\n },\n {\n \"content\": \"Add typed product data access in lib/products.ts with 'use cache' and cacheTag('products')\",\n \"id\": \"2\",\n \"priority\": \"high\",\n \"status\": \"in_progress\"\n },\n {\n \"content\": \"Create admin catalog page with inline Server Action form that revalidates the 'products' tag\",\n \"id\": \"3\",\n \"priority\": \"high\",\n \"status\": \"pending\"\n },\n {\n \"content\": \"Run lint/build verification\",\n \"id\": \"4\",\n \"priority\": \"medium\",\n \"status\": \"pending\"\n }\n]","title":"3 todos","metadata":{"todos":[{"content":"Enable Cache Components in next.config.ts","id":"1","priority":"high","status":"completed"},{"content":"Add typed product data access in lib/products.ts with 'use cache' and cacheTag('products')","id":"2","priority":"high","status":"in_progress"},{"content":"Create admin catalog page with inline Server Action form that revalidates the 'products' tag","id":"3","priority":"high","status":"pending"},{"content":"Run lint/build verification","id":"4","priority":"medium","status":"pending"}]},"time":{"start":1781392632371,"end":1781392632375}}}}
+{"type":"step_finish","timestamp":1781392632384,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec3466a3800129esVtf5BG8BIX","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec34658f50016Pg9vtwl3hf0bx","type":"step-finish","reason":"tool-calls","snapshot":"7a146fa19d720a6a1a3d33c9c98f2b8b7f21ec2c","cost":0.00685696,"tokens":{"input":304,"output":147,"reasoning":0,"cache":{"read":37376,"write":0}}}}
+{"type":"step_start","timestamp":1781392634165,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec3467129001LiLNH5LQbN00Ea","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec3466a490014iDs44kNNc79TA","type":"step-start","snapshot":"7a146fa19d720a6a1a3d33c9c98f2b8b7f21ec2c"}}
+{"type":"tool_use","timestamp":1781392640618,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec3467230001cXOwHX0g1BL9np","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec3466a490014iDs44kNNc79TA","type":"tool","callID":"write_23","tool":"write","state":{"status":"completed","input":{"content":"export interface Product {\n id: number\n name: string\n price: number\n}\n\nexport async function getAllProducts(): Promise {\n await new Promise((resolve) => setTimeout(resolve, 100))\n\n return [\n { id: 1, name: 'Laptop', price: 999 },\n { id: 2, name: 'Phone', price: 699 },\n { id: 3, name: 'Tablet', price: 499 },\n { id: 4, name: 'Headphones', price: 199 },\n { id: 5, name: 'Watch', price: 299 },\n ]\n}\n","filePath":"/workspace/lib/db.ts"},"output":"","title":"lib/db.ts","metadata":{"diagnostics":{"/workspace/next.config.ts":[],"/workspace/lib/db.js":[],"/workspace/app/layout.tsx":[],"/workspace/app/page.tsx":[],"/workspace/lib/db.ts":[],"/workspace/lib/products.ts":[]},"filepath":"/workspace/lib/db.ts","exists":false},"time":{"start":1781392637607,"end":1781392640617}}}}
+{"type":"tool_use","timestamp":1781392641759,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec3467ead00140GwzZE3gzSQqg","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec3466a490014iDs44kNNc79TA","type":"tool","callID":"write_24","tool":"write","state":{"status":"completed","input":{"content":"import { cacheTag } from 'next/cache'\nimport { getAllProducts, type Product } from './db'\n\nexport async function getProducts(): Promise {\n 'use cache'\n cacheTag('products')\n return getAllProducts()\n}\n","filePath":"/workspace/lib/products.ts"},"output":"","title":"lib/products.ts","metadata":{"diagnostics":{"/workspace/next.config.ts":[],"/workspace/lib/db.js":[],"/workspace/app/layout.tsx":[],"/workspace/app/page.tsx":[],"/workspace/lib/db.ts":[],"/workspace/lib/products.ts":[]},"filepath":"/workspace/lib/products.ts","exists":false},"time":{"start":1781392638747,"end":1781392641753}}}}
+{"type":"step_finish","timestamp":1781392641764,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec3468eda001OMNH2eogwB94OY","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec3466a490014iDs44kNNc79TA","type":"step-finish","reason":"tool-calls","snapshot":"b3218574ceea587349f8fca44b8cb7c3cb67f905","cost":0.00749867,"tokens":{"input":389,"output":277,"reasoning":0,"cache":{"read":37632,"write":0}}}}
+{"type":"step_start","timestamp":1781392643699,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec346966f001R0ingCgszbNffy","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec3468efc0018udAEmBGSSJMPp","type":"step-start","snapshot":"b3218574ceea587349f8fca44b8cb7c3cb67f905"}}
+{"type":"tool_use","timestamp":1781392644272,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec34697df001FUpGZkfqc971MQ","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec3468efc0018udAEmBGSSJMPp","type":"tool","callID":"bash_25","tool":"bash","state":{"status":"completed","input":{"command":"rm /workspace/lib/db.js","description":"Remove old JavaScript db file"},"output":"","title":"Remove old JavaScript db file","metadata":{"output":"","exit":0,"description":"Remove old JavaScript db file"},"time":{"start":1781392644265,"end":1781392644270}}}}
+{"type":"step_finish","timestamp":1781392644275,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec34698af001Le67V3suwyKgXu","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec3468efc0018udAEmBGSSJMPp","type":"step-finish","reason":"tool-calls","snapshot":"114020e2d5a86382c678c2ede317ce4c6beb4e8c","cost":0.00666448,"tokens":{"input":432,"output":48,"reasoning":0,"cache":{"read":37888,"write":0}}}}
+{"type":"step_start","timestamp":1781392646230,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec346a04f001ApTzJDDjj2geiN","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec34698c0001TTp03bVksr1VhS","type":"step-start","snapshot":"114020e2d5a86382c678c2ede317ce4c6beb4e8c"}}
+{"type":"tool_use","timestamp":1781392647801,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec346a15a001kI02WMdy9sWGLP","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec34698c0001TTp03bVksr1VhS","type":"tool","callID":"todowrite_26","tool":"todowrite","state":{"status":"completed","input":{"todos":[{"content":"Enable Cache Components in next.config.ts","id":"1","priority":"high","status":"completed"},{"content":"Add typed product data access in lib/products.ts with 'use cache' and cacheTag('products')","id":"2","priority":"high","status":"completed"},{"content":"Create admin catalog page with inline Server Action form that revalidates the 'products' tag","id":"3","priority":"high","status":"in_progress"},{"content":"Run lint/build verification","id":"4","priority":"medium","status":"pending"}]},"output":"[\n {\n \"content\": \"Enable Cache Components in next.config.ts\",\n \"id\": \"1\",\n \"priority\": \"high\",\n \"status\": \"completed\"\n },\n {\n \"content\": \"Add typed product data access in lib/products.ts with 'use cache' and cacheTag('products')\",\n \"id\": \"2\",\n \"priority\": \"high\",\n \"status\": \"completed\"\n },\n {\n \"content\": \"Create admin catalog page with inline Server Action form that revalidates the 'products' tag\",\n \"id\": \"3\",\n \"priority\": \"high\",\n \"status\": \"in_progress\"\n },\n {\n \"content\": \"Run lint/build verification\",\n \"id\": \"4\",\n \"priority\": \"medium\",\n \"status\": \"pending\"\n }\n]","title":"2 todos","metadata":{"todos":[{"content":"Enable Cache Components in next.config.ts","id":"1","priority":"high","status":"completed"},{"content":"Add typed product data access in lib/products.ts with 'use cache' and cacheTag('products')","id":"2","priority":"high","status":"completed"},{"content":"Create admin catalog page with inline Server Action form that revalidates the 'products' tag","id":"3","priority":"high","status":"in_progress"},{"content":"Run lint/build verification","id":"4","priority":"medium","status":"pending"}]},"time":{"start":1781392647796,"end":1781392647799}}}}
+{"type":"step_finish","timestamp":1781392647807,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec346a678001WSmxw2qfdqU9Nh","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec34698c0001TTp03bVksr1VhS","type":"step-finish","reason":"tool-calls","snapshot":"114020e2d5a86382c678c2ede317ce4c6beb4e8c","cost":0.00691314,"tokens":{"input":238,"output":146,"reasoning":0,"cache":{"read":38144,"write":0}}}}
+{"type":"step_start","timestamp":1781392650033,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec346af2b001tWGKLiiz1K5S8B","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec346a68e001kvKHbPn2S7NJJh","type":"step-start","snapshot":"114020e2d5a86382c678c2ede317ce4c6beb4e8c"}}
+{"type":"tool_use","timestamp":1781392653817,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec346af2e001LCjvFS1gXxzwhw","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec346a68e001kvKHbPn2S7NJJh","type":"tool","callID":"write_27","tool":"write","state":{"status":"completed","input":{"content":"import { revalidateTag } from 'next/cache'\nimport { getProducts } from '@/lib/products'\n\nasync function syncCatalog() {\n 'use server'\n\n await new Promise((resolve) => setTimeout(resolve, 100))\n\n revalidateTag('products', 'max')\n}\n\nexport default async function CatalogPage() {\n const products = await getProducts()\n\n return (\n \n
Product Catalog
\n
\n \n
\n
\n {products.map((product) => (\n
\n {product.name} — ${product.price}\n
\n ))}\n
\n \n )\n}\n","filePath":"/workspace/app/admin/catalog/page.tsx"},"output":"","title":"app/admin/catalog/page.tsx","metadata":{"diagnostics":{"/workspace/next.config.ts":[],"/workspace/lib/db.js":[],"/workspace/app/layout.tsx":[],"/workspace/app/page.tsx":[],"/workspace/lib/db.ts":[],"/workspace/lib/products.ts":[],"/workspace/app/admin/catalog/page.tsx":[]},"filepath":"/workspace/app/admin/catalog/page.tsx","exists":false},"time":{"start":1781392653186,"end":1781392653814}}}}
+{"type":"step_finish","timestamp":1781392653821,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec346bdf7001AHaowmHND6gGdQ","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec346a68e001kvKHbPn2S7NJJh","type":"step-finish","reason":"tool-calls","snapshot":"b29b350eb87440c3d1bc615a6fb35f1945056164","cost":0.00757214,"tokens":{"input":578,"output":230,"reasoning":0,"cache":{"read":38144,"write":0}}}}
+{"type":"step_start","timestamp":1781392655751,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec346c584001qyMMJjQKSS7JHD","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec346be11001lSGqSdj7kATxeZ","type":"step-start","snapshot":"b29b350eb87440c3d1bc615a6fb35f1945056164"}}
+{"type":"tool_use","timestamp":1781392658050,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec346c8bc0010QoQrI009l7HyE","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec346be11001lSGqSdj7kATxeZ","type":"tool","callID":"todowrite_28","tool":"todowrite","state":{"status":"completed","input":{"todos":[{"content":"Enable Cache Components in next.config.ts","id":"1","priority":"high","status":"completed"},{"content":"Add typed product data access in lib/products.ts with 'use cache' and cacheTag('products')","id":"2","priority":"high","status":"completed"},{"content":"Create admin catalog page with inline Server Action form that revalidates the 'products' tag","id":"3","priority":"high","status":"completed"},{"content":"Run lint/build verification","id":"4","priority":"medium","status":"in_progress"}]},"output":"[\n {\n \"content\": \"Enable Cache Components in next.config.ts\",\n \"id\": \"1\",\n \"priority\": \"high\",\n \"status\": \"completed\"\n },\n {\n \"content\": \"Add typed product data access in lib/products.ts with 'use cache' and cacheTag('products')\",\n \"id\": \"2\",\n \"priority\": \"high\",\n \"status\": \"completed\"\n },\n {\n \"content\": \"Create admin catalog page with inline Server Action form that revalidates the 'products' tag\",\n \"id\": \"3\",\n \"priority\": \"high\",\n \"status\": \"completed\"\n },\n {\n \"content\": \"Run lint/build verification\",\n \"id\": \"4\",\n \"priority\": \"medium\",\n \"status\": \"in_progress\"\n }\n]","title":"1 todos","metadata":{"todos":[{"content":"Enable Cache Components in next.config.ts","id":"1","priority":"high","status":"completed"},{"content":"Add typed product data access in lib/products.ts with 'use cache' and cacheTag('products')","id":"2","priority":"high","status":"completed"},{"content":"Create admin catalog page with inline Server Action form that revalidates the 'products' tag","id":"3","priority":"high","status":"completed"},{"content":"Run lint/build verification","id":"4","priority":"medium","status":"in_progress"}]},"time":{"start":1781392658046,"end":1781392658048}}}}
+{"type":"step_finish","timestamp":1781392658053,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec346ce81001ZxbpZNBmo3QdTl","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec346be11001lSGqSdj7kATxeZ","type":"step-finish","reason":"tool-calls","snapshot":"b29b350eb87440c3d1bc615a6fb35f1945056164","cost":0.00722936,"tokens":{"input":312,"output":187,"reasoning":0,"cache":{"read":38656,"write":0}}}}
+{"type":"step_start","timestamp":1781392659909,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec346d5c2001VfAZHCRGSN6UxO","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec346ce92001vQaSGEBfbNDg8r","type":"step-start","snapshot":"b29b350eb87440c3d1bc615a6fb35f1945056164"}}
+{"type":"tool_use","timestamp":1781392669291,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec346d5c4001Y27WA09aeNgQeO","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec346ce92001vQaSGEBfbNDg8r","type":"tool","callID":"bash_29","tool":"bash","state":{"status":"completed","input":{"command":"npm run build","description":"Build Next.js app to verify changes","timeout":300000},"output":"\n> build\n> next build\n\nAttention: Next.js now collects completely anonymous telemetry regarding usage.\nThis information is used to shape Next.js' roadmap and prioritize features.\nYou can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:\nhttps://nextjs.org/telemetry\n\n▲ Next.js 16.3.0-canary.50 (Turbopack)\n- Cache Components enabled\n\n Creating an optimized production build ...\n✓ Compiled successfully in 5.1s\n Running TypeScript ...\n\n We detected TypeScript in your project and reconfigured your tsconfig.json file for you.\n The following suggested values were added to your tsconfig.json. These values can be changed to fit your project's needs:\n\n \t- include was updated to add '.next/dev/types/**/*.ts'\n\n Finished TypeScript in 1730ms ...\n Collecting page data using 1 worker ...\n Generating static pages using 1 worker (0/4) ...\n Generating static pages using 1 worker (1/4) \r\n Generating static pages using 1 worker (2/4) \r\n Generating static pages using 1 worker (3/4) \r\n✓ Generating static pages using 1 worker (4/4) in 172ms\n Finalizing page optimization ...\n\nRoute (app) Revalidate Expire\n┌ ○ /\n├ ○ /_not-found\n└ ○ /admin/catalog 15m 1y\n\n\n○ (Static) prerendered as static content\n\n","title":"Build Next.js app to verify changes","metadata":{"output":"\n> build\n> next build\n\nAttention: Next.js now collects completely anonymous telemetry regarding usage.\nThis information is used to shape Next.js' roadmap and prioritize features.\nYou can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:\nhttps://nextjs.org/telemetry\n\n▲ Next.js 16.3.0-canary.50 (Turbopack)\n- Cache Components enabled\n\n Creating an optimized production build ...\n✓ Compiled successfully in 5.1s\n Running TypeScript ...\n\n We detected TypeScript in your project and reconfigured your tsconfig.json file for you.\n The following suggested values were added to your tsconfig.json. These values can be changed to fit your project's needs:\n\n \t- include was updated to add '.next/dev/types/**/*.ts'\n\n Finished TypeScript in 1730ms ...\n Collecting page data using 1 worker ...\n Generating static pages using 1 worker (0/4) ...\n Generating static pages using 1 worker (1/4) \r\n Generating static pages using 1 worker (2/4) \r\n Generating static pages using 1 worker (3/4) \r\n✓ Generating static pages using 1 worker (4/4) in 172ms\n Finalizing page optimization ...\n\nRoute (app) Revalidate Expire\n┌ ○ /\n├ ○ /_not-found\n└ ○ /admin/catalog 15m 1y\n\n\n○ (Static) prerendered as static content\n\n","exit":0,"description":"Build Next.js app to verify changes"},"time":{"start":1781392660139,"end":1781392669287}}}}
+{"type":"step_finish","timestamp":1781392669404,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec346fa69001M7DeDKqDpY0anB","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec346ce92001vQaSGEBfbNDg8r","type":"step-finish","reason":"tool-calls","snapshot":"460b27e2cd1b5edf9e9dbbb552d80304d94ca51f","cost":0.00679707,"tokens":{"input":437,"output":39,"reasoning":0,"cache":{"read":38912,"write":0}}}}
+{"type":"step_start","timestamp":1781392671213,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec34701ea001EjN8SwKHlmxrIl","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec346faeb001X10Y0HGcAMf8L3","type":"step-start","snapshot":"460b27e2cd1b5edf9e9dbbb552d80304d94ca51f"}}
+{"type":"tool_use","timestamp":1781392685650,"sessionID":"ses_13cbb922affe86wOEqVAq01qO3","part":{"id":"prt_ec347384b001t893Lpcgwbu2tF","sessionID":"ses_13cbb922affe86wOEqVAq01qO3","messageID":"msg_ec346faeb001X10Y0HGcAMf8L3","type":"tool","callID":"read_30","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/app/admin/catalog/page.tsx"},"output":"\n00001| import { revalidateTag } from 'next/cache'\n00002| import { getProducts } from '@/lib/products'\n00003| \n00004| async function syncCatalog() {\n00005| 'use server'\n00006| \n00007| await new Promise((resolve) => setTimeout(resolve, 100))\n00008| \n00009| revalidateTag('products', 'max')\n00010| }\n00011| \n00012| export default async function CatalogPage() {\n00013| const products = await getProducts()\n00014| \n00015| return (\n00016| \n00017|
\n00006| )\n00007| }\n00008| \n\n(End of file - total 8 lines)\n",
+ "title": "app/page.tsx",
+ "metadata": {
+ "preview": "export default function Page() {\n return (\n
\n
Home
\n
\n )\n}\n"
+ },
+ "time": {
+ "start": 1781392509593,
+ "end": 1781392509596
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:10.398Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "args": {
+ "filePath": "/workspace/app/layout.tsx",
+ "_extractedPath": "/workspace/app/layout.tsx"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392510398,
+ "sessionID": "ses_13cbb922affe86wOEqVAq01qO3",
+ "part": {
+ "id": "prt_ec3448a9a001iUJwHhlnuwVNFo",
+ "sessionID": "ses_13cbb922affe86wOEqVAq01qO3",
+ "messageID": "msg_ec3447c6d001IrdJjg2Jsx0WbL",
+ "type": "tool",
+ "callID": "read_4",
+ "tool": "read",
+ "state": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/app/layout.tsx"
+ },
+ "output": "\n00001| import type { Metadata } from 'next'\n00002| \n00003| export const metadata: Metadata = {\n00004| title: 'Create Next App',\n00005| description: 'Generated by create next app',\n00006| }\n00007| \n00008| export default function RootLayout({\n00009| children,\n00010| }: Readonly<{\n00011| children: React.ReactNode\n00012| }>) {\n00013| return (\n00014| \n00015| {children}\n00016| \n00017| )\n00018| }\n00019| \n\n(End of file - total 19 lines)\n",
+ "title": "app/layout.tsx",
+ "metadata": {
+ "preview": "import type { Metadata } from 'next'\n\nexport const metadata: Metadata = {\n title: 'Create Next App',\n description: 'Generated by create next app',\n}\n\nexport default function RootLayout({\n children,\n}: Readonly<{\n children: React.ReactNode\n}>) {\n return (\n \n {children}\n \n )\n}\n"
+ },
+ "time": {
+ "start": 1781392510357,
+ "end": 1781392510394
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:10.398Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| import type { Metadata } from 'next'\n00002| \n00003| export const metadata: Metadata = {\n00004| title: 'Create Next App',\n00005| description: 'Generated by create next app',\n00006| }\n00007| \n00008| export default function RootLayout({\n00009| children,\n00010| }: Readonly<{\n00011| children: React.ReactNode\n00012| }>) {\n00013| return (\n00014| \n00015| {children}\n00016| \n00017| )\n00018| }\n00019| \n\n(End of file - total 19 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/app/layout.tsx"
+ },
+ "output": "\n00001| import type { Metadata } from 'next'\n00002| \n00003| export const metadata: Metadata = {\n00004| title: 'Create Next App',\n00005| description: 'Generated by create next app',\n00006| }\n00007| \n00008| export default function RootLayout({\n00009| children,\n00010| }: Readonly<{\n00011| children: React.ReactNode\n00012| }>) {\n00013| return (\n00014| \n00015| {children}\n00016| \n00017| )\n00018| }\n00019| \n\n(End of file - total 19 lines)\n",
+ "title": "app/layout.tsx",
+ "metadata": {
+ "preview": "import type { Metadata } from 'next'\n\nexport const metadata: Metadata = {\n title: 'Create Next App',\n description: 'Generated by create next app',\n}\n\nexport default function RootLayout({\n children,\n}: Readonly<{\n children: React.ReactNode\n}>) {\n return (\n \n {children}\n \n )\n}\n"
+ },
+ "time": {
+ "start": 1781392510357,
+ "end": 1781392510394
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:10.399Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "args": {
+ "filePath": "/workspace/package.json",
+ "_extractedPath": "/workspace/package.json"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392510399,
+ "sessionID": "ses_13cbb922affe86wOEqVAq01qO3",
+ "part": {
+ "id": "prt_ec3448dac0012L3WvwA4I5IuFF",
+ "sessionID": "ses_13cbb922affe86wOEqVAq01qO3",
+ "messageID": "msg_ec3447c6d001IrdJjg2Jsx0WbL",
+ "type": "tool",
+ "callID": "read_5",
+ "tool": "read",
+ "state": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/package.json"
+ },
+ "output": "\n00001| {\n00002| \"private\": true,\n00003| \"type\": \"module\",\n00004| \"scripts\": {\n00005| \"dev\": \"next dev\",\n00006| \"build\": \"next build\",\n00007| \"start\": \"next start\"\n00008| },\n00009| \"dependencies\": {\n00010| \"@ai-sdk/react\": \"2.0.0-beta.28\",\n00011| \"@modelcontextprotocol/sdk\": \"^1.17.0\",\n00012| \"ai\": \"5.0.59\",\n00013| \"next\": \"^16.3.0-canary.50\",\n00014| \"react\": \"19.1.0\",\n00015| \"react-dom\": \"19.1.0\",\n00016| \"zod\": \"^4.0.10\"\n00017| },\n00018| \"devDependencies\": {\n00019| \"@types/node\": \"^20\",\n00020| \"@types/react\": \"^19\",\n00021| \"@types/react-dom\": \"^19\",\n00022| \"@vitejs/plugin-react\": \"^4.4.1\",\n00023| \"typescript\": \"^5\",\n00024| \"vite-tsconfig-paths\": \"^5.1.4\",\n00025| \"vitest\": \"^3.1.3\"\n00026| }\n00027| }\n00028| \n\n(End of file - total 28 lines)\n",
+ "title": "package.json",
+ "metadata": {
+ "preview": "{\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"next dev\",\n \"build\": \"next build\",\n \"start\": \"next start\"\n },\n \"dependencies\": {\n \"@ai-sdk/react\": \"2.0.0-beta.28\",\n \"@modelcontextprotocol/sdk\": \"^1.17.0\",\n \"ai\": \"5.0.59\",\n \"next\": \"^16.3.0-canary.50\",\n \"react\": \"19.1.0\",\n \"react-dom\": \"19.1.0\",\n \"zod\": \"^4.0.10\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^20\",\n \"@types/react\": \"^19\","
+ },
+ "time": {
+ "start": 1781392510381,
+ "end": 1781392510394
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:10.399Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| {\n00002| \"private\": true,\n00003| \"type\": \"module\",\n00004| \"scripts\": {\n00005| \"dev\": \"next dev\",\n00006| \"build\": \"next build\",\n00007| \"start\": \"next start\"\n00008| },\n00009| \"dependencies\": {\n00010| \"@ai-sdk/react\": \"2.0.0-beta.28\",\n00011| \"@modelcontextprotocol/sdk\": \"^1.17.0\",\n00012| \"ai\": \"5.0.59\",\n00013| \"next\": \"^16.3.0-canary.50\",\n00014| \"react\": \"19.1.0\",\n00015| \"react-dom\": \"19.1.0\",\n00016| \"zod\": \"^4.0.10\"\n00017| },\n00018| \"devDependencies\": {\n00019| \"@types/node\": \"^20\",\n00020| \"@types/react\": \"^19\",\n00021| \"@types/react-dom\": \"^19\",\n00022| \"@vitejs/plugin-react\": \"^4.4.1\",\n00023| \"typescript\": \"^5\",\n00024| \"vite-tsconfig-paths\": \"^5.1.4\",\n00025| \"vitest\": \"^3.1.3\"\n00026| }\n00027| }\n00028| \n\n(End of file - total 28 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/package.json"
+ },
+ "output": "\n00001| {\n00002| \"private\": true,\n00003| \"type\": \"module\",\n00004| \"scripts\": {\n00005| \"dev\": \"next dev\",\n00006| \"build\": \"next build\",\n00007| \"start\": \"next start\"\n00008| },\n00009| \"dependencies\": {\n00010| \"@ai-sdk/react\": \"2.0.0-beta.28\",\n00011| \"@modelcontextprotocol/sdk\": \"^1.17.0\",\n00012| \"ai\": \"5.0.59\",\n00013| \"next\": \"^16.3.0-canary.50\",\n00014| \"react\": \"19.1.0\",\n00015| \"react-dom\": \"19.1.0\",\n00016| \"zod\": \"^4.0.10\"\n00017| },\n00018| \"devDependencies\": {\n00019| \"@types/node\": \"^20\",\n00020| \"@types/react\": \"^19\",\n00021| \"@types/react-dom\": \"^19\",\n00022| \"@vitejs/plugin-react\": \"^4.4.1\",\n00023| \"typescript\": \"^5\",\n00024| \"vite-tsconfig-paths\": \"^5.1.4\",\n00025| \"vitest\": \"^3.1.3\"\n00026| }\n00027| }\n00028| \n\n(End of file - total 28 lines)\n",
+ "title": "package.json",
+ "metadata": {
+ "preview": "{\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"next dev\",\n \"build\": \"next build\",\n \"start\": \"next start\"\n },\n \"dependencies\": {\n \"@ai-sdk/react\": \"2.0.0-beta.28\",\n \"@modelcontextprotocol/sdk\": \"^1.17.0\",\n \"ai\": \"5.0.59\",\n \"next\": \"^16.3.0-canary.50\",\n \"react\": \"19.1.0\",\n \"react-dom\": \"19.1.0\",\n \"zod\": \"^4.0.10\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^20\",\n \"@types/react\": \"^19\","
+ },
+ "time": {
+ "start": 1781392510381,
+ "end": 1781392510394
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:10.763Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "args": {
+ "filePath": "/workspace/lib/db.js",
+ "_extractedPath": "/workspace/lib/db.js"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392510763,
+ "sessionID": "ses_13cbb922affe86wOEqVAq01qO3",
+ "part": {
+ "id": "prt_ec3448db9001qN2ViTUTDrLAsI",
+ "sessionID": "ses_13cbb922affe86wOEqVAq01qO3",
+ "messageID": "msg_ec3447c6d001IrdJjg2Jsx0WbL",
+ "type": "tool",
+ "callID": "read_6",
+ "tool": "read",
+ "state": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/lib/db.js"
+ },
+ "output": "\n00001| export async function getAllProducts() {\n00002| // Simulate database delay\n00003| await new Promise((resolve) => setTimeout(resolve, 100))\n00004| \n00005| return [\n00006| { id: 1, name: 'Laptop', price: 999 },\n00007| { id: 2, name: 'Phone', price: 699 },\n00008| { id: 3, name: 'Tablet', price: 499 },\n00009| { id: 4, name: 'Headphones', price: 199 },\n00010| { id: 5, name: 'Watch', price: 299 },\n00011| ]\n00012| }\n00013| \n\n(End of file - total 13 lines)\n",
+ "title": "lib/db.js",
+ "metadata": {
+ "preview": "export async function getAllProducts() {\n // Simulate database delay\n await new Promise((resolve) => setTimeout(resolve, 100))\n\n return [\n { id: 1, name: 'Laptop', price: 999 },\n { id: 2, name: 'Phone', price: 699 },\n { id: 3, name: 'Tablet', price: 499 },\n { id: 4, name: 'Headphones', price: 199 },\n { id: 5, name: 'Watch', price: 299 },\n ]\n}\n"
+ },
+ "time": {
+ "start": 1781392510746,
+ "end": 1781392510748
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:10.763Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| export async function getAllProducts() {\n00002| // Simulate database delay\n00003| await new Promise((resolve) => setTimeout(resolve, 100))\n00004| \n00005| return [\n00006| { id: 1, name: 'Laptop', price: 999 },\n00007| { id: 2, name: 'Phone', price: 699 },\n00008| { id: 3, name: 'Tablet', price: 499 },\n00009| { id: 4, name: 'Headphones', price: 199 },\n00010| { id: 5, name: 'Watch', price: 299 },\n00011| ]\n00012| }\n00013| \n\n(End of file - total 13 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/lib/db.js"
+ },
+ "output": "\n00001| export async function getAllProducts() {\n00002| // Simulate database delay\n00003| await new Promise((resolve) => setTimeout(resolve, 100))\n00004| \n00005| return [\n00006| { id: 1, name: 'Laptop', price: 999 },\n00007| { id: 2, name: 'Phone', price: 699 },\n00008| { id: 3, name: 'Tablet', price: 499 },\n00009| { id: 4, name: 'Headphones', price: 199 },\n00010| { id: 5, name: 'Watch', price: 299 },\n00011| ]\n00012| }\n00013| \n\n(End of file - total 13 lines)\n",
+ "title": "lib/db.js",
+ "metadata": {
+ "preview": "export async function getAllProducts() {\n // Simulate database delay\n await new Promise((resolve) => setTimeout(resolve, 100))\n\n return [\n { id: 1, name: 'Laptop', price: 999 },\n { id: 2, name: 'Phone', price: 699 },\n { id: 3, name: 'Tablet', price: 499 },\n { id: 4, name: 'Headphones', price: 199 },\n { id: 5, name: 'Watch', price: 299 },\n ]\n}\n"
+ },
+ "time": {
+ "start": 1781392510746,
+ "end": 1781392510748
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:11.181Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "args": {
+ "filePath": "/workspace/next.config.ts",
+ "_extractedPath": "/workspace/next.config.ts"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392511181,
+ "sessionID": "ses_13cbb922affe86wOEqVAq01qO3",
+ "part": {
+ "id": "prt_ec3448f1c001HjD7mvx3YPIjpP",
+ "sessionID": "ses_13cbb922affe86wOEqVAq01qO3",
+ "messageID": "msg_ec3447c6d001IrdJjg2Jsx0WbL",
+ "type": "tool",
+ "callID": "read_7",
+ "tool": "read",
+ "state": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/next.config.ts"
+ },
+ "output": "\n00001| import type { NextConfig } from 'next'\n00002| \n00003| const nextConfig: NextConfig = {}\n00004| \n00005| export default nextConfig\n00006| \n\n(End of file - total 6 lines)\n",
+ "title": "next.config.ts",
+ "metadata": {
+ "preview": "import type { NextConfig } from 'next'\n\nconst nextConfig: NextConfig = {}\n\nexport default nextConfig\n"
+ },
+ "time": {
+ "start": 1781392511173,
+ "end": 1781392511176
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:11.181Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| import type { NextConfig } from 'next'\n00002| \n00003| const nextConfig: NextConfig = {}\n00004| \n00005| export default nextConfig\n00006| \n\n(End of file - total 6 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/next.config.ts"
+ },
+ "output": "\n00001| import type { NextConfig } from 'next'\n00002| \n00003| const nextConfig: NextConfig = {}\n00004| \n00005| export default nextConfig\n00006| \n\n(End of file - total 6 lines)\n",
+ "title": "next.config.ts",
+ "metadata": {
+ "preview": "import type { NextConfig } from 'next'\n\nconst nextConfig: NextConfig = {}\n\nexport default nextConfig\n"
+ },
+ "time": {
+ "start": 1781392511173,
+ "end": 1781392511176
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:11.493Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "args": {
+ "filePath": "/workspace/tsconfig.json",
+ "_extractedPath": "/workspace/tsconfig.json"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392511493,
+ "sessionID": "ses_13cbb922affe86wOEqVAq01qO3",
+ "part": {
+ "id": "prt_ec34490c7001TlpxNiS4x1Ln72",
+ "sessionID": "ses_13cbb922affe86wOEqVAq01qO3",
+ "messageID": "msg_ec3447c6d001IrdJjg2Jsx0WbL",
+ "type": "tool",
+ "callID": "read_8",
+ "tool": "read",
+ "state": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/tsconfig.json"
+ },
+ "output": "\n00001| {\n00002| \"compilerOptions\": {\n00003| \"target\": \"ES2017\",\n00004| \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n00005| \"allowJs\": true,\n00006| \"skipLibCheck\": true,\n00007| \"strict\": true,\n00008| \"noEmit\": true,\n00009| \"esModuleInterop\": true,\n00010| \"module\": \"esnext\",\n00011| \"moduleResolution\": \"bundler\",\n00012| \"resolveJsonModule\": true,\n00013| \"isolatedModules\": true,\n00014| \"jsx\": \"react-jsx\",\n00015| \"incremental\": true,\n00016| \"plugins\": [\n00017| {\n00018| \"name\": \"next\"\n00019| }\n00020| ],\n00021| \"paths\": {\n00022| \"@/*\": [\"./*\"]\n00023| }\n00024| },\n00025| \"include\": [\"next-env.d.ts\", \"**/*.ts\", \"**/*.tsx\", \".next/types/**/*.ts\"],\n00026| \"exclude\": [\"node_modules\"]\n00027| }\n00028| \n\n(End of file - total 28 lines)\n",
+ "title": "tsconfig.json",
+ "metadata": {
+ "preview": "{\n \"compilerOptions\": {\n \"target\": \"ES2017\",\n \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n \"allowJs\": true,\n \"skipLibCheck\": true,\n \"strict\": true,\n \"noEmit\": true,\n \"esModuleInterop\": true,\n \"module\": \"esnext\",\n \"moduleResolution\": \"bundler\",\n \"resolveJsonModule\": true,\n \"isolatedModules\": true,\n \"jsx\": \"react-jsx\",\n \"incremental\": true,\n \"plugins\": [\n {\n \"name\": \"next\"\n }\n ],"
+ },
+ "time": {
+ "start": 1781392511482,
+ "end": 1781392511485
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:11.493Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| {\n00002| \"compilerOptions\": {\n00003| \"target\": \"ES2017\",\n00004| \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n00005| \"allowJs\": true,\n00006| \"skipLibCheck\": true,\n00007| \"strict\": true,\n00008| \"noEmit\": true,\n00009| \"esModuleInterop\": true,\n00010| \"module\": \"esnext\",\n00011| \"moduleResolution\": \"bundler\",\n00012| \"resolveJsonModule\": true,\n00013| \"isolatedModules\": true,\n00014| \"jsx\": \"react-jsx\",\n00015| \"incremental\": true,\n00016| \"plugins\": [\n00017| {\n00018| \"name\": \"next\"\n00019| }\n00020| ],\n00021| \"paths\": {\n00022| \"@/*\": [\"./*\"]\n00023| }\n00024| },\n00025| \"include\": [\"next-env.d.ts\", \"**/*.ts\", \"**/*.tsx\", \".next/types/**/*.ts\"],\n00026| \"exclude\": [\"node_modules\"]\n00027| }\n00028| \n\n(End of file - total 28 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/tsconfig.json"
+ },
+ "output": "\n00001| {\n00002| \"compilerOptions\": {\n00003| \"target\": \"ES2017\",\n00004| \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n00005| \"allowJs\": true,\n00006| \"skipLibCheck\": true,\n00007| \"strict\": true,\n00008| \"noEmit\": true,\n00009| \"esModuleInterop\": true,\n00010| \"module\": \"esnext\",\n00011| \"moduleResolution\": \"bundler\",\n00012| \"resolveJsonModule\": true,\n00013| \"isolatedModules\": true,\n00014| \"jsx\": \"react-jsx\",\n00015| \"incremental\": true,\n00016| \"plugins\": [\n00017| {\n00018| \"name\": \"next\"\n00019| }\n00020| ],\n00021| \"paths\": {\n00022| \"@/*\": [\"./*\"]\n00023| }\n00024| },\n00025| \"include\": [\"next-env.d.ts\", \"**/*.ts\", \"**/*.tsx\", \".next/types/**/*.ts\"],\n00026| \"exclude\": [\"node_modules\"]\n00027| }\n00028| \n\n(End of file - total 28 lines)\n",
+ "title": "tsconfig.json",
+ "metadata": {
+ "preview": "{\n \"compilerOptions\": {\n \"target\": \"ES2017\",\n \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n \"allowJs\": true,\n \"skipLibCheck\": true,\n \"strict\": true,\n \"noEmit\": true,\n \"esModuleInterop\": true,\n \"module\": \"esnext\",\n \"moduleResolution\": \"bundler\",\n \"resolveJsonModule\": true,\n \"isolatedModules\": true,\n \"jsx\": \"react-jsx\",\n \"incremental\": true,\n \"plugins\": [\n {\n \"name\": \"next\"\n }\n ],"
+ },
+ "time": {
+ "start": 1781392511482,
+ "end": 1781392511485
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:14.651Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "shell",
+ "originalName": "bash",
+ "args": {
+ "command": "find node_modules/next -maxdepth 3 -type d -name \"docs\" 2>/dev/null | head -20",
+ "description": "Find Next.js docs directories",
+ "_extractedCommand": "find node_modules/next -maxdepth 3 -type d -name \"docs\" 2>/dev/null | head -20"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392514651,
+ "sessionID": "ses_13cbb922affe86wOEqVAq01qO3",
+ "part": {
+ "id": "prt_ec3449a59001xPLcVKnPz521lx",
+ "sessionID": "ses_13cbb922affe86wOEqVAq01qO3",
+ "messageID": "msg_ec344921a001qvzJEfL2Nu52gE",
+ "type": "tool",
+ "callID": "bash_9",
+ "tool": "bash",
+ "state": {
+ "status": "completed",
+ "input": {
+ "command": "find node_modules/next -maxdepth 3 -type d -name \"docs\" 2>/dev/null | head -20",
+ "description": "Find Next.js docs directories"
+ },
+ "output": "node_modules/next/dist/docs\n",
+ "title": "Find Next.js docs directories",
+ "metadata": {
+ "output": "node_modules/next/dist/docs\n",
+ "exit": 0,
+ "description": "Find Next.js docs directories"
+ },
+ "time": {
+ "start": 1781392514564,
+ "end": 1781392514650
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:14.651Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "shell",
+ "originalName": "bash",
+ "result": "node_modules/next/dist/docs\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "command": "find node_modules/next -maxdepth 3 -type d -name \"docs\" 2>/dev/null | head -20",
+ "description": "Find Next.js docs directories"
+ },
+ "output": "node_modules/next/dist/docs\n",
+ "title": "Find Next.js docs directories",
+ "metadata": {
+ "output": "node_modules/next/dist/docs\n",
+ "exit": 0,
+ "description": "Find Next.js docs directories"
+ },
+ "time": {
+ "start": 1781392514564,
+ "end": 1781392514650
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:15.204Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "shell",
+ "originalName": "bash",
+ "args": {
+ "command": "find node_modules/next -type f -name \"*.md\" 2>/dev/null | head -50",
+ "description": "Find Next.js markdown docs",
+ "_extractedCommand": "find node_modules/next -type f -name \"*.md\" 2>/dev/null | head -50"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392515204,
+ "sessionID": "ses_13cbb922affe86wOEqVAq01qO3",
+ "part": {
+ "id": "prt_ec3449e08001denqA8FAeTAY9P",
+ "sessionID": "ses_13cbb922affe86wOEqVAq01qO3",
+ "messageID": "msg_ec344921a001qvzJEfL2Nu52gE",
+ "type": "tool",
+ "callID": "bash_10",
+ "tool": "bash",
+ "state": {
+ "status": "completed",
+ "input": {
+ "command": "find node_modules/next -type f -name \"*.md\" 2>/dev/null | head -50",
+ "description": "Find Next.js markdown docs"
+ },
+ "output": "node_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/01-pages-and-layouts.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/02-dynamic-routes.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/03-linking-and-navigating.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/05-custom-app.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/06-custom-document.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/07-api-routes.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/08-custom-error.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/index.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/06-configuring/12-error-handling.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/06-configuring/index.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/index.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/01-get-static-props.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/02-get-static-paths.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/03-get-server-side-props.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/05-client-side.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/index.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/01-server-side-rendering.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/02-static-site-generation.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/04-automatic-static-optimization.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/05-client-side-rendering.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/index.md\nnode_modules/next/dist/docs/02-pages/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/get-initial-props.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/get-server-side-props.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/get-static-paths.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/get-static-props.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/next-request.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/next-response.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/use-params.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/use-report-web-vitals.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/use-router.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/use-search-params.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/userAgent.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-edge.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/08-turbopack.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/01-configuration.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/02-creating-an-adapter.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/03-api-reference.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/04-testing-adapters.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/05-routing-with-next-routing.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/06-implementing-ppr-in-an-adapter.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/07-runtime-integration.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/08-invoking-entrypoints.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/09-output-types.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/10-routing-information.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/11-use-cases.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/04-config/01-typescript.md\n",
+ "title": "Find Next.js markdown docs",
+ "metadata": {
+ "output": "node_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/01-pages-and-layouts.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/02-dynamic-routes.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/03-linking-and-navigating.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/05-custom-app.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/06-custom-document.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/07-api-routes.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/08-custom-error.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/index.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/06-configuring/12-error-handling.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/06-configuring/index.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/index.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/01-get-static-props.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/02-get-static-paths.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/03-get-server-side-props.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/05-client-side.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/index.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/01-server-side-rendering.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/02-static-site-generation.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/04-automatic-static-optimization.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/05-client-side-rendering.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/index.md\nnode_modules/next/dist/docs/02-pages/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/get-initial-props.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/get-server-side-props.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/get-static-paths.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/get-static-props.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/next-request.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/next-response.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/use-params.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/use-report-web-vitals.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/use-router.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/use-search-params.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/userAgent.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-edge.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/08-turbopack.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/01-configuration.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/02-creating-an-adapter.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/03-api-reference.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/04-testing-adapters.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/05-routing-with-next-routing.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/06-implementing-ppr-in-an-adapter.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/07-runtime-integration.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/08-invoking-entrypoints.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/09-output-types.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/10-routing-information.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/11-use-cases.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/04-config/01-typescript.md\n",
+ "exit": 0,
+ "description": "Find Next.js markdown docs"
+ },
+ "time": {
+ "start": 1781392515192,
+ "end": 1781392515201
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:15.204Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "shell",
+ "originalName": "bash",
+ "result": "node_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/01-pages-and-layouts.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/02-dynamic-routes.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/03-linking-and-navigating.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/05-custom-app.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/06-custom-document.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/07-api-routes.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/08-custom-error.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/index.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/06-configuring/12-error-handling.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/06-configuring/index.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/index.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/01-get-static-props.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/02-get-static-paths.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/03-get-server-side-props.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/05-client-side.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/index.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/01-server-side-rendering.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/02-static-site-generation.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/04-automatic-static-optimization.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/05-client-side-rendering.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/index.md\nnode_modules/next/dist/docs/02-pages/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/get-initial-props.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/get-server-side-props.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/get-static-paths.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/get-static-props.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/next-request.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/next-response.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/use-params.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/use-report-web-vitals.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/use-router.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/use-search-params.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/userAgent.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-edge.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/08-turbopack.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/01-configuration.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/02-creating-an-adapter.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/03-api-reference.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/04-testing-adapters.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/05-routing-with-next-routing.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/06-implementing-ppr-in-an-adapter.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/07-runtime-integration.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/08-invoking-entrypoints.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/09-output-types.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/10-routing-information.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/11-use-cases.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/04-config/01-typescript.md\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "command": "find node_modules/next -type f -name \"*.md\" 2>/dev/null | head -50",
+ "description": "Find Next.js markdown docs"
+ },
+ "output": "node_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/01-pages-and-layouts.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/02-dynamic-routes.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/03-linking-and-navigating.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/05-custom-app.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/06-custom-document.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/07-api-routes.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/08-custom-error.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/index.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/06-configuring/12-error-handling.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/06-configuring/index.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/index.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/01-get-static-props.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/02-get-static-paths.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/03-get-server-side-props.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/05-client-side.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/index.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/01-server-side-rendering.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/02-static-site-generation.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/04-automatic-static-optimization.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/05-client-side-rendering.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/index.md\nnode_modules/next/dist/docs/02-pages/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/get-initial-props.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/get-server-side-props.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/get-static-paths.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/get-static-props.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/next-request.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/next-response.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/use-params.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/use-report-web-vitals.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/use-router.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/use-search-params.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/userAgent.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-edge.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/08-turbopack.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/01-configuration.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/02-creating-an-adapter.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/03-api-reference.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/04-testing-adapters.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/05-routing-with-next-routing.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/06-implementing-ppr-in-an-adapter.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/07-runtime-integration.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/08-invoking-entrypoints.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/09-output-types.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/10-routing-information.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/11-use-cases.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/04-config/01-typescript.md\n",
+ "title": "Find Next.js markdown docs",
+ "metadata": {
+ "output": "node_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/01-pages-and-layouts.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/02-dynamic-routes.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/03-linking-and-navigating.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/05-custom-app.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/06-custom-document.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/07-api-routes.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/08-custom-error.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/index.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/06-configuring/12-error-handling.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/06-configuring/index.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/index.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/01-get-static-props.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/02-get-static-paths.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/03-get-server-side-props.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/05-client-side.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/index.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/01-server-side-rendering.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/02-static-site-generation.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/04-automatic-static-optimization.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/05-client-side-rendering.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/index.md\nnode_modules/next/dist/docs/02-pages/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/get-initial-props.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/get-server-side-props.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/get-static-paths.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/get-static-props.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/next-request.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/next-response.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/use-params.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/use-report-web-vitals.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/use-router.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/use-search-params.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/userAgent.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-edge.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/08-turbopack.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/01-configuration.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/02-creating-an-adapter.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/03-api-reference.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/04-testing-adapters.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/05-routing-with-next-routing.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/06-implementing-ppr-in-an-adapter.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/07-runtime-integration.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/08-invoking-entrypoints.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/09-output-types.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/10-routing-information.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/11-use-cases.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/04-config/01-typescript.md\n",
+ "exit": 0,
+ "description": "Find Next.js markdown docs"
+ },
+ "time": {
+ "start": 1781392515192,
+ "end": 1781392515201
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:18.608Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "shell",
+ "originalName": "bash",
+ "args": {
+ "command": "find node_modules/next/dist/docs -type f -name \"*.md\" | xargs grep -l -i \"cache tag\\|revalidateTag\\|unstable_cache\" 2>/dev/null | head -20",
+ "description": "Find docs about cache tags",
+ "_extractedCommand": "find node_modules/next/dist/docs -type f -name \"*.md\" | xargs grep -l -i \"cache tag\\|revalidateTag\\|unstable_cache\" 2>/dev/null | head -20"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392518608,
+ "sessionID": "ses_13cbb922affe86wOEqVAq01qO3",
+ "part": {
+ "id": "prt_ec344a9680012UKbHkDu3sVQrW",
+ "sessionID": "ses_13cbb922affe86wOEqVAq01qO3",
+ "messageID": "msg_ec344a0a7001s1Lif3OURR0h5H",
+ "type": "tool",
+ "callID": "bash_11",
+ "tool": "bash",
+ "state": {
+ "status": "completed",
+ "input": {
+ "command": "find node_modules/next/dist/docs -type f -name \"*.md\" | xargs grep -l -i \"cache tag\\|revalidateTag\\|unstable_cache\" 2>/dev/null | head -20",
+ "description": "Find docs about cache tags"
+ },
+ "output": "node_modules/next/dist/docs/01-app/02-guides/backend-for-frontend.md\nnode_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/cdn-caching.md\nnode_modules/next/dist/docs/01-app/02-guides/deploying-to-platforms.md\nnode_modules/next/dist/docs/01-app/02-guides/draft-mode.md\nnode_modules/next/dist/docs/01-app/02-guides/how-revalidation-works.md\nnode_modules/next/dist/docs/01-app/02-guides/incremental-static-regeneration.md\nnode_modules/next/dist/docs/01-app/02-guides/migrating-to-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/ppr-platform-guide.md\nnode_modules/next/dist/docs/01-app/02-guides/prefetching.md\nnode_modules/next/dist/docs/01-app/02-guides/production-checklist.md\nnode_modules/next/dist/docs/01-app/02-guides/redirecting.md\nnode_modules/next/dist/docs/01-app/02-guides/rendering-philosophy.md\nnode_modules/next/dist/docs/01-app/02-guides/self-hosting.md\nnode_modules/next/dist/docs/01-app/02-guides/upgrading/codemods.md\nnode_modules/next/dist/docs/01-app/02-guides/upgrading/version-16.md\nnode_modules/next/dist/docs/01-app/04-glossary.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheLife.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cookies.md\n",
+ "title": "Find docs about cache tags",
+ "metadata": {
+ "output": "node_modules/next/dist/docs/01-app/02-guides/backend-for-frontend.md\nnode_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/cdn-caching.md\nnode_modules/next/dist/docs/01-app/02-guides/deploying-to-platforms.md\nnode_modules/next/dist/docs/01-app/02-guides/draft-mode.md\nnode_modules/next/dist/docs/01-app/02-guides/how-revalidation-works.md\nnode_modules/next/dist/docs/01-app/02-guides/incremental-static-regeneration.md\nnode_modules/next/dist/docs/01-app/02-guides/migrating-to-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/ppr-platform-guide.md\nnode_modules/next/dist/docs/01-app/02-guides/prefetching.md\nnode_modules/next/dist/docs/01-app/02-guides/production-checklist.md\nnode_modules/next/dist/docs/01-app/02-guides/redirecting.md\nnode_modules/next/dist/docs/01-app/02-guides/rendering-philosophy.md\nnode_modules/next/dist/docs/01-app/02-guides/self-hosting.md\nnode_modules/next/dist/docs/01-app/02-guides/upgrading/codemods.md\nnode_modules/next/dist/docs/01-app/02-guides/upgrading/version-16.md\nnode_modules/next/dist/docs/01-app/04-glossary.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheLife.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cookies.md\n",
+ "exit": 0,
+ "description": "Find docs about cache tags"
+ },
+ "time": {
+ "start": 1781392518576,
+ "end": 1781392518608
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:18.608Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "shell",
+ "originalName": "bash",
+ "result": "node_modules/next/dist/docs/01-app/02-guides/backend-for-frontend.md\nnode_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/cdn-caching.md\nnode_modules/next/dist/docs/01-app/02-guides/deploying-to-platforms.md\nnode_modules/next/dist/docs/01-app/02-guides/draft-mode.md\nnode_modules/next/dist/docs/01-app/02-guides/how-revalidation-works.md\nnode_modules/next/dist/docs/01-app/02-guides/incremental-static-regeneration.md\nnode_modules/next/dist/docs/01-app/02-guides/migrating-to-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/ppr-platform-guide.md\nnode_modules/next/dist/docs/01-app/02-guides/prefetching.md\nnode_modules/next/dist/docs/01-app/02-guides/production-checklist.md\nnode_modules/next/dist/docs/01-app/02-guides/redirecting.md\nnode_modules/next/dist/docs/01-app/02-guides/rendering-philosophy.md\nnode_modules/next/dist/docs/01-app/02-guides/self-hosting.md\nnode_modules/next/dist/docs/01-app/02-guides/upgrading/codemods.md\nnode_modules/next/dist/docs/01-app/02-guides/upgrading/version-16.md\nnode_modules/next/dist/docs/01-app/04-glossary.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheLife.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cookies.md\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "command": "find node_modules/next/dist/docs -type f -name \"*.md\" | xargs grep -l -i \"cache tag\\|revalidateTag\\|unstable_cache\" 2>/dev/null | head -20",
+ "description": "Find docs about cache tags"
+ },
+ "output": "node_modules/next/dist/docs/01-app/02-guides/backend-for-frontend.md\nnode_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/cdn-caching.md\nnode_modules/next/dist/docs/01-app/02-guides/deploying-to-platforms.md\nnode_modules/next/dist/docs/01-app/02-guides/draft-mode.md\nnode_modules/next/dist/docs/01-app/02-guides/how-revalidation-works.md\nnode_modules/next/dist/docs/01-app/02-guides/incremental-static-regeneration.md\nnode_modules/next/dist/docs/01-app/02-guides/migrating-to-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/ppr-platform-guide.md\nnode_modules/next/dist/docs/01-app/02-guides/prefetching.md\nnode_modules/next/dist/docs/01-app/02-guides/production-checklist.md\nnode_modules/next/dist/docs/01-app/02-guides/redirecting.md\nnode_modules/next/dist/docs/01-app/02-guides/rendering-philosophy.md\nnode_modules/next/dist/docs/01-app/02-guides/self-hosting.md\nnode_modules/next/dist/docs/01-app/02-guides/upgrading/codemods.md\nnode_modules/next/dist/docs/01-app/02-guides/upgrading/version-16.md\nnode_modules/next/dist/docs/01-app/04-glossary.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheLife.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cookies.md\n",
+ "title": "Find docs about cache tags",
+ "metadata": {
+ "output": "node_modules/next/dist/docs/01-app/02-guides/backend-for-frontend.md\nnode_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/cdn-caching.md\nnode_modules/next/dist/docs/01-app/02-guides/deploying-to-platforms.md\nnode_modules/next/dist/docs/01-app/02-guides/draft-mode.md\nnode_modules/next/dist/docs/01-app/02-guides/how-revalidation-works.md\nnode_modules/next/dist/docs/01-app/02-guides/incremental-static-regeneration.md\nnode_modules/next/dist/docs/01-app/02-guides/migrating-to-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/ppr-platform-guide.md\nnode_modules/next/dist/docs/01-app/02-guides/prefetching.md\nnode_modules/next/dist/docs/01-app/02-guides/production-checklist.md\nnode_modules/next/dist/docs/01-app/02-guides/redirecting.md\nnode_modules/next/dist/docs/01-app/02-guides/rendering-philosophy.md\nnode_modules/next/dist/docs/01-app/02-guides/self-hosting.md\nnode_modules/next/dist/docs/01-app/02-guides/upgrading/codemods.md\nnode_modules/next/dist/docs/01-app/02-guides/upgrading/version-16.md\nnode_modules/next/dist/docs/01-app/04-glossary.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheLife.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cookies.md\n",
+ "exit": 0,
+ "description": "Find docs about cache tags"
+ },
+ "time": {
+ "start": 1781392518576,
+ "end": 1781392518608
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:19.283Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "shell",
+ "originalName": "bash",
+ "args": {
+ "command": "find node_modules/next/dist/docs -type f -name \"*.md\" | xargs grep -l -i \"server action\" 2>/dev/null | head -20",
+ "description": "Find docs about Server Actions",
+ "_extractedCommand": "find node_modules/next/dist/docs -type f -name \"*.md\" | xargs grep -l -i \"server action\" 2>/dev/null | head -20"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392519283,
+ "sessionID": "ses_13cbb922affe86wOEqVAq01qO3",
+ "part": {
+ "id": "prt_ec344adb4001XV4Gh6k8bK5H6x",
+ "sessionID": "ses_13cbb922affe86wOEqVAq01qO3",
+ "messageID": "msg_ec344a0a7001s1Lif3OURR0h5H",
+ "type": "tool",
+ "callID": "bash_12",
+ "tool": "bash",
+ "state": {
+ "status": "completed",
+ "input": {
+ "command": "find node_modules/next/dist/docs -type f -name \"*.md\" | xargs grep -l -i \"server action\" 2>/dev/null | head -20",
+ "description": "Find docs about Server Actions"
+ },
+ "output": "node_modules/next/dist/docs/01-app/02-guides/authentication.md\nnode_modules/next/dist/docs/01-app/02-guides/backend-for-frontend.md\nnode_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/data-security.md\nnode_modules/next/dist/docs/01-app/02-guides/deploying-to-platforms.md\nnode_modules/next/dist/docs/01-app/02-guides/draft-mode.md\nnode_modules/next/dist/docs/01-app/02-guides/forms.md\nnode_modules/next/dist/docs/01-app/02-guides/incremental-static-regeneration.md\nnode_modules/next/dist/docs/01-app/02-guides/internationalization.md\nnode_modules/next/dist/docs/01-app/02-guides/mcp.md\nnode_modules/next/dist/docs/01-app/02-guides/migrating-to-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/multi-zones.md\nnode_modules/next/dist/docs/01-app/02-guides/ppr-platform-guide.md\nnode_modules/next/dist/docs/01-app/02-guides/prefetching.md\nnode_modules/next/dist/docs/01-app/02-guides/production-checklist.md\nnode_modules/next/dist/docs/01-app/02-guides/progressive-web-apps.md\nnode_modules/next/dist/docs/01-app/02-guides/redirecting.md\nnode_modules/next/dist/docs/01-app/02-guides/self-hosting.md\nnode_modules/next/dist/docs/01-app/02-guides/single-page-applications.md\nnode_modules/next/dist/docs/01-app/02-guides/static-exports.md\n",
+ "title": "Find docs about Server Actions",
+ "metadata": {
+ "output": "node_modules/next/dist/docs/01-app/02-guides/authentication.md\nnode_modules/next/dist/docs/01-app/02-guides/backend-for-frontend.md\nnode_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/data-security.md\nnode_modules/next/dist/docs/01-app/02-guides/deploying-to-platforms.md\nnode_modules/next/dist/docs/01-app/02-guides/draft-mode.md\nnode_modules/next/dist/docs/01-app/02-guides/forms.md\nnode_modules/next/dist/docs/01-app/02-guides/incremental-static-regeneration.md\nnode_modules/next/dist/docs/01-app/02-guides/internationalization.md\nnode_modules/next/dist/docs/01-app/02-guides/mcp.md\nnode_modules/next/dist/docs/01-app/02-guides/migrating-to-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/multi-zones.md\nnode_modules/next/dist/docs/01-app/02-guides/ppr-platform-guide.md\nnode_modules/next/dist/docs/01-app/02-guides/prefetching.md\nnode_modules/next/dist/docs/01-app/02-guides/production-checklist.md\nnode_modules/next/dist/docs/01-app/02-guides/progressive-web-apps.md\nnode_modules/next/dist/docs/01-app/02-guides/redirecting.md\nnode_modules/next/dist/docs/01-app/02-guides/self-hosting.md\nnode_modules/next/dist/docs/01-app/02-guides/single-page-applications.md\nnode_modules/next/dist/docs/01-app/02-guides/static-exports.md\n",
+ "exit": 0,
+ "description": "Find docs about Server Actions"
+ },
+ "time": {
+ "start": 1781392519273,
+ "end": 1781392519282
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:19.283Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "shell",
+ "originalName": "bash",
+ "result": "node_modules/next/dist/docs/01-app/02-guides/authentication.md\nnode_modules/next/dist/docs/01-app/02-guides/backend-for-frontend.md\nnode_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/data-security.md\nnode_modules/next/dist/docs/01-app/02-guides/deploying-to-platforms.md\nnode_modules/next/dist/docs/01-app/02-guides/draft-mode.md\nnode_modules/next/dist/docs/01-app/02-guides/forms.md\nnode_modules/next/dist/docs/01-app/02-guides/incremental-static-regeneration.md\nnode_modules/next/dist/docs/01-app/02-guides/internationalization.md\nnode_modules/next/dist/docs/01-app/02-guides/mcp.md\nnode_modules/next/dist/docs/01-app/02-guides/migrating-to-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/multi-zones.md\nnode_modules/next/dist/docs/01-app/02-guides/ppr-platform-guide.md\nnode_modules/next/dist/docs/01-app/02-guides/prefetching.md\nnode_modules/next/dist/docs/01-app/02-guides/production-checklist.md\nnode_modules/next/dist/docs/01-app/02-guides/progressive-web-apps.md\nnode_modules/next/dist/docs/01-app/02-guides/redirecting.md\nnode_modules/next/dist/docs/01-app/02-guides/self-hosting.md\nnode_modules/next/dist/docs/01-app/02-guides/single-page-applications.md\nnode_modules/next/dist/docs/01-app/02-guides/static-exports.md\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "command": "find node_modules/next/dist/docs -type f -name \"*.md\" | xargs grep -l -i \"server action\" 2>/dev/null | head -20",
+ "description": "Find docs about Server Actions"
+ },
+ "output": "node_modules/next/dist/docs/01-app/02-guides/authentication.md\nnode_modules/next/dist/docs/01-app/02-guides/backend-for-frontend.md\nnode_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/data-security.md\nnode_modules/next/dist/docs/01-app/02-guides/deploying-to-platforms.md\nnode_modules/next/dist/docs/01-app/02-guides/draft-mode.md\nnode_modules/next/dist/docs/01-app/02-guides/forms.md\nnode_modules/next/dist/docs/01-app/02-guides/incremental-static-regeneration.md\nnode_modules/next/dist/docs/01-app/02-guides/internationalization.md\nnode_modules/next/dist/docs/01-app/02-guides/mcp.md\nnode_modules/next/dist/docs/01-app/02-guides/migrating-to-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/multi-zones.md\nnode_modules/next/dist/docs/01-app/02-guides/ppr-platform-guide.md\nnode_modules/next/dist/docs/01-app/02-guides/prefetching.md\nnode_modules/next/dist/docs/01-app/02-guides/production-checklist.md\nnode_modules/next/dist/docs/01-app/02-guides/progressive-web-apps.md\nnode_modules/next/dist/docs/01-app/02-guides/redirecting.md\nnode_modules/next/dist/docs/01-app/02-guides/self-hosting.md\nnode_modules/next/dist/docs/01-app/02-guides/single-page-applications.md\nnode_modules/next/dist/docs/01-app/02-guides/static-exports.md\n",
+ "title": "Find docs about Server Actions",
+ "metadata": {
+ "output": "node_modules/next/dist/docs/01-app/02-guides/authentication.md\nnode_modules/next/dist/docs/01-app/02-guides/backend-for-frontend.md\nnode_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/data-security.md\nnode_modules/next/dist/docs/01-app/02-guides/deploying-to-platforms.md\nnode_modules/next/dist/docs/01-app/02-guides/draft-mode.md\nnode_modules/next/dist/docs/01-app/02-guides/forms.md\nnode_modules/next/dist/docs/01-app/02-guides/incremental-static-regeneration.md\nnode_modules/next/dist/docs/01-app/02-guides/internationalization.md\nnode_modules/next/dist/docs/01-app/02-guides/mcp.md\nnode_modules/next/dist/docs/01-app/02-guides/migrating-to-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/multi-zones.md\nnode_modules/next/dist/docs/01-app/02-guides/ppr-platform-guide.md\nnode_modules/next/dist/docs/01-app/02-guides/prefetching.md\nnode_modules/next/dist/docs/01-app/02-guides/production-checklist.md\nnode_modules/next/dist/docs/01-app/02-guides/progressive-web-apps.md\nnode_modules/next/dist/docs/01-app/02-guides/redirecting.md\nnode_modules/next/dist/docs/01-app/02-guides/self-hosting.md\nnode_modules/next/dist/docs/01-app/02-guides/single-page-applications.md\nnode_modules/next/dist/docs/01-app/02-guides/static-exports.md\n",
+ "exit": 0,
+ "description": "Find docs about Server Actions"
+ },
+ "time": {
+ "start": 1781392519273,
+ "end": 1781392519282
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:23.004Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "args": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md",
+ "_extractedPath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392523004,
+ "sessionID": "ses_13cbb922affe86wOEqVAq01qO3",
+ "part": {
+ "id": "prt_ec344b8f5001m3S53q9Vd8Z52y",
+ "sessionID": "ses_13cbb922affe86wOEqVAq01qO3",
+ "messageID": "msg_ec344b081001UDgqI32s2JbBcf",
+ "type": "tool",
+ "callID": "read_13",
+ "tool": "read",
+ "state": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md"
+ },
+ "output": "\n00001| ---\n00002| title: cacheTag\n00003| description: Learn how to use the cacheTag function to manage cache invalidation in your Next.js application.\n00004| related:\n00005| title: Related\n00006| description: View related API references.\n00007| links:\n00008| - app/api-reference/config/next-config-js/cacheComponents\n00009| - app/api-reference/directives/use-cache\n00010| - app/api-reference/functions/revalidateTag\n00011| - app/api-reference/functions/updateTag\n00012| - app/api-reference/functions/cacheLife\n00013| ---\n00014| \n00015| The `cacheTag` function allows you to tag cached data for on-demand invalidation. By associating tags with cache entries, you can selectively purge or revalidate specific cache entries without affecting other cached data.\n00016| \n00017| ## Usage\n00018| \n00019| To use `cacheTag`, enable the [`cacheComponents` flag](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.js` file:\n00020| \n00021| ```ts filename=\"next.config.ts\" switcher\n00022| import type { NextConfig } from 'next'\n00023| \n00024| const nextConfig: NextConfig = {\n00025| cacheComponents: true,\n00026| }\n00027| \n00028| export default nextConfig\n00029| ```\n00030| \n00031| ```js filename=\"next.config.js\" switcher\n00032| const nextConfig = {\n00033| cacheComponents: true,\n00034| }\n00035| \n00036| export default nextConfig\n00037| ```\n00038| \n00039| The `cacheTag` function takes one or more string values.\n00040| \n00041| ```tsx filename=\"app/data.ts\" switcher\n00042| import { cacheTag } from 'next/cache'\n00043| \n00044| export async function getData() {\n00045| 'use cache'\n00046| cacheTag('my-data')\n00047| const data = await fetch('/api/data')\n00048| return data\n00049| }\n00050| ```\n00051| \n00052| ```jsx filename=\"app/data.js\" switcher\n00053| import { cacheTag } from 'next/cache'\n00054| \n00055| export async function getData() {\n00056| 'use cache'\n00057| cacheTag('my-data')\n00058| const data = await fetch('/api/data')\n00059| return data\n00060| }\n00061| ```\n00062| \n00063| You can then purge the cache on-demand from a [Server Function](/docs/app/getting-started/mutating-data) or [Route Handler](/docs/app/api-reference/file-conventions/route):\n00064| \n00065| - Use [`updateTag`](/docs/app/api-reference/functions/updateTag) for read-your-own-writes scenarios, such as forms and other user-triggered mutations, where a user makes a change and the next read should fetch fresh data immediately. `updateTag` is only available inside Server Functions.\n00066| - Use [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) when it is acceptable to serve stale data while revalidation happens in the background, or when revalidating from a [Route Handler](/docs/app/api-reference/file-conventions/route) or other context.\n00067| \n00068| For example, this Server Function adds a post and then purges every cache entry tagged `'my-data'` so the next read reflects the change:\n00069| \n00070| ```tsx filename=\"app/action.ts\" switcher\n00071| 'use server'\n00072| \n00073| import { updateTag } from 'next/cache'\n00074| \n00075| export default async function submit() {\n00076| await addPost()\n00077| updateTag('my-data')\n00078| }\n00079| ```\n00080| \n00081| ```jsx filename=\"app/action.js\" switcher\n00082| 'use server'\n00083| \n00084| import { updateTag } from 'next/cache'\n00085| \n00086| export default async function submit() {\n00087| await addPost()\n00088| updateTag('my-data')\n00089| }\n00090| ```\n00091| \n00092| ## Good to know\n00093| \n00094| - **Idempotent Tags**: Applying the same tag multiple times has no additional effect.\n00095| - **Multiple Tags**: You can assign multiple tags to a single cache entry by passing multiple string values to `cacheTag`.\n00096| \n00097| ```tsx\n00098| cacheTag('tag-one', 'tag-two')\n00099| ```\n00100| \n00101| - **Limits**: A single `cacheTag()` call accepts up to 128 tags, each with a maximum length of 256 characters. Tags longer than 256 characters are skipped, and any tags past the 128th in one call are dropped. Both cases log a console warning.\n00102| \n00103| ## Examples\n00104| \n00105| ### Tagging components or functions\n00106| \n00107| Tag your cached data by calling `cacheTag` within a cached function or component:\n00108| \n00109| ```tsx filename=\"app/components/bookings.tsx\" switcher\n00110| import { cacheTag } from 'next/cache'\n00111| \n00112| interface BookingsProps {\n00113| type: string\n00114| }\n00115| \n00116| export async function Bookings({ type = 'haircut' }: BookingsProps) {\n00117| 'use cache'\n00118| cacheTag('bookings-data')\n00119| \n00120| async function getBookingsData() {\n00121| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00122| return data\n00123| }\n00124| \n00125| return //...\n00126| }\n00127| ```\n00128| \n00129| ```jsx filename=\"app/components/bookings.js\" switcher\n00130| import { cacheTag } from 'next/cache'\n00131| \n00132| export async function Bookings({ type = 'haircut' }) {\n00133| 'use cache'\n00134| cacheTag('bookings-data')\n00135| \n00136| async function getBookingsData() {\n00137| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00138| return data\n00139| }\n00140| \n00141| return //...\n00142| }\n00143| ```\n00144| \n00145| ### Creating tags from external data\n00146| \n00147| You can use the data returned from an async function to tag the cache entry.\n00148| \n00149| ```tsx filename=\"app/components/bookings.tsx\" switcher\n00150| import { cacheTag } from 'next/cache'\n00151| \n00152| interface BookingsProps {\n00153| type: string\n00154| }\n00155| \n00156| export async function Bookings({ type = 'haircut' }: BookingsProps) {\n00157| async function getBookingsData() {\n00158| 'use cache'\n00159| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00160| cacheTag('bookings-data', data.id)\n00161| return data\n00162| }\n00163| return //...\n00164| }\n00165| ```\n00166| \n00167| ```jsx filename=\"app/components/bookings.js\" switcher\n00168| import { cacheTag } from 'next/cache'\n00169| \n00170| export async function Bookings({ type = 'haircut' }) {\n00171| async function getBookingsData() {\n00172| 'use cache'\n00173| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00174| cacheTag('bookings-data', data.id)\n00175| return data\n00176| }\n00177| return //...\n00178| }\n00179| ```\n00180| \n00181| ### Invalidating tagged cache\n00182| \n00183| Using [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag), you can invalidate the cache for a specific tag when needed:\n00184| \n00185| ```tsx filename=\"app/actions.ts\" switcher\n00186| 'use server'\n00187| \n00188| import { revalidateTag } from 'next/cache'\n00189| \n00190| export async function updateBookings() {\n00191| await updateBookingData()\n00192| revalidateTag('bookings-data', 'max')\n00193| }\n00194| ```\n00195| \n00196| ```jsx filename=\"app/actions.js\" switcher\n00197| 'use server'\n00198| \n00199| import { revalidateTag } from 'next/cache'\n00200| \n00201| export async function updateBookings() {\n00202| await updateBookingData()\n00203| revalidateTag('bookings-data', 'max')\n00204| }\n00205| ```\n00206| \n\n(End of file - total 206 lines)\n",
+ "title": "node_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md",
+ "metadata": {
+ "preview": "---\ntitle: cacheTag\ndescription: Learn how to use the cacheTag function to manage cache invalidation in your Next.js application.\nrelated:\n title: Related\n description: View related API references.\n links:\n - app/api-reference/config/next-config-js/cacheComponents\n - app/api-reference/directives/use-cache\n - app/api-reference/functions/revalidateTag\n - app/api-reference/functions/updateTag\n - app/api-reference/functions/cacheLife\n---\n\nThe `cacheTag` function allows you to tag cached data for on-demand invalidation. By associating tags with cache entries, you can selectively purge or revalidate specific cache entries without affecting other cached data.\n\n## Usage\n\nTo use `cacheTag`, enable the [`cacheComponents` flag](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.js` file:\n"
+ },
+ "time": {
+ "start": 1781392522995,
+ "end": 1781392523000
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:23.004Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| ---\n00002| title: cacheTag\n00003| description: Learn how to use the cacheTag function to manage cache invalidation in your Next.js application.\n00004| related:\n00005| title: Related\n00006| description: View related API references.\n00007| links:\n00008| - app/api-reference/config/next-config-js/cacheComponents\n00009| - app/api-reference/directives/use-cache\n00010| - app/api-reference/functions/revalidateTag\n00011| - app/api-reference/functions/updateTag\n00012| - app/api-reference/functions/cacheLife\n00013| ---\n00014| \n00015| The `cacheTag` function allows you to tag cached data for on-demand invalidation. By associating tags with cache entries, you can selectively purge or revalidate specific cache entries without affecting other cached data.\n00016| \n00017| ## Usage\n00018| \n00019| To use `cacheTag`, enable the [`cacheComponents` flag](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.js` file:\n00020| \n00021| ```ts filename=\"next.config.ts\" switcher\n00022| import type { NextConfig } from 'next'\n00023| \n00024| const nextConfig: NextConfig = {\n00025| cacheComponents: true,\n00026| }\n00027| \n00028| export default nextConfig\n00029| ```\n00030| \n00031| ```js filename=\"next.config.js\" switcher\n00032| const nextConfig = {\n00033| cacheComponents: true,\n00034| }\n00035| \n00036| export default nextConfig\n00037| ```\n00038| \n00039| The `cacheTag` function takes one or more string values.\n00040| \n00041| ```tsx filename=\"app/data.ts\" switcher\n00042| import { cacheTag } from 'next/cache'\n00043| \n00044| export async function getData() {\n00045| 'use cache'\n00046| cacheTag('my-data')\n00047| const data = await fetch('/api/data')\n00048| return data\n00049| }\n00050| ```\n00051| \n00052| ```jsx filename=\"app/data.js\" switcher\n00053| import { cacheTag } from 'next/cache'\n00054| \n00055| export async function getData() {\n00056| 'use cache'\n00057| cacheTag('my-data')\n00058| const data = await fetch('/api/data')\n00059| return data\n00060| }\n00061| ```\n00062| \n00063| You can then purge the cache on-demand from a [Server Function](/docs/app/getting-started/mutating-data) or [Route Handler](/docs/app/api-reference/file-conventions/route):\n00064| \n00065| - Use [`updateTag`](/docs/app/api-reference/functions/updateTag) for read-your-own-writes scenarios, such as forms and other user-triggered mutations, where a user makes a change and the next read should fetch fresh data immediately. `updateTag` is only available inside Server Functions.\n00066| - Use [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) when it is acceptable to serve stale data while revalidation happens in the background, or when revalidating from a [Route Handler](/docs/app/api-reference/file-conventions/route) or other context.\n00067| \n00068| For example, this Server Function adds a post and then purges every cache entry tagged `'my-data'` so the next read reflects the change:\n00069| \n00070| ```tsx filename=\"app/action.ts\" switcher\n00071| 'use server'\n00072| \n00073| import { updateTag } from 'next/cache'\n00074| \n00075| export default async function submit() {\n00076| await addPost()\n00077| updateTag('my-data')\n00078| }\n00079| ```\n00080| \n00081| ```jsx filename=\"app/action.js\" switcher\n00082| 'use server'\n00083| \n00084| import { updateTag } from 'next/cache'\n00085| \n00086| export default async function submit() {\n00087| await addPost()\n00088| updateTag('my-data')\n00089| }\n00090| ```\n00091| \n00092| ## Good to know\n00093| \n00094| - **Idempotent Tags**: Applying the same tag multiple times has no additional effect.\n00095| - **Multiple Tags**: You can assign multiple tags to a single cache entry by passing multiple string values to `cacheTag`.\n00096| \n00097| ```tsx\n00098| cacheTag('tag-one', 'tag-two')\n00099| ```\n00100| \n00101| - **Limits**: A single `cacheTag()` call accepts up to 128 tags, each with a maximum length of 256 characters. Tags longer than 256 characters are skipped, and any tags past the 128th in one call are dropped. Both cases log a console warning.\n00102| \n00103| ## Examples\n00104| \n00105| ### Tagging components or functions\n00106| \n00107| Tag your cached data by calling `cacheTag` within a cached function or component:\n00108| \n00109| ```tsx filename=\"app/components/bookings.tsx\" switcher\n00110| import { cacheTag } from 'next/cache'\n00111| \n00112| interface BookingsProps {\n00113| type: string\n00114| }\n00115| \n00116| export async function Bookings({ type = 'haircut' }: BookingsProps) {\n00117| 'use cache'\n00118| cacheTag('bookings-data')\n00119| \n00120| async function getBookingsData() {\n00121| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00122| return data\n00123| }\n00124| \n00125| return //...\n00126| }\n00127| ```\n00128| \n00129| ```jsx filename=\"app/components/bookings.js\" switcher\n00130| import { cacheTag } from 'next/cache'\n00131| \n00132| export async function Bookings({ type = 'haircut' }) {\n00133| 'use cache'\n00134| cacheTag('bookings-data')\n00135| \n00136| async function getBookingsData() {\n00137| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00138| return data\n00139| }\n00140| \n00141| return //...\n00142| }\n00143| ```\n00144| \n00145| ### Creating tags from external data\n00146| \n00147| You can use the data returned from an async function to tag the cache entry.\n00148| \n00149| ```tsx filename=\"app/components/bookings.tsx\" switcher\n00150| import { cacheTag } from 'next/cache'\n00151| \n00152| interface BookingsProps {\n00153| type: string\n00154| }\n00155| \n00156| export async function Bookings({ type = 'haircut' }: BookingsProps) {\n00157| async function getBookingsData() {\n00158| 'use cache'\n00159| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00160| cacheTag('bookings-data', data.id)\n00161| return data\n00162| }\n00163| return //...\n00164| }\n00165| ```\n00166| \n00167| ```jsx filename=\"app/components/bookings.js\" switcher\n00168| import { cacheTag } from 'next/cache'\n00169| \n00170| export async function Bookings({ type = 'haircut' }) {\n00171| async function getBookingsData() {\n00172| 'use cache'\n00173| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00174| cacheTag('bookings-data', data.id)\n00175| return data\n00176| }\n00177| return //...\n00178| }\n00179| ```\n00180| \n00181| ### Invalidating tagged cache\n00182| \n00183| Using [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag), you can invalidate the cache for a specific tag when needed:\n00184| \n00185| ```tsx filename=\"app/actions.ts\" switcher\n00186| 'use server'\n00187| \n00188| import { revalidateTag } from 'next/cache'\n00189| \n00190| export async function updateBookings() {\n00191| await updateBookingData()\n00192| revalidateTag('bookings-data', 'max')\n00193| }\n00194| ```\n00195| \n00196| ```jsx filename=\"app/actions.js\" switcher\n00197| 'use server'\n00198| \n00199| import { revalidateTag } from 'next/cache'\n00200| \n00201| export async function updateBookings() {\n00202| await updateBookingData()\n00203| revalidateTag('bookings-data', 'max')\n00204| }\n00205| ```\n00206| \n\n(End of file - total 206 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md"
+ },
+ "output": "\n00001| ---\n00002| title: cacheTag\n00003| description: Learn how to use the cacheTag function to manage cache invalidation in your Next.js application.\n00004| related:\n00005| title: Related\n00006| description: View related API references.\n00007| links:\n00008| - app/api-reference/config/next-config-js/cacheComponents\n00009| - app/api-reference/directives/use-cache\n00010| - app/api-reference/functions/revalidateTag\n00011| - app/api-reference/functions/updateTag\n00012| - app/api-reference/functions/cacheLife\n00013| ---\n00014| \n00015| The `cacheTag` function allows you to tag cached data for on-demand invalidation. By associating tags with cache entries, you can selectively purge or revalidate specific cache entries without affecting other cached data.\n00016| \n00017| ## Usage\n00018| \n00019| To use `cacheTag`, enable the [`cacheComponents` flag](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.js` file:\n00020| \n00021| ```ts filename=\"next.config.ts\" switcher\n00022| import type { NextConfig } from 'next'\n00023| \n00024| const nextConfig: NextConfig = {\n00025| cacheComponents: true,\n00026| }\n00027| \n00028| export default nextConfig\n00029| ```\n00030| \n00031| ```js filename=\"next.config.js\" switcher\n00032| const nextConfig = {\n00033| cacheComponents: true,\n00034| }\n00035| \n00036| export default nextConfig\n00037| ```\n00038| \n00039| The `cacheTag` function takes one or more string values.\n00040| \n00041| ```tsx filename=\"app/data.ts\" switcher\n00042| import { cacheTag } from 'next/cache'\n00043| \n00044| export async function getData() {\n00045| 'use cache'\n00046| cacheTag('my-data')\n00047| const data = await fetch('/api/data')\n00048| return data\n00049| }\n00050| ```\n00051| \n00052| ```jsx filename=\"app/data.js\" switcher\n00053| import { cacheTag } from 'next/cache'\n00054| \n00055| export async function getData() {\n00056| 'use cache'\n00057| cacheTag('my-data')\n00058| const data = await fetch('/api/data')\n00059| return data\n00060| }\n00061| ```\n00062| \n00063| You can then purge the cache on-demand from a [Server Function](/docs/app/getting-started/mutating-data) or [Route Handler](/docs/app/api-reference/file-conventions/route):\n00064| \n00065| - Use [`updateTag`](/docs/app/api-reference/functions/updateTag) for read-your-own-writes scenarios, such as forms and other user-triggered mutations, where a user makes a change and the next read should fetch fresh data immediately. `updateTag` is only available inside Server Functions.\n00066| - Use [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) when it is acceptable to serve stale data while revalidation happens in the background, or when revalidating from a [Route Handler](/docs/app/api-reference/file-conventions/route) or other context.\n00067| \n00068| For example, this Server Function adds a post and then purges every cache entry tagged `'my-data'` so the next read reflects the change:\n00069| \n00070| ```tsx filename=\"app/action.ts\" switcher\n00071| 'use server'\n00072| \n00073| import { updateTag } from 'next/cache'\n00074| \n00075| export default async function submit() {\n00076| await addPost()\n00077| updateTag('my-data')\n00078| }\n00079| ```\n00080| \n00081| ```jsx filename=\"app/action.js\" switcher\n00082| 'use server'\n00083| \n00084| import { updateTag } from 'next/cache'\n00085| \n00086| export default async function submit() {\n00087| await addPost()\n00088| updateTag('my-data')\n00089| }\n00090| ```\n00091| \n00092| ## Good to know\n00093| \n00094| - **Idempotent Tags**: Applying the same tag multiple times has no additional effect.\n00095| - **Multiple Tags**: You can assign multiple tags to a single cache entry by passing multiple string values to `cacheTag`.\n00096| \n00097| ```tsx\n00098| cacheTag('tag-one', 'tag-two')\n00099| ```\n00100| \n00101| - **Limits**: A single `cacheTag()` call accepts up to 128 tags, each with a maximum length of 256 characters. Tags longer than 256 characters are skipped, and any tags past the 128th in one call are dropped. Both cases log a console warning.\n00102| \n00103| ## Examples\n00104| \n00105| ### Tagging components or functions\n00106| \n00107| Tag your cached data by calling `cacheTag` within a cached function or component:\n00108| \n00109| ```tsx filename=\"app/components/bookings.tsx\" switcher\n00110| import { cacheTag } from 'next/cache'\n00111| \n00112| interface BookingsProps {\n00113| type: string\n00114| }\n00115| \n00116| export async function Bookings({ type = 'haircut' }: BookingsProps) {\n00117| 'use cache'\n00118| cacheTag('bookings-data')\n00119| \n00120| async function getBookingsData() {\n00121| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00122| return data\n00123| }\n00124| \n00125| return //...\n00126| }\n00127| ```\n00128| \n00129| ```jsx filename=\"app/components/bookings.js\" switcher\n00130| import { cacheTag } from 'next/cache'\n00131| \n00132| export async function Bookings({ type = 'haircut' }) {\n00133| 'use cache'\n00134| cacheTag('bookings-data')\n00135| \n00136| async function getBookingsData() {\n00137| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00138| return data\n00139| }\n00140| \n00141| return //...\n00142| }\n00143| ```\n00144| \n00145| ### Creating tags from external data\n00146| \n00147| You can use the data returned from an async function to tag the cache entry.\n00148| \n00149| ```tsx filename=\"app/components/bookings.tsx\" switcher\n00150| import { cacheTag } from 'next/cache'\n00151| \n00152| interface BookingsProps {\n00153| type: string\n00154| }\n00155| \n00156| export async function Bookings({ type = 'haircut' }: BookingsProps) {\n00157| async function getBookingsData() {\n00158| 'use cache'\n00159| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00160| cacheTag('bookings-data', data.id)\n00161| return data\n00162| }\n00163| return //...\n00164| }\n00165| ```\n00166| \n00167| ```jsx filename=\"app/components/bookings.js\" switcher\n00168| import { cacheTag } from 'next/cache'\n00169| \n00170| export async function Bookings({ type = 'haircut' }) {\n00171| async function getBookingsData() {\n00172| 'use cache'\n00173| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00174| cacheTag('bookings-data', data.id)\n00175| return data\n00176| }\n00177| return //...\n00178| }\n00179| ```\n00180| \n00181| ### Invalidating tagged cache\n00182| \n00183| Using [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag), you can invalidate the cache for a specific tag when needed:\n00184| \n00185| ```tsx filename=\"app/actions.ts\" switcher\n00186| 'use server'\n00187| \n00188| import { revalidateTag } from 'next/cache'\n00189| \n00190| export async function updateBookings() {\n00191| await updateBookingData()\n00192| revalidateTag('bookings-data', 'max')\n00193| }\n00194| ```\n00195| \n00196| ```jsx filename=\"app/actions.js\" switcher\n00197| 'use server'\n00198| \n00199| import { revalidateTag } from 'next/cache'\n00200| \n00201| export async function updateBookings() {\n00202| await updateBookingData()\n00203| revalidateTag('bookings-data', 'max')\n00204| }\n00205| ```\n00206| \n\n(End of file - total 206 lines)\n",
+ "title": "node_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md",
+ "metadata": {
+ "preview": "---\ntitle: cacheTag\ndescription: Learn how to use the cacheTag function to manage cache invalidation in your Next.js application.\nrelated:\n title: Related\n description: View related API references.\n links:\n - app/api-reference/config/next-config-js/cacheComponents\n - app/api-reference/directives/use-cache\n - app/api-reference/functions/revalidateTag\n - app/api-reference/functions/updateTag\n - app/api-reference/functions/cacheLife\n---\n\nThe `cacheTag` function allows you to tag cached data for on-demand invalidation. By associating tags with cache entries, you can selectively purge or revalidate specific cache entries without affecting other cached data.\n\n## Usage\n\nTo use `cacheTag`, enable the [`cacheComponents` flag](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.js` file:\n"
+ },
+ "time": {
+ "start": 1781392522995,
+ "end": 1781392523000
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:23.138Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "args": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md",
+ "_extractedPath": "/workspace/node_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392523138,
+ "sessionID": "ses_13cbb922affe86wOEqVAq01qO3",
+ "part": {
+ "id": "prt_ec344bef7001d4mFyKfx3tmYy8",
+ "sessionID": "ses_13cbb922affe86wOEqVAq01qO3",
+ "messageID": "msg_ec344b081001UDgqI32s2JbBcf",
+ "type": "tool",
+ "callID": "read_14",
+ "tool": "read",
+ "state": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md"
+ },
+ "output": "\n00001| ---\n00002| title: Caching and Revalidating (Previous Model)\n00003| nav_title: Caching (Previous Model)\n00004| description: Learn how to cache and revalidate data using fetch options, unstable_cache, and route segment configs for projects not using Cache Components.\n00005| ---\n00006| \n00007| > This guide assumes you are **not** using [Cache Components](/docs/app/getting-started/caching) which was introduced in version 16 under the [`cacheComponents` flag](/docs/app/api-reference/config/next-config-js/cacheComponents).\n00008| \n00009| ## Caching `fetch` requests\n00010| \n00011| By default, [`fetch`](/docs/app/api-reference/functions/fetch) requests are not cached. You can cache individual requests by setting the `cache` option to `'force-cache'`.\n00012| \n00013| ```tsx filename=\"app/page.tsx\" switcher\n00014| export default async function Page() {\n00015| const data = await fetch('https://...', { cache: 'force-cache' })\n00016| }\n00017| ```\n00018| \n00019| ```jsx filename=\"app/page.jsx\" switcher\n00020| export default async function Page() {\n00021| const data = await fetch('https://...', { cache: 'force-cache' })\n00022| }\n00023| ```\n00024| \n00025| See the [`fetch` API reference](/docs/app/api-reference/functions/fetch) to learn more.\n00026| \n00027| ### `unstable_cache` for non-`fetch` functions\n00028| \n00029| `unstable_cache` allows you to cache the result of database queries and other async functions that don't use `fetch`. Wrap `unstable_cache` around the function:\n00030| \n00031| ```ts filename=\"app/lib/data.ts\" switcher\n00032| import { unstable_cache } from 'next/cache'\n00033| import { db } from '@/lib/db'\n00034| \n00035| export const getCachedUser = unstable_cache(\n00036| async (id: string) => {\n00037| return db\n00038| .select()\n00039| .from(users)\n00040| .where(eq(users.id, id))\n00041| .then((res) => res[0])\n00042| },\n00043| ['user'], // cache key prefix\n00044| {\n00045| tags: ['user'],\n00046| revalidate: 3600,\n00047| }\n00048| )\n00049| ```\n00050| \n00051| ```js filename=\"app/lib/data.js\" switcher\n00052| import { unstable_cache } from 'next/cache'\n00053| import { db } from '@/lib/db'\n00054| \n00055| export const getCachedUser = unstable_cache(\n00056| async (id) => {\n00057| return db\n00058| .select()\n00059| .from(users)\n00060| .where(eq(users.id, id))\n00061| .then((res) => res[0])\n00062| },\n00063| ['user'], // cache key prefix\n00064| {\n00065| tags: ['user'],\n00066| revalidate: 3600,\n00067| }\n00068| )\n00069| ```\n00070| \n00071| The third argument accepts:\n00072| \n00073| - `tags`: an array of tags for on-demand revalidation with `revalidateTag`.\n00074| - `revalidate`: the number of seconds before the cache is revalidated.\n00075| \n00076| See the [`unstable_cache` API reference](/docs/app/api-reference/functions/unstable_cache) to learn more.\n00077| \n00078| ### Route segment config\n00079| \n00080| You can configure caching behavior at the route level by exporting config options from a [Page](/docs/app/api-reference/file-conventions/page), [Layout](/docs/app/api-reference/file-conventions/layout), or [Route Handler](/docs/app/api-reference/file-conventions/route).\n00081| \n00082| #### `dynamic`\n00083| \n00084| Change the dynamic behavior of a layout or page to fully static or fully dynamic.\n00085| \n00086| ```tsx filename=\"layout.tsx | page.tsx | route.ts\" switcher\n00087| export const dynamic = 'auto'\n00088| // 'auto' | 'force-dynamic' | 'error' | 'force-static'\n00089| ```\n00090| \n00091| ```jsx filename=\"layout.js | page.js | route.js\" switcher\n00092| export const dynamic = 'auto'\n00093| // 'auto' | 'force-dynamic' | 'error' | 'force-static'\n00094| ```\n00095| \n00096| - **`'auto'`** (default): The default option to cache as much as possible without preventing any components from opting into dynamic behavior.\n00097| - **`'force-dynamic'`**: Force [dynamic rendering](/docs/app/glossary#dynamic-rendering), which will result in routes being rendered for each user at request time. This option is equivalent to:\n00098| - Setting the option of every `fetch()` request in a layout or page to `{ cache: 'no-store', next: { revalidate: 0 } }`.\n00099| - Setting the segment config to `export const fetchCache = 'force-no-store'`\n00100| - **`'error'`**: Force prerendering and cache the data of a layout or page by causing an error if any components use Request-time APIs or uncached data. This option is equivalent to:\n00101| - `getStaticProps()` in the `pages` directory.\n00102| - Setting the option of every `fetch()` request in a layout or page to `{ cache: 'force-cache' }`.\n00103| - Setting the segment config to `fetchCache = 'only-cache'`.\n00104| - **`'force-static'`**: Force prerendering and cache the data of a layout or page by forcing [`cookies`](/docs/app/api-reference/functions/cookies), [`headers()`](/docs/app/api-reference/functions/headers) and [`useSearchParams()`](/docs/app/api-reference/functions/use-search-params) to return empty values. It is possible to [`revalidate`](#route-segment-config-revalidate), [`revalidatePath`](/docs/app/api-reference/functions/revalidatePath), or [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag), in pages or layouts rendered with `force-static`.\n00105| \n00106| #### `fetchCache`\n00107| \n00108| \n00109| This is an advanced option that should only be used if you specifically need to override the default behavior.\n00110| \n00111| By default, Next.js **will cache** any `fetch()` requests that are reachable **before** any Request-time APIs are used and **will not cache** `fetch` requests that are discovered **after** Request-time APIs are used.\n00112| \n00113| `fetchCache` allows you to override the default `cache` option of all `fetch` requests in a layout or page.\n00114| \n00115| ```tsx filename=\"layout.tsx | page.tsx | route.ts\" switcher\n00116| export const fetchCache = 'auto'\n00117| // 'auto' | 'default-cache' | 'only-cache'\n00118| // 'force-cache' | 'force-no-store' | 'default-no-store' | 'only-no-store'\n00119| ```\n00120| \n00121| ```jsx filename=\"layout.js | page.js | route.js\" switcher\n00122| export const fetchCache = 'auto'\n00123| // 'auto' | 'default-cache' | 'only-cache'\n00124| // 'force-cache' | 'force-no-store' | 'default-no-store' | 'only-no-store'\n00125| ```\n00126| \n00127| - **`'auto'`** (default): The default option to cache `fetch` requests before Request-time APIs with the `cache` option they provide and not cache `fetch` requests after Request-time APIs.\n00128| - **`'default-cache'`**: Allow any `cache` option to be passed to `fetch` but if no option is provided then set the `cache` option to `'force-cache'`. This means that even `fetch` requests after Request-time APIs are considered static.\n00129| - **`'only-cache'`**: Ensure all `fetch` requests opt into caching by changing the default to `cache: 'force-cache'` if no option is provided and causing an error if any `fetch` requests use `cache: 'no-store'`.\n00130| - **`'force-cache'`**: Ensure all `fetch` requests opt into caching by setting the `cache` option of all `fetch` requests to `'force-cache'`.\n00131| - **`'default-no-store'`**: Allow any `cache` option to be passed to `fetch` but if no option is provided then set the `cache` option to `'no-store'`. This means that even `fetch` requests before Request-time APIs are considered dynamic.\n00132| - **`'only-no-store'`**: Ensure all `fetch` requests opt out of caching by changing the default to `cache: 'no-store'` if no option is provided and causing an error if any `fetch` requests use `cache: 'force-cache'`\n00133| - **`'force-no-store'`**: Ensure all `fetch` requests opt out of caching by setting the `cache` option of all `fetch` requests to `'no-store'`. This forces all `fetch` requests to be re-fetched every request even if they provide a `'force-cache'` option.\n00134| \n00135| ##### Cross-route segment behavior\n00136| \n00137| - Any options set across each layout and page of a single route need to be compatible with each other.\n00138| - If both the `'only-cache'` and `'force-cache'` are provided, then `'force-cache'` wins. If both `'only-no-store'` and `'force-no-store'` are provided, then `'force-no-store'` wins. The force option changes the behavior across the route so a single segment with `'force-*'` would prevent any errors caused by `'only-*'`.\n00139| - The intention of the `'only-*'` and `'force-*'` options is to guarantee the whole route is either fully static or fully dynamic. This means:\n00140| - A combination of `'only-cache'` and `'only-no-store'` in a single route is not allowed.\n00141| - A combination of `'force-cache'` and `'force-no-store'` in a single route is not allowed.\n00142| - A parent cannot provide `'default-no-store'` if a child provides `'auto'` or `'*-cache'` since that could make the same fetch have different behavior.\n00143| - It is generally recommended to leave shared parent layouts as `'auto'` and customize the options where child segments diverge.\n00144| \n00145| \n00146| \n00147| ## Time-based revalidation\n00148| \n00149| Use the `next.revalidate` option on `fetch` to revalidate data after a specified number of seconds:\n00150| \n00151| ```tsx filename=\"app/page.tsx\" switcher\n00152| export default async function Page() {\n00153| const data = await fetch('https://...', { next: { revalidate: 3600 } })\n00154| }\n00155| ```\n00156| \n00157| ```jsx filename=\"app/page.jsx\" switcher\n00158| export default async function Page() {\n00159| const data = await fetch('https://...', { next: { revalidate: 3600 } })\n00160| }\n00161| ```\n00162| \n00163| For non-`fetch` functions, `unstable_cache` accepts a `revalidate` option in its configuration (see [example above](#unstable_cache-for-non-fetch-functions)).\n00164| \n00165| ### Route segment config `revalidate`\n00166| \n00167| Set the default revalidation time for a layout or page. This option does not override the `revalidate` value set by individual `fetch` requests.\n00168| \n00169| ```tsx filename=\"layout.tsx | page.tsx | route.ts\" switcher\n00170| export const revalidate = false\n00171| // false | 0 | number\n00172| ```\n00173| \n00174| ```jsx filename=\"layout.js | page.js | route.js\" switcher\n00175| export const revalidate = false\n00176| // false | 0 | number\n00177| ```\n00178| \n00179| - **`false`** (default): The default heuristic to cache any `fetch` requests that set their `cache` option to `'force-cache'` or are discovered before a Request-time API is used. Semantically equivalent to `revalidate: Infinity` which effectively means the resource should be cached indefinitely. It is still possible for individual `fetch` requests to use `cache: 'no-store'` or `revalidate: 0` to avoid being cached and make the route dynamically rendered. Or set `revalidate` to a positive number lower than the route default to increase the revalidation frequency of a route.\n00180| - **`0`**: Ensure a layout or page is always dynamically rendered even if no Request-time APIs or uncached data fetches are discovered. This option changes the default of `fetch` requests that do not set a `cache` option to `'no-store'` but leaves `fetch` requests that opt into `'force-cache'` or use a positive `revalidate` as is.\n00181| - **`number`**: (in seconds) Set the default revalidation frequency of a layout or page to `n` seconds.\n00182| \n00183| > **Good to know**:\n00184| >\n00185| > - The revalidate value needs to be statically analyzable. For example `revalidate = 600` is valid, but `revalidate = 60 * 10` is not.\n00186| > - The revalidate value is not available when using the deprecated `runtime = 'edge'`.\n00187| > - In Development, Pages are _always_ rendered on-demand and are never cached. This allows you to see changes immediately without waiting for a revalidation period to pass.\n00188| \n00189| #### Revalidation frequency\n00190| \n00191| - The lowest `revalidate` across each layout and page of a single route will determine the revalidation frequency of the _entire_ route. This ensures that child pages are revalidated as frequently as their parent layouts.\n00192| - Individual `fetch` requests can set a lower `revalidate` than the route's default `revalidate` to increase the revalidation frequency of the entire route. This allows you to dynamically opt-in to more frequent revalidation for certain routes based on some criteria.\n00193| \n00194| ## On-demand revalidation\n00195| \n00196| To revalidate cached data after an event, use [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) or [`revalidatePath`](/docs/app/api-reference/functions/revalidatePath) in a [Server Action](/docs/app/getting-started/mutating-data) or [Route Handler](/docs/app/api-reference/file-conventions/route).\n00197| \n00198| ### Tagging cached data\n00199| \n00200| Tag `fetch` requests with `next.tags` to enable on-demand cache invalidation:\n00201| \n00202| ```tsx filename=\"app/lib/data.ts\" switcher\n00203| export async function getUserById(id: string) {\n00204| const data = await fetch(`https://...`, {\n00205| next: { tags: ['user'] },\n00206| })\n00207| }\n00208| ```\n00209| \n00210| ```jsx filename=\"app/lib/data.js\" switcher\n00211| export async function getUserById(id) {\n00212| const data = await fetch(`https://...`, {\n00213| next: { tags: ['user'] },\n00214| })\n00215| }\n00216| ```\n00217| \n00218| For non-`fetch` functions, `unstable_cache` also accepts a `tags` option (see [example above](#unstable_cache-for-non-fetch-functions)).\n00219| \n00220| ### `revalidateTag`\n00221| \n00222| Invalidate cached data by tag using [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag):\n00223| \n00224| ```tsx filename=\"app/lib/actions.ts\" switcher\n00225| import { revalidateTag } from 'next/cache'\n00226| \n00227| export async function updateUser(id: string) {\n00228| // Mutate data\n00229| revalidateTag('user', 'max')\n00230| }\n00231| ```\n00232| \n00233| ```jsx filename=\"app/lib/actions.js\" switcher\n00234| import { revalidateTag } from 'next/cache'\n00235| \n00236| export async function updateUser(id) {\n00237| // Mutate data\n00238| revalidateTag('user', 'max')\n00239| }\n00240| ```\n00241| \n00242| ### `revalidatePath`\n00243| \n00244| Invalidate all cached data for a specific route path using [`revalidatePath`](/docs/app/api-reference/functions/revalidatePath):\n00245| \n00246| ```tsx filename=\"app/lib/actions.ts\" switcher\n00247| import { revalidatePath } from 'next/cache'\n00248| \n00249| export async function updateUser(id: string) {\n00250| // Mutate data\n00251| revalidatePath('/profile')\n00252| }\n00253| ```\n00254| \n00255| ```jsx filename=\"app/lib/actions.js\" switcher\n00256| import { revalidatePath } from 'next/cache'\n00257| \n00258| export async function updateUser(id) {\n00259| // Mutate data\n00260| revalidatePath('/profile')\n00261| }\n00262| ```\n00263| \n00264| ## Deduplicating requests\n00265| \n00266| If you are not using `fetch` (which is [automatically memoized](/docs/app/api-reference/functions/fetch#memoization)), and instead using an ORM or database directly, you can wrap your data access with the [React `cache`](https://react.dev/reference/react/cache) function to deduplicate requests within a single render pass:\n00267| \n00268| ```tsx filename=\"app/lib/data.ts\" switcher\n00269| import { cache } from 'react'\n00270| import { db, posts, eq } from '@/lib/db'\n00271| \n00272| export const getPost = cache(async (id: string) => {\n00273| const post = await db.query.posts.findFirst({\n00274| where: eq(posts.id, parseInt(id)),\n00275| })\n00276| })\n00277| ```\n00278| \n00279| ```jsx filename=\"app/lib/data.js\" switcher\n00280| import { cache } from 'react'\n00281| import { db, posts, eq } from '@/lib/db'\n00282| \n00283| export const getPost = cache(async (id) => {\n00284| const post = await db.query.posts.findFirst({\n00285| where: eq(posts.id, parseInt(id)),\n00286| })\n00287| })\n00288| ```\n00289| \n00290| ## Preloading data\n00291| \n00292| You can preload data by creating a utility function that you eagerly call above blocking requests. This lets you initiate data fetching early, so the data is already available by the time the component renders.\n00293| \n00294| Combine the [`server-only` package](https://www.npmjs.com/package/server-only) with React's [`cache`](https://react.dev/reference/react/cache) to create a reusable preload utility:\n00295| \n00296| ```ts filename=\"utils/get-item.ts\" switcher\n00297| import { cache } from 'react'\n00298| import 'server-only'\n00299| \n00300| export const getItem = cache(async (id: string) => {\n00301| // ...\n00302| })\n00303| \n00304| export const preload = (id: string) => {\n00305| void getItem(id)\n00306| }\n00307| ```\n00308| \n00309| ```js filename=\"utils/get-item.js\" switcher\n00310| import { cache } from 'react'\n00311| import 'server-only'\n00312| \n00313| export const getItem = cache(async (id) => {\n00314| // ...\n00315| })\n00316| \n00317| export const preload = (id) => {\n00318| void getItem(id)\n00319| }\n00320| ```\n00321| \n00322| Then call `preload()` before any blocking work so the data starts loading immediately:\n00323| \n00324| ```tsx filename=\"app/item/[id]/page.tsx\" switcher\n00325| import { getItem, preload, checkIsAvailable } from '@/lib/data'\n00326| \n00327| export default async function Page({\n00328| params,\n00329| }: {\n00330| params: Promise<{ id: string }>\n00331| }) {\n00332| const { id } = await params\n00333| // Start loading item data\n00334| preload(id)\n00335| // Perform another asynchronous task\n00336| const isAvailable = await checkIsAvailable()\n00337| \n00338| return isAvailable ? : null\n00339| }\n00340| \n00341| async function Item({ id }: { id: string }) {\n00342| const result = await getItem(id)\n00343| // ...\n00344| }\n00345| ```\n00346| \n00347| ```jsx filename=\"app/item/[id]/page.js\" switcher\n00348| import { getItem, preload, checkIsAvailable } from '@/lib/data'\n00349| \n00350| export default async function Page({ params }) {\n00351| const { id } = await params\n00352| // Start loading item data\n00353| preload(id)\n00354| // Perform another asynchronous task\n00355| const isAvailable = await checkIsAvailable()\n00356| \n00357| return isAvailable ? : null\n00358| }\n00359| \n00360| async function Item({ id }) {\n00361| const result = await getItem(id)\n00362| // ...\n00363| }\n00364| ```\n00365| \n\n(End of file - total 365 lines)\n",
+ "title": "node_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md",
+ "metadata": {
+ "preview": "---\ntitle: Caching and Revalidating (Previous Model)\nnav_title: Caching (Previous Model)\ndescription: Learn how to cache and revalidate data using fetch options, unstable_cache, and route segment configs for projects not using Cache Components.\n---\n\n> This guide assumes you are **not** using [Cache Components](/docs/app/getting-started/caching) which was introduced in version 16 under the [`cacheComponents` flag](/docs/app/api-reference/config/next-config-js/cacheComponents).\n\n## Caching `fetch` requests\n\nBy default, [`fetch`](/docs/app/api-reference/functions/fetch) requests are not cached. You can cache individual requests by setting the `cache` option to `'force-cache'`.\n\n```tsx filename=\"app/page.tsx\" switcher\nexport default async function Page() {\n const data = await fetch('https://...', { cache: 'force-cache' })\n}\n```\n\n```jsx filename=\"app/page.jsx\" switcher\nexport default async function Page() {"
+ },
+ "time": {
+ "start": 1781392523132,
+ "end": 1781392523137
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:23.138Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| ---\n00002| title: Caching and Revalidating (Previous Model)\n00003| nav_title: Caching (Previous Model)\n00004| description: Learn how to cache and revalidate data using fetch options, unstable_cache, and route segment configs for projects not using Cache Components.\n00005| ---\n00006| \n00007| > This guide assumes you are **not** using [Cache Components](/docs/app/getting-started/caching) which was introduced in version 16 under the [`cacheComponents` flag](/docs/app/api-reference/config/next-config-js/cacheComponents).\n00008| \n00009| ## Caching `fetch` requests\n00010| \n00011| By default, [`fetch`](/docs/app/api-reference/functions/fetch) requests are not cached. You can cache individual requests by setting the `cache` option to `'force-cache'`.\n00012| \n00013| ```tsx filename=\"app/page.tsx\" switcher\n00014| export default async function Page() {\n00015| const data = await fetch('https://...', { cache: 'force-cache' })\n00016| }\n00017| ```\n00018| \n00019| ```jsx filename=\"app/page.jsx\" switcher\n00020| export default async function Page() {\n00021| const data = await fetch('https://...', { cache: 'force-cache' })\n00022| }\n00023| ```\n00024| \n00025| See the [`fetch` API reference](/docs/app/api-reference/functions/fetch) to learn more.\n00026| \n00027| ### `unstable_cache` for non-`fetch` functions\n00028| \n00029| `unstable_cache` allows you to cache the result of database queries and other async functions that don't use `fetch`. Wrap `unstable_cache` around the function:\n00030| \n00031| ```ts filename=\"app/lib/data.ts\" switcher\n00032| import { unstable_cache } from 'next/cache'\n00033| import { db } from '@/lib/db'\n00034| \n00035| export const getCachedUser = unstable_cache(\n00036| async (id: string) => {\n00037| return db\n00038| .select()\n00039| .from(users)\n00040| .where(eq(users.id, id))\n00041| .then((res) => res[0])\n00042| },\n00043| ['user'], // cache key prefix\n00044| {\n00045| tags: ['user'],\n00046| revalidate: 3600,\n00047| }\n00048| )\n00049| ```\n00050| \n00051| ```js filename=\"app/lib/data.js\" switcher\n00052| import { unstable_cache } from 'next/cache'\n00053| import { db } from '@/lib/db'\n00054| \n00055| export const getCachedUser = unstable_cache(\n00056| async (id) => {\n00057| return db\n00058| .select()\n00059| .from(users)\n00060| .where(eq(users.id, id))\n00061| .then((res) => res[0])\n00062| },\n00063| ['user'], // cache key prefix\n00064| {\n00065| tags: ['user'],\n00066| revalidate: 3600,\n00067| }\n00068| )\n00069| ```\n00070| \n00071| The third argument accepts:\n00072| \n00073| - `tags`: an array of tags for on-demand revalidation with `revalidateTag`.\n00074| - `revalidate`: the number of seconds before the cache is revalidated.\n00075| \n00076| See the [`unstable_cache` API reference](/docs/app/api-reference/functions/unstable_cache) to learn more.\n00077| \n00078| ### Route segment config\n00079| \n00080| You can configure caching behavior at the route level by exporting config options from a [Page](/docs/app/api-reference/file-conventions/page), [Layout](/docs/app/api-reference/file-conventions/layout), or [Route Handler](/docs/app/api-reference/file-conventions/route).\n00081| \n00082| #### `dynamic`\n00083| \n00084| Change the dynamic behavior of a layout or page to fully static or fully dynamic.\n00085| \n00086| ```tsx filename=\"layout.tsx | page.tsx | route.ts\" switcher\n00087| export const dynamic = 'auto'\n00088| // 'auto' | 'force-dynamic' | 'error' | 'force-static'\n00089| ```\n00090| \n00091| ```jsx filename=\"layout.js | page.js | route.js\" switcher\n00092| export const dynamic = 'auto'\n00093| // 'auto' | 'force-dynamic' | 'error' | 'force-static'\n00094| ```\n00095| \n00096| - **`'auto'`** (default): The default option to cache as much as possible without preventing any components from opting into dynamic behavior.\n00097| - **`'force-dynamic'`**: Force [dynamic rendering](/docs/app/glossary#dynamic-rendering), which will result in routes being rendered for each user at request time. This option is equivalent to:\n00098| - Setting the option of every `fetch()` request in a layout or page to `{ cache: 'no-store', next: { revalidate: 0 } }`.\n00099| - Setting the segment config to `export const fetchCache = 'force-no-store'`\n00100| - **`'error'`**: Force prerendering and cache the data of a layout or page by causing an error if any components use Request-time APIs or uncached data. This option is equivalent to:\n00101| - `getStaticProps()` in the `pages` directory.\n00102| - Setting the option of every `fetch()` request in a layout or page to `{ cache: 'force-cache' }`.\n00103| - Setting the segment config to `fetchCache = 'only-cache'`.\n00104| - **`'force-static'`**: Force prerendering and cache the data of a layout or page by forcing [`cookies`](/docs/app/api-reference/functions/cookies), [`headers()`](/docs/app/api-reference/functions/headers) and [`useSearchParams()`](/docs/app/api-reference/functions/use-search-params) to return empty values. It is possible to [`revalidate`](#route-segment-config-revalidate), [`revalidatePath`](/docs/app/api-reference/functions/revalidatePath), or [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag), in pages or layouts rendered with `force-static`.\n00105| \n00106| #### `fetchCache`\n00107| \n00108| \n00109| This is an advanced option that should only be used if you specifically need to override the default behavior.\n00110| \n00111| By default, Next.js **will cache** any `fetch()` requests that are reachable **before** any Request-time APIs are used and **will not cache** `fetch` requests that are discovered **after** Request-time APIs are used.\n00112| \n00113| `fetchCache` allows you to override the default `cache` option of all `fetch` requests in a layout or page.\n00114| \n00115| ```tsx filename=\"layout.tsx | page.tsx | route.ts\" switcher\n00116| export const fetchCache = 'auto'\n00117| // 'auto' | 'default-cache' | 'only-cache'\n00118| // 'force-cache' | 'force-no-store' | 'default-no-store' | 'only-no-store'\n00119| ```\n00120| \n00121| ```jsx filename=\"layout.js | page.js | route.js\" switcher\n00122| export const fetchCache = 'auto'\n00123| // 'auto' | 'default-cache' | 'only-cache'\n00124| // 'force-cache' | 'force-no-store' | 'default-no-store' | 'only-no-store'\n00125| ```\n00126| \n00127| - **`'auto'`** (default): The default option to cache `fetch` requests before Request-time APIs with the `cache` option they provide and not cache `fetch` requests after Request-time APIs.\n00128| - **`'default-cache'`**: Allow any `cache` option to be passed to `fetch` but if no option is provided then set the `cache` option to `'force-cache'`. This means that even `fetch` requests after Request-time APIs are considered static.\n00129| - **`'only-cache'`**: Ensure all `fetch` requests opt into caching by changing the default to `cache: 'force-cache'` if no option is provided and causing an error if any `fetch` requests use `cache: 'no-store'`.\n00130| - **`'force-cache'`**: Ensure all `fetch` requests opt into caching by setting the `cache` option of all `fetch` requests to `'force-cache'`.\n00131| - **`'default-no-store'`**: Allow any `cache` option to be passed to `fetch` but if no option is provided then set the `cache` option to `'no-store'`. This means that even `fetch` requests before Request-time APIs are considered dynamic.\n00132| - **`'only-no-store'`**: Ensure all `fetch` requests opt out of caching by changing the default to `cache: 'no-store'` if no option is provided and causing an error if any `fetch` requests use `cache: 'force-cache'`\n00133| - **`'force-no-store'`**: Ensure all `fetch` requests opt out of caching by setting the `cache` option of all `fetch` requests to `'no-store'`. This forces all `fetch` requests to be re-fetched every request even if they provide a `'force-cache'` option.\n00134| \n00135| ##### Cross-route segment behavior\n00136| \n00137| - Any options set across each layout and page of a single route need to be compatible with each other.\n00138| - If both the `'only-cache'` and `'force-cache'` are provided, then `'force-cache'` wins. If both `'only-no-store'` and `'force-no-store'` are provided, then `'force-no-store'` wins. The force option changes the behavior across the route so a single segment with `'force-*'` would prevent any errors caused by `'only-*'`.\n00139| - The intention of the `'only-*'` and `'force-*'` options is to guarantee the whole route is either fully static or fully dynamic. This means:\n00140| - A combination of `'only-cache'` and `'only-no-store'` in a single route is not allowed.\n00141| - A combination of `'force-cache'` and `'force-no-store'` in a single route is not allowed.\n00142| - A parent cannot provide `'default-no-store'` if a child provides `'auto'` or `'*-cache'` since that could make the same fetch have different behavior.\n00143| - It is generally recommended to leave shared parent layouts as `'auto'` and customize the options where child segments diverge.\n00144| \n00145| \n00146| \n00147| ## Time-based revalidation\n00148| \n00149| Use the `next.revalidate` option on `fetch` to revalidate data after a specified number of seconds:\n00150| \n00151| ```tsx filename=\"app/page.tsx\" switcher\n00152| export default async function Page() {\n00153| const data = await fetch('https://...', { next: { revalidate: 3600 } })\n00154| }\n00155| ```\n00156| \n00157| ```jsx filename=\"app/page.jsx\" switcher\n00158| export default async function Page() {\n00159| const data = await fetch('https://...', { next: { revalidate: 3600 } })\n00160| }\n00161| ```\n00162| \n00163| For non-`fetch` functions, `unstable_cache` accepts a `revalidate` option in its configuration (see [example above](#unstable_cache-for-non-fetch-functions)).\n00164| \n00165| ### Route segment config `revalidate`\n00166| \n00167| Set the default revalidation time for a layout or page. This option does not override the `revalidate` value set by individual `fetch` requests.\n00168| \n00169| ```tsx filename=\"layout.tsx | page.tsx | route.ts\" switcher\n00170| export const revalidate = false\n00171| // false | 0 | number\n00172| ```\n00173| \n00174| ```jsx filename=\"layout.js | page.js | route.js\" switcher\n00175| export const revalidate = false\n00176| // false | 0 | number\n00177| ```\n00178| \n00179| - **`false`** (default): The default heuristic to cache any `fetch` requests that set their `cache` option to `'force-cache'` or are discovered before a Request-time API is used. Semantically equivalent to `revalidate: Infinity` which effectively means the resource should be cached indefinitely. It is still possible for individual `fetch` requests to use `cache: 'no-store'` or `revalidate: 0` to avoid being cached and make the route dynamically rendered. Or set `revalidate` to a positive number lower than the route default to increase the revalidation frequency of a route.\n00180| - **`0`**: Ensure a layout or page is always dynamically rendered even if no Request-time APIs or uncached data fetches are discovered. This option changes the default of `fetch` requests that do not set a `cache` option to `'no-store'` but leaves `fetch` requests that opt into `'force-cache'` or use a positive `revalidate` as is.\n00181| - **`number`**: (in seconds) Set the default revalidation frequency of a layout or page to `n` seconds.\n00182| \n00183| > **Good to know**:\n00184| >\n00185| > - The revalidate value needs to be statically analyzable. For example `revalidate = 600` is valid, but `revalidate = 60 * 10` is not.\n00186| > - The revalidate value is not available when using the deprecated `runtime = 'edge'`.\n00187| > - In Development, Pages are _always_ rendered on-demand and are never cached. This allows you to see changes immediately without waiting for a revalidation period to pass.\n00188| \n00189| #### Revalidation frequency\n00190| \n00191| - The lowest `revalidate` across each layout and page of a single route will determine the revalidation frequency of the _entire_ route. This ensures that child pages are revalidated as frequently as their parent layouts.\n00192| - Individual `fetch` requests can set a lower `revalidate` than the route's default `revalidate` to increase the revalidation frequency of the entire route. This allows you to dynamically opt-in to more frequent revalidation for certain routes based on some criteria.\n00193| \n00194| ## On-demand revalidation\n00195| \n00196| To revalidate cached data after an event, use [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) or [`revalidatePath`](/docs/app/api-reference/functions/revalidatePath) in a [Server Action](/docs/app/getting-started/mutating-data) or [Route Handler](/docs/app/api-reference/file-conventions/route).\n00197| \n00198| ### Tagging cached data\n00199| \n00200| Tag `fetch` requests with `next.tags` to enable on-demand cache invalidation:\n00201| \n00202| ```tsx filename=\"app/lib/data.ts\" switcher\n00203| export async function getUserById(id: string) {\n00204| const data = await fetch(`https://...`, {\n00205| next: { tags: ['user'] },\n00206| })\n00207| }\n00208| ```\n00209| \n00210| ```jsx filename=\"app/lib/data.js\" switcher\n00211| export async function getUserById(id) {\n00212| const data = await fetch(`https://...`, {\n00213| next: { tags: ['user'] },\n00214| })\n00215| }\n00216| ```\n00217| \n00218| For non-`fetch` functions, `unstable_cache` also accepts a `tags` option (see [example above](#unstable_cache-for-non-fetch-functions)).\n00219| \n00220| ### `revalidateTag`\n00221| \n00222| Invalidate cached data by tag using [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag):\n00223| \n00224| ```tsx filename=\"app/lib/actions.ts\" switcher\n00225| import { revalidateTag } from 'next/cache'\n00226| \n00227| export async function updateUser(id: string) {\n00228| // Mutate data\n00229| revalidateTag('user', 'max')\n00230| }\n00231| ```\n00232| \n00233| ```jsx filename=\"app/lib/actions.js\" switcher\n00234| import { revalidateTag } from 'next/cache'\n00235| \n00236| export async function updateUser(id) {\n00237| // Mutate data\n00238| revalidateTag('user', 'max')\n00239| }\n00240| ```\n00241| \n00242| ### `revalidatePath`\n00243| \n00244| Invalidate all cached data for a specific route path using [`revalidatePath`](/docs/app/api-reference/functions/revalidatePath):\n00245| \n00246| ```tsx filename=\"app/lib/actions.ts\" switcher\n00247| import { revalidatePath } from 'next/cache'\n00248| \n00249| export async function updateUser(id: string) {\n00250| // Mutate data\n00251| revalidatePath('/profile')\n00252| }\n00253| ```\n00254| \n00255| ```jsx filename=\"app/lib/actions.js\" switcher\n00256| import { revalidatePath } from 'next/cache'\n00257| \n00258| export async function updateUser(id) {\n00259| // Mutate data\n00260| revalidatePath('/profile')\n00261| }\n00262| ```\n00263| \n00264| ## Deduplicating requests\n00265| \n00266| If you are not using `fetch` (which is [automatically memoized](/docs/app/api-reference/functions/fetch#memoization)), and instead using an ORM or database directly, you can wrap your data access with the [React `cache`](https://react.dev/reference/react/cache) function to deduplicate requests within a single render pass:\n00267| \n00268| ```tsx filename=\"app/lib/data.ts\" switcher\n00269| import { cache } from 'react'\n00270| import { db, posts, eq } from '@/lib/db'\n00271| \n00272| export const getPost = cache(async (id: string) => {\n00273| const post = await db.query.posts.findFirst({\n00274| where: eq(posts.id, parseInt(id)),\n00275| })\n00276| })\n00277| ```\n00278| \n00279| ```jsx filename=\"app/lib/data.js\" switcher\n00280| import { cache } from 'react'\n00281| import { db, posts, eq } from '@/lib/db'\n00282| \n00283| export const getPost = cache(async (id) => {\n00284| const post = await db.query.posts.findFirst({\n00285| where: eq(posts.id, parseInt(id)),\n00286| })\n00287| })\n00288| ```\n00289| \n00290| ## Preloading data\n00291| \n00292| You can preload data by creating a utility function that you eagerly call above blocking requests. This lets you initiate data fetching early, so the data is already available by the time the component renders.\n00293| \n00294| Combine the [`server-only` package](https://www.npmjs.com/package/server-only) with React's [`cache`](https://react.dev/reference/react/cache) to create a reusable preload utility:\n00295| \n00296| ```ts filename=\"utils/get-item.ts\" switcher\n00297| import { cache } from 'react'\n00298| import 'server-only'\n00299| \n00300| export const getItem = cache(async (id: string) => {\n00301| // ...\n00302| })\n00303| \n00304| export const preload = (id: string) => {\n00305| void getItem(id)\n00306| }\n00307| ```\n00308| \n00309| ```js filename=\"utils/get-item.js\" switcher\n00310| import { cache } from 'react'\n00311| import 'server-only'\n00312| \n00313| export const getItem = cache(async (id) => {\n00314| // ...\n00315| })\n00316| \n00317| export const preload = (id) => {\n00318| void getItem(id)\n00319| }\n00320| ```\n00321| \n00322| Then call `preload()` before any blocking work so the data starts loading immediately:\n00323| \n00324| ```tsx filename=\"app/item/[id]/page.tsx\" switcher\n00325| import { getItem, preload, checkIsAvailable } from '@/lib/data'\n00326| \n00327| export default async function Page({\n00328| params,\n00329| }: {\n00330| params: Promise<{ id: string }>\n00331| }) {\n00332| const { id } = await params\n00333| // Start loading item data\n00334| preload(id)\n00335| // Perform another asynchronous task\n00336| const isAvailable = await checkIsAvailable()\n00337| \n00338| return isAvailable ? : null\n00339| }\n00340| \n00341| async function Item({ id }: { id: string }) {\n00342| const result = await getItem(id)\n00343| // ...\n00344| }\n00345| ```\n00346| \n00347| ```jsx filename=\"app/item/[id]/page.js\" switcher\n00348| import { getItem, preload, checkIsAvailable } from '@/lib/data'\n00349| \n00350| export default async function Page({ params }) {\n00351| const { id } = await params\n00352| // Start loading item data\n00353| preload(id)\n00354| // Perform another asynchronous task\n00355| const isAvailable = await checkIsAvailable()\n00356| \n00357| return isAvailable ? : null\n00358| }\n00359| \n00360| async function Item({ id }) {\n00361| const result = await getItem(id)\n00362| // ...\n00363| }\n00364| ```\n00365| \n\n(End of file - total 365 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md"
+ },
+ "output": "\n00001| ---\n00002| title: Caching and Revalidating (Previous Model)\n00003| nav_title: Caching (Previous Model)\n00004| description: Learn how to cache and revalidate data using fetch options, unstable_cache, and route segment configs for projects not using Cache Components.\n00005| ---\n00006| \n00007| > This guide assumes you are **not** using [Cache Components](/docs/app/getting-started/caching) which was introduced in version 16 under the [`cacheComponents` flag](/docs/app/api-reference/config/next-config-js/cacheComponents).\n00008| \n00009| ## Caching `fetch` requests\n00010| \n00011| By default, [`fetch`](/docs/app/api-reference/functions/fetch) requests are not cached. You can cache individual requests by setting the `cache` option to `'force-cache'`.\n00012| \n00013| ```tsx filename=\"app/page.tsx\" switcher\n00014| export default async function Page() {\n00015| const data = await fetch('https://...', { cache: 'force-cache' })\n00016| }\n00017| ```\n00018| \n00019| ```jsx filename=\"app/page.jsx\" switcher\n00020| export default async function Page() {\n00021| const data = await fetch('https://...', { cache: 'force-cache' })\n00022| }\n00023| ```\n00024| \n00025| See the [`fetch` API reference](/docs/app/api-reference/functions/fetch) to learn more.\n00026| \n00027| ### `unstable_cache` for non-`fetch` functions\n00028| \n00029| `unstable_cache` allows you to cache the result of database queries and other async functions that don't use `fetch`. Wrap `unstable_cache` around the function:\n00030| \n00031| ```ts filename=\"app/lib/data.ts\" switcher\n00032| import { unstable_cache } from 'next/cache'\n00033| import { db } from '@/lib/db'\n00034| \n00035| export const getCachedUser = unstable_cache(\n00036| async (id: string) => {\n00037| return db\n00038| .select()\n00039| .from(users)\n00040| .where(eq(users.id, id))\n00041| .then((res) => res[0])\n00042| },\n00043| ['user'], // cache key prefix\n00044| {\n00045| tags: ['user'],\n00046| revalidate: 3600,\n00047| }\n00048| )\n00049| ```\n00050| \n00051| ```js filename=\"app/lib/data.js\" switcher\n00052| import { unstable_cache } from 'next/cache'\n00053| import { db } from '@/lib/db'\n00054| \n00055| export const getCachedUser = unstable_cache(\n00056| async (id) => {\n00057| return db\n00058| .select()\n00059| .from(users)\n00060| .where(eq(users.id, id))\n00061| .then((res) => res[0])\n00062| },\n00063| ['user'], // cache key prefix\n00064| {\n00065| tags: ['user'],\n00066| revalidate: 3600,\n00067| }\n00068| )\n00069| ```\n00070| \n00071| The third argument accepts:\n00072| \n00073| - `tags`: an array of tags for on-demand revalidation with `revalidateTag`.\n00074| - `revalidate`: the number of seconds before the cache is revalidated.\n00075| \n00076| See the [`unstable_cache` API reference](/docs/app/api-reference/functions/unstable_cache) to learn more.\n00077| \n00078| ### Route segment config\n00079| \n00080| You can configure caching behavior at the route level by exporting config options from a [Page](/docs/app/api-reference/file-conventions/page), [Layout](/docs/app/api-reference/file-conventions/layout), or [Route Handler](/docs/app/api-reference/file-conventions/route).\n00081| \n00082| #### `dynamic`\n00083| \n00084| Change the dynamic behavior of a layout or page to fully static or fully dynamic.\n00085| \n00086| ```tsx filename=\"layout.tsx | page.tsx | route.ts\" switcher\n00087| export const dynamic = 'auto'\n00088| // 'auto' | 'force-dynamic' | 'error' | 'force-static'\n00089| ```\n00090| \n00091| ```jsx filename=\"layout.js | page.js | route.js\" switcher\n00092| export const dynamic = 'auto'\n00093| // 'auto' | 'force-dynamic' | 'error' | 'force-static'\n00094| ```\n00095| \n00096| - **`'auto'`** (default): The default option to cache as much as possible without preventing any components from opting into dynamic behavior.\n00097| - **`'force-dynamic'`**: Force [dynamic rendering](/docs/app/glossary#dynamic-rendering), which will result in routes being rendered for each user at request time. This option is equivalent to:\n00098| - Setting the option of every `fetch()` request in a layout or page to `{ cache: 'no-store', next: { revalidate: 0 } }`.\n00099| - Setting the segment config to `export const fetchCache = 'force-no-store'`\n00100| - **`'error'`**: Force prerendering and cache the data of a layout or page by causing an error if any components use Request-time APIs or uncached data. This option is equivalent to:\n00101| - `getStaticProps()` in the `pages` directory.\n00102| - Setting the option of every `fetch()` request in a layout or page to `{ cache: 'force-cache' }`.\n00103| - Setting the segment config to `fetchCache = 'only-cache'`.\n00104| - **`'force-static'`**: Force prerendering and cache the data of a layout or page by forcing [`cookies`](/docs/app/api-reference/functions/cookies), [`headers()`](/docs/app/api-reference/functions/headers) and [`useSearchParams()`](/docs/app/api-reference/functions/use-search-params) to return empty values. It is possible to [`revalidate`](#route-segment-config-revalidate), [`revalidatePath`](/docs/app/api-reference/functions/revalidatePath), or [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag), in pages or layouts rendered with `force-static`.\n00105| \n00106| #### `fetchCache`\n00107| \n00108| \n00109| This is an advanced option that should only be used if you specifically need to override the default behavior.\n00110| \n00111| By default, Next.js **will cache** any `fetch()` requests that are reachable **before** any Request-time APIs are used and **will not cache** `fetch` requests that are discovered **after** Request-time APIs are used.\n00112| \n00113| `fetchCache` allows you to override the default `cache` option of all `fetch` requests in a layout or page.\n00114| \n00115| ```tsx filename=\"layout.tsx | page.tsx | route.ts\" switcher\n00116| export const fetchCache = 'auto'\n00117| // 'auto' | 'default-cache' | 'only-cache'\n00118| // 'force-cache' | 'force-no-store' | 'default-no-store' | 'only-no-store'\n00119| ```\n00120| \n00121| ```jsx filename=\"layout.js | page.js | route.js\" switcher\n00122| export const fetchCache = 'auto'\n00123| // 'auto' | 'default-cache' | 'only-cache'\n00124| // 'force-cache' | 'force-no-store' | 'default-no-store' | 'only-no-store'\n00125| ```\n00126| \n00127| - **`'auto'`** (default): The default option to cache `fetch` requests before Request-time APIs with the `cache` option they provide and not cache `fetch` requests after Request-time APIs.\n00128| - **`'default-cache'`**: Allow any `cache` option to be passed to `fetch` but if no option is provided then set the `cache` option to `'force-cache'`. This means that even `fetch` requests after Request-time APIs are considered static.\n00129| - **`'only-cache'`**: Ensure all `fetch` requests opt into caching by changing the default to `cache: 'force-cache'` if no option is provided and causing an error if any `fetch` requests use `cache: 'no-store'`.\n00130| - **`'force-cache'`**: Ensure all `fetch` requests opt into caching by setting the `cache` option of all `fetch` requests to `'force-cache'`.\n00131| - **`'default-no-store'`**: Allow any `cache` option to be passed to `fetch` but if no option is provided then set the `cache` option to `'no-store'`. This means that even `fetch` requests before Request-time APIs are considered dynamic.\n00132| - **`'only-no-store'`**: Ensure all `fetch` requests opt out of caching by changing the default to `cache: 'no-store'` if no option is provided and causing an error if any `fetch` requests use `cache: 'force-cache'`\n00133| - **`'force-no-store'`**: Ensure all `fetch` requests opt out of caching by setting the `cache` option of all `fetch` requests to `'no-store'`. This forces all `fetch` requests to be re-fetched every request even if they provide a `'force-cache'` option.\n00134| \n00135| ##### Cross-route segment behavior\n00136| \n00137| - Any options set across each layout and page of a single route need to be compatible with each other.\n00138| - If both the `'only-cache'` and `'force-cache'` are provided, then `'force-cache'` wins. If both `'only-no-store'` and `'force-no-store'` are provided, then `'force-no-store'` wins. The force option changes the behavior across the route so a single segment with `'force-*'` would prevent any errors caused by `'only-*'`.\n00139| - The intention of the `'only-*'` and `'force-*'` options is to guarantee the whole route is either fully static or fully dynamic. This means:\n00140| - A combination of `'only-cache'` and `'only-no-store'` in a single route is not allowed.\n00141| - A combination of `'force-cache'` and `'force-no-store'` in a single route is not allowed.\n00142| - A parent cannot provide `'default-no-store'` if a child provides `'auto'` or `'*-cache'` since that could make the same fetch have different behavior.\n00143| - It is generally recommended to leave shared parent layouts as `'auto'` and customize the options where child segments diverge.\n00144| \n00145| \n00146| \n00147| ## Time-based revalidation\n00148| \n00149| Use the `next.revalidate` option on `fetch` to revalidate data after a specified number of seconds:\n00150| \n00151| ```tsx filename=\"app/page.tsx\" switcher\n00152| export default async function Page() {\n00153| const data = await fetch('https://...', { next: { revalidate: 3600 } })\n00154| }\n00155| ```\n00156| \n00157| ```jsx filename=\"app/page.jsx\" switcher\n00158| export default async function Page() {\n00159| const data = await fetch('https://...', { next: { revalidate: 3600 } })\n00160| }\n00161| ```\n00162| \n00163| For non-`fetch` functions, `unstable_cache` accepts a `revalidate` option in its configuration (see [example above](#unstable_cache-for-non-fetch-functions)).\n00164| \n00165| ### Route segment config `revalidate`\n00166| \n00167| Set the default revalidation time for a layout or page. This option does not override the `revalidate` value set by individual `fetch` requests.\n00168| \n00169| ```tsx filename=\"layout.tsx | page.tsx | route.ts\" switcher\n00170| export const revalidate = false\n00171| // false | 0 | number\n00172| ```\n00173| \n00174| ```jsx filename=\"layout.js | page.js | route.js\" switcher\n00175| export const revalidate = false\n00176| // false | 0 | number\n00177| ```\n00178| \n00179| - **`false`** (default): The default heuristic to cache any `fetch` requests that set their `cache` option to `'force-cache'` or are discovered before a Request-time API is used. Semantically equivalent to `revalidate: Infinity` which effectively means the resource should be cached indefinitely. It is still possible for individual `fetch` requests to use `cache: 'no-store'` or `revalidate: 0` to avoid being cached and make the route dynamically rendered. Or set `revalidate` to a positive number lower than the route default to increase the revalidation frequency of a route.\n00180| - **`0`**: Ensure a layout or page is always dynamically rendered even if no Request-time APIs or uncached data fetches are discovered. This option changes the default of `fetch` requests that do not set a `cache` option to `'no-store'` but leaves `fetch` requests that opt into `'force-cache'` or use a positive `revalidate` as is.\n00181| - **`number`**: (in seconds) Set the default revalidation frequency of a layout or page to `n` seconds.\n00182| \n00183| > **Good to know**:\n00184| >\n00185| > - The revalidate value needs to be statically analyzable. For example `revalidate = 600` is valid, but `revalidate = 60 * 10` is not.\n00186| > - The revalidate value is not available when using the deprecated `runtime = 'edge'`.\n00187| > - In Development, Pages are _always_ rendered on-demand and are never cached. This allows you to see changes immediately without waiting for a revalidation period to pass.\n00188| \n00189| #### Revalidation frequency\n00190| \n00191| - The lowest `revalidate` across each layout and page of a single route will determine the revalidation frequency of the _entire_ route. This ensures that child pages are revalidated as frequently as their parent layouts.\n00192| - Individual `fetch` requests can set a lower `revalidate` than the route's default `revalidate` to increase the revalidation frequency of the entire route. This allows you to dynamically opt-in to more frequent revalidation for certain routes based on some criteria.\n00193| \n00194| ## On-demand revalidation\n00195| \n00196| To revalidate cached data after an event, use [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) or [`revalidatePath`](/docs/app/api-reference/functions/revalidatePath) in a [Server Action](/docs/app/getting-started/mutating-data) or [Route Handler](/docs/app/api-reference/file-conventions/route).\n00197| \n00198| ### Tagging cached data\n00199| \n00200| Tag `fetch` requests with `next.tags` to enable on-demand cache invalidation:\n00201| \n00202| ```tsx filename=\"app/lib/data.ts\" switcher\n00203| export async function getUserById(id: string) {\n00204| const data = await fetch(`https://...`, {\n00205| next: { tags: ['user'] },\n00206| })\n00207| }\n00208| ```\n00209| \n00210| ```jsx filename=\"app/lib/data.js\" switcher\n00211| export async function getUserById(id) {\n00212| const data = await fetch(`https://...`, {\n00213| next: { tags: ['user'] },\n00214| })\n00215| }\n00216| ```\n00217| \n00218| For non-`fetch` functions, `unstable_cache` also accepts a `tags` option (see [example above](#unstable_cache-for-non-fetch-functions)).\n00219| \n00220| ### `revalidateTag`\n00221| \n00222| Invalidate cached data by tag using [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag):\n00223| \n00224| ```tsx filename=\"app/lib/actions.ts\" switcher\n00225| import { revalidateTag } from 'next/cache'\n00226| \n00227| export async function updateUser(id: string) {\n00228| // Mutate data\n00229| revalidateTag('user', 'max')\n00230| }\n00231| ```\n00232| \n00233| ```jsx filename=\"app/lib/actions.js\" switcher\n00234| import { revalidateTag } from 'next/cache'\n00235| \n00236| export async function updateUser(id) {\n00237| // Mutate data\n00238| revalidateTag('user', 'max')\n00239| }\n00240| ```\n00241| \n00242| ### `revalidatePath`\n00243| \n00244| Invalidate all cached data for a specific route path using [`revalidatePath`](/docs/app/api-reference/functions/revalidatePath):\n00245| \n00246| ```tsx filename=\"app/lib/actions.ts\" switcher\n00247| import { revalidatePath } from 'next/cache'\n00248| \n00249| export async function updateUser(id: string) {\n00250| // Mutate data\n00251| revalidatePath('/profile')\n00252| }\n00253| ```\n00254| \n00255| ```jsx filename=\"app/lib/actions.js\" switcher\n00256| import { revalidatePath } from 'next/cache'\n00257| \n00258| export async function updateUser(id) {\n00259| // Mutate data\n00260| revalidatePath('/profile')\n00261| }\n00262| ```\n00263| \n00264| ## Deduplicating requests\n00265| \n00266| If you are not using `fetch` (which is [automatically memoized](/docs/app/api-reference/functions/fetch#memoization)), and instead using an ORM or database directly, you can wrap your data access with the [React `cache`](https://react.dev/reference/react/cache) function to deduplicate requests within a single render pass:\n00267| \n00268| ```tsx filename=\"app/lib/data.ts\" switcher\n00269| import { cache } from 'react'\n00270| import { db, posts, eq } from '@/lib/db'\n00271| \n00272| export const getPost = cache(async (id: string) => {\n00273| const post = await db.query.posts.findFirst({\n00274| where: eq(posts.id, parseInt(id)),\n00275| })\n00276| })\n00277| ```\n00278| \n00279| ```jsx filename=\"app/lib/data.js\" switcher\n00280| import { cache } from 'react'\n00281| import { db, posts, eq } from '@/lib/db'\n00282| \n00283| export const getPost = cache(async (id) => {\n00284| const post = await db.query.posts.findFirst({\n00285| where: eq(posts.id, parseInt(id)),\n00286| })\n00287| })\n00288| ```\n00289| \n00290| ## Preloading data\n00291| \n00292| You can preload data by creating a utility function that you eagerly call above blocking requests. This lets you initiate data fetching early, so the data is already available by the time the component renders.\n00293| \n00294| Combine the [`server-only` package](https://www.npmjs.com/package/server-only) with React's [`cache`](https://react.dev/reference/react/cache) to create a reusable preload utility:\n00295| \n00296| ```ts filename=\"utils/get-item.ts\" switcher\n00297| import { cache } from 'react'\n00298| import 'server-only'\n00299| \n00300| export const getItem = cache(async (id: string) => {\n00301| // ...\n00302| })\n00303| \n00304| export const preload = (id: string) => {\n00305| void getItem(id)\n00306| }\n00307| ```\n00308| \n00309| ```js filename=\"utils/get-item.js\" switcher\n00310| import { cache } from 'react'\n00311| import 'server-only'\n00312| \n00313| export const getItem = cache(async (id) => {\n00314| // ...\n00315| })\n00316| \n00317| export const preload = (id) => {\n00318| void getItem(id)\n00319| }\n00320| ```\n00321| \n00322| Then call `preload()` before any blocking work so the data starts loading immediately:\n00323| \n00324| ```tsx filename=\"app/item/[id]/page.tsx\" switcher\n00325| import { getItem, preload, checkIsAvailable } from '@/lib/data'\n00326| \n00327| export default async function Page({\n00328| params,\n00329| }: {\n00330| params: Promise<{ id: string }>\n00331| }) {\n00332| const { id } = await params\n00333| // Start loading item data\n00334| preload(id)\n00335| // Perform another asynchronous task\n00336| const isAvailable = await checkIsAvailable()\n00337| \n00338| return isAvailable ? : null\n00339| }\n00340| \n00341| async function Item({ id }: { id: string }) {\n00342| const result = await getItem(id)\n00343| // ...\n00344| }\n00345| ```\n00346| \n00347| ```jsx filename=\"app/item/[id]/page.js\" switcher\n00348| import { getItem, preload, checkIsAvailable } from '@/lib/data'\n00349| \n00350| export default async function Page({ params }) {\n00351| const { id } = await params\n00352| // Start loading item data\n00353| preload(id)\n00354| // Perform another asynchronous task\n00355| const isAvailable = await checkIsAvailable()\n00356| \n00357| return isAvailable ? : null\n00358| }\n00359| \n00360| async function Item({ id }) {\n00361| const result = await getItem(id)\n00362| // ...\n00363| }\n00364| ```\n00365| \n\n(End of file - total 365 lines)\n",
+ "title": "node_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md",
+ "metadata": {
+ "preview": "---\ntitle: Caching and Revalidating (Previous Model)\nnav_title: Caching (Previous Model)\ndescription: Learn how to cache and revalidate data using fetch options, unstable_cache, and route segment configs for projects not using Cache Components.\n---\n\n> This guide assumes you are **not** using [Cache Components](/docs/app/getting-started/caching) which was introduced in version 16 under the [`cacheComponents` flag](/docs/app/api-reference/config/next-config-js/cacheComponents).\n\n## Caching `fetch` requests\n\nBy default, [`fetch`](/docs/app/api-reference/functions/fetch) requests are not cached. You can cache individual requests by setting the `cache` option to `'force-cache'`.\n\n```tsx filename=\"app/page.tsx\" switcher\nexport default async function Page() {\n const data = await fetch('https://...', { cache: 'force-cache' })\n}\n```\n\n```jsx filename=\"app/page.jsx\" switcher\nexport default async function Page() {"
+ },
+ "time": {
+ "start": 1781392523132,
+ "end": 1781392523137
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:32.400Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "shell",
+ "originalName": "bash",
+ "args": {
+ "command": "find node_modules/next/dist/docs -type f -name \"revalidateTag.md\" -o -name \"updateTag.md\" -o -name \"use-cache.md\" 2>/dev/null | head -20",
+ "description": "Find revalidateTag and use-cache docs",
+ "_extractedCommand": "find node_modules/next/dist/docs -type f -name \"revalidateTag.md\" -o -name \"updateTag.md\" -o -name \"use-cache.md\" 2>/dev/null | head -20"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392532400,
+ "sessionID": "ses_13cbb922affe86wOEqVAq01qO3",
+ "part": {
+ "id": "prt_ec344e004001WnTtGoiGgHAYHd",
+ "sessionID": "ses_13cbb922affe86wOEqVAq01qO3",
+ "messageID": "msg_ec344bf90001lTvGjUoDLuh2bZ",
+ "type": "tool",
+ "callID": "bash_15",
+ "tool": "bash",
+ "state": {
+ "status": "completed",
+ "input": {
+ "command": "find node_modules/next/dist/docs -type f -name \"revalidateTag.md\" -o -name \"updateTag.md\" -o -name \"use-cache.md\" 2>/dev/null | head -20",
+ "description": "Find revalidateTag and use-cache docs"
+ },
+ "output": "node_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/updateTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache.md\n",
+ "title": "Find revalidateTag and use-cache docs",
+ "metadata": {
+ "output": "node_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/updateTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache.md\n",
+ "exit": 0,
+ "description": "Find revalidateTag and use-cache docs"
+ },
+ "time": {
+ "start": 1781392532392,
+ "end": 1781392532396
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:32.400Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "shell",
+ "originalName": "bash",
+ "result": "node_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/updateTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache.md\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "command": "find node_modules/next/dist/docs -type f -name \"revalidateTag.md\" -o -name \"updateTag.md\" -o -name \"use-cache.md\" 2>/dev/null | head -20",
+ "description": "Find revalidateTag and use-cache docs"
+ },
+ "output": "node_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/updateTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache.md\n",
+ "title": "Find revalidateTag and use-cache docs",
+ "metadata": {
+ "output": "node_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/updateTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache.md\n",
+ "exit": 0,
+ "description": "Find revalidateTag and use-cache docs"
+ },
+ "time": {
+ "start": 1781392532392,
+ "end": 1781392532396
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:35.357Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "args": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md",
+ "_extractedPath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392535357,
+ "sessionID": "ses_13cbb922affe86wOEqVAq01qO3",
+ "part": {
+ "id": "prt_ec344eb18001qsaBPUPXqiJI57",
+ "sessionID": "ses_13cbb922affe86wOEqVAq01qO3",
+ "messageID": "msg_ec344e3ba001wSxQa7jb952GvG",
+ "type": "tool",
+ "callID": "read_16",
+ "tool": "read",
+ "state": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md"
+ },
+ "output": "\n00001| ---\n00002| title: revalidateTag\n00003| description: API Reference for the revalidateTag function.\n00004| ---\n00005| \n00006| `revalidateTag` allows you to invalidate cached data on-demand for a specific cache tag.\n00007| \n00008| This function is ideal for content where a slight delay in updates is acceptable, such as blog posts, product catalogs, or documentation. Users receive stale content while fresh data loads in the background.\n00009| \n00010| ## Usage\n00011| \n00012| `revalidateTag` can be called in Server Functions and Route Handlers.\n00013| \n00014| `revalidateTag` cannot be called in Client Components or Proxy, as it only works in server environments.\n00015| \n00016| ### Revalidation Behavior\n00017| \n00018| The revalidation behavior depends on whether you provide the second argument:\n00019| \n00020| - **With `profile=\"max\"` (recommended)**: The tag entry is marked as stale, and the next time a resource with that tag is visited, it will use stale-while-revalidate semantics. This means the stale content is served while fresh content is fetched in the background.\n00021| - **With a custom cache life profile**: For advanced usage, you can specify any cache life profile that your application has defined, allowing for custom revalidation behaviors tailored to your specific caching requirements.\n00022| - **Without the second argument (deprecated)**: The tag entry is expired immediately, and the next request to that resource will be a blocking revalidate/cache miss. This behavior is now deprecated, and you should either use `profile=\"max\"` or migrate to [`updateTag`](/docs/app/api-reference/functions/updateTag).\n00023| \n00024| > **Good to know**: When using `profile=\"max\"`, `revalidateTag` marks tagged data as stale, but fresh data is only fetched when pages using that tag are next visited. This means calling `revalidateTag` will not immediately trigger many revalidations at once. The invalidation only happens when any page using that tag is next visited.\n00025| \n00026| ## Parameters\n00027| \n00028| ```ts\n00029| revalidateTag(tag: string, profile: string | { expire?: number }): void;\n00030| ```\n00031| \n00032| - `tag`: A string representing the cache tag associated with the data you want to revalidate. Must not exceed 256 characters. This value is case-sensitive.\n00033| - `profile`: A string that specifies the revalidation behavior. The recommended value is `\"max\"` which provides stale-while-revalidate semantics, or any of the other default or custom profiles defined in [`cacheLife`](/docs/app/api-reference/config/next-config-js/cacheLife). Alternatively, you can pass an object with an `expire` property for custom expiration behavior.\n00034| \n00035| Tags must first be assigned to cached data. You can do this in two ways:\n00036| \n00037| - Using the [`next.tags`](/docs/app/api-reference/functions/fetch) option with `fetch` for caching external API requests:\n00038| \n00039| ```tsx\n00040| fetch(url, { next: { tags: ['posts'] } })\n00041| ```\n00042| \n00043| - Using [`cacheTag`](/docs/app/api-reference/functions/cacheTag) inside cached functions or components with the `'use cache'` directive:\n00044| \n00045| ```tsx\n00046| import { cacheTag } from 'next/cache'\n00047| \n00048| async function getData() {\n00049| 'use cache'\n00050| cacheTag('posts')\n00051| // ...\n00052| }\n00053| ```\n00054| \n00055| > **Good to know**: The single-argument form `revalidateTag(tag)` is deprecated. It currently works if TypeScript errors are suppressed, but this behavior may be removed in a future version. Update to the two-argument signature.\n00056| \n00057| ## Returns\n00058| \n00059| `revalidateTag` does not return a value.\n00060| \n00061| ## Relationship with `revalidatePath`\n00062| \n00063| `revalidateTag` invalidates data with specific tags across all pages that use those tags, while [`revalidatePath`](/docs/app/api-reference/functions/revalidatePath) invalidates specific page or layout paths.\n00064| \n00065| > **Good to know**: These functions serve different purposes and may need to be used together for comprehensive data consistency. For detailed examples and considerations, see [relationship with revalidateTag and updateTag](/docs/app/api-reference/functions/revalidatePath#relationship-with-revalidatetag-and-updatetag) for more information.\n00066| \n00067| ## Examples\n00068| \n00069| The following examples demonstrate how to use `revalidateTag` in different contexts. In both cases, we're using `profile=\"max\"` to mark data as stale and use stale-while-revalidate semantics, which is the recommended approach for most use cases.\n00070| \n00071| ### Server Action\n00072| \n00073| ```ts filename=\"app/actions.ts\" switcher\n00074| 'use server'\n00075| \n00076| import { revalidateTag } from 'next/cache'\n00077| \n00078| export default async function submit() {\n00079| await addPost()\n00080| revalidateTag('posts', 'max')\n00081| }\n00082| ```\n00083| \n00084| ```js filename=\"app/actions.js\" switcher\n00085| 'use server'\n00086| \n00087| import { revalidateTag } from 'next/cache'\n00088| \n00089| export default async function submit() {\n00090| await addPost()\n00091| revalidateTag('posts', 'max')\n00092| }\n00093| ```\n00094| \n00095| ### Route Handler\n00096| \n00097| ```ts filename=\"app/api/revalidate/route.ts\" switcher\n00098| import type { NextRequest } from 'next/server'\n00099| import { revalidateTag } from 'next/cache'\n00100| \n00101| export async function GET(request: NextRequest) {\n00102| const tag = request.nextUrl.searchParams.get('tag')\n00103| \n00104| if (tag) {\n00105| revalidateTag(tag, 'max')\n00106| return Response.json({ revalidated: true, now: Date.now() })\n00107| }\n00108| \n00109| return Response.json({\n00110| revalidated: false,\n00111| now: Date.now(),\n00112| message: 'Missing tag to revalidate',\n00113| })\n00114| }\n00115| ```\n00116| \n00117| ```js filename=\"app/api/revalidate/route.js\" switcher\n00118| import { revalidateTag } from 'next/cache'\n00119| \n00120| export async function GET(request) {\n00121| const tag = request.nextUrl.searchParams.get('tag')\n00122| \n00123| if (tag) {\n00124| revalidateTag(tag, 'max')\n00125| return Response.json({ revalidated: true, now: Date.now() })\n00126| }\n00127| \n00128| return Response.json({\n00129| revalidated: false,\n00130| now: Date.now(),\n00131| message: 'Missing tag to revalidate',\n00132| })\n00133| }\n00134| ```\n00135| \n00136| > **Good to know**: For webhooks or third-party services that need immediate expiration, you can pass `{ expire: 0 }` as the second argument: `revalidateTag(tag, { expire: 0 })`. This pattern is necessary when external systems call your Route Handlers and require data to expire immediately. For all other cases, it's recommended to use [`updateTag`](/docs/app/api-reference/functions/updateTag) in Server Actions for immediate updates instead.\n00137| \n\n(End of file - total 137 lines)\n",
+ "title": "node_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md",
+ "metadata": {
+ "preview": "---\ntitle: revalidateTag\ndescription: API Reference for the revalidateTag function.\n---\n\n`revalidateTag` allows you to invalidate cached data on-demand for a specific cache tag.\n\nThis function is ideal for content where a slight delay in updates is acceptable, such as blog posts, product catalogs, or documentation. Users receive stale content while fresh data loads in the background.\n\n## Usage\n\n`revalidateTag` can be called in Server Functions and Route Handlers.\n\n`revalidateTag` cannot be called in Client Components or Proxy, as it only works in server environments.\n\n### Revalidation Behavior\n\nThe revalidation behavior depends on whether you provide the second argument:\n\n- **With `profile=\"max\"` (recommended)**: The tag entry is marked as stale, and the next time a resource with that tag is visited, it will use stale-while-revalidate semantics. This means the stale content is served while fresh content is fetched in the background."
+ },
+ "time": {
+ "start": 1781392535349,
+ "end": 1781392535354
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:35.357Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| ---\n00002| title: revalidateTag\n00003| description: API Reference for the revalidateTag function.\n00004| ---\n00005| \n00006| `revalidateTag` allows you to invalidate cached data on-demand for a specific cache tag.\n00007| \n00008| This function is ideal for content where a slight delay in updates is acceptable, such as blog posts, product catalogs, or documentation. Users receive stale content while fresh data loads in the background.\n00009| \n00010| ## Usage\n00011| \n00012| `revalidateTag` can be called in Server Functions and Route Handlers.\n00013| \n00014| `revalidateTag` cannot be called in Client Components or Proxy, as it only works in server environments.\n00015| \n00016| ### Revalidation Behavior\n00017| \n00018| The revalidation behavior depends on whether you provide the second argument:\n00019| \n00020| - **With `profile=\"max\"` (recommended)**: The tag entry is marked as stale, and the next time a resource with that tag is visited, it will use stale-while-revalidate semantics. This means the stale content is served while fresh content is fetched in the background.\n00021| - **With a custom cache life profile**: For advanced usage, you can specify any cache life profile that your application has defined, allowing for custom revalidation behaviors tailored to your specific caching requirements.\n00022| - **Without the second argument (deprecated)**: The tag entry is expired immediately, and the next request to that resource will be a blocking revalidate/cache miss. This behavior is now deprecated, and you should either use `profile=\"max\"` or migrate to [`updateTag`](/docs/app/api-reference/functions/updateTag).\n00023| \n00024| > **Good to know**: When using `profile=\"max\"`, `revalidateTag` marks tagged data as stale, but fresh data is only fetched when pages using that tag are next visited. This means calling `revalidateTag` will not immediately trigger many revalidations at once. The invalidation only happens when any page using that tag is next visited.\n00025| \n00026| ## Parameters\n00027| \n00028| ```ts\n00029| revalidateTag(tag: string, profile: string | { expire?: number }): void;\n00030| ```\n00031| \n00032| - `tag`: A string representing the cache tag associated with the data you want to revalidate. Must not exceed 256 characters. This value is case-sensitive.\n00033| - `profile`: A string that specifies the revalidation behavior. The recommended value is `\"max\"` which provides stale-while-revalidate semantics, or any of the other default or custom profiles defined in [`cacheLife`](/docs/app/api-reference/config/next-config-js/cacheLife). Alternatively, you can pass an object with an `expire` property for custom expiration behavior.\n00034| \n00035| Tags must first be assigned to cached data. You can do this in two ways:\n00036| \n00037| - Using the [`next.tags`](/docs/app/api-reference/functions/fetch) option with `fetch` for caching external API requests:\n00038| \n00039| ```tsx\n00040| fetch(url, { next: { tags: ['posts'] } })\n00041| ```\n00042| \n00043| - Using [`cacheTag`](/docs/app/api-reference/functions/cacheTag) inside cached functions or components with the `'use cache'` directive:\n00044| \n00045| ```tsx\n00046| import { cacheTag } from 'next/cache'\n00047| \n00048| async function getData() {\n00049| 'use cache'\n00050| cacheTag('posts')\n00051| // ...\n00052| }\n00053| ```\n00054| \n00055| > **Good to know**: The single-argument form `revalidateTag(tag)` is deprecated. It currently works if TypeScript errors are suppressed, but this behavior may be removed in a future version. Update to the two-argument signature.\n00056| \n00057| ## Returns\n00058| \n00059| `revalidateTag` does not return a value.\n00060| \n00061| ## Relationship with `revalidatePath`\n00062| \n00063| `revalidateTag` invalidates data with specific tags across all pages that use those tags, while [`revalidatePath`](/docs/app/api-reference/functions/revalidatePath) invalidates specific page or layout paths.\n00064| \n00065| > **Good to know**: These functions serve different purposes and may need to be used together for comprehensive data consistency. For detailed examples and considerations, see [relationship with revalidateTag and updateTag](/docs/app/api-reference/functions/revalidatePath#relationship-with-revalidatetag-and-updatetag) for more information.\n00066| \n00067| ## Examples\n00068| \n00069| The following examples demonstrate how to use `revalidateTag` in different contexts. In both cases, we're using `profile=\"max\"` to mark data as stale and use stale-while-revalidate semantics, which is the recommended approach for most use cases.\n00070| \n00071| ### Server Action\n00072| \n00073| ```ts filename=\"app/actions.ts\" switcher\n00074| 'use server'\n00075| \n00076| import { revalidateTag } from 'next/cache'\n00077| \n00078| export default async function submit() {\n00079| await addPost()\n00080| revalidateTag('posts', 'max')\n00081| }\n00082| ```\n00083| \n00084| ```js filename=\"app/actions.js\" switcher\n00085| 'use server'\n00086| \n00087| import { revalidateTag } from 'next/cache'\n00088| \n00089| export default async function submit() {\n00090| await addPost()\n00091| revalidateTag('posts', 'max')\n00092| }\n00093| ```\n00094| \n00095| ### Route Handler\n00096| \n00097| ```ts filename=\"app/api/revalidate/route.ts\" switcher\n00098| import type { NextRequest } from 'next/server'\n00099| import { revalidateTag } from 'next/cache'\n00100| \n00101| export async function GET(request: NextRequest) {\n00102| const tag = request.nextUrl.searchParams.get('tag')\n00103| \n00104| if (tag) {\n00105| revalidateTag(tag, 'max')\n00106| return Response.json({ revalidated: true, now: Date.now() })\n00107| }\n00108| \n00109| return Response.json({\n00110| revalidated: false,\n00111| now: Date.now(),\n00112| message: 'Missing tag to revalidate',\n00113| })\n00114| }\n00115| ```\n00116| \n00117| ```js filename=\"app/api/revalidate/route.js\" switcher\n00118| import { revalidateTag } from 'next/cache'\n00119| \n00120| export async function GET(request) {\n00121| const tag = request.nextUrl.searchParams.get('tag')\n00122| \n00123| if (tag) {\n00124| revalidateTag(tag, 'max')\n00125| return Response.json({ revalidated: true, now: Date.now() })\n00126| }\n00127| \n00128| return Response.json({\n00129| revalidated: false,\n00130| now: Date.now(),\n00131| message: 'Missing tag to revalidate',\n00132| })\n00133| }\n00134| ```\n00135| \n00136| > **Good to know**: For webhooks or third-party services that need immediate expiration, you can pass `{ expire: 0 }` as the second argument: `revalidateTag(tag, { expire: 0 })`. This pattern is necessary when external systems call your Route Handlers and require data to expire immediately. For all other cases, it's recommended to use [`updateTag`](/docs/app/api-reference/functions/updateTag) in Server Actions for immediate updates instead.\n00137| \n\n(End of file - total 137 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md"
+ },
+ "output": "\n00001| ---\n00002| title: revalidateTag\n00003| description: API Reference for the revalidateTag function.\n00004| ---\n00005| \n00006| `revalidateTag` allows you to invalidate cached data on-demand for a specific cache tag.\n00007| \n00008| This function is ideal for content where a slight delay in updates is acceptable, such as blog posts, product catalogs, or documentation. Users receive stale content while fresh data loads in the background.\n00009| \n00010| ## Usage\n00011| \n00012| `revalidateTag` can be called in Server Functions and Route Handlers.\n00013| \n00014| `revalidateTag` cannot be called in Client Components or Proxy, as it only works in server environments.\n00015| \n00016| ### Revalidation Behavior\n00017| \n00018| The revalidation behavior depends on whether you provide the second argument:\n00019| \n00020| - **With `profile=\"max\"` (recommended)**: The tag entry is marked as stale, and the next time a resource with that tag is visited, it will use stale-while-revalidate semantics. This means the stale content is served while fresh content is fetched in the background.\n00021| - **With a custom cache life profile**: For advanced usage, you can specify any cache life profile that your application has defined, allowing for custom revalidation behaviors tailored to your specific caching requirements.\n00022| - **Without the second argument (deprecated)**: The tag entry is expired immediately, and the next request to that resource will be a blocking revalidate/cache miss. This behavior is now deprecated, and you should either use `profile=\"max\"` or migrate to [`updateTag`](/docs/app/api-reference/functions/updateTag).\n00023| \n00024| > **Good to know**: When using `profile=\"max\"`, `revalidateTag` marks tagged data as stale, but fresh data is only fetched when pages using that tag are next visited. This means calling `revalidateTag` will not immediately trigger many revalidations at once. The invalidation only happens when any page using that tag is next visited.\n00025| \n00026| ## Parameters\n00027| \n00028| ```ts\n00029| revalidateTag(tag: string, profile: string | { expire?: number }): void;\n00030| ```\n00031| \n00032| - `tag`: A string representing the cache tag associated with the data you want to revalidate. Must not exceed 256 characters. This value is case-sensitive.\n00033| - `profile`: A string that specifies the revalidation behavior. The recommended value is `\"max\"` which provides stale-while-revalidate semantics, or any of the other default or custom profiles defined in [`cacheLife`](/docs/app/api-reference/config/next-config-js/cacheLife). Alternatively, you can pass an object with an `expire` property for custom expiration behavior.\n00034| \n00035| Tags must first be assigned to cached data. You can do this in two ways:\n00036| \n00037| - Using the [`next.tags`](/docs/app/api-reference/functions/fetch) option with `fetch` for caching external API requests:\n00038| \n00039| ```tsx\n00040| fetch(url, { next: { tags: ['posts'] } })\n00041| ```\n00042| \n00043| - Using [`cacheTag`](/docs/app/api-reference/functions/cacheTag) inside cached functions or components with the `'use cache'` directive:\n00044| \n00045| ```tsx\n00046| import { cacheTag } from 'next/cache'\n00047| \n00048| async function getData() {\n00049| 'use cache'\n00050| cacheTag('posts')\n00051| // ...\n00052| }\n00053| ```\n00054| \n00055| > **Good to know**: The single-argument form `revalidateTag(tag)` is deprecated. It currently works if TypeScript errors are suppressed, but this behavior may be removed in a future version. Update to the two-argument signature.\n00056| \n00057| ## Returns\n00058| \n00059| `revalidateTag` does not return a value.\n00060| \n00061| ## Relationship with `revalidatePath`\n00062| \n00063| `revalidateTag` invalidates data with specific tags across all pages that use those tags, while [`revalidatePath`](/docs/app/api-reference/functions/revalidatePath) invalidates specific page or layout paths.\n00064| \n00065| > **Good to know**: These functions serve different purposes and may need to be used together for comprehensive data consistency. For detailed examples and considerations, see [relationship with revalidateTag and updateTag](/docs/app/api-reference/functions/revalidatePath#relationship-with-revalidatetag-and-updatetag) for more information.\n00066| \n00067| ## Examples\n00068| \n00069| The following examples demonstrate how to use `revalidateTag` in different contexts. In both cases, we're using `profile=\"max\"` to mark data as stale and use stale-while-revalidate semantics, which is the recommended approach for most use cases.\n00070| \n00071| ### Server Action\n00072| \n00073| ```ts filename=\"app/actions.ts\" switcher\n00074| 'use server'\n00075| \n00076| import { revalidateTag } from 'next/cache'\n00077| \n00078| export default async function submit() {\n00079| await addPost()\n00080| revalidateTag('posts', 'max')\n00081| }\n00082| ```\n00083| \n00084| ```js filename=\"app/actions.js\" switcher\n00085| 'use server'\n00086| \n00087| import { revalidateTag } from 'next/cache'\n00088| \n00089| export default async function submit() {\n00090| await addPost()\n00091| revalidateTag('posts', 'max')\n00092| }\n00093| ```\n00094| \n00095| ### Route Handler\n00096| \n00097| ```ts filename=\"app/api/revalidate/route.ts\" switcher\n00098| import type { NextRequest } from 'next/server'\n00099| import { revalidateTag } from 'next/cache'\n00100| \n00101| export async function GET(request: NextRequest) {\n00102| const tag = request.nextUrl.searchParams.get('tag')\n00103| \n00104| if (tag) {\n00105| revalidateTag(tag, 'max')\n00106| return Response.json({ revalidated: true, now: Date.now() })\n00107| }\n00108| \n00109| return Response.json({\n00110| revalidated: false,\n00111| now: Date.now(),\n00112| message: 'Missing tag to revalidate',\n00113| })\n00114| }\n00115| ```\n00116| \n00117| ```js filename=\"app/api/revalidate/route.js\" switcher\n00118| import { revalidateTag } from 'next/cache'\n00119| \n00120| export async function GET(request) {\n00121| const tag = request.nextUrl.searchParams.get('tag')\n00122| \n00123| if (tag) {\n00124| revalidateTag(tag, 'max')\n00125| return Response.json({ revalidated: true, now: Date.now() })\n00126| }\n00127| \n00128| return Response.json({\n00129| revalidated: false,\n00130| now: Date.now(),\n00131| message: 'Missing tag to revalidate',\n00132| })\n00133| }\n00134| ```\n00135| \n00136| > **Good to know**: For webhooks or third-party services that need immediate expiration, you can pass `{ expire: 0 }` as the second argument: `revalidateTag(tag, { expire: 0 })`. This pattern is necessary when external systems call your Route Handlers and require data to expire immediately. For all other cases, it's recommended to use [`updateTag`](/docs/app/api-reference/functions/updateTag) in Server Actions for immediate updates instead.\n00137| \n\n(End of file - total 137 lines)\n",
+ "title": "node_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md",
+ "metadata": {
+ "preview": "---\ntitle: revalidateTag\ndescription: API Reference for the revalidateTag function.\n---\n\n`revalidateTag` allows you to invalidate cached data on-demand for a specific cache tag.\n\nThis function is ideal for content where a slight delay in updates is acceptable, such as blog posts, product catalogs, or documentation. Users receive stale content while fresh data loads in the background.\n\n## Usage\n\n`revalidateTag` can be called in Server Functions and Route Handlers.\n\n`revalidateTag` cannot be called in Client Components or Proxy, as it only works in server environments.\n\n### Revalidation Behavior\n\nThe revalidation behavior depends on whether you provide the second argument:\n\n- **With `profile=\"max\"` (recommended)**: The tag entry is marked as stale, and the next time a resource with that tag is visited, it will use stale-while-revalidate semantics. This means the stale content is served while fresh content is fetched in the background."
+ },
+ "time": {
+ "start": 1781392535349,
+ "end": 1781392535354
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:35.932Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "args": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/updateTag.md",
+ "_extractedPath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/updateTag.md"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392535932,
+ "sessionID": "ses_13cbb922affe86wOEqVAq01qO3",
+ "part": {
+ "id": "prt_ec344ef38001pON2KZebO318l0",
+ "sessionID": "ses_13cbb922affe86wOEqVAq01qO3",
+ "messageID": "msg_ec344e3ba001wSxQa7jb952GvG",
+ "type": "tool",
+ "callID": "read_17",
+ "tool": "read",
+ "state": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/updateTag.md"
+ },
+ "output": "\n00001| ---\n00002| title: updateTag\n00003| description: API Reference for the updateTag function.\n00004| ---\n00005| \n00006| `updateTag` allows you to update cached data on-demand for a specific cache tag from within [Server Actions](/docs/app/getting-started/mutating-data).\n00007| \n00008| This function is designed for **read-your-own-writes** scenarios, where a user makes a change (like creating a post), and the UI immediately shows the change, rather than stale data.\n00009| \n00010| ## Usage\n00011| \n00012| `updateTag` can **only** be called from within [Server Actions](/docs/app/getting-started/mutating-data). It cannot be used in Route Handlers, Client Components, or any other context.\n00013| \n00014| If you need to invalidate cache tags in Route Handlers or other contexts, use [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) instead.\n00015| \n00016| > **Good to know**: `updateTag` immediately expires the cached data for the specified tag. The next request will wait to fetch fresh data rather than serving stale content from the cache, ensuring users see their changes immediately.\n00017| \n00018| ## Parameters\n00019| \n00020| ```tsx\n00021| updateTag(tag: string): void;\n00022| ```\n00023| \n00024| - `tag`: A string representing the cache tag associated with the data you want to update. Must not exceed 256 characters. This value is case-sensitive.\n00025| \n00026| Tags must first be assigned to cached data. You can do this in two ways:\n00027| \n00028| - Using the [`next.tags`](/docs/app/api-reference/functions/fetch) option with `fetch` for caching external API requests:\n00029| \n00030| ```tsx\n00031| fetch(url, { next: { tags: ['posts'] } })\n00032| ```\n00033| \n00034| - Using [`cacheTag`](/docs/app/api-reference/functions/cacheTag) inside cached functions or components with the `'use cache'` directive:\n00035| \n00036| ```tsx\n00037| import { cacheTag } from 'next/cache'\n00038| \n00039| async function getData() {\n00040| 'use cache'\n00041| cacheTag('posts')\n00042| // ...\n00043| }\n00044| ```\n00045| \n00046| ## Returns\n00047| \n00048| `updateTag` does not return a value.\n00049| \n00050| ## Differences from revalidateTag\n00051| \n00052| While both `updateTag` and `revalidateTag` invalidate cached data, they serve different purposes:\n00053| \n00054| - **`updateTag`**:\n00055| - Can only be used in Server Actions\n00056| - Next request waits for fresh data (no stale content served)\n00057| - Designed for read-your-own-writes scenarios\n00058| \n00059| - **`revalidateTag`**:\n00060| - Can be used in Server Actions and Route Handlers\n00061| - With `profile=\"max\"` (recommended): Serves cached data while fetching fresh data in the background (stale-while-revalidate)\n00062| - With custom profile: Can be configured to any cache life profile for advanced usage\n00063| - Without profile: legacy behavior which is equivalent to `updateTag`\n00064| \n00065| ## Examples\n00066| \n00067| ### Server Action with Read-Your-Own-Writes\n00068| \n00069| ```ts filename=\"app/actions.ts\" switcher\n00070| 'use server'\n00071| \n00072| import { updateTag } from 'next/cache'\n00073| import { redirect } from 'next/navigation'\n00074| \n00075| export async function createPost(formData: FormData) {\n00076| const title = formData.get('title')\n00077| const content = formData.get('content')\n00078| \n00079| // Create the post in your database\n00080| const post = await db.post.create({\n00081| data: { title, content },\n00082| })\n00083| \n00084| // Invalidate cache tags so the new post is immediately visible\n00085| // 'posts' tag: affects any page that displays a list of posts\n00086| updateTag('posts')\n00087| // 'post-{id}' tag: affects the individual post detail page\n00088| updateTag(`post-${post.id}`)\n00089| \n00090| // Redirect to the new post - user will see fresh data, not cached\n00091| redirect(`/posts/${post.id}`)\n00092| }\n00093| ```\n00094| \n00095| ```js filename=\"app/actions.js\" switcher\n00096| 'use server'\n00097| \n00098| import { updateTag } from 'next/cache'\n00099| import { redirect } from 'next/navigation'\n00100| \n00101| export async function createPost(formData) {\n00102| const title = formData.get('title')\n00103| const content = formData.get('content')\n00104| \n00105| // Create the post in your database\n00106| const post = await db.post.create({\n00107| data: { title, content },\n00108| })\n00109| \n00110| // Invalidate cache tags so the new post is immediately visible\n00111| // 'posts' tag: affects any page that displays a list of posts\n00112| updateTag('posts')\n00113| // 'post-{id}' tag: affects the individual post detail page\n00114| updateTag(`post-${post.id}`)\n00115| \n00116| // Redirect to the new post - user will see fresh data, not cached\n00117| redirect(`/posts/${post.id}`)\n00118| }\n00119| ```\n00120| \n00121| ### Error when used outside Server Actions\n00122| \n00123| ```ts filename=\"app/api/posts/route.ts\" switcher\n00124| import { updateTag } from 'next/cache'\n00125| \n00126| export async function POST() {\n00127| // This will throw an error\n00128| updateTag('posts')\n00129| // Error: updateTag can only be called from within a Server Action\n00130| \n00131| // Use revalidateTag instead in Route Handlers\n00132| revalidateTag('posts', 'max')\n00133| }\n00134| ```\n00135| \n00136| ## When to use updateTag\n00137| \n00138| Use `updateTag` when:\n00139| \n00140| - You're in a Server Action\n00141| - You need immediate cache invalidation for read-your-own-writes\n00142| - You want to ensure the next request sees updated data\n00143| \n00144| Use `revalidateTag` instead when:\n00145| \n00146| - You're in a Route Handler or other non-action context\n00147| - You want stale-while-revalidate semantics\n00148| - You're building a webhook or API endpoint for cache invalidation\n00149| \n00150| ## Related\n00151| \n00152| - [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) - For invalidating tags in Route Handlers\n00153| - [`revalidatePath`](/docs/app/api-reference/functions/revalidatePath) - For invalidating specific paths\n00154| \n\n(End of file - total 154 lines)\n",
+ "title": "node_modules/next/dist/docs/01-app/03-api-reference/04-functions/updateTag.md",
+ "metadata": {
+ "preview": "---\ntitle: updateTag\ndescription: API Reference for the updateTag function.\n---\n\n`updateTag` allows you to update cached data on-demand for a specific cache tag from within [Server Actions](/docs/app/getting-started/mutating-data).\n\nThis function is designed for **read-your-own-writes** scenarios, where a user makes a change (like creating a post), and the UI immediately shows the change, rather than stale data.\n\n## Usage\n\n`updateTag` can **only** be called from within [Server Actions](/docs/app/getting-started/mutating-data). It cannot be used in Route Handlers, Client Components, or any other context.\n\nIf you need to invalidate cache tags in Route Handlers or other contexts, use [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) instead.\n\n> **Good to know**: `updateTag` immediately expires the cached data for the specified tag. The next request will wait to fetch fresh data rather than serving stale content from the cache, ensuring users see their changes immediately.\n\n## Parameters\n\n```tsx"
+ },
+ "time": {
+ "start": 1781392535928,
+ "end": 1781392535932
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:35.932Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| ---\n00002| title: updateTag\n00003| description: API Reference for the updateTag function.\n00004| ---\n00005| \n00006| `updateTag` allows you to update cached data on-demand for a specific cache tag from within [Server Actions](/docs/app/getting-started/mutating-data).\n00007| \n00008| This function is designed for **read-your-own-writes** scenarios, where a user makes a change (like creating a post), and the UI immediately shows the change, rather than stale data.\n00009| \n00010| ## Usage\n00011| \n00012| `updateTag` can **only** be called from within [Server Actions](/docs/app/getting-started/mutating-data). It cannot be used in Route Handlers, Client Components, or any other context.\n00013| \n00014| If you need to invalidate cache tags in Route Handlers or other contexts, use [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) instead.\n00015| \n00016| > **Good to know**: `updateTag` immediately expires the cached data for the specified tag. The next request will wait to fetch fresh data rather than serving stale content from the cache, ensuring users see their changes immediately.\n00017| \n00018| ## Parameters\n00019| \n00020| ```tsx\n00021| updateTag(tag: string): void;\n00022| ```\n00023| \n00024| - `tag`: A string representing the cache tag associated with the data you want to update. Must not exceed 256 characters. This value is case-sensitive.\n00025| \n00026| Tags must first be assigned to cached data. You can do this in two ways:\n00027| \n00028| - Using the [`next.tags`](/docs/app/api-reference/functions/fetch) option with `fetch` for caching external API requests:\n00029| \n00030| ```tsx\n00031| fetch(url, { next: { tags: ['posts'] } })\n00032| ```\n00033| \n00034| - Using [`cacheTag`](/docs/app/api-reference/functions/cacheTag) inside cached functions or components with the `'use cache'` directive:\n00035| \n00036| ```tsx\n00037| import { cacheTag } from 'next/cache'\n00038| \n00039| async function getData() {\n00040| 'use cache'\n00041| cacheTag('posts')\n00042| // ...\n00043| }\n00044| ```\n00045| \n00046| ## Returns\n00047| \n00048| `updateTag` does not return a value.\n00049| \n00050| ## Differences from revalidateTag\n00051| \n00052| While both `updateTag` and `revalidateTag` invalidate cached data, they serve different purposes:\n00053| \n00054| - **`updateTag`**:\n00055| - Can only be used in Server Actions\n00056| - Next request waits for fresh data (no stale content served)\n00057| - Designed for read-your-own-writes scenarios\n00058| \n00059| - **`revalidateTag`**:\n00060| - Can be used in Server Actions and Route Handlers\n00061| - With `profile=\"max\"` (recommended): Serves cached data while fetching fresh data in the background (stale-while-revalidate)\n00062| - With custom profile: Can be configured to any cache life profile for advanced usage\n00063| - Without profile: legacy behavior which is equivalent to `updateTag`\n00064| \n00065| ## Examples\n00066| \n00067| ### Server Action with Read-Your-Own-Writes\n00068| \n00069| ```ts filename=\"app/actions.ts\" switcher\n00070| 'use server'\n00071| \n00072| import { updateTag } from 'next/cache'\n00073| import { redirect } from 'next/navigation'\n00074| \n00075| export async function createPost(formData: FormData) {\n00076| const title = formData.get('title')\n00077| const content = formData.get('content')\n00078| \n00079| // Create the post in your database\n00080| const post = await db.post.create({\n00081| data: { title, content },\n00082| })\n00083| \n00084| // Invalidate cache tags so the new post is immediately visible\n00085| // 'posts' tag: affects any page that displays a list of posts\n00086| updateTag('posts')\n00087| // 'post-{id}' tag: affects the individual post detail page\n00088| updateTag(`post-${post.id}`)\n00089| \n00090| // Redirect to the new post - user will see fresh data, not cached\n00091| redirect(`/posts/${post.id}`)\n00092| }\n00093| ```\n00094| \n00095| ```js filename=\"app/actions.js\" switcher\n00096| 'use server'\n00097| \n00098| import { updateTag } from 'next/cache'\n00099| import { redirect } from 'next/navigation'\n00100| \n00101| export async function createPost(formData) {\n00102| const title = formData.get('title')\n00103| const content = formData.get('content')\n00104| \n00105| // Create the post in your database\n00106| const post = await db.post.create({\n00107| data: { title, content },\n00108| })\n00109| \n00110| // Invalidate cache tags so the new post is immediately visible\n00111| // 'posts' tag: affects any page that displays a list of posts\n00112| updateTag('posts')\n00113| // 'post-{id}' tag: affects the individual post detail page\n00114| updateTag(`post-${post.id}`)\n00115| \n00116| // Redirect to the new post - user will see fresh data, not cached\n00117| redirect(`/posts/${post.id}`)\n00118| }\n00119| ```\n00120| \n00121| ### Error when used outside Server Actions\n00122| \n00123| ```ts filename=\"app/api/posts/route.ts\" switcher\n00124| import { updateTag } from 'next/cache'\n00125| \n00126| export async function POST() {\n00127| // This will throw an error\n00128| updateTag('posts')\n00129| // Error: updateTag can only be called from within a Server Action\n00130| \n00131| // Use revalidateTag instead in Route Handlers\n00132| revalidateTag('posts', 'max')\n00133| }\n00134| ```\n00135| \n00136| ## When to use updateTag\n00137| \n00138| Use `updateTag` when:\n00139| \n00140| - You're in a Server Action\n00141| - You need immediate cache invalidation for read-your-own-writes\n00142| - You want to ensure the next request sees updated data\n00143| \n00144| Use `revalidateTag` instead when:\n00145| \n00146| - You're in a Route Handler or other non-action context\n00147| - You want stale-while-revalidate semantics\n00148| - You're building a webhook or API endpoint for cache invalidation\n00149| \n00150| ## Related\n00151| \n00152| - [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) - For invalidating tags in Route Handlers\n00153| - [`revalidatePath`](/docs/app/api-reference/functions/revalidatePath) - For invalidating specific paths\n00154| \n\n(End of file - total 154 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/updateTag.md"
+ },
+ "output": "\n00001| ---\n00002| title: updateTag\n00003| description: API Reference for the updateTag function.\n00004| ---\n00005| \n00006| `updateTag` allows you to update cached data on-demand for a specific cache tag from within [Server Actions](/docs/app/getting-started/mutating-data).\n00007| \n00008| This function is designed for **read-your-own-writes** scenarios, where a user makes a change (like creating a post), and the UI immediately shows the change, rather than stale data.\n00009| \n00010| ## Usage\n00011| \n00012| `updateTag` can **only** be called from within [Server Actions](/docs/app/getting-started/mutating-data). It cannot be used in Route Handlers, Client Components, or any other context.\n00013| \n00014| If you need to invalidate cache tags in Route Handlers or other contexts, use [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) instead.\n00015| \n00016| > **Good to know**: `updateTag` immediately expires the cached data for the specified tag. The next request will wait to fetch fresh data rather than serving stale content from the cache, ensuring users see their changes immediately.\n00017| \n00018| ## Parameters\n00019| \n00020| ```tsx\n00021| updateTag(tag: string): void;\n00022| ```\n00023| \n00024| - `tag`: A string representing the cache tag associated with the data you want to update. Must not exceed 256 characters. This value is case-sensitive.\n00025| \n00026| Tags must first be assigned to cached data. You can do this in two ways:\n00027| \n00028| - Using the [`next.tags`](/docs/app/api-reference/functions/fetch) option with `fetch` for caching external API requests:\n00029| \n00030| ```tsx\n00031| fetch(url, { next: { tags: ['posts'] } })\n00032| ```\n00033| \n00034| - Using [`cacheTag`](/docs/app/api-reference/functions/cacheTag) inside cached functions or components with the `'use cache'` directive:\n00035| \n00036| ```tsx\n00037| import { cacheTag } from 'next/cache'\n00038| \n00039| async function getData() {\n00040| 'use cache'\n00041| cacheTag('posts')\n00042| // ...\n00043| }\n00044| ```\n00045| \n00046| ## Returns\n00047| \n00048| `updateTag` does not return a value.\n00049| \n00050| ## Differences from revalidateTag\n00051| \n00052| While both `updateTag` and `revalidateTag` invalidate cached data, they serve different purposes:\n00053| \n00054| - **`updateTag`**:\n00055| - Can only be used in Server Actions\n00056| - Next request waits for fresh data (no stale content served)\n00057| - Designed for read-your-own-writes scenarios\n00058| \n00059| - **`revalidateTag`**:\n00060| - Can be used in Server Actions and Route Handlers\n00061| - With `profile=\"max\"` (recommended): Serves cached data while fetching fresh data in the background (stale-while-revalidate)\n00062| - With custom profile: Can be configured to any cache life profile for advanced usage\n00063| - Without profile: legacy behavior which is equivalent to `updateTag`\n00064| \n00065| ## Examples\n00066| \n00067| ### Server Action with Read-Your-Own-Writes\n00068| \n00069| ```ts filename=\"app/actions.ts\" switcher\n00070| 'use server'\n00071| \n00072| import { updateTag } from 'next/cache'\n00073| import { redirect } from 'next/navigation'\n00074| \n00075| export async function createPost(formData: FormData) {\n00076| const title = formData.get('title')\n00077| const content = formData.get('content')\n00078| \n00079| // Create the post in your database\n00080| const post = await db.post.create({\n00081| data: { title, content },\n00082| })\n00083| \n00084| // Invalidate cache tags so the new post is immediately visible\n00085| // 'posts' tag: affects any page that displays a list of posts\n00086| updateTag('posts')\n00087| // 'post-{id}' tag: affects the individual post detail page\n00088| updateTag(`post-${post.id}`)\n00089| \n00090| // Redirect to the new post - user will see fresh data, not cached\n00091| redirect(`/posts/${post.id}`)\n00092| }\n00093| ```\n00094| \n00095| ```js filename=\"app/actions.js\" switcher\n00096| 'use server'\n00097| \n00098| import { updateTag } from 'next/cache'\n00099| import { redirect } from 'next/navigation'\n00100| \n00101| export async function createPost(formData) {\n00102| const title = formData.get('title')\n00103| const content = formData.get('content')\n00104| \n00105| // Create the post in your database\n00106| const post = await db.post.create({\n00107| data: { title, content },\n00108| })\n00109| \n00110| // Invalidate cache tags so the new post is immediately visible\n00111| // 'posts' tag: affects any page that displays a list of posts\n00112| updateTag('posts')\n00113| // 'post-{id}' tag: affects the individual post detail page\n00114| updateTag(`post-${post.id}`)\n00115| \n00116| // Redirect to the new post - user will see fresh data, not cached\n00117| redirect(`/posts/${post.id}`)\n00118| }\n00119| ```\n00120| \n00121| ### Error when used outside Server Actions\n00122| \n00123| ```ts filename=\"app/api/posts/route.ts\" switcher\n00124| import { updateTag } from 'next/cache'\n00125| \n00126| export async function POST() {\n00127| // This will throw an error\n00128| updateTag('posts')\n00129| // Error: updateTag can only be called from within a Server Action\n00130| \n00131| // Use revalidateTag instead in Route Handlers\n00132| revalidateTag('posts', 'max')\n00133| }\n00134| ```\n00135| \n00136| ## When to use updateTag\n00137| \n00138| Use `updateTag` when:\n00139| \n00140| - You're in a Server Action\n00141| - You need immediate cache invalidation for read-your-own-writes\n00142| - You want to ensure the next request sees updated data\n00143| \n00144| Use `revalidateTag` instead when:\n00145| \n00146| - You're in a Route Handler or other non-action context\n00147| - You want stale-while-revalidate semantics\n00148| - You're building a webhook or API endpoint for cache invalidation\n00149| \n00150| ## Related\n00151| \n00152| - [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) - For invalidating tags in Route Handlers\n00153| - [`revalidatePath`](/docs/app/api-reference/functions/revalidatePath) - For invalidating specific paths\n00154| \n\n(End of file - total 154 lines)\n",
+ "title": "node_modules/next/dist/docs/01-app/03-api-reference/04-functions/updateTag.md",
+ "metadata": {
+ "preview": "---\ntitle: updateTag\ndescription: API Reference for the updateTag function.\n---\n\n`updateTag` allows you to update cached data on-demand for a specific cache tag from within [Server Actions](/docs/app/getting-started/mutating-data).\n\nThis function is designed for **read-your-own-writes** scenarios, where a user makes a change (like creating a post), and the UI immediately shows the change, rather than stale data.\n\n## Usage\n\n`updateTag` can **only** be called from within [Server Actions](/docs/app/getting-started/mutating-data). It cannot be used in Route Handlers, Client Components, or any other context.\n\nIf you need to invalidate cache tags in Route Handlers or other contexts, use [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) instead.\n\n> **Good to know**: `updateTag` immediately expires the cached data for the specified tag. The next request will wait to fetch fresh data rather than serving stale content from the cache, ensuring users see their changes immediately.\n\n## Parameters\n\n```tsx"
+ },
+ "time": {
+ "start": 1781392535928,
+ "end": 1781392535932
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:35.988Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "args": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache.md",
+ "_extractedPath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache.md"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392535988,
+ "sessionID": "ses_13cbb922affe86wOEqVAq01qO3",
+ "part": {
+ "id": "prt_ec344f17a001XyhvKihJp5kESx",
+ "sessionID": "ses_13cbb922affe86wOEqVAq01qO3",
+ "messageID": "msg_ec344e3ba001wSxQa7jb952GvG",
+ "type": "tool",
+ "callID": "read_18",
+ "tool": "read",
+ "state": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache.md"
+ },
+ "output": "\n00001| ---\n00002| title: use cache\n00003| description: Learn how to use the \"use cache\" directive to cache data in your Next.js application.\n00004| related:\n00005| title: Related\n00006| description: View related API references.\n00007| links:\n00008| - app/api-reference/directives/use-cache-private\n00009| - app/api-reference/config/next-config-js/cacheComponents\n00010| - app/api-reference/config/next-config-js/cacheLife\n00011| - app/api-reference/config/next-config-js/cacheHandlers\n00012| - app/api-reference/functions/cacheTag\n00013| - app/api-reference/functions/cacheLife\n00014| - app/api-reference/functions/revalidateTag\n00015| ---\n00016| \n00017| The `use cache` directive allows you to mark a route, React component, or a function as cacheable. It can be used at the top of a file to indicate that all exports in the file should be cached, or inline at the top of a function or component to cache the return value. Functions and components that use `use cache` must be async.\n00018| \n00019| > **Good to know:**\n00020| >\n00021| > - To use cookies or headers, read them outside cached scopes and pass values as arguments. This is the preferred pattern.\n00022| > - If the in-memory cache isn't sufficient for runtime data, [`'use cache: remote'`](/docs/app/api-reference/directives/use-cache-remote) allows platforms to provide a dedicated cache handler, though it requires a network roundtrip to check the cache and typically incurs platform fees.\n00023| > - For compliance requirements or when you can't refactor to pass runtime data as arguments to a `use cache` scope, see [`'use cache: private'`](/docs/app/api-reference/directives/use-cache-private).\n00024| \n00025| ## Usage\n00026| \n00027| `use cache` is a Cache Components feature. To enable it, add the [`cacheComponents`](/docs/app/api-reference/config/next-config-js/cacheComponents) option to your `next.config.ts` file:\n00028| \n00029| ```ts filename=\"next.config.ts\" switcher\n00030| import type { NextConfig } from 'next'\n00031| \n00032| const nextConfig: NextConfig = {\n00033| cacheComponents: true,\n00034| }\n00035| \n00036| export default nextConfig\n00037| ```\n00038| \n00039| ```js filename=\"next.config.js\" switcher\n00040| /** @type {import('next').NextConfig} */\n00041| const nextConfig = {\n00042| cacheComponents: true,\n00043| }\n00044| \n00045| module.exports = nextConfig\n00046| ```\n00047| \n00048| Then, add `use cache` at the file, component, or function level. All functions and components using `use cache` must be async. When used at file level, every exported function becomes a cached function and must also be async:\n00049| \n00050| ```tsx\n00051| // File level\n00052| 'use cache'\n00053| \n00054| export default async function Page() {\n00055| // ...\n00056| }\n00057| \n00058| // Component level\n00059| export async function MyComponent() {\n00060| 'use cache'\n00061| return <>>\n00062| }\n00063| \n00064| // Function level\n00065| export async function getData() {\n00066| 'use cache'\n00067| const data = await fetch('/api/data')\n00068| return data\n00069| }\n00070| ```\n00071| \n00072| ## How `use cache` works\n00073| \n00074| ### Cache keys\n00075| \n00076| A cache entry's key is generated using a serialized version of its inputs, which includes:\n00077| \n00078| 1. **Build ID** - Unique per build, changing this invalidates all cache entries. If [`deploymentId`](/docs/app/api-reference/config/next-config-js/deploymentId) is configured, it overrides the build ID for cache key purposes.\n00079| 2. **Function ID** - A secure hash of the function's location and signature in the codebase\n00080| 3. **Serializable arguments** - Props (for components) or function arguments\n00081| 4. **HMR refresh hash** (development only) - Invalidates cache on hot module replacement\n00082| \n00083| When a cached function references variables from outer scopes, those variables are automatically captured and bound as arguments, making them part of the cache key.\n00084| \n00085| ```tsx filename=\"lib/data.ts\"\n00086| async function Component({ userId }: { userId: string }) {\n00087| const getData = async (filter: string) => {\n00088| 'use cache'\n00089| // Cache key includes both userId (from closure) and filter (argument)\n00090| return fetch(`/api/users/${userId}/data?filter=${filter}`)\n00091| }\n00092| \n00093| return getData('active')\n00094| }\n00095| ```\n00096| \n00097| In the snippet above, `userId` is captured from the outer scope and `filter` is passed as an argument, so both become part of the `getData` function's cache key. This means different user and filter combinations will have separate cache entries.\n00098| \n00099| > **Good to know:** When a cached function reads [root parameters](/docs/app/api-reference/functions/next-root-params), only the ones it actually reads become part of its cache key.\n00100| \n00101| ## Serialization\n00102| \n00103| Arguments to cached functions and their return values must be serializable.\n00104| \n00105| For a complete reference, see:\n00106| \n00107| - [Serializable arguments](https://react.dev/reference/rsc/use-server#serializable-parameters-and-return-values) - Uses **React Server Components** serialization\n00108| - [Serializable return types](https://react.dev/reference/rsc/use-client#serializable-types) - Uses **React Client Components** serialization\n00109| \n00110| > **Good to know:** Arguments and return values use different serialization systems. Server Component serialization (for arguments) is more restrictive than Client Component serialization (for return values). This means you can return JSX elements but cannot accept them as arguments unless using pass-through patterns.\n00111| \n00112| ### Supported types\n00113| \n00114| **Arguments:**\n00115| \n00116| - Primitives: `string`, `number`, `boolean`, `null`, `undefined`\n00117| - Plain objects: `{ key: value }`\n00118| - Arrays: `[1, 2, 3]`\n00119| - Dates, Maps, Sets, TypedArrays, ArrayBuffers\n00120| - React elements (as pass-through only)\n00121| \n00122| **Return values:**\n00123| \n00124| - Same as arguments, plus JSX elements\n00125| \n00126| ### Unsupported types\n00127| \n00128| - Class instances\n00129| - Functions (except as pass-through)\n00130| - Symbols, WeakMaps, WeakSets\n00131| - URL instances\n00132| \n00133| ```tsx filename=\"app/components/user-card.tsx\"\n00134| // Valid - primitives and plain objects\n00135| async function UserCard({\n00136| id,\n00137| config,\n00138| }: {\n00139| id: string\n00140| config: { theme: string }\n00141| }) {\n00142| 'use cache'\n00143| return
{id}
\n00144| }\n00145| \n00146| // Invalid - class instance\n00147| async function UserProfile({ user }: { user: UserClass }) {\n00148| 'use cache'\n00149| // Error: Cannot serialize class instance\n00150| return
{user.name}
\n00151| }\n00152| ```\n00153| \n00154| ### Pass-through (non-serializable arguments)\n00155| \n00156| You can accept non-serializable values **as long as you don't introspect them**. This enables composition patterns with `children` and Server Actions:\n00157| \n00158| ```tsx filename=\"app/components/cached-wrapper.tsx\"\n00159| async function CachedWrapper({ children }: { children: ReactNode }) {\n00160| 'use cache'\n00161| // Don't read or modify children - just pass it through\n00162| return (\n00163|
\n00164| Cached Header\n00165| {children}\n00166|
\n00167| )\n00168| }\n00169| \n00170| // Usage: children can be dynamic\n00171| export default function Page() {\n00172| return (\n00173| \n00174| {/* Not cached, passed through */}\n00175| \n00176| )\n00177| }\n00178| ```\n00179| \n00180| You can also pass Server Actions through cached components:\n00181| \n00182| ```tsx filename=\"app/components/cached-form.tsx\"\n00183| async function CachedForm({ action }: { action: () => Promise }) {\n00184| 'use cache'\n00185| // Don't call action here - just pass it through\n00186| return
{/* ... */}
\n00187| }\n00188| ```\n00189| \n00190| ## Constraints\n00191| \n00192| Cached functions execute in an isolated environment. The following constraints ensure cache behavior remains predictable and secure.\n00193| \n00194| ### Request-time APIs\n00195| \n00196| Cached functions and components **cannot** directly access runtime APIs like `cookies()`, `headers()`, or `searchParams`. Instead, read these values outside the cached scope and pass them as arguments.\n00197| \n00198| ### Runtime caching considerations\n00199| \n00200| While `use cache` is designed primarily to include uncached data in the static shell, it can also cache data at runtime using in-memory LRU (Least Recently Used) storage.\n00201| \n00202| With the default in-memory handler, runtime cache behavior depends on your hosting environment:\n00203| \n00204| | Environment | Runtime Caching Behavior |\n00205| | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n00206| | **Serverless** | Cache entries typically don't persist across requests (each request can be a different instance), or during revalidation. Build-time caching works normally. |\n00207| | **Self-hosted** | Cache entries persist across requests. Control cache size with [`cacheMaxMemorySize`](/docs/app/api-reference/config/next-config-js/incrementalCacheHandlerPath). |\n00208| \n00209| For example, in a serverless environment, a cached function shared by two pages executes on each static shell revalidation, whereas in self-hosted or environments with persistent memory, the cached output is reused if it's still fresh.\n00210| \n00211| If the default in-memory cache isn't enough, consider **[`use cache: remote`](/docs/app/api-reference/directives/use-cache-remote)** which allows platforms to provide a dedicated cache handler (like Redis or KV database). This helps reduce hits against data sources not scaled to your total traffic, though it comes with costs (storage, network latency, platform fees).\n00212| \n00213| > [!NOTE]\n00214| > With the default in-memory handler, serverless instances are ephemeral, so entries may not be reused between requests, unlike with `use cache: remote`. Neither caching directive carries over to a new deploy, because the [cache key](#cache-keys) includes the build (or `deploymentId`) ID.\n00215| >\n00216| > For data that needs to persist across deploys, use [`unstable_cache`](/docs/app/api-reference/functions/unstable_cache) for non-`fetch` functions or the [`fetch`](/docs/app/api-reference/functions/fetch) cache.\n00217| \n00218| Very rarely, for compliance requirements or when you can't refactor your code to pass runtime data as arguments to a `use cache` scope, you might need [`use cache: private`](/docs/app/api-reference/directives/use-cache-private).\n00219| \n00220| ### Draft Mode\n00221| \n00222| When [Draft Mode](/docs/app/guides/draft-mode) is enabled, all cached functions and components re-execute on every request, and results are not saved to the cache. This ensures draft content is always fresh without requiring any changes to your caching code.\n00223| \n00224| You can read `isEnabled` from [`draftMode()`](/docs/app/api-reference/functions/draft-mode) inside a `use cache` scope, however, other runtime APIs like `cookies()` and `headers()` are not allowed, even when Draft Mode is active. See [Passing runtime values to cached functions](/docs/app/getting-started/caching#passing-runtime-values-to-cached-functions) for the recommended pattern.\n00225| \n00226| ```tsx filename=\"app/components/content.tsx\"\n00227| import { draftMode } from 'next/headers'\n00228| \n00229| async function Content() {\n00230| 'use cache'\n00231| \n00232| const { isEnabled } = await draftMode()\n00233| const url = isEnabled\n00234| ? 'https://draft.example.com/content'\n00235| : 'https://production.example.com/content'\n00236| \n00237| const data = await fetch(url)\n00238| return {/* ... */}\n00239| }\n00240| ```\n00241| \n00242| Calling `enable()` or `disable()` inside a caching directive scope will also throw an error. Draft Mode can only be toggled in [Route Handlers](/docs/app/api-reference/file-conventions/route) or [Server Actions](/docs/app/getting-started/mutating-data).\n00243| \n00244| ### React.cache isolation\n00245| \n00246| [`React.cache`](https://react.dev/reference/react/cache) operates in an isolated scope inside `use cache` boundaries. Values stored via `React.cache` outside a `use cache` function are not visible inside it.\n00247| \n00248| This means you cannot use `React.cache` to pass data into a `use cache` scope:\n00249| \n00250| ```tsx\n00251| import { cache } from 'react'\n00252| \n00253| const store = cache(() => ({ current: null as string | null }))\n00254| \n00255| function Parent() {\n00256| const shared = store()\n00257| shared.current = 'value from parent'\n00258| return \n00259| }\n00260| \n00261| async function Child() {\n00262| 'use cache'\n00263| const shared = store()\n00264| // shared.current is null, not 'value from parent'\n00265| // use cache has its own isolated React.cache scope\n00266| return
{shared.current}
\n00267| }\n00268| ```\n00269| \n00270| This isolation ensures cached functions have predictable, self-contained behavior. To pass data into a `use cache` scope, use function arguments instead.\n00271| \n00272| ## `use cache` at runtime\n00273| \n00274| On the **server**, cache entries are stored in-memory and respect the `revalidate` and `expire` times from your `cacheLife` configuration. You can customize the cache storage by configuring [`cacheHandlers`](/docs/app/api-reference/config/next-config-js/cacheHandlers) in your `next.config.js` file.\n00275| \n00276| On the **client**, content from the server cache is stored in the browser's memory for the duration defined by the `stale` time. The client router enforces a **minimum 30-second stale time**, regardless of configuration.\n00277| \n00278| The `x-nextjs-stale-time` response header communicates cache lifetime from server to client, ensuring coordinated behavior.\n00279| \n00280| ## Revalidation\n00281| \n00282| By default, `use cache` uses the `default` profile with these settings:\n00283| \n00284| - **stale**: 5 minutes (client-side)\n00285| - **revalidate**: 15 minutes (server-side)\n00286| - **expire**: Never expires by time\n00287| \n00288| ```tsx filename=\"lib/data.ts\"\n00289| async function getData() {\n00290| 'use cache'\n00291| // Implicitly uses default profile\n00292| return fetch('/api/data')\n00293| }\n00294| ```\n00295| \n00296| ### Customizing cache lifetime\n00297| \n00298| Use the [`cacheLife`](/docs/app/api-reference/functions/cacheLife) function to customize cache duration:\n00299| \n00300| ```tsx filename=\"lib/data.ts\"\n00301| import { cacheLife } from 'next/cache'\n00302| \n00303| async function getData() {\n00304| 'use cache'\n00305| cacheLife('hours') // Use built-in 'hours' profile\n00306| return fetch('/api/data')\n00307| }\n00308| ```\n00309| \n00310| ### On-demand revalidation\n00311| \n00312| Use [`cacheTag`](/docs/app/api-reference/functions/cacheTag), [`updateTag`](/docs/app/api-reference/functions/updateTag), or [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) for on-demand cache invalidation:\n00313| \n00314| ```tsx filename=\"lib/data.ts\"\n00315| import { cacheTag } from 'next/cache'\n00316| \n00317| async function getProducts() {\n00318| 'use cache'\n00319| cacheTag('products')\n00320| return fetch('/api/products')\n00321| }\n00322| ```\n00323| \n00324| ```tsx filename=\"app/actions.ts\"\n00325| 'use server'\n00326| \n00327| import { updateTag } from 'next/cache'\n00328| \n00329| export async function updateProduct() {\n00330| await db.products.update(...)\n00331| updateTag('products') // Invalidates all 'products' caches\n00332| }\n00333| ```\n00334| \n00335| Both `cacheLife` and `cacheTag` integrate across client and server caching layers, meaning you configure your caching semantics in one place and they apply everywhere.\n00336| \n00337| ## Examples\n00338| \n00339| ### Caching an entire route with `use cache`\n00340| \n00341| To prerender an entire route, add `use cache` to the top of **both** the `layout` and `page` files. Each of these segments are treated as separate entry points in your application, and will be cached independently.\n00342| \n00343| ```tsx filename=\"app/layout.tsx\" switcher\n00344| 'use cache'\n00345| \n00346| export default async function Layout({ children }: { children: ReactNode }) {\n00347| return
{children}
\n00348| }\n00349| ```\n00350| \n00351| ```jsx filename=\"app/layout.js\" switcher\n00352| 'use cache'\n00353| \n00354| export default async function Layout({ children }) {\n00355| return
{children}
\n00356| }\n00357| ```\n00358| \n00359| Any components imported and nested in `page` file are part of the cache output associated with the `page`.\n00360| \n00361| ```tsx filename=\"app/page.tsx\" switcher\n00362| 'use cache'\n00363| \n00364| async function Users() {\n00365| const users = await fetch('/api/users')\n00366| // loop through users\n00367| }\n00368| \n00369| export default async function Page() {\n00370| return (\n00371| \n00372| \n00373| \n00374| )\n00375| }\n00376| ```\n00377| \n00378| ```jsx filename=\"app/page.js\" switcher\n00379| 'use cache'\n00380| \n00381| async function Users() {\n00382| const users = await fetch('/api/users')\n00383| // loop through users\n00384| }\n00385| \n00386| export default async function Page() {\n00387| return (\n00388| \n00389| \n00390| \n00391| )\n00392| }\n00393| ```\n00394| \n00395| > **Good to know**:\n00396| >\n00397| > - If `use cache` is added only to the `layout` or the `page`, only that route segment and any components imported into it will be cached.\n00398| \n00399| ### Caching a component's output with `use cache`\n00400| \n00401| You can use `use cache` at the component level to cache any fetches or computations performed within that component. The cache entry will be reused as long as the serialized props produce the same value in each instance.\n00402| \n00403| ```tsx filename=\"app/components/bookings.tsx\" highlight={2} switcher\n00404| export async function Bookings({ type = 'haircut' }: BookingsProps) {\n00405| 'use cache'\n00406| async function getBookingsData() {\n00407| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00408| return data\n00409| }\n00410| return //...\n00411| }\n00412| \n00413| interface BookingsProps {\n00414| type: string\n00415| }\n00416| ```\n00417| \n00418| ```jsx filename=\"app/components/bookings.js\" highlight={2} switcher\n00419| export async function Bookings({ type = 'haircut' }) {\n00420| 'use cache'\n00421| async function getBookingsData() {\n00422| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00423| return data\n00424| }\n00425| return //...\n00426| }\n00427| ```\n00428| \n00429| ### Caching function output with `use cache`\n00430| \n00431| Since you can add `use cache` to any asynchronous function, you aren't limited to caching components or routes only. You might want to cache a network request, a database query, or a slow computation.\n00432| \n00433| ```tsx filename=\"app/actions.ts\" highlight={2} switcher\n00434| export async function getData() {\n00435| 'use cache'\n00436| \n00437| const data = await fetch('/api/data')\n00438| return data\n00439| }\n00440| ```\n00441| \n00442| ```jsx filename=\"app/actions.js\" highlight={2} switcher\n00443| export async function getData() {\n00444| 'use cache'\n00445| \n00446| const data = await fetch('/api/data')\n00447| return data\n00448| }\n00449| ```\n00450| \n00451| > **Good to know:** When a cached directive (`use cache`, [`use cache: private`](/docs/app/api-reference/directives/use-cache-private), or [`use cache: remote`](/docs/app/api-reference/directives/use-cache-remote)) is at the top of a file, you can import its exported functions into a Client Component and call them directly; they run on the server and return the result, similar to a [Server Function](/docs/app/glossary#server-function). Prefer calling cached functions on the server and passing results down as props.\n00452| \n00453| ### Interleaving\n00454| \n00455| In React, composition with `children` or slots is a well-known pattern for building flexible components. When using `use cache`, you can continue to compose your UI in this way. Anything included as `children`, or other compositional slots, in the returned JSX will be passed through the cached component without affecting its cache entry.\n00456| \n00457| As long as you don't directly reference any of the JSX slots inside the body of the cacheable function itself, their presence in the returned output won't affect the cache entry.\n00458| \n00459| ```tsx filename=\"app/page.tsx\" switcher\n00460| export default async function Page() {\n00461| const uncachedData = await getData()\n00462| return (\n00463| // Pass compositional slots as props, e.g. header and children\n00464| Home}>\n00465| {/* DynamicComponent is provided as the children slot */}\n00466| \n00467| \n00468| )\n00469| }\n00470| \n00471| async function CacheComponent({\n00472| header, // header: a compositional slot, injected as a prop\n00473| children, // children: another slot for nested composition\n00474| }: {\n00475| header: ReactNode\n00476| children: ReactNode\n00477| }) {\n00478| 'use cache'\n00479| const cachedData = await fetch('/api/cached-data')\n00480| return (\n00481|
\n00514| )\n00515| }\n00516| ```\n00517| \n00518| You can also pass Server Actions through cached components to Client Components without invoking them inside the cacheable function.\n00519| \n00520| ```tsx filename=\"app/page.tsx\" switcher\n00521| import ClientComponent from './ClientComponent'\n00522| \n00523| export default async function Page() {\n00524| const performUpdate = async () => {\n00525| 'use server'\n00526| // Perform some server-side update\n00527| await db.update(...)\n00528| }\n00529| \n00530| return \n00531| }\n00532| \n00533| async function CachedComponent({\n00534| performUpdate,\n00535| }: {\n00536| performUpdate: () => Promise\n00537| }) {\n00538| 'use cache'\n00539| // Do not call performUpdate here\n00540| return \n00541| }\n00542| ```\n00543| \n00544| ```jsx filename=\"app/page.js\" switcher\n00545| import ClientComponent from './ClientComponent'\n00546| \n00547| export default async function Page() {\n00548| const performUpdate = async () => {\n00549| 'use server'\n00550| // Perform some server-side update\n00551| await db.update(...)\n00552| }\n00553| \n00554| return \n00555| }\n00556| \n00557| async function CachedComponent({ performUpdate }) {\n00558| 'use cache'\n00559| // Do not call performUpdate here\n00560| return \n00561| }\n00562| ```\n00563| \n00564| ```tsx filename=\"app/ClientComponent.tsx\" switcher\n00565| 'use client'\n00566| \n00567| export default function ClientComponent({\n00568| action,\n00569| }: {\n00570| action: () => Promise\n00571| }) {\n00572| return \n00573| }\n00574| ```\n00575| \n00576| ```jsx filename=\"app/ClientComponent.js\" switcher\n00577| 'use client'\n00578| \n00579| export default function ClientComponent({ action }) {\n00580| return \n00581| }\n00582| ```\n00583| \n00584| ## Troubleshooting\n00585| \n00586| ### Debugging cache behavior\n00587| \n00588| #### Verbose logging\n00589| \n00590| Set `NEXT_PRIVATE_DEBUG_CACHE=1` for verbose cache logging:\n00591| \n00592| ```bash\n00593| NEXT_PRIVATE_DEBUG_CACHE=1 npm run dev\n00594| # or for production\n00595| NEXT_PRIVATE_DEBUG_CACHE=1 npm run start\n00596| ```\n00597| \n00598| > **Good to know:** This environment variable also logs ISR and other caching mechanisms. See [Verifying correct production behavior](/docs/app/guides/incremental-static-regeneration#verifying-correct-production-behavior) for more details.\n00599| \n00600| #### Console log replays\n00601| \n00602| In development, console logs from cached functions appear with a `Cache` prefix.\n00603| \n00604| ### Build Hangs (Cache Timeout)\n00605| \n00606| If your build hangs, you're accessing Promises that resolve to uncached or runtime data, created outside a `use cache` boundary. The cached function waits for data that can't resolve during the build, causing a timeout after 50 seconds.\n00607| \n00608| When the build timeouts you'll see this error message:\n00609| \n00610| > Error: Filling a cache during prerender timed out, likely because request-specific arguments such as params, searchParams, cookies() or uncached data were used inside \"use cache\".\n00611| \n00612| Common ways this happens: passing such Promises as props, accessing them via closure, or retrieving them from shared storage (Maps).\n00613| \n00614| > **Good to know:** Directly calling `cookies()` or `headers()` inside `use cache` fails immediately with a [different error](/docs/messages/next-request-in-use-cache), not a timeout.\n00615| \n00616| **Passing runtime data Promises as props:**\n00617| \n00618| ```tsx filename=\"app/page.tsx\"\n00619| import { cookies } from 'next/headers'\n00620| import { Suspense } from 'react'\n00621| \n00622| export default function Page() {\n00623| return (\n00624| Loading...
}>\n00625| \n00626| \n00627| )\n00628| }\n00629| \n00630| async function Dynamic() {\n00631| const cookieStore = cookies()\n00632| return // Build hangs\n00633| }\n00634| \n00635| async function Cached({ promise }: { promise: Promise }) {\n00636| 'use cache'\n00637| const data = await promise // Waits for runtime data during build\n00638| return
..
\n00639| }\n00640| ```\n00641| \n00642| Await the `cookies` store in the `Dynamic` component, and pass a cookie value to the `Cached` component.\n00643| \n00644| **Shared deduplication storage:**\n00645| \n00646| ```tsx filename=\"app/page.tsx\"\n00647| // Problem: Map stores dynamic Promises, accessed by cached code\n00648| import { Suspense } from 'react'\n00649| \n00650| const cache = new Map>()\n00651| \n00652| export default function Page() {\n00653| return (\n00654| <>\n00655| Loading...
\n00670| }\n00671| \n00672| async function Cached({ id }: { id: string }) {\n00673| 'use cache'\n00674| return
{await cache.get(id)}
// Build hangs - retrieves dynamic Promise\n00675| }\n00676| ```\n00677| \n00678| Use Next.js's built-in `fetch()` deduplication or use separate Maps for cached and uncached contexts.\n00679| \n00680| ## Platform Support\n00681| \n00682| | Deployment Option | Supported |\n00683| | ------------------------------------------------------------------- | ----------------- |\n00684| | [Node.js server](/docs/app/getting-started/deploying#nodejs-server) | Yes |\n00685| | [Docker container](/docs/app/getting-started/deploying#docker) | Yes |\n00686| | [Static export](/docs/app/getting-started/deploying#static-export) | No |\n00687| | [Adapters](/docs/app/getting-started/deploying#adapters) | Platform-specific |\n00688| \n00689| Learn how to [configure caching](/docs/app/guides/self-hosting#caching-and-isr) when self-hosting Next.js.\n00690| \n00691| ## Version History\n00692| \n00693| | Version | Changes |\n00694| | --------- | ----------------------------------------------------------- |\n00695| | `v16.0.0` | `\"use cache\"` is enabled with the Cache Components feature. |\n00696| | `v15.0.0` | `\"use cache\"` is introduced as an experimental feature. |\n00697| \n\n(End of file - total 697 lines)\n",
+ "title": "node_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache.md",
+ "metadata": {
+ "preview": "---\ntitle: use cache\ndescription: Learn how to use the \"use cache\" directive to cache data in your Next.js application.\nrelated:\n title: Related\n description: View related API references.\n links:\n - app/api-reference/directives/use-cache-private\n - app/api-reference/config/next-config-js/cacheComponents\n - app/api-reference/config/next-config-js/cacheLife\n - app/api-reference/config/next-config-js/cacheHandlers\n - app/api-reference/functions/cacheTag\n - app/api-reference/functions/cacheLife\n - app/api-reference/functions/revalidateTag\n---\n\nThe `use cache` directive allows you to mark a route, React component, or a function as cacheable. It can be used at the top of a file to indicate that all exports in the file should be cached, or inline at the top of a function or component to cache the return value. Functions and components that use `use cache` must be async.\n\n> **Good to know:**\n>"
+ },
+ "time": {
+ "start": 1781392535983,
+ "end": 1781392535986
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:35.988Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| ---\n00002| title: use cache\n00003| description: Learn how to use the \"use cache\" directive to cache data in your Next.js application.\n00004| related:\n00005| title: Related\n00006| description: View related API references.\n00007| links:\n00008| - app/api-reference/directives/use-cache-private\n00009| - app/api-reference/config/next-config-js/cacheComponents\n00010| - app/api-reference/config/next-config-js/cacheLife\n00011| - app/api-reference/config/next-config-js/cacheHandlers\n00012| - app/api-reference/functions/cacheTag\n00013| - app/api-reference/functions/cacheLife\n00014| - app/api-reference/functions/revalidateTag\n00015| ---\n00016| \n00017| The `use cache` directive allows you to mark a route, React component, or a function as cacheable. It can be used at the top of a file to indicate that all exports in the file should be cached, or inline at the top of a function or component to cache the return value. Functions and components that use `use cache` must be async.\n00018| \n00019| > **Good to know:**\n00020| >\n00021| > - To use cookies or headers, read them outside cached scopes and pass values as arguments. This is the preferred pattern.\n00022| > - If the in-memory cache isn't sufficient for runtime data, [`'use cache: remote'`](/docs/app/api-reference/directives/use-cache-remote) allows platforms to provide a dedicated cache handler, though it requires a network roundtrip to check the cache and typically incurs platform fees.\n00023| > - For compliance requirements or when you can't refactor to pass runtime data as arguments to a `use cache` scope, see [`'use cache: private'`](/docs/app/api-reference/directives/use-cache-private).\n00024| \n00025| ## Usage\n00026| \n00027| `use cache` is a Cache Components feature. To enable it, add the [`cacheComponents`](/docs/app/api-reference/config/next-config-js/cacheComponents) option to your `next.config.ts` file:\n00028| \n00029| ```ts filename=\"next.config.ts\" switcher\n00030| import type { NextConfig } from 'next'\n00031| \n00032| const nextConfig: NextConfig = {\n00033| cacheComponents: true,\n00034| }\n00035| \n00036| export default nextConfig\n00037| ```\n00038| \n00039| ```js filename=\"next.config.js\" switcher\n00040| /** @type {import('next').NextConfig} */\n00041| const nextConfig = {\n00042| cacheComponents: true,\n00043| }\n00044| \n00045| module.exports = nextConfig\n00046| ```\n00047| \n00048| Then, add `use cache` at the file, component, or function level. All functions and components using `use cache` must be async. When used at file level, every exported function becomes a cached function and must also be async:\n00049| \n00050| ```tsx\n00051| // File level\n00052| 'use cache'\n00053| \n00054| export default async function Page() {\n00055| // ...\n00056| }\n00057| \n00058| // Component level\n00059| export async function MyComponent() {\n00060| 'use cache'\n00061| return <>>\n00062| }\n00063| \n00064| // Function level\n00065| export async function getData() {\n00066| 'use cache'\n00067| const data = await fetch('/api/data')\n00068| return data\n00069| }\n00070| ```\n00071| \n00072| ## How `use cache` works\n00073| \n00074| ### Cache keys\n00075| \n00076| A cache entry's key is generated using a serialized version of its inputs, which includes:\n00077| \n00078| 1. **Build ID** - Unique per build, changing this invalidates all cache entries. If [`deploymentId`](/docs/app/api-reference/config/next-config-js/deploymentId) is configured, it overrides the build ID for cache key purposes.\n00079| 2. **Function ID** - A secure hash of the function's location and signature in the codebase\n00080| 3. **Serializable arguments** - Props (for components) or function arguments\n00081| 4. **HMR refresh hash** (development only) - Invalidates cache on hot module replacement\n00082| \n00083| When a cached function references variables from outer scopes, those variables are automatically captured and bound as arguments, making them part of the cache key.\n00084| \n00085| ```tsx filename=\"lib/data.ts\"\n00086| async function Component({ userId }: { userId: string }) {\n00087| const getData = async (filter: string) => {\n00088| 'use cache'\n00089| // Cache key includes both userId (from closure) and filter (argument)\n00090| return fetch(`/api/users/${userId}/data?filter=${filter}`)\n00091| }\n00092| \n00093| return getData('active')\n00094| }\n00095| ```\n00096| \n00097| In the snippet above, `userId` is captured from the outer scope and `filter` is passed as an argument, so both become part of the `getData` function's cache key. This means different user and filter combinations will have separate cache entries.\n00098| \n00099| > **Good to know:** When a cached function reads [root parameters](/docs/app/api-reference/functions/next-root-params), only the ones it actually reads become part of its cache key.\n00100| \n00101| ## Serialization\n00102| \n00103| Arguments to cached functions and their return values must be serializable.\n00104| \n00105| For a complete reference, see:\n00106| \n00107| - [Serializable arguments](https://react.dev/reference/rsc/use-server#serializable-parameters-and-return-values) - Uses **React Server Components** serialization\n00108| - [Serializable return types](https://react.dev/reference/rsc/use-client#serializable-types) - Uses **React Client Components** serialization\n00109| \n00110| > **Good to know:** Arguments and return values use different serialization systems. Server Component serialization (for arguments) is more restrictive than Client Component serialization (for return values). This means you can return JSX elements but cannot accept them as arguments unless using pass-through patterns.\n00111| \n00112| ### Supported types\n00113| \n00114| **Arguments:**\n00115| \n00116| - Primitives: `string`, `number`, `boolean`, `null`, `undefined`\n00117| - Plain objects: `{ key: value }`\n00118| - Arrays: `[1, 2, 3]`\n00119| - Dates, Maps, Sets, TypedArrays, ArrayBuffers\n00120| - React elements (as pass-through only)\n00121| \n00122| **Return values:**\n00123| \n00124| - Same as arguments, plus JSX elements\n00125| \n00126| ### Unsupported types\n00127| \n00128| - Class instances\n00129| - Functions (except as pass-through)\n00130| - Symbols, WeakMaps, WeakSets\n00131| - URL instances\n00132| \n00133| ```tsx filename=\"app/components/user-card.tsx\"\n00134| // Valid - primitives and plain objects\n00135| async function UserCard({\n00136| id,\n00137| config,\n00138| }: {\n00139| id: string\n00140| config: { theme: string }\n00141| }) {\n00142| 'use cache'\n00143| return
{id}
\n00144| }\n00145| \n00146| // Invalid - class instance\n00147| async function UserProfile({ user }: { user: UserClass }) {\n00148| 'use cache'\n00149| // Error: Cannot serialize class instance\n00150| return
{user.name}
\n00151| }\n00152| ```\n00153| \n00154| ### Pass-through (non-serializable arguments)\n00155| \n00156| You can accept non-serializable values **as long as you don't introspect them**. This enables composition patterns with `children` and Server Actions:\n00157| \n00158| ```tsx filename=\"app/components/cached-wrapper.tsx\"\n00159| async function CachedWrapper({ children }: { children: ReactNode }) {\n00160| 'use cache'\n00161| // Don't read or modify children - just pass it through\n00162| return (\n00163|
\n00164| Cached Header\n00165| {children}\n00166|
\n00167| )\n00168| }\n00169| \n00170| // Usage: children can be dynamic\n00171| export default function Page() {\n00172| return (\n00173| \n00174| {/* Not cached, passed through */}\n00175| \n00176| )\n00177| }\n00178| ```\n00179| \n00180| You can also pass Server Actions through cached components:\n00181| \n00182| ```tsx filename=\"app/components/cached-form.tsx\"\n00183| async function CachedForm({ action }: { action: () => Promise }) {\n00184| 'use cache'\n00185| // Don't call action here - just pass it through\n00186| return
{/* ... */}
\n00187| }\n00188| ```\n00189| \n00190| ## Constraints\n00191| \n00192| Cached functions execute in an isolated environment. The following constraints ensure cache behavior remains predictable and secure.\n00193| \n00194| ### Request-time APIs\n00195| \n00196| Cached functions and components **cannot** directly access runtime APIs like `cookies()`, `headers()`, or `searchParams`. Instead, read these values outside the cached scope and pass them as arguments.\n00197| \n00198| ### Runtime caching considerations\n00199| \n00200| While `use cache` is designed primarily to include uncached data in the static shell, it can also cache data at runtime using in-memory LRU (Least Recently Used) storage.\n00201| \n00202| With the default in-memory handler, runtime cache behavior depends on your hosting environment:\n00203| \n00204| | Environment | Runtime Caching Behavior |\n00205| | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n00206| | **Serverless** | Cache entries typically don't persist across requests (each request can be a different instance), or during revalidation. Build-time caching works normally. |\n00207| | **Self-hosted** | Cache entries persist across requests. Control cache size with [`cacheMaxMemorySize`](/docs/app/api-reference/config/next-config-js/incrementalCacheHandlerPath). |\n00208| \n00209| For example, in a serverless environment, a cached function shared by two pages executes on each static shell revalidation, whereas in self-hosted or environments with persistent memory, the cached output is reused if it's still fresh.\n00210| \n00211| If the default in-memory cache isn't enough, consider **[`use cache: remote`](/docs/app/api-reference/directives/use-cache-remote)** which allows platforms to provide a dedicated cache handler (like Redis or KV database). This helps reduce hits against data sources not scaled to your total traffic, though it comes with costs (storage, network latency, platform fees).\n00212| \n00213| > [!NOTE]\n00214| > With the default in-memory handler, serverless instances are ephemeral, so entries may not be reused between requests, unlike with `use cache: remote`. Neither caching directive carries over to a new deploy, because the [cache key](#cache-keys) includes the build (or `deploymentId`) ID.\n00215| >\n00216| > For data that needs to persist across deploys, use [`unstable_cache`](/docs/app/api-reference/functions/unstable_cache) for non-`fetch` functions or the [`fetch`](/docs/app/api-reference/functions/fetch) cache.\n00217| \n00218| Very rarely, for compliance requirements or when you can't refactor your code to pass runtime data as arguments to a `use cache` scope, you might need [`use cache: private`](/docs/app/api-reference/directives/use-cache-private).\n00219| \n00220| ### Draft Mode\n00221| \n00222| When [Draft Mode](/docs/app/guides/draft-mode) is enabled, all cached functions and components re-execute on every request, and results are not saved to the cache. This ensures draft content is always fresh without requiring any changes to your caching code.\n00223| \n00224| You can read `isEnabled` from [`draftMode()`](/docs/app/api-reference/functions/draft-mode) inside a `use cache` scope, however, other runtime APIs like `cookies()` and `headers()` are not allowed, even when Draft Mode is active. See [Passing runtime values to cached functions](/docs/app/getting-started/caching#passing-runtime-values-to-cached-functions) for the recommended pattern.\n00225| \n00226| ```tsx filename=\"app/components/content.tsx\"\n00227| import { draftMode } from 'next/headers'\n00228| \n00229| async function Content() {\n00230| 'use cache'\n00231| \n00232| const { isEnabled } = await draftMode()\n00233| const url = isEnabled\n00234| ? 'https://draft.example.com/content'\n00235| : 'https://production.example.com/content'\n00236| \n00237| const data = await fetch(url)\n00238| return {/* ... */}\n00239| }\n00240| ```\n00241| \n00242| Calling `enable()` or `disable()` inside a caching directive scope will also throw an error. Draft Mode can only be toggled in [Route Handlers](/docs/app/api-reference/file-conventions/route) or [Server Actions](/docs/app/getting-started/mutating-data).\n00243| \n00244| ### React.cache isolation\n00245| \n00246| [`React.cache`](https://react.dev/reference/react/cache) operates in an isolated scope inside `use cache` boundaries. Values stored via `React.cache` outside a `use cache` function are not visible inside it.\n00247| \n00248| This means you cannot use `React.cache` to pass data into a `use cache` scope:\n00249| \n00250| ```tsx\n00251| import { cache } from 'react'\n00252| \n00253| const store = cache(() => ({ current: null as string | null }))\n00254| \n00255| function Parent() {\n00256| const shared = store()\n00257| shared.current = 'value from parent'\n00258| return \n00259| }\n00260| \n00261| async function Child() {\n00262| 'use cache'\n00263| const shared = store()\n00264| // shared.current is null, not 'value from parent'\n00265| // use cache has its own isolated React.cache scope\n00266| return
{shared.current}
\n00267| }\n00268| ```\n00269| \n00270| This isolation ensures cached functions have predictable, self-contained behavior. To pass data into a `use cache` scope, use function arguments instead.\n00271| \n00272| ## `use cache` at runtime\n00273| \n00274| On the **server**, cache entries are stored in-memory and respect the `revalidate` and `expire` times from your `cacheLife` configuration. You can customize the cache storage by configuring [`cacheHandlers`](/docs/app/api-reference/config/next-config-js/cacheHandlers) in your `next.config.js` file.\n00275| \n00276| On the **client**, content from the server cache is stored in the browser's memory for the duration defined by the `stale` time. The client router enforces a **minimum 30-second stale time**, regardless of configuration.\n00277| \n00278| The `x-nextjs-stale-time` response header communicates cache lifetime from server to client, ensuring coordinated behavior.\n00279| \n00280| ## Revalidation\n00281| \n00282| By default, `use cache` uses the `default` profile with these settings:\n00283| \n00284| - **stale**: 5 minutes (client-side)\n00285| - **revalidate**: 15 minutes (server-side)\n00286| - **expire**: Never expires by time\n00287| \n00288| ```tsx filename=\"lib/data.ts\"\n00289| async function getData() {\n00290| 'use cache'\n00291| // Implicitly uses default profile\n00292| return fetch('/api/data')\n00293| }\n00294| ```\n00295| \n00296| ### Customizing cache lifetime\n00297| \n00298| Use the [`cacheLife`](/docs/app/api-reference/functions/cacheLife) function to customize cache duration:\n00299| \n00300| ```tsx filename=\"lib/data.ts\"\n00301| import { cacheLife } from 'next/cache'\n00302| \n00303| async function getData() {\n00304| 'use cache'\n00305| cacheLife('hours') // Use built-in 'hours' profile\n00306| return fetch('/api/data')\n00307| }\n00308| ```\n00309| \n00310| ### On-demand revalidation\n00311| \n00312| Use [`cacheTag`](/docs/app/api-reference/functions/cacheTag), [`updateTag`](/docs/app/api-reference/functions/updateTag), or [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) for on-demand cache invalidation:\n00313| \n00314| ```tsx filename=\"lib/data.ts\"\n00315| import { cacheTag } from 'next/cache'\n00316| \n00317| async function getProducts() {\n00318| 'use cache'\n00319| cacheTag('products')\n00320| return fetch('/api/products')\n00321| }\n00322| ```\n00323| \n00324| ```tsx filename=\"app/actions.ts\"\n00325| 'use server'\n00326| \n00327| import { updateTag } from 'next/cache'\n00328| \n00329| export async function updateProduct() {\n00330| await db.products.update(...)\n00331| updateTag('products') // Invalidates all 'products' caches\n00332| }\n00333| ```\n00334| \n00335| Both `cacheLife` and `cacheTag` integrate across client and server caching layers, meaning you configure your caching semantics in one place and they apply everywhere.\n00336| \n00337| ## Examples\n00338| \n00339| ### Caching an entire route with `use cache`\n00340| \n00341| To prerender an entire route, add `use cache` to the top of **both** the `layout` and `page` files. Each of these segments are treated as separate entry points in your application, and will be cached independently.\n00342| \n00343| ```tsx filename=\"app/layout.tsx\" switcher\n00344| 'use cache'\n00345| \n00346| export default async function Layout({ children }: { children: ReactNode }) {\n00347| return
{children}
\n00348| }\n00349| ```\n00350| \n00351| ```jsx filename=\"app/layout.js\" switcher\n00352| 'use cache'\n00353| \n00354| export default async function Layout({ children }) {\n00355| return
{children}
\n00356| }\n00357| ```\n00358| \n00359| Any components imported and nested in `page` file are part of the cache output associated with the `page`.\n00360| \n00361| ```tsx filename=\"app/page.tsx\" switcher\n00362| 'use cache'\n00363| \n00364| async function Users() {\n00365| const users = await fetch('/api/users')\n00366| // loop through users\n00367| }\n00368| \n00369| export default async function Page() {\n00370| return (\n00371| \n00372| \n00373| \n00374| )\n00375| }\n00376| ```\n00377| \n00378| ```jsx filename=\"app/page.js\" switcher\n00379| 'use cache'\n00380| \n00381| async function Users() {\n00382| const users = await fetch('/api/users')\n00383| // loop through users\n00384| }\n00385| \n00386| export default async function Page() {\n00387| return (\n00388| \n00389| \n00390| \n00391| )\n00392| }\n00393| ```\n00394| \n00395| > **Good to know**:\n00396| >\n00397| > - If `use cache` is added only to the `layout` or the `page`, only that route segment and any components imported into it will be cached.\n00398| \n00399| ### Caching a component's output with `use cache`\n00400| \n00401| You can use `use cache` at the component level to cache any fetches or computations performed within that component. The cache entry will be reused as long as the serialized props produce the same value in each instance.\n00402| \n00403| ```tsx filename=\"app/components/bookings.tsx\" highlight={2} switcher\n00404| export async function Bookings({ type = 'haircut' }: BookingsProps) {\n00405| 'use cache'\n00406| async function getBookingsData() {\n00407| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00408| return data\n00409| }\n00410| return //...\n00411| }\n00412| \n00413| interface BookingsProps {\n00414| type: string\n00415| }\n00416| ```\n00417| \n00418| ```jsx filename=\"app/components/bookings.js\" highlight={2} switcher\n00419| export async function Bookings({ type = 'haircut' }) {\n00420| 'use cache'\n00421| async function getBookingsData() {\n00422| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00423| return data\n00424| }\n00425| return //...\n00426| }\n00427| ```\n00428| \n00429| ### Caching function output with `use cache`\n00430| \n00431| Since you can add `use cache` to any asynchronous function, you aren't limited to caching components or routes only. You might want to cache a network request, a database query, or a slow computation.\n00432| \n00433| ```tsx filename=\"app/actions.ts\" highlight={2} switcher\n00434| export async function getData() {\n00435| 'use cache'\n00436| \n00437| const data = await fetch('/api/data')\n00438| return data\n00439| }\n00440| ```\n00441| \n00442| ```jsx filename=\"app/actions.js\" highlight={2} switcher\n00443| export async function getData() {\n00444| 'use cache'\n00445| \n00446| const data = await fetch('/api/data')\n00447| return data\n00448| }\n00449| ```\n00450| \n00451| > **Good to know:** When a cached directive (`use cache`, [`use cache: private`](/docs/app/api-reference/directives/use-cache-private), or [`use cache: remote`](/docs/app/api-reference/directives/use-cache-remote)) is at the top of a file, you can import its exported functions into a Client Component and call them directly; they run on the server and return the result, similar to a [Server Function](/docs/app/glossary#server-function). Prefer calling cached functions on the server and passing results down as props.\n00452| \n00453| ### Interleaving\n00454| \n00455| In React, composition with `children` or slots is a well-known pattern for building flexible components. When using `use cache`, you can continue to compose your UI in this way. Anything included as `children`, or other compositional slots, in the returned JSX will be passed through the cached component without affecting its cache entry.\n00456| \n00457| As long as you don't directly reference any of the JSX slots inside the body of the cacheable function itself, their presence in the returned output won't affect the cache entry.\n00458| \n00459| ```tsx filename=\"app/page.tsx\" switcher\n00460| export default async function Page() {\n00461| const uncachedData = await getData()\n00462| return (\n00463| // Pass compositional slots as props, e.g. header and children\n00464| Home}>\n00465| {/* DynamicComponent is provided as the children slot */}\n00466| \n00467| \n00468| )\n00469| }\n00470| \n00471| async function CacheComponent({\n00472| header, // header: a compositional slot, injected as a prop\n00473| children, // children: another slot for nested composition\n00474| }: {\n00475| header: ReactNode\n00476| children: ReactNode\n00477| }) {\n00478| 'use cache'\n00479| const cachedData = await fetch('/api/cached-data')\n00480| return (\n00481|
\n00514| )\n00515| }\n00516| ```\n00517| \n00518| You can also pass Server Actions through cached components to Client Components without invoking them inside the cacheable function.\n00519| \n00520| ```tsx filename=\"app/page.tsx\" switcher\n00521| import ClientComponent from './ClientComponent'\n00522| \n00523| export default async function Page() {\n00524| const performUpdate = async () => {\n00525| 'use server'\n00526| // Perform some server-side update\n00527| await db.update(...)\n00528| }\n00529| \n00530| return \n00531| }\n00532| \n00533| async function CachedComponent({\n00534| performUpdate,\n00535| }: {\n00536| performUpdate: () => Promise\n00537| }) {\n00538| 'use cache'\n00539| // Do not call performUpdate here\n00540| return \n00541| }\n00542| ```\n00543| \n00544| ```jsx filename=\"app/page.js\" switcher\n00545| import ClientComponent from './ClientComponent'\n00546| \n00547| export default async function Page() {\n00548| const performUpdate = async () => {\n00549| 'use server'\n00550| // Perform some server-side update\n00551| await db.update(...)\n00552| }\n00553| \n00554| return \n00555| }\n00556| \n00557| async function CachedComponent({ performUpdate }) {\n00558| 'use cache'\n00559| // Do not call performUpdate here\n00560| return \n00561| }\n00562| ```\n00563| \n00564| ```tsx filename=\"app/ClientComponent.tsx\" switcher\n00565| 'use client'\n00566| \n00567| export default function ClientComponent({\n00568| action,\n00569| }: {\n00570| action: () => Promise\n00571| }) {\n00572| return \n00573| }\n00574| ```\n00575| \n00576| ```jsx filename=\"app/ClientComponent.js\" switcher\n00577| 'use client'\n00578| \n00579| export default function ClientComponent({ action }) {\n00580| return \n00581| }\n00582| ```\n00583| \n00584| ## Troubleshooting\n00585| \n00586| ### Debugging cache behavior\n00587| \n00588| #### Verbose logging\n00589| \n00590| Set `NEXT_PRIVATE_DEBUG_CACHE=1` for verbose cache logging:\n00591| \n00592| ```bash\n00593| NEXT_PRIVATE_DEBUG_CACHE=1 npm run dev\n00594| # or for production\n00595| NEXT_PRIVATE_DEBUG_CACHE=1 npm run start\n00596| ```\n00597| \n00598| > **Good to know:** This environment variable also logs ISR and other caching mechanisms. See [Verifying correct production behavior](/docs/app/guides/incremental-static-regeneration#verifying-correct-production-behavior) for more details.\n00599| \n00600| #### Console log replays\n00601| \n00602| In development, console logs from cached functions appear with a `Cache` prefix.\n00603| \n00604| ### Build Hangs (Cache Timeout)\n00605| \n00606| If your build hangs, you're accessing Promises that resolve to uncached or runtime data, created outside a `use cache` boundary. The cached function waits for data that can't resolve during the build, causing a timeout after 50 seconds.\n00607| \n00608| When the build timeouts you'll see this error message:\n00609| \n00610| > Error: Filling a cache during prerender timed out, likely because request-specific arguments such as params, searchParams, cookies() or uncached data were used inside \"use cache\".\n00611| \n00612| Common ways this happens: passing such Promises as props, accessing them via closure, or retrieving them from shared storage (Maps).\n00613| \n00614| > **Good to know:** Directly calling `cookies()` or `headers()` inside `use cache` fails immediately with a [different error](/docs/messages/next-request-in-use-cache), not a timeout.\n00615| \n00616| **Passing runtime data Promises as props:**\n00617| \n00618| ```tsx filename=\"app/page.tsx\"\n00619| import { cookies } from 'next/headers'\n00620| import { Suspense } from 'react'\n00621| \n00622| export default function Page() {\n00623| return (\n00624| Loading...
}>\n00625| \n00626| \n00627| )\n00628| }\n00629| \n00630| async function Dynamic() {\n00631| const cookieStore = cookies()\n00632| return // Build hangs\n00633| }\n00634| \n00635| async function Cached({ promise }: { promise: Promise }) {\n00636| 'use cache'\n00637| const data = await promise // Waits for runtime data during build\n00638| return
..
\n00639| }\n00640| ```\n00641| \n00642| Await the `cookies` store in the `Dynamic` component, and pass a cookie value to the `Cached` component.\n00643| \n00644| **Shared deduplication storage:**\n00645| \n00646| ```tsx filename=\"app/page.tsx\"\n00647| // Problem: Map stores dynamic Promises, accessed by cached code\n00648| import { Suspense } from 'react'\n00649| \n00650| const cache = new Map>()\n00651| \n00652| export default function Page() {\n00653| return (\n00654| <>\n00655| Loading...
\n00670| }\n00671| \n00672| async function Cached({ id }: { id: string }) {\n00673| 'use cache'\n00674| return
{await cache.get(id)}
// Build hangs - retrieves dynamic Promise\n00675| }\n00676| ```\n00677| \n00678| Use Next.js's built-in `fetch()` deduplication or use separate Maps for cached and uncached contexts.\n00679| \n00680| ## Platform Support\n00681| \n00682| | Deployment Option | Supported |\n00683| | ------------------------------------------------------------------- | ----------------- |\n00684| | [Node.js server](/docs/app/getting-started/deploying#nodejs-server) | Yes |\n00685| | [Docker container](/docs/app/getting-started/deploying#docker) | Yes |\n00686| | [Static export](/docs/app/getting-started/deploying#static-export) | No |\n00687| | [Adapters](/docs/app/getting-started/deploying#adapters) | Platform-specific |\n00688| \n00689| Learn how to [configure caching](/docs/app/guides/self-hosting#caching-and-isr) when self-hosting Next.js.\n00690| \n00691| ## Version History\n00692| \n00693| | Version | Changes |\n00694| | --------- | ----------------------------------------------------------- |\n00695| | `v16.0.0` | `\"use cache\"` is enabled with the Cache Components feature. |\n00696| | `v15.0.0` | `\"use cache\"` is introduced as an experimental feature. |\n00697| \n\n(End of file - total 697 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache.md"
+ },
+ "output": "\n00001| ---\n00002| title: use cache\n00003| description: Learn how to use the \"use cache\" directive to cache data in your Next.js application.\n00004| related:\n00005| title: Related\n00006| description: View related API references.\n00007| links:\n00008| - app/api-reference/directives/use-cache-private\n00009| - app/api-reference/config/next-config-js/cacheComponents\n00010| - app/api-reference/config/next-config-js/cacheLife\n00011| - app/api-reference/config/next-config-js/cacheHandlers\n00012| - app/api-reference/functions/cacheTag\n00013| - app/api-reference/functions/cacheLife\n00014| - app/api-reference/functions/revalidateTag\n00015| ---\n00016| \n00017| The `use cache` directive allows you to mark a route, React component, or a function as cacheable. It can be used at the top of a file to indicate that all exports in the file should be cached, or inline at the top of a function or component to cache the return value. Functions and components that use `use cache` must be async.\n00018| \n00019| > **Good to know:**\n00020| >\n00021| > - To use cookies or headers, read them outside cached scopes and pass values as arguments. This is the preferred pattern.\n00022| > - If the in-memory cache isn't sufficient for runtime data, [`'use cache: remote'`](/docs/app/api-reference/directives/use-cache-remote) allows platforms to provide a dedicated cache handler, though it requires a network roundtrip to check the cache and typically incurs platform fees.\n00023| > - For compliance requirements or when you can't refactor to pass runtime data as arguments to a `use cache` scope, see [`'use cache: private'`](/docs/app/api-reference/directives/use-cache-private).\n00024| \n00025| ## Usage\n00026| \n00027| `use cache` is a Cache Components feature. To enable it, add the [`cacheComponents`](/docs/app/api-reference/config/next-config-js/cacheComponents) option to your `next.config.ts` file:\n00028| \n00029| ```ts filename=\"next.config.ts\" switcher\n00030| import type { NextConfig } from 'next'\n00031| \n00032| const nextConfig: NextConfig = {\n00033| cacheComponents: true,\n00034| }\n00035| \n00036| export default nextConfig\n00037| ```\n00038| \n00039| ```js filename=\"next.config.js\" switcher\n00040| /** @type {import('next').NextConfig} */\n00041| const nextConfig = {\n00042| cacheComponents: true,\n00043| }\n00044| \n00045| module.exports = nextConfig\n00046| ```\n00047| \n00048| Then, add `use cache` at the file, component, or function level. All functions and components using `use cache` must be async. When used at file level, every exported function becomes a cached function and must also be async:\n00049| \n00050| ```tsx\n00051| // File level\n00052| 'use cache'\n00053| \n00054| export default async function Page() {\n00055| // ...\n00056| }\n00057| \n00058| // Component level\n00059| export async function MyComponent() {\n00060| 'use cache'\n00061| return <>>\n00062| }\n00063| \n00064| // Function level\n00065| export async function getData() {\n00066| 'use cache'\n00067| const data = await fetch('/api/data')\n00068| return data\n00069| }\n00070| ```\n00071| \n00072| ## How `use cache` works\n00073| \n00074| ### Cache keys\n00075| \n00076| A cache entry's key is generated using a serialized version of its inputs, which includes:\n00077| \n00078| 1. **Build ID** - Unique per build, changing this invalidates all cache entries. If [`deploymentId`](/docs/app/api-reference/config/next-config-js/deploymentId) is configured, it overrides the build ID for cache key purposes.\n00079| 2. **Function ID** - A secure hash of the function's location and signature in the codebase\n00080| 3. **Serializable arguments** - Props (for components) or function arguments\n00081| 4. **HMR refresh hash** (development only) - Invalidates cache on hot module replacement\n00082| \n00083| When a cached function references variables from outer scopes, those variables are automatically captured and bound as arguments, making them part of the cache key.\n00084| \n00085| ```tsx filename=\"lib/data.ts\"\n00086| async function Component({ userId }: { userId: string }) {\n00087| const getData = async (filter: string) => {\n00088| 'use cache'\n00089| // Cache key includes both userId (from closure) and filter (argument)\n00090| return fetch(`/api/users/${userId}/data?filter=${filter}`)\n00091| }\n00092| \n00093| return getData('active')\n00094| }\n00095| ```\n00096| \n00097| In the snippet above, `userId` is captured from the outer scope and `filter` is passed as an argument, so both become part of the `getData` function's cache key. This means different user and filter combinations will have separate cache entries.\n00098| \n00099| > **Good to know:** When a cached function reads [root parameters](/docs/app/api-reference/functions/next-root-params), only the ones it actually reads become part of its cache key.\n00100| \n00101| ## Serialization\n00102| \n00103| Arguments to cached functions and their return values must be serializable.\n00104| \n00105| For a complete reference, see:\n00106| \n00107| - [Serializable arguments](https://react.dev/reference/rsc/use-server#serializable-parameters-and-return-values) - Uses **React Server Components** serialization\n00108| - [Serializable return types](https://react.dev/reference/rsc/use-client#serializable-types) - Uses **React Client Components** serialization\n00109| \n00110| > **Good to know:** Arguments and return values use different serialization systems. Server Component serialization (for arguments) is more restrictive than Client Component serialization (for return values). This means you can return JSX elements but cannot accept them as arguments unless using pass-through patterns.\n00111| \n00112| ### Supported types\n00113| \n00114| **Arguments:**\n00115| \n00116| - Primitives: `string`, `number`, `boolean`, `null`, `undefined`\n00117| - Plain objects: `{ key: value }`\n00118| - Arrays: `[1, 2, 3]`\n00119| - Dates, Maps, Sets, TypedArrays, ArrayBuffers\n00120| - React elements (as pass-through only)\n00121| \n00122| **Return values:**\n00123| \n00124| - Same as arguments, plus JSX elements\n00125| \n00126| ### Unsupported types\n00127| \n00128| - Class instances\n00129| - Functions (except as pass-through)\n00130| - Symbols, WeakMaps, WeakSets\n00131| - URL instances\n00132| \n00133| ```tsx filename=\"app/components/user-card.tsx\"\n00134| // Valid - primitives and plain objects\n00135| async function UserCard({\n00136| id,\n00137| config,\n00138| }: {\n00139| id: string\n00140| config: { theme: string }\n00141| }) {\n00142| 'use cache'\n00143| return
{id}
\n00144| }\n00145| \n00146| // Invalid - class instance\n00147| async function UserProfile({ user }: { user: UserClass }) {\n00148| 'use cache'\n00149| // Error: Cannot serialize class instance\n00150| return
{user.name}
\n00151| }\n00152| ```\n00153| \n00154| ### Pass-through (non-serializable arguments)\n00155| \n00156| You can accept non-serializable values **as long as you don't introspect them**. This enables composition patterns with `children` and Server Actions:\n00157| \n00158| ```tsx filename=\"app/components/cached-wrapper.tsx\"\n00159| async function CachedWrapper({ children }: { children: ReactNode }) {\n00160| 'use cache'\n00161| // Don't read or modify children - just pass it through\n00162| return (\n00163|
\n00164| Cached Header\n00165| {children}\n00166|
\n00167| )\n00168| }\n00169| \n00170| // Usage: children can be dynamic\n00171| export default function Page() {\n00172| return (\n00173| \n00174| {/* Not cached, passed through */}\n00175| \n00176| )\n00177| }\n00178| ```\n00179| \n00180| You can also pass Server Actions through cached components:\n00181| \n00182| ```tsx filename=\"app/components/cached-form.tsx\"\n00183| async function CachedForm({ action }: { action: () => Promise }) {\n00184| 'use cache'\n00185| // Don't call action here - just pass it through\n00186| return
{/* ... */}
\n00187| }\n00188| ```\n00189| \n00190| ## Constraints\n00191| \n00192| Cached functions execute in an isolated environment. The following constraints ensure cache behavior remains predictable and secure.\n00193| \n00194| ### Request-time APIs\n00195| \n00196| Cached functions and components **cannot** directly access runtime APIs like `cookies()`, `headers()`, or `searchParams`. Instead, read these values outside the cached scope and pass them as arguments.\n00197| \n00198| ### Runtime caching considerations\n00199| \n00200| While `use cache` is designed primarily to include uncached data in the static shell, it can also cache data at runtime using in-memory LRU (Least Recently Used) storage.\n00201| \n00202| With the default in-memory handler, runtime cache behavior depends on your hosting environment:\n00203| \n00204| | Environment | Runtime Caching Behavior |\n00205| | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n00206| | **Serverless** | Cache entries typically don't persist across requests (each request can be a different instance), or during revalidation. Build-time caching works normally. |\n00207| | **Self-hosted** | Cache entries persist across requests. Control cache size with [`cacheMaxMemorySize`](/docs/app/api-reference/config/next-config-js/incrementalCacheHandlerPath). |\n00208| \n00209| For example, in a serverless environment, a cached function shared by two pages executes on each static shell revalidation, whereas in self-hosted or environments with persistent memory, the cached output is reused if it's still fresh.\n00210| \n00211| If the default in-memory cache isn't enough, consider **[`use cache: remote`](/docs/app/api-reference/directives/use-cache-remote)** which allows platforms to provide a dedicated cache handler (like Redis or KV database). This helps reduce hits against data sources not scaled to your total traffic, though it comes with costs (storage, network latency, platform fees).\n00212| \n00213| > [!NOTE]\n00214| > With the default in-memory handler, serverless instances are ephemeral, so entries may not be reused between requests, unlike with `use cache: remote`. Neither caching directive carries over to a new deploy, because the [cache key](#cache-keys) includes the build (or `deploymentId`) ID.\n00215| >\n00216| > For data that needs to persist across deploys, use [`unstable_cache`](/docs/app/api-reference/functions/unstable_cache) for non-`fetch` functions or the [`fetch`](/docs/app/api-reference/functions/fetch) cache.\n00217| \n00218| Very rarely, for compliance requirements or when you can't refactor your code to pass runtime data as arguments to a `use cache` scope, you might need [`use cache: private`](/docs/app/api-reference/directives/use-cache-private).\n00219| \n00220| ### Draft Mode\n00221| \n00222| When [Draft Mode](/docs/app/guides/draft-mode) is enabled, all cached functions and components re-execute on every request, and results are not saved to the cache. This ensures draft content is always fresh without requiring any changes to your caching code.\n00223| \n00224| You can read `isEnabled` from [`draftMode()`](/docs/app/api-reference/functions/draft-mode) inside a `use cache` scope, however, other runtime APIs like `cookies()` and `headers()` are not allowed, even when Draft Mode is active. See [Passing runtime values to cached functions](/docs/app/getting-started/caching#passing-runtime-values-to-cached-functions) for the recommended pattern.\n00225| \n00226| ```tsx filename=\"app/components/content.tsx\"\n00227| import { draftMode } from 'next/headers'\n00228| \n00229| async function Content() {\n00230| 'use cache'\n00231| \n00232| const { isEnabled } = await draftMode()\n00233| const url = isEnabled\n00234| ? 'https://draft.example.com/content'\n00235| : 'https://production.example.com/content'\n00236| \n00237| const data = await fetch(url)\n00238| return {/* ... */}\n00239| }\n00240| ```\n00241| \n00242| Calling `enable()` or `disable()` inside a caching directive scope will also throw an error. Draft Mode can only be toggled in [Route Handlers](/docs/app/api-reference/file-conventions/route) or [Server Actions](/docs/app/getting-started/mutating-data).\n00243| \n00244| ### React.cache isolation\n00245| \n00246| [`React.cache`](https://react.dev/reference/react/cache) operates in an isolated scope inside `use cache` boundaries. Values stored via `React.cache` outside a `use cache` function are not visible inside it.\n00247| \n00248| This means you cannot use `React.cache` to pass data into a `use cache` scope:\n00249| \n00250| ```tsx\n00251| import { cache } from 'react'\n00252| \n00253| const store = cache(() => ({ current: null as string | null }))\n00254| \n00255| function Parent() {\n00256| const shared = store()\n00257| shared.current = 'value from parent'\n00258| return \n00259| }\n00260| \n00261| async function Child() {\n00262| 'use cache'\n00263| const shared = store()\n00264| // shared.current is null, not 'value from parent'\n00265| // use cache has its own isolated React.cache scope\n00266| return
{shared.current}
\n00267| }\n00268| ```\n00269| \n00270| This isolation ensures cached functions have predictable, self-contained behavior. To pass data into a `use cache` scope, use function arguments instead.\n00271| \n00272| ## `use cache` at runtime\n00273| \n00274| On the **server**, cache entries are stored in-memory and respect the `revalidate` and `expire` times from your `cacheLife` configuration. You can customize the cache storage by configuring [`cacheHandlers`](/docs/app/api-reference/config/next-config-js/cacheHandlers) in your `next.config.js` file.\n00275| \n00276| On the **client**, content from the server cache is stored in the browser's memory for the duration defined by the `stale` time. The client router enforces a **minimum 30-second stale time**, regardless of configuration.\n00277| \n00278| The `x-nextjs-stale-time` response header communicates cache lifetime from server to client, ensuring coordinated behavior.\n00279| \n00280| ## Revalidation\n00281| \n00282| By default, `use cache` uses the `default` profile with these settings:\n00283| \n00284| - **stale**: 5 minutes (client-side)\n00285| - **revalidate**: 15 minutes (server-side)\n00286| - **expire**: Never expires by time\n00287| \n00288| ```tsx filename=\"lib/data.ts\"\n00289| async function getData() {\n00290| 'use cache'\n00291| // Implicitly uses default profile\n00292| return fetch('/api/data')\n00293| }\n00294| ```\n00295| \n00296| ### Customizing cache lifetime\n00297| \n00298| Use the [`cacheLife`](/docs/app/api-reference/functions/cacheLife) function to customize cache duration:\n00299| \n00300| ```tsx filename=\"lib/data.ts\"\n00301| import { cacheLife } from 'next/cache'\n00302| \n00303| async function getData() {\n00304| 'use cache'\n00305| cacheLife('hours') // Use built-in 'hours' profile\n00306| return fetch('/api/data')\n00307| }\n00308| ```\n00309| \n00310| ### On-demand revalidation\n00311| \n00312| Use [`cacheTag`](/docs/app/api-reference/functions/cacheTag), [`updateTag`](/docs/app/api-reference/functions/updateTag), or [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) for on-demand cache invalidation:\n00313| \n00314| ```tsx filename=\"lib/data.ts\"\n00315| import { cacheTag } from 'next/cache'\n00316| \n00317| async function getProducts() {\n00318| 'use cache'\n00319| cacheTag('products')\n00320| return fetch('/api/products')\n00321| }\n00322| ```\n00323| \n00324| ```tsx filename=\"app/actions.ts\"\n00325| 'use server'\n00326| \n00327| import { updateTag } from 'next/cache'\n00328| \n00329| export async function updateProduct() {\n00330| await db.products.update(...)\n00331| updateTag('products') // Invalidates all 'products' caches\n00332| }\n00333| ```\n00334| \n00335| Both `cacheLife` and `cacheTag` integrate across client and server caching layers, meaning you configure your caching semantics in one place and they apply everywhere.\n00336| \n00337| ## Examples\n00338| \n00339| ### Caching an entire route with `use cache`\n00340| \n00341| To prerender an entire route, add `use cache` to the top of **both** the `layout` and `page` files. Each of these segments are treated as separate entry points in your application, and will be cached independently.\n00342| \n00343| ```tsx filename=\"app/layout.tsx\" switcher\n00344| 'use cache'\n00345| \n00346| export default async function Layout({ children }: { children: ReactNode }) {\n00347| return
{children}
\n00348| }\n00349| ```\n00350| \n00351| ```jsx filename=\"app/layout.js\" switcher\n00352| 'use cache'\n00353| \n00354| export default async function Layout({ children }) {\n00355| return
{children}
\n00356| }\n00357| ```\n00358| \n00359| Any components imported and nested in `page` file are part of the cache output associated with the `page`.\n00360| \n00361| ```tsx filename=\"app/page.tsx\" switcher\n00362| 'use cache'\n00363| \n00364| async function Users() {\n00365| const users = await fetch('/api/users')\n00366| // loop through users\n00367| }\n00368| \n00369| export default async function Page() {\n00370| return (\n00371| \n00372| \n00373| \n00374| )\n00375| }\n00376| ```\n00377| \n00378| ```jsx filename=\"app/page.js\" switcher\n00379| 'use cache'\n00380| \n00381| async function Users() {\n00382| const users = await fetch('/api/users')\n00383| // loop through users\n00384| }\n00385| \n00386| export default async function Page() {\n00387| return (\n00388| \n00389| \n00390| \n00391| )\n00392| }\n00393| ```\n00394| \n00395| > **Good to know**:\n00396| >\n00397| > - If `use cache` is added only to the `layout` or the `page`, only that route segment and any components imported into it will be cached.\n00398| \n00399| ### Caching a component's output with `use cache`\n00400| \n00401| You can use `use cache` at the component level to cache any fetches or computations performed within that component. The cache entry will be reused as long as the serialized props produce the same value in each instance.\n00402| \n00403| ```tsx filename=\"app/components/bookings.tsx\" highlight={2} switcher\n00404| export async function Bookings({ type = 'haircut' }: BookingsProps) {\n00405| 'use cache'\n00406| async function getBookingsData() {\n00407| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00408| return data\n00409| }\n00410| return //...\n00411| }\n00412| \n00413| interface BookingsProps {\n00414| type: string\n00415| }\n00416| ```\n00417| \n00418| ```jsx filename=\"app/components/bookings.js\" highlight={2} switcher\n00419| export async function Bookings({ type = 'haircut' }) {\n00420| 'use cache'\n00421| async function getBookingsData() {\n00422| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00423| return data\n00424| }\n00425| return //...\n00426| }\n00427| ```\n00428| \n00429| ### Caching function output with `use cache`\n00430| \n00431| Since you can add `use cache` to any asynchronous function, you aren't limited to caching components or routes only. You might want to cache a network request, a database query, or a slow computation.\n00432| \n00433| ```tsx filename=\"app/actions.ts\" highlight={2} switcher\n00434| export async function getData() {\n00435| 'use cache'\n00436| \n00437| const data = await fetch('/api/data')\n00438| return data\n00439| }\n00440| ```\n00441| \n00442| ```jsx filename=\"app/actions.js\" highlight={2} switcher\n00443| export async function getData() {\n00444| 'use cache'\n00445| \n00446| const data = await fetch('/api/data')\n00447| return data\n00448| }\n00449| ```\n00450| \n00451| > **Good to know:** When a cached directive (`use cache`, [`use cache: private`](/docs/app/api-reference/directives/use-cache-private), or [`use cache: remote`](/docs/app/api-reference/directives/use-cache-remote)) is at the top of a file, you can import its exported functions into a Client Component and call them directly; they run on the server and return the result, similar to a [Server Function](/docs/app/glossary#server-function). Prefer calling cached functions on the server and passing results down as props.\n00452| \n00453| ### Interleaving\n00454| \n00455| In React, composition with `children` or slots is a well-known pattern for building flexible components. When using `use cache`, you can continue to compose your UI in this way. Anything included as `children`, or other compositional slots, in the returned JSX will be passed through the cached component without affecting its cache entry.\n00456| \n00457| As long as you don't directly reference any of the JSX slots inside the body of the cacheable function itself, their presence in the returned output won't affect the cache entry.\n00458| \n00459| ```tsx filename=\"app/page.tsx\" switcher\n00460| export default async function Page() {\n00461| const uncachedData = await getData()\n00462| return (\n00463| // Pass compositional slots as props, e.g. header and children\n00464| Home}>\n00465| {/* DynamicComponent is provided as the children slot */}\n00466| \n00467| \n00468| )\n00469| }\n00470| \n00471| async function CacheComponent({\n00472| header, // header: a compositional slot, injected as a prop\n00473| children, // children: another slot for nested composition\n00474| }: {\n00475| header: ReactNode\n00476| children: ReactNode\n00477| }) {\n00478| 'use cache'\n00479| const cachedData = await fetch('/api/cached-data')\n00480| return (\n00481|
\n00514| )\n00515| }\n00516| ```\n00517| \n00518| You can also pass Server Actions through cached components to Client Components without invoking them inside the cacheable function.\n00519| \n00520| ```tsx filename=\"app/page.tsx\" switcher\n00521| import ClientComponent from './ClientComponent'\n00522| \n00523| export default async function Page() {\n00524| const performUpdate = async () => {\n00525| 'use server'\n00526| // Perform some server-side update\n00527| await db.update(...)\n00528| }\n00529| \n00530| return \n00531| }\n00532| \n00533| async function CachedComponent({\n00534| performUpdate,\n00535| }: {\n00536| performUpdate: () => Promise\n00537| }) {\n00538| 'use cache'\n00539| // Do not call performUpdate here\n00540| return \n00541| }\n00542| ```\n00543| \n00544| ```jsx filename=\"app/page.js\" switcher\n00545| import ClientComponent from './ClientComponent'\n00546| \n00547| export default async function Page() {\n00548| const performUpdate = async () => {\n00549| 'use server'\n00550| // Perform some server-side update\n00551| await db.update(...)\n00552| }\n00553| \n00554| return \n00555| }\n00556| \n00557| async function CachedComponent({ performUpdate }) {\n00558| 'use cache'\n00559| // Do not call performUpdate here\n00560| return \n00561| }\n00562| ```\n00563| \n00564| ```tsx filename=\"app/ClientComponent.tsx\" switcher\n00565| 'use client'\n00566| \n00567| export default function ClientComponent({\n00568| action,\n00569| }: {\n00570| action: () => Promise\n00571| }) {\n00572| return \n00573| }\n00574| ```\n00575| \n00576| ```jsx filename=\"app/ClientComponent.js\" switcher\n00577| 'use client'\n00578| \n00579| export default function ClientComponent({ action }) {\n00580| return \n00581| }\n00582| ```\n00583| \n00584| ## Troubleshooting\n00585| \n00586| ### Debugging cache behavior\n00587| \n00588| #### Verbose logging\n00589| \n00590| Set `NEXT_PRIVATE_DEBUG_CACHE=1` for verbose cache logging:\n00591| \n00592| ```bash\n00593| NEXT_PRIVATE_DEBUG_CACHE=1 npm run dev\n00594| # or for production\n00595| NEXT_PRIVATE_DEBUG_CACHE=1 npm run start\n00596| ```\n00597| \n00598| > **Good to know:** This environment variable also logs ISR and other caching mechanisms. See [Verifying correct production behavior](/docs/app/guides/incremental-static-regeneration#verifying-correct-production-behavior) for more details.\n00599| \n00600| #### Console log replays\n00601| \n00602| In development, console logs from cached functions appear with a `Cache` prefix.\n00603| \n00604| ### Build Hangs (Cache Timeout)\n00605| \n00606| If your build hangs, you're accessing Promises that resolve to uncached or runtime data, created outside a `use cache` boundary. The cached function waits for data that can't resolve during the build, causing a timeout after 50 seconds.\n00607| \n00608| When the build timeouts you'll see this error message:\n00609| \n00610| > Error: Filling a cache during prerender timed out, likely because request-specific arguments such as params, searchParams, cookies() or uncached data were used inside \"use cache\".\n00611| \n00612| Common ways this happens: passing such Promises as props, accessing them via closure, or retrieving them from shared storage (Maps).\n00613| \n00614| > **Good to know:** Directly calling `cookies()` or `headers()` inside `use cache` fails immediately with a [different error](/docs/messages/next-request-in-use-cache), not a timeout.\n00615| \n00616| **Passing runtime data Promises as props:**\n00617| \n00618| ```tsx filename=\"app/page.tsx\"\n00619| import { cookies } from 'next/headers'\n00620| import { Suspense } from 'react'\n00621| \n00622| export default function Page() {\n00623| return (\n00624| Loading...
}>\n00625| \n00626| \n00627| )\n00628| }\n00629| \n00630| async function Dynamic() {\n00631| const cookieStore = cookies()\n00632| return // Build hangs\n00633| }\n00634| \n00635| async function Cached({ promise }: { promise: Promise }) {\n00636| 'use cache'\n00637| const data = await promise // Waits for runtime data during build\n00638| return
..
\n00639| }\n00640| ```\n00641| \n00642| Await the `cookies` store in the `Dynamic` component, and pass a cookie value to the `Cached` component.\n00643| \n00644| **Shared deduplication storage:**\n00645| \n00646| ```tsx filename=\"app/page.tsx\"\n00647| // Problem: Map stores dynamic Promises, accessed by cached code\n00648| import { Suspense } from 'react'\n00649| \n00650| const cache = new Map>()\n00651| \n00652| export default function Page() {\n00653| return (\n00654| <>\n00655| Loading...
+
+ )
+}
+
+import type { Metadata } from 'next'
+
+export const metadata: Metadata = {
+ title: 'Create Next App',
+ description: 'Generated by create next app',
+}
+
+export default function RootLayout({
+ children,
+}: Readonly<{
+ children: React.ReactNode
+}>) {
+ return (
+
+ {children}
+
+ )
+}
+
+export default function Page() {
+ return (
+
+
Home
+
+ )
+}
+
+export async function getAllProducts() {
+ // Simulate database delay
+ await new Promise((resolve) => setTimeout(resolve, 100))
+
+ return [
+ { id: 1, name: 'Laptop', price: 999, inventory: 42, available: true },
+ { id: 2, name: 'Phone', price: 699, inventory: 128, available: true },
+ { id: 3, name: 'Tablet', price: 499, inventory: 76, available: true },
+ { id: 4, name: 'Headphones', price: 199, inventory: 15, available: true },
+ { id: 5, name: 'Watch', price: 299, inventory: 0, available: false },
+ ]
+}
+
+'use cache'
+
+import { cacheLife, cacheTag } from 'next/cache'
+import { getAllProducts } from './db'
+
+export async function getProducts() {
+ cacheLife('max')
+ cacheTag('products')
+ return getAllProducts()
+}
+
+///
+///
+import \"./.next/types/routes.d.ts\";
+import \"./.next/types/root-params.d.ts\";
+
+// NOTE: This file should not be edited
+// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
+
+import type { NextConfig } from 'next'
+
+const nextConfig: NextConfig = {
+ cacheComponents: true,
+}
+
+export default nextConfig
+
+
+import { defineConfig } from 'vitest/config';
+export default defineConfig({
+ test: {
+ include: ['EVAL.ts'],
+ globals: false,
+ },
+});
+"
+
+ ❯ EVAL.ts:74:18
+ 72| test('Page fetches products via lib/db', () => {
+ 73| // Keep data source expectation explicit without location assumption…
+ 74| expect(source).toMatch(/import.*getAllProducts.*lib\/db|from.*lib\/d…
+ | ^
+ 75| expect(source).toMatch(/await\s+getAllProducts\s*\(|getAllProducts\s…
+ 76| })
+
+⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/1]⎯
+
diff --git a/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-029-use-cache-directive/run-2/outputs/scripts/build.txt b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-029-use-cache-directive/run-2/outputs/scripts/build.txt
new file mode 100644
index 000000000..13c28d503
--- /dev/null
+++ b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-029-use-cache-directive/run-2/outputs/scripts/build.txt
@@ -0,0 +1,27 @@
+
+> build
+> next build
+
+▲ Next.js 16.3.0-canary.50 (Turbopack)
+- Cache Components enabled
+
+ Creating an optimized production build ...
+✓ Compiled successfully in 5.7s
+ Running TypeScript ...
+ Finished TypeScript in 2.5s ...
+ Collecting page data using 1 worker ...
+ Generating static pages using 1 worker (0/4) ...
+ Generating static pages using 1 worker (1/4)
+ Generating static pages using 1 worker (2/4)
+ Generating static pages using 1 worker (3/4)
+✓ Generating static pages using 1 worker (4/4) in 205ms
+ Finalizing page optimization ...
+
+Route (app) Revalidate Expire
+┌ ○ /
+├ ○ /_not-found
+└ ○ /admin/catalog 30d 1y
+
+
+○ (Static) prerendered as static content
+
diff --git a/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-029-use-cache-directive/run-2/result.json b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-029-use-cache-directive/run-2/result.json
new file mode 100644
index 000000000..4936eb291
--- /dev/null
+++ b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-029-use-cache-directive/run-2/result.json
@@ -0,0 +1,93 @@
+{
+ "status": "failed",
+ "duration": 299.668,
+ "model": "vercel/moonshotai/kimi-k2.7-code",
+ "transcriptPath": "./transcript.json",
+ "transcriptRawPath": "./transcript-raw.jsonl",
+ "o11y": {
+ "totalTurns": 1,
+ "toolCalls": {
+ "file_read": 14,
+ "file_write": 4,
+ "file_edit": 0,
+ "shell": 9,
+ "web_fetch": 0,
+ "web_search": 0,
+ "glob": 6,
+ "grep": 0,
+ "list_dir": 0,
+ "agent_task": 0,
+ "unknown": 4
+ },
+ "totalToolCalls": 37,
+ "webFetches": [],
+ "filesRead": [
+ "/workspace/app/page.tsx",
+ "/workspace/app/layout.tsx",
+ "/workspace/package.json",
+ "/workspace/next.config.ts",
+ "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md",
+ "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md",
+ "/workspace/node_modules/next/dist/docs/01-app/02-guides/forms.md",
+ "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache.md",
+ "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/cacheComponents.md",
+ "/workspace/node_modules/next/dist/docs/01-app/01-getting-started/09-revalidating.md",
+ "/workspace/tsconfig.json",
+ "/workspace/lib/db.js",
+ "/workspace/lib/products.ts",
+ "/workspace/app/admin/catalog/page.tsx"
+ ],
+ "filesModified": [
+ "/workspace/next.config.ts",
+ "/workspace/lib/products.ts",
+ "/workspace/app/admin/catalog/page.tsx",
+ "/workspace/lib/db.js"
+ ],
+ "shellCommands": [
+ {
+ "command": "ls -la",
+ "success": true
+ },
+ {
+ "command": "ls node_modules/next/dist | head -50",
+ "success": true
+ },
+ {
+ "command": "ls node_modules/next/dist/docs | head -100 && echo '---' && ls node_modules/next/dist/docs/app | head -100",
+ "success": true
+ },
+ {
+ "command": "find node_modules/next/dist/docs -maxdepth 3 -type f | head -80",
+ "success": true
+ },
+ {
+ "command": "grep -rl \"revalidateTag\\|unstable_cache\\|cacheTag\\|cacheLife\" node_modules/next/dist/docs/01-app | head -30",
+ "success": true
+ },
+ {
+ "command": "find node_modules/next/dist/docs/01-app -type f | grep -iE \"(server-action|cache|revalid|form)\" | head -60",
+ "success": true
+ },
+ {
+ "command": "ls -la lib app",
+ "success": true
+ },
+ {
+ "command": "npm run build",
+ "success": true
+ },
+ {
+ "command": "npx tsc --noEmit",
+ "success": true
+ }
+ ],
+ "errors": [],
+ "thinkingBlocks": 0
+ },
+ "outputPaths": {
+ "eval": "./outputs/eval.txt",
+ "scripts": {
+ "build": "./outputs/scripts/build.txt"
+ }
+ }
+}
\ No newline at end of file
diff --git a/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-029-use-cache-directive/run-2/transcript-raw.jsonl b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-029-use-cache-directive/run-2/transcript-raw.jsonl
new file mode 100644
index 000000000..a6eff3319
--- /dev/null
+++ b/results/kimi-k2.7-code--agents-md/2026-06-13T23-14-22.142Z/agent-029-use-cache-directive/run-2/transcript-raw.jsonl
@@ -0,0 +1,82 @@
+{"type":"step_start","timestamp":1781392510360,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec3448d83001Ao4N6lHCzMkv0A","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec3448782001hDAyyxp6vWl5RD","type":"step-start","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012"}}
+{"type":"tool_use","timestamp":1781392515338,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec3449624001IReeWzKiLChaxo","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec3448782001hDAyyxp6vWl5RD","type":"tool","callID":"todowrite_0","tool":"todowrite","state":{"status":"completed","input":{"todos":[{"id":"1","content":"Explore workspace and Next.js docs for cache tags and Server Actions","status":"in_progress","priority":"high"},{"id":"2","content":"Implement admin catalog page with inline Server Action sync form","status":"pending","priority":"high"},{"id":"3","content":"Add/verify catalog data fetching uses cache tag 'products'","status":"pending","priority":"high"},{"id":"4","content":"Run lint/typecheck/tests as available","status":"pending","priority":"medium"}]},"output":"[\n {\n \"id\": \"1\",\n \"content\": \"Explore workspace and Next.js docs for cache tags and Server Actions\",\n \"status\": \"in_progress\",\n \"priority\": \"high\"\n },\n {\n \"id\": \"2\",\n \"content\": \"Implement admin catalog page with inline Server Action sync form\",\n \"status\": \"pending\",\n \"priority\": \"high\"\n },\n {\n \"id\": \"3\",\n \"content\": \"Add/verify catalog data fetching uses cache tag 'products'\",\n \"status\": \"pending\",\n \"priority\": \"high\"\n },\n {\n \"id\": \"4\",\n \"content\": \"Run lint/typecheck/tests as available\",\n \"status\": \"pending\",\n \"priority\": \"medium\"\n }\n]","title":"4 todos","metadata":{"todos":[{"id":"1","content":"Explore workspace and Next.js docs for cache tags and Server Actions","status":"in_progress","priority":"high"},{"id":"2","content":"Implement admin catalog page with inline Server Action sync form","status":"pending","priority":"high"},{"id":"3","content":"Add/verify catalog data fetching uses cache tag 'products'","status":"pending","priority":"high"},{"id":"4","content":"Run lint/typecheck/tests as available","status":"pending","priority":"medium"}]},"time":{"start":1781392515329,"end":1781392515334}}}}
+{"type":"step_finish","timestamp":1781392515344,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec344a109001Dyl845NY2biiyj","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec3448782001hDAyyxp6vWl5RD","type":"step-finish","reason":"tool-calls","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012","cost":0.00254256,"tokens":{"input":0,"output":251,"reasoning":0,"cache":{"read":9616,"write":0}}}}
+{"type":"step_start","timestamp":1781392517018,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec344a798001CE6BFi7W4UW0Ey","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec344a11e001CDiE40tpKQDtfO","type":"step-start","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012"}}
+{"type":"tool_use","timestamp":1781392517470,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec344a798002VptunouQcVWiTH","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec344a11e001CDiE40tpKQDtfO","type":"tool","callID":"bash_1","tool":"bash","state":{"status":"completed","input":{"command":"ls -la","description":"List workspace contents"},"output":"total 196\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 238 Jun 13 23:15 .\ndrwxr-xr-x 20 root root 286 Jun 13 23:15 ..\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 154 Jun 13 23:15 .git\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 14 Jun 13 23:14 .gitignore\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 327 Jun 13 23:14 AGENTS.md\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 11 Jun 13 23:14 CLAUDE.md\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 11 Jun 13 23:14 GEMINI.md\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 40 Jun 13 23:14 app\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 19 Jun 13 23:14 lib\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 101 Jun 13 23:14 next.config.ts\ndrwxr-xr-x 179 vercel-sandbox vercel-sandbox 8192 Jun 13 23:14 node_modules\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 1549 Jun 13 23:15 opencode.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 154377 Jun 13 23:15 package-lock.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 603 Jun 13 23:14 package.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 599 Jun 13 23:14 tsconfig.json\n","title":"List workspace contents","metadata":{"output":"total 196\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 238 Jun 13 23:15 .\ndrwxr-xr-x 20 root root 286 Jun 13 23:15 ..\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 154 Jun 13 23:15 .git\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 14 Jun 13 23:14 .gitignore\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 327 Jun 13 23:14 AGENTS.md\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 11 Jun 13 23:14 CLAUDE.md\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 11 Jun 13 23:14 GEMINI.md\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 40 Jun 13 23:14 app\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 19 Jun 13 23:14 lib\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 101 Jun 13 23:14 next.config.ts\ndrwxr-xr-x 179 vercel-sandbox vercel-sandbox 8192 Jun 13 23:14 node_modules\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 1549 Jun 13 23:15 opencode.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 154377 Jun 13 23:15 package-lock.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 603 Jun 13 23:14 package.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 599 Jun 13 23:14 tsconfig.json\n","exit":0,"description":"List workspace contents"},"time":{"start":1781392517412,"end":1781392517467}}}}
+{"type":"tool_use","timestamp":1781392518224,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec344a929001vKSJD1dtrDNrYy","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec344a11e001CDiE40tpKQDtfO","type":"tool","callID":"glob_2","tool":"glob","state":{"status":"completed","input":{"pattern":"**/*","path":"/workspace"},"output":"/workspace/opencode.json\n/workspace/node_modules/.package-lock.json\n/workspace/node_modules/esbuild/bin/esbuild\n/workspace/node_modules/type-is/node_modules/content-type/dist/index.d.ts\n/workspace/node_modules/type-is/node_modules/content-type/README.md\n/workspace/node_modules/esbuild/lib/main.d.ts\n/workspace/node_modules/type-is/node_modules/content-type/dist/index.js.map\n/workspace/node_modules/type-is/node_modules/content-type/package.json\n/workspace/node_modules/type-is/node_modules/content-type/dist/index.js\n/workspace/node_modules/esbuild/README.md\n/workspace/node_modules/esbuild/LICENSE.md\n/workspace/node_modules/type-is/node_modules/content-type/LICENSE\n/workspace/node_modules/es-module-lexer/types/lexer.d.ts\n/workspace/node_modules/esbuild/package.json\n/workspace/node_modules/dequal/lite/index.d.ts\n/workspace/node_modules/es-module-lexer/README.md\n/workspace/node_modules/esbuild/lib/main.js\n/workspace/node_modules/dequal/index.d.ts\n/workspace/node_modules/dequal/lite/index.mjs\n/workspace/node_modules/es-module-lexer/package.json\n/workspace/node_modules/es-object-atoms/ToObject.d.ts\n/workspace/node_modules/std-env/dist/index.d.ts\n/workspace/node_modules/es-object-atoms/RequireObjectCoercible.d.ts\n/workspace/node_modules/es-module-lexer/lexer.js\n/workspace/node_modules/dequal/dist/index.mjs\n/workspace/node_modules/es-object-atoms/isObject.d.ts\n/workspace/node_modules/es-object-atoms/index.d.ts\n/workspace/node_modules/tinyglobby/dist/index.d.mts\n/workspace/node_modules/es-object-atoms/README.md\n/workspace/node_modules/std-env/dist/index.d.mts\n/workspace/node_modules/type-is/README.md\n/workspace/node_modules/dequal/readme.md\n/workspace/node_modules/es-object-atoms/CHANGELOG.md\n/workspace/node_modules/hasown/.github/FUNDING.yml\n/workspace/node_modules/type-is/HISTORY.md\n/workspace/node_modules/es-module-lexer/dist/lexer.js\n/workspace/node_modules/dequal/package.json\n/workspace/node_modules/es-object-atoms/tsconfig.json\n/workspace/node_modules/tinyglobby/dist/index.mjs\n/workspace/node_modules/std-env/dist/index.mjs\n/workspace/node_modules/dequal/lite/index.min.js\n/workspace/node_modules/hasown/index.d.ts\n/workspace/node_modules/es-object-atoms/package.json\n/workspace/node_modules/type-is/package.json\n/workspace/node_modules/hasown/eslint.config.mjs\n/workspace/node_modules/es-object-atoms/ToObject.js\n/workspace/node_modules/type-is/index.js\n/workspace/node_modules/hasown/README.md\n/workspace/node_modules/es-object-atoms/RequireObjectCoercible.js\n/workspace/node_modules/type-is/LICENSE\n/workspace/node_modules/es-object-atoms/isObject.js\n/workspace/node_modules/tinyglobby/README.md\n/workspace/node_modules/dequal/dist/index.min.js\n/workspace/node_modules/hasown/CHANGELOG.md\n/workspace/node_modules/tinyrainbow/dist/node.d.ts\n/workspace/node_modules/std-env/README.md\n/workspace/node_modules/hasown/tsconfig.json\n/workspace/node_modules/tinyglobby/package.json\n/workspace/node_modules/hasown/package.json\n/workspace/node_modules/tinyglobby/dist/index.d.cts\n/workspace/node_modules/esbuild/install.js\n/workspace/node_modules/std-env/package.json\n/workspace/node_modules/dequal/lite/index.js\n/workspace/node_modules/hasown/index.js\n/workspace/node_modules/es-object-atoms/index.js\n/workspace/node_modules/es-module-lexer/dist/lexer.asm.js\n/workspace/node_modules/tinyrainbow/dist/index-8b61d5bc.d.ts\n/workspace/node_modules/std-env/dist/index.d.cts\n/workspace/node_modules/globrex/readme.md\n/workspace/node_modules/dequal/dist/index.js\n/workspace/node_modules/hasown/LICENSE\n/workspace/node_modules/tinyrainbow/dist/browser.d.ts\n/workspace/node_modules/tinyglobby/dist/index.cjs\n/workspace/node_modules/dequal/license\n/workspace/node_modules/hasown/.nycrc\n/workspace/node_modules/globrex/license\n/workspace/node_modules/globrex/index.js\n/workspace/node_modules/check-error/README.md\n/workspace/node_modules/assertion-error/index.d.ts\n/workspace/node_modules/tinyrainbow/README.md\n/workspace/node_modules/std-env/dist/index.cjs\n/workspace/node_modules/tinyglobby/LICENSE\n/workspace/node_modules/es-module-lexer/dist/lexer.cjs\n/workspace/node_modules/tinyrainbow/package.json\n/workspace/node_modules/check-error/package.json\n/workspace/node_modules/assertion-error/README.md\n/workspace/node_modules/tinyrainbow/dist/node.js\n/workspace/node_modules/globrex/package.json\n/workspace/node_modules/std-env/LICENCE\n/workspace/node_modules/check-error/index.js\n/workspace/node_modules/assertion-error/package.json\n/workspace/node_modules/check-error/LICENSE\n/workspace/node_modules/assertion-error/index.js\n/workspace/node_modules/tinyrainbow/dist/chunk-BVHSVHOK.js\n/workspace/node_modules/assertion-error/LICENSE\n/workspace/node_modules/es-module-lexer/LICENSE\n/workspace/node_modules/tinyrainbow/dist/browser.js\n/workspace/node_modules/tinyrainbow/LICENCE\n/workspace/app/page.tsx\n/workspace/app/layout.tsx\n\n(Results are truncated. Consider using a more specific path or pattern.)","title":"","metadata":{"count":100,"truncated":true},"time":{"start":1781392518164,"end":1781392518222}}}}
+{"type":"tool_use","timestamp":1781392518873,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec344ac19001zX5foEftxQbgsS","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec344a11e001CDiE40tpKQDtfO","type":"tool","callID":"glob_3","tool":"glob","state":{"status":"completed","input":{"pattern":"node_modules/next/dist/docs/**/*.md","path":"/workspace"},"output":"No files found","title":"","metadata":{"count":0,"truncated":false},"time":{"start":1781392518865,"end":1781392518871}}}}
+{"type":"step_finish","timestamp":1781392518881,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec344aed80016IDnUh9fTC8Hvg","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec344a11e001CDiE40tpKQDtfO","type":"step-finish","reason":"tool-calls","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012","cost":0.00232602,"tokens":{"input":550,"output":72,"reasoning":0,"cache":{"read":9472,"write":0}}}}
+{"type":"step_start","timestamp":1781392520710,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec344b5fa001M8IbmU8Clvm5wt","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec344aee9001O7LOSWA0DzHXzx","type":"step-start","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012"}}
+{"type":"tool_use","timestamp":1781392521659,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec344b923001y1PwDY6DzyOSEb","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec344aee9001O7LOSWA0DzHXzx","type":"tool","callID":"glob_4","tool":"glob","state":{"status":"completed","input":{"pattern":"node_modules/next/dist/docs/**/*","path":"/workspace"},"output":"No files found","title":"","metadata":{"count":0,"truncated":false},"time":{"start":1781392521648,"end":1781392521658}}}}
+{"type":"step_finish","timestamp":1781392521664,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec344b9bb001rF5dNhttZhiZTR","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec344aee9001O7LOSWA0DzHXzx","type":"step-finish","reason":"tool-calls","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012","cost":0.00330519,"tokens":{"input":1625,"output":41,"reasoning":0,"cache":{"read":9984,"write":0}}}}
+{"type":"step_start","timestamp":1781392523076,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec344bf3c001v34CyBtAiLDqlx","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec344b9cc001FUPdMhHRL6mSty","type":"step-start","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012"}}
+{"type":"tool_use","timestamp":1781392523620,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec344c02a0012KWTmvlJ66sOG4","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec344b9cc001FUPdMhHRL6mSty","type":"tool","callID":"bash_5","tool":"bash","state":{"status":"completed","input":{"command":"ls node_modules/next/dist | head -50","description":"List next dist contents"},"output":"api\nbin\nbuild\nbundle-analyzer\ncli\nclient\ncompiled\ndiagnostics\ndocs\nesm\nexperimental\nexport\nlib\nnext-devtools\npages\nserver\nshared\nstyled-jsx\ntelemetry\ntrace\ntypes.d.ts\n","title":"List next dist contents","metadata":{"output":"api\nbin\nbuild\nbundle-analyzer\ncli\nclient\ncompiled\ndiagnostics\ndocs\nesm\nexperimental\nexport\nlib\nnext-devtools\npages\nserver\nshared\nstyled-jsx\ntelemetry\ntrace\ntypes.d.ts\n","exit":0,"description":"List next dist contents"},"time":{"start":1781392523606,"end":1781392523613}}}}
+{"type":"step_finish","timestamp":1781392523625,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec344c15f001ApxBXO55aPiYXZ","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec344b9cc001FUPdMhHRL6mSty","type":"step-finish","reason":"tool-calls","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012","cost":0.00218075,"tokens":{"input":149,"output":49,"reasoning":0,"cache":{"read":11520,"write":0}}}}
+{"type":"step_start","timestamp":1781392525197,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec344c78b001vUw4ztWRZlab9Z","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec344c175001ZpEguHTXspwtF7","type":"step-start","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012"}}
+{"type":"tool_use","timestamp":1781392525909,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec344c78c0015Ncwu0UnKqWs7y","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec344c175001ZpEguHTXspwtF7","type":"tool","callID":"bash_6","tool":"bash","state":{"status":"completed","input":{"command":"ls node_modules/next/dist/docs | head -100 && echo '---' && ls node_modules/next/dist/docs/app | head -100","description":"List docs directory"},"output":"01-app\n02-pages\n03-architecture\n04-community\nindex.md\n---\nls: cannot access 'node_modules/next/dist/docs/app': No such file or directory\n","title":"List docs directory","metadata":{"output":"01-app\n02-pages\n03-architecture\n04-community\nindex.md\n---\nls: cannot access 'node_modules/next/dist/docs/app': No such file or directory\n","exit":0,"description":"List docs directory"},"time":{"start":1781392525901,"end":1781392525907}}}}
+{"type":"step_finish","timestamp":1781392525916,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec344ca540013U006X5ri0ujUV","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec344c175001ZpEguHTXspwtF7","type":"step-finish","reason":"tool-calls","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012","cost":0.00229,"tokens":{"input":264,"output":49,"reasoning":0,"cache":{"read":11520,"write":0}}}}
+{"type":"step_start","timestamp":1781392527542,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec344d0ae001y0qIhFSTW076ot","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec344ca64001GkurmexhVgrUAL","type":"step-start","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012"}}
+{"type":"tool_use","timestamp":1781392527987,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec344d0ae0027vWFl53fdAMpjL","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec344ca64001GkurmexhVgrUAL","type":"tool","callID":"bash_7","tool":"bash","state":{"status":"completed","input":{"command":"find node_modules/next/dist/docs -maxdepth 3 -type f | head -80","description":"Find docs files up to depth 3"},"output":"node_modules/next/dist/docs/02-pages/03-building-your-application/index.md\nnode_modules/next/dist/docs/02-pages/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-edge.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/08-turbopack.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/index.md\nnode_modules/next/dist/docs/02-pages/02-guides/analytics.md\nnode_modules/next/dist/docs/02-pages/02-guides/authentication.md\nnode_modules/next/dist/docs/02-pages/02-guides/babel.md\nnode_modules/next/dist/docs/02-pages/02-guides/ci-build-caching.md\nnode_modules/next/dist/docs/02-pages/02-guides/content-security-policy.md\nnode_modules/next/dist/docs/02-pages/02-guides/css-in-js.md\nnode_modules/next/dist/docs/02-pages/02-guides/custom-server.md\nnode_modules/next/dist/docs/02-pages/02-guides/debugging.md\nnode_modules/next/dist/docs/02-pages/02-guides/draft-mode.md\nnode_modules/next/dist/docs/02-pages/02-guides/environment-variables.md\nnode_modules/next/dist/docs/02-pages/02-guides/forms.md\nnode_modules/next/dist/docs/02-pages/02-guides/incremental-static-regeneration.md\nnode_modules/next/dist/docs/02-pages/02-guides/index.md\nnode_modules/next/dist/docs/02-pages/02-guides/instrumentation.md\nnode_modules/next/dist/docs/02-pages/02-guides/internationalization.md\nnode_modules/next/dist/docs/02-pages/02-guides/lazy-loading.md\nnode_modules/next/dist/docs/02-pages/02-guides/mdx.md\nnode_modules/next/dist/docs/02-pages/02-guides/multi-zones.md\nnode_modules/next/dist/docs/02-pages/02-guides/open-telemetry.md\nnode_modules/next/dist/docs/02-pages/02-guides/package-bundling.md\nnode_modules/next/dist/docs/02-pages/02-guides/post-css.md\nnode_modules/next/dist/docs/02-pages/02-guides/preview-mode.md\nnode_modules/next/dist/docs/02-pages/02-guides/production-checklist.md\nnode_modules/next/dist/docs/02-pages/02-guides/redirecting.md\nnode_modules/next/dist/docs/02-pages/02-guides/sass.md\nnode_modules/next/dist/docs/02-pages/02-guides/scripts.md\nnode_modules/next/dist/docs/02-pages/02-guides/self-hosting.md\nnode_modules/next/dist/docs/02-pages/02-guides/static-exports.md\nnode_modules/next/dist/docs/02-pages/02-guides/tailwind-v3-css.md\nnode_modules/next/dist/docs/02-pages/02-guides/third-party-libraries.md\nnode_modules/next/dist/docs/02-pages/01-getting-started/01-installation.md\nnode_modules/next/dist/docs/02-pages/01-getting-started/02-project-structure.md\nnode_modules/next/dist/docs/02-pages/01-getting-started/04-images.md\nnode_modules/next/dist/docs/02-pages/01-getting-started/05-fonts.md\nnode_modules/next/dist/docs/02-pages/01-getting-started/06-css.md\nnode_modules/next/dist/docs/02-pages/01-getting-started/11-deploying.md\nnode_modules/next/dist/docs/02-pages/01-getting-started/index.md\nnode_modules/next/dist/docs/index.md\nnode_modules/next/dist/docs/01-app/02-guides/adopting-partial-prefetching.md\nnode_modules/next/dist/docs/01-app/02-guides/ai-agents.md\nnode_modules/next/dist/docs/01-app/02-guides/analytics.md\nnode_modules/next/dist/docs/01-app/02-guides/authentication.md\nnode_modules/next/dist/docs/01-app/02-guides/backend-for-frontend.md\nnode_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/cdn-caching.md\nnode_modules/next/dist/docs/01-app/02-guides/ci-build-caching.md\nnode_modules/next/dist/docs/01-app/02-guides/content-security-policy.md\nnode_modules/next/dist/docs/01-app/02-guides/css-in-js.md\nnode_modules/next/dist/docs/01-app/02-guides/custom-server.md\nnode_modules/next/dist/docs/01-app/02-guides/data-security.md\nnode_modules/next/dist/docs/01-app/02-guides/debugging.md\nnode_modules/next/dist/docs/01-app/02-guides/deploying-to-platforms.md\nnode_modules/next/dist/docs/01-app/02-guides/draft-mode.md\nnode_modules/next/dist/docs/01-app/02-guides/environment-variables.md\nnode_modules/next/dist/docs/01-app/02-guides/forms.md\nnode_modules/next/dist/docs/01-app/02-guides/how-revalidation-works.md\nnode_modules/next/dist/docs/01-app/02-guides/incremental-static-regeneration-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/incremental-static-regeneration.md\nnode_modules/next/dist/docs/01-app/02-guides/index.md\nnode_modules/next/dist/docs/01-app/02-guides/instant-navigation.md\nnode_modules/next/dist/docs/01-app/02-guides/instrumentation.md\nnode_modules/next/dist/docs/01-app/02-guides/internationalization.md\nnode_modules/next/dist/docs/01-app/02-guides/json-ld.md\nnode_modules/next/dist/docs/01-app/02-guides/lazy-loading.md\nnode_modules/next/dist/docs/01-app/02-guides/local-development.md\nnode_modules/next/dist/docs/01-app/02-guides/mcp.md\nnode_modules/next/dist/docs/01-app/02-guides/mdx.md\nnode_modules/next/dist/docs/01-app/02-guides/memory-usage.md\nnode_modules/next/dist/docs/01-app/02-guides/migrating-to-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/multi-tenant.md\nnode_modules/next/dist/docs/01-app/02-guides/multi-zones.md\nnode_modules/next/dist/docs/01-app/02-guides/open-telemetry.md\nnode_modules/next/dist/docs/01-app/02-guides/package-bundling.md\nnode_modules/next/dist/docs/01-app/02-guides/ppr-platform-guide.md\nnode_modules/next/dist/docs/01-app/02-guides/prefetching.md\n","title":"Find docs files up to depth 3","metadata":{"output":"node_modules/next/dist/docs/02-pages/03-building-your-application/index.md\nnode_modules/next/dist/docs/02-pages/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-edge.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/08-turbopack.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/index.md\nnode_modules/next/dist/docs/02-pages/02-guides/analytics.md\nnode_modules/next/dist/docs/02-pages/02-guides/authentication.md\nnode_modules/next/dist/docs/02-pages/02-guides/babel.md\nnode_modules/next/dist/docs/02-pages/02-guides/ci-build-caching.md\nnode_modules/next/dist/docs/02-pages/02-guides/content-security-policy.md\nnode_modules/next/dist/docs/02-pages/02-guides/css-in-js.md\nnode_modules/next/dist/docs/02-pages/02-guides/custom-server.md\nnode_modules/next/dist/docs/02-pages/02-guides/debugging.md\nnode_modules/next/dist/docs/02-pages/02-guides/draft-mode.md\nnode_modules/next/dist/docs/02-pages/02-guides/environment-variables.md\nnode_modules/next/dist/docs/02-pages/02-guides/forms.md\nnode_modules/next/dist/docs/02-pages/02-guides/incremental-static-regeneration.md\nnode_modules/next/dist/docs/02-pages/02-guides/index.md\nnode_modules/next/dist/docs/02-pages/02-guides/instrumentation.md\nnode_modules/next/dist/docs/02-pages/02-guides/internationalization.md\nnode_modules/next/dist/docs/02-pages/02-guides/lazy-loading.md\nnode_modules/next/dist/docs/02-pages/02-guides/mdx.md\nnode_modules/next/dist/docs/02-pages/02-guides/multi-zones.md\nnode_modules/next/dist/docs/02-pages/02-guides/open-telemetry.md\nnode_modules/next/dist/docs/02-pages/02-guides/package-bundling.md\nnode_modules/next/dist/docs/02-pages/02-guides/post-css.md\nnode_modules/next/dist/docs/02-pages/02-guides/preview-mode.md\nnode_modules/next/dist/docs/02-pages/02-guides/production-checklist.md\nnode_modules/next/dist/docs/02-pages/02-guides/redirecting.md\nnode_modules/next/dist/docs/02-pages/02-guides/sass.md\nnode_modules/next/dist/docs/02-pages/02-guides/scripts.md\nnode_modules/next/dist/docs/02-pages/02-guides/self-hosting.md\nnode_modules/next/dist/docs/02-pages/02-guides/static-exports.md\nnode_modules/next/dist/docs/02-pages/02-guides/tailwind-v3-css.md\nnode_modules/next/dist/docs/02-pages/02-guides/third-party-libraries.md\nnode_modules/next/dist/docs/02-pages/01-getting-started/01-installation.md\nnode_modules/next/dist/docs/02-pages/01-getting-started/02-project-structure.md\nnode_modules/next/dist/docs/02-pages/01-getting-started/04-images.md\nnode_modules/next/dist/docs/02-pages/01-getting-started/05-fonts.md\nnode_modules/next/dist/docs/02-pages/01-getting-started/06-css.md\nnode_modules/next/dist/docs/02-pages/01-getting-started/11-deploying.md\nnode_modules/next/dist/docs/02-pages/01-getting-started/index.md\nnode_modules/next/dist/docs/index.md\nnode_modules/next/dist/docs/01-app/02-guides/adopting-partial-prefetching.md\nnode_modules/next/dist/docs/01-app/02-guides/ai-agents.md\nnode_modules/next/dist/docs/01-app/02-guides/analytics.md\nnode_modules/next/dist/docs/01-app/02-guides/authentication.md\nnode_modules/next/dist/docs/01-app/02-guides/backend-for-frontend.md\nnode_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/cdn-caching.md\nnode_modules/next/dist/docs/01-app/02-guides/ci-build-caching.md\nnode_modules/next/dist/docs/01-app/02-guides/content-security-policy.md\nnode_modules/next/dist/docs/01-app/02-guides/css-in-js.md\nnode_modules/next/dist/docs/01-app/02-guides/custom-server.md\nnode_modules/next/dist/docs/01-app/02-guides/data-security.md\nnode_modules/next/dist/docs/01-app/02-guides/debugging.md\nnode_modules/next/dist/docs/01-app/02-guides/deploying-to-platforms.md\nnode_modules/next/dist/docs/01-app/02-guides/draft-mode.md\nnode_modules/next/dist/docs/01-app/02-guides/environment-variables.md\nnode_modules/next/dist/docs/01-app/02-guides/forms.md\nnode_modules/next/dist/docs/01-app/02-guides/how-revalidation-works.md\nnode_modules/next/dist/docs/01-app/02-guides/incremental-static-regeneration-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/incremental-static-regeneration.md\nnode_modules/next/dist/docs/01-app/02-guides/index.md\nnode_modules/next/dist/docs/01-app/02-guides/instant-navigation.md\nnode_modules/next/dist/docs/01-app/02-guides/instrumentation.md\nnode_modules/next/dist/docs/01-app/02-guides/internationalization.md\nnode_modules/next/dist/docs/01-app/02-guides/json-ld.md\nnode_modules/next/dist/docs/01-app/02-guides/lazy-loading.md\nnode_modules/next/dist/docs/01-app/02-guides/local-development.md\nnode_modules/next/dist/docs/01-app/02-guides/mcp.md\nnode_modules/next/dist/docs/01-app/02-guides/mdx.md\nnode_modules/next/dist/docs/01-app/02-guides/memory-usage.md\nnode_modules/next/dist/docs/01-app/02-guides/migrating-to-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/multi-tenant.md\nnode_modules/next/dist/docs/01-app/02-guides/multi-zones.md\nnode_modules/next/dist/docs/01-app/02-guides/open-telemetry.md\nnode_modules/next/dist/docs/01-app/02-guides/package-bundling.md\nnode_modules/next/dist/docs/01-app/02-guides/ppr-platform-guide.md\nnode_modules/next/dist/docs/01-app/02-guides/prefetching.md\n","exit":0,"description":"Find docs files up to depth 3"},"time":{"start":1781392527978,"end":1781392527985}}}}
+{"type":"step_finish","timestamp":1781392527996,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec344d272001yyEDs6rBWzLj6x","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec344ca64001GkurmexhVgrUAL","type":"step-finish","reason":"tool-calls","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012","cost":0.00216771,"tokens":{"input":109,"output":45,"reasoning":0,"cache":{"read":11776,"write":0}}}}
+{"type":"step_start","timestamp":1781392529556,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec344d88d001SNC2YlulqXz7ab","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec344d28b001H7tzVpQq1bJRSE","type":"step-start","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012"}}
+{"type":"tool_use","timestamp":1781392530751,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec344d952001OkFGZ6tUHsexM5","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec344d28b001H7tzVpQq1bJRSE","type":"tool","callID":"bash_8","tool":"bash","state":{"status":"completed","input":{"command":"grep -rl \"revalidateTag\\|unstable_cache\\|cacheTag\\|cacheLife\" node_modules/next/dist/docs/01-app | head -30","description":"Find docs mentioning cache tags"},"output":"node_modules/next/dist/docs/01-app/02-guides/backend-for-frontend.md\nnode_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/cdn-caching.md\nnode_modules/next/dist/docs/01-app/02-guides/deploying-to-platforms.md\nnode_modules/next/dist/docs/01-app/02-guides/draft-mode.md\nnode_modules/next/dist/docs/01-app/02-guides/how-revalidation-works.md\nnode_modules/next/dist/docs/01-app/02-guides/incremental-static-regeneration-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/incremental-static-regeneration.md\nnode_modules/next/dist/docs/01-app/02-guides/instant-navigation.md\nnode_modules/next/dist/docs/01-app/02-guides/migrating-to-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/ppr-platform-guide.md\nnode_modules/next/dist/docs/01-app/02-guides/prefetching.md\nnode_modules/next/dist/docs/01-app/02-guides/production-checklist.md\nnode_modules/next/dist/docs/01-app/02-guides/redirecting.md\nnode_modules/next/dist/docs/01-app/02-guides/rendering-philosophy.md\nnode_modules/next/dist/docs/01-app/02-guides/self-hosting.md\nnode_modules/next/dist/docs/01-app/02-guides/upgrading/codemods.md\nnode_modules/next/dist/docs/01-app/02-guides/upgrading/version-16.md\nnode_modules/next/dist/docs/01-app/04-glossary.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheLife.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cookies.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/fetch.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/next-root-params.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidatePath.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/unstable_cache.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/unstable_noStore.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/updateTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/use-router.md\n","title":"Find docs mentioning cache tags","metadata":{"output":"node_modules/next/dist/docs/01-app/02-guides/backend-for-frontend.md\nnode_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/cdn-caching.md\nnode_modules/next/dist/docs/01-app/02-guides/deploying-to-platforms.md\nnode_modules/next/dist/docs/01-app/02-guides/draft-mode.md\nnode_modules/next/dist/docs/01-app/02-guides/how-revalidation-works.md\nnode_modules/next/dist/docs/01-app/02-guides/incremental-static-regeneration-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/incremental-static-regeneration.md\nnode_modules/next/dist/docs/01-app/02-guides/instant-navigation.md\nnode_modules/next/dist/docs/01-app/02-guides/migrating-to-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/ppr-platform-guide.md\nnode_modules/next/dist/docs/01-app/02-guides/prefetching.md\nnode_modules/next/dist/docs/01-app/02-guides/production-checklist.md\nnode_modules/next/dist/docs/01-app/02-guides/redirecting.md\nnode_modules/next/dist/docs/01-app/02-guides/rendering-philosophy.md\nnode_modules/next/dist/docs/01-app/02-guides/self-hosting.md\nnode_modules/next/dist/docs/01-app/02-guides/upgrading/codemods.md\nnode_modules/next/dist/docs/01-app/02-guides/upgrading/version-16.md\nnode_modules/next/dist/docs/01-app/04-glossary.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheLife.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cookies.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/fetch.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/next-root-params.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidatePath.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/unstable_cache.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/unstable_noStore.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/updateTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/use-router.md\n","exit":0,"description":"Find docs mentioning cache tags"},"time":{"start":1781392530719,"end":1781392530750}}}}
+{"type":"tool_use","timestamp":1781392531448,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec344dd22001630EVzsA6ApOsU","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec344d28b001H7tzVpQq1bJRSE","type":"tool","callID":"bash_9","tool":"bash","state":{"status":"completed","input":{"command":"find node_modules/next/dist/docs/01-app -type f | grep -iE \"(server-action|cache|revalid|form)\" | head -60","description":"Find docs files for caching/actions/forms"},"output":"node_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/deploying-to-platforms.md\nnode_modules/next/dist/docs/01-app/02-guides/forms.md\nnode_modules/next/dist/docs/01-app/02-guides/how-revalidation-works.md\nnode_modules/next/dist/docs/01-app/02-guides/incremental-static-regeneration-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/migrating-to-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/ppr-platform-guide.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheLife.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidatePath.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/unstable_cache.md\nnode_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache-private.md\nnode_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache-remote.md\nnode_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache.md\nnode_modules/next/dist/docs/01-app/03-api-reference/02-components/form.md\nnode_modules/next/dist/docs/01-app/03-api-reference/07-adapters/10-routing-information.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/cacheComponents.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/cacheHandlers.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/cacheLife.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/incrementalCacheHandlerPath.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/serverComponentsHmrCache.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/turbopackFileSystemCache.md\nnode_modules/next/dist/docs/01-app/01-getting-started/09-revalidating.md\n","title":"Find docs files for caching/actions/forms","metadata":{"output":"node_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/deploying-to-platforms.md\nnode_modules/next/dist/docs/01-app/02-guides/forms.md\nnode_modules/next/dist/docs/01-app/02-guides/how-revalidation-works.md\nnode_modules/next/dist/docs/01-app/02-guides/incremental-static-regeneration-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/migrating-to-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/ppr-platform-guide.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheLife.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidatePath.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/unstable_cache.md\nnode_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache-private.md\nnode_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache-remote.md\nnode_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache.md\nnode_modules/next/dist/docs/01-app/03-api-reference/02-components/form.md\nnode_modules/next/dist/docs/01-app/03-api-reference/07-adapters/10-routing-information.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/cacheComponents.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/cacheHandlers.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/cacheLife.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/incrementalCacheHandlerPath.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/serverComponentsHmrCache.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/turbopackFileSystemCache.md\nnode_modules/next/dist/docs/01-app/01-getting-started/09-revalidating.md\n","exit":0,"description":"Find docs files for caching/actions/forms"},"time":{"start":1781392531427,"end":1781392531442}}}}
+{"type":"step_finish","timestamp":1781392531452,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec344dff4001eK8hlkoHmQ9WO6","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec344d28b001H7tzVpQq1bJRSE","type":"step-finish","reason":"tool-calls","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012","cost":0.00388926,"tokens":{"input":1538,"output":136,"reasoning":0,"cache":{"read":11776,"write":0}}}}
+{"type":"step_start","timestamp":1781392532813,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec344e5440016dSZex7KC6MKAw","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec344e00b001jo6Yj8btd2NmTi","type":"step-start","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012"}}
+{"type":"tool_use","timestamp":1781392533643,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec344e7a7001jhI2uAw6AiiTqP","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec344e00b001jo6Yj8btd2NmTi","type":"tool","callID":"read_10","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/app/page.tsx"},"output":"\n00001| export default function Page() {\n00002| return (\n00003|
\n00004|
Home
\n00005|
\n00006| )\n00007| }\n00008| \n\n(End of file - total 8 lines)\n","title":"app/page.tsx","metadata":{"preview":"export default function Page() {\n return (\n
\n
Home
\n
\n )\n}\n"},"time":{"start":1781392533635,"end":1781392533639}}}}
+{"type":"tool_use","timestamp":1781392533862,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec344e887001QeFmiOdplyc7E7","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec344e00b001jo6Yj8btd2NmTi","type":"tool","callID":"read_11","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/app/layout.tsx"},"output":"\n00001| import type { Metadata } from 'next'\n00002| \n00003| export const metadata: Metadata = {\n00004| title: 'Create Next App',\n00005| description: 'Generated by create next app',\n00006| }\n00007| \n00008| export default function RootLayout({\n00009| children,\n00010| }: Readonly<{\n00011| children: React.ReactNode\n00012| }>) {\n00013| return (\n00014| \n00015| {children}\n00016| \n00017| )\n00018| }\n00019| \n\n(End of file - total 19 lines)\n","title":"app/layout.tsx","metadata":{"preview":"import type { Metadata } from 'next'\n\nexport const metadata: Metadata = {\n title: 'Create Next App',\n description: 'Generated by create next app',\n}\n\nexport default function RootLayout({\n children,\n}: Readonly<{\n children: React.ReactNode\n}>) {\n return (\n \n {children}\n \n )\n}\n"},"time":{"start":1781392533851,"end":1781392533860}}}}
+{"type":"tool_use","timestamp":1781392534260,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec344ea2000134bXbVjhisqmdg","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec344e00b001jo6Yj8btd2NmTi","type":"tool","callID":"read_13","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/package.json"},"output":"\n00001| {\n00002| \"private\": true,\n00003| \"type\": \"module\",\n00004| \"scripts\": {\n00005| \"dev\": \"next dev\",\n00006| \"build\": \"next build\",\n00007| \"start\": \"next start\"\n00008| },\n00009| \"dependencies\": {\n00010| \"@ai-sdk/react\": \"2.0.0-beta.28\",\n00011| \"@modelcontextprotocol/sdk\": \"^1.17.0\",\n00012| \"ai\": \"5.0.59\",\n00013| \"next\": \"^16.3.0-canary.50\",\n00014| \"react\": \"19.1.0\",\n00015| \"react-dom\": \"19.1.0\",\n00016| \"zod\": \"^4.0.10\"\n00017| },\n00018| \"devDependencies\": {\n00019| \"@types/node\": \"^20\",\n00020| \"@types/react\": \"^19\",\n00021| \"@types/react-dom\": \"^19\",\n00022| \"@vitejs/plugin-react\": \"^4.4.1\",\n00023| \"typescript\": \"^5\",\n00024| \"vite-tsconfig-paths\": \"^5.1.4\",\n00025| \"vitest\": \"^3.1.3\"\n00026| }\n00027| }\n00028| \n\n(End of file - total 28 lines)\n","title":"package.json","metadata":{"preview":"{\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"next dev\",\n \"build\": \"next build\",\n \"start\": \"next start\"\n },\n \"dependencies\": {\n \"@ai-sdk/react\": \"2.0.0-beta.28\",\n \"@modelcontextprotocol/sdk\": \"^1.17.0\",\n \"ai\": \"5.0.59\",\n \"next\": \"^16.3.0-canary.50\",\n \"react\": \"19.1.0\",\n \"react-dom\": \"19.1.0\",\n \"zod\": \"^4.0.10\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^20\",\n \"@types/react\": \"^19\","},"time":{"start":1781392534248,"end":1781392534251}}}}
+{"type":"tool_use","timestamp":1781392534455,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec344eaea001463Jwj8J3BsTI7","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec344e00b001jo6Yj8btd2NmTi","type":"tool","callID":"read_14","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/next.config.ts"},"output":"\n00001| import type { NextConfig } from 'next'\n00002| \n00003| const nextConfig: NextConfig = {}\n00004| \n00005| export default nextConfig\n00006| \n\n(End of file - total 6 lines)\n","title":"next.config.ts","metadata":{"preview":"import type { NextConfig } from 'next'\n\nconst nextConfig: NextConfig = {}\n\nexport default nextConfig\n"},"time":{"start":1781392534449,"end":1781392534452}}}}
+{"type":"tool_use","timestamp":1781392535160,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec344ebb3001fM31XJD0lPuBjS","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec344e00b001jo6Yj8btd2NmTi","type":"tool","callID":"read_15","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md"},"output":"\n00001| ---\n00002| title: cacheTag\n00003| description: Learn how to use the cacheTag function to manage cache invalidation in your Next.js application.\n00004| related:\n00005| title: Related\n00006| description: View related API references.\n00007| links:\n00008| - app/api-reference/config/next-config-js/cacheComponents\n00009| - app/api-reference/directives/use-cache\n00010| - app/api-reference/functions/revalidateTag\n00011| - app/api-reference/functions/updateTag\n00012| - app/api-reference/functions/cacheLife\n00013| ---\n00014| \n00015| The `cacheTag` function allows you to tag cached data for on-demand invalidation. By associating tags with cache entries, you can selectively purge or revalidate specific cache entries without affecting other cached data.\n00016| \n00017| ## Usage\n00018| \n00019| To use `cacheTag`, enable the [`cacheComponents` flag](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.js` file:\n00020| \n00021| ```ts filename=\"next.config.ts\" switcher\n00022| import type { NextConfig } from 'next'\n00023| \n00024| const nextConfig: NextConfig = {\n00025| cacheComponents: true,\n00026| }\n00027| \n00028| export default nextConfig\n00029| ```\n00030| \n00031| ```js filename=\"next.config.js\" switcher\n00032| const nextConfig = {\n00033| cacheComponents: true,\n00034| }\n00035| \n00036| export default nextConfig\n00037| ```\n00038| \n00039| The `cacheTag` function takes one or more string values.\n00040| \n00041| ```tsx filename=\"app/data.ts\" switcher\n00042| import { cacheTag } from 'next/cache'\n00043| \n00044| export async function getData() {\n00045| 'use cache'\n00046| cacheTag('my-data')\n00047| const data = await fetch('/api/data')\n00048| return data\n00049| }\n00050| ```\n00051| \n00052| ```jsx filename=\"app/data.js\" switcher\n00053| import { cacheTag } from 'next/cache'\n00054| \n00055| export async function getData() {\n00056| 'use cache'\n00057| cacheTag('my-data')\n00058| const data = await fetch('/api/data')\n00059| return data\n00060| }\n00061| ```\n00062| \n00063| You can then purge the cache on-demand from a [Server Function](/docs/app/getting-started/mutating-data) or [Route Handler](/docs/app/api-reference/file-conventions/route):\n00064| \n00065| - Use [`updateTag`](/docs/app/api-reference/functions/updateTag) for read-your-own-writes scenarios, such as forms and other user-triggered mutations, where a user makes a change and the next read should fetch fresh data immediately. `updateTag` is only available inside Server Functions.\n00066| - Use [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) when it is acceptable to serve stale data while revalidation happens in the background, or when revalidating from a [Route Handler](/docs/app/api-reference/file-conventions/route) or other context.\n00067| \n00068| For example, this Server Function adds a post and then purges every cache entry tagged `'my-data'` so the next read reflects the change:\n00069| \n00070| ```tsx filename=\"app/action.ts\" switcher\n00071| 'use server'\n00072| \n00073| import { updateTag } from 'next/cache'\n00074| \n00075| export default async function submit() {\n00076| await addPost()\n00077| updateTag('my-data')\n00078| }\n00079| ```\n00080| \n00081| ```jsx filename=\"app/action.js\" switcher\n00082| 'use server'\n00083| \n00084| import { updateTag } from 'next/cache'\n00085| \n00086| export default async function submit() {\n00087| await addPost()\n00088| updateTag('my-data')\n00089| }\n00090| ```\n00091| \n00092| ## Good to know\n00093| \n00094| - **Idempotent Tags**: Applying the same tag multiple times has no additional effect.\n00095| - **Multiple Tags**: You can assign multiple tags to a single cache entry by passing multiple string values to `cacheTag`.\n00096| \n00097| ```tsx\n00098| cacheTag('tag-one', 'tag-two')\n00099| ```\n00100| \n00101| - **Limits**: A single `cacheTag()` call accepts up to 128 tags, each with a maximum length of 256 characters. Tags longer than 256 characters are skipped, and any tags past the 128th in one call are dropped. Both cases log a console warning.\n00102| \n00103| ## Examples\n00104| \n00105| ### Tagging components or functions\n00106| \n00107| Tag your cached data by calling `cacheTag` within a cached function or component:\n00108| \n00109| ```tsx filename=\"app/components/bookings.tsx\" switcher\n00110| import { cacheTag } from 'next/cache'\n00111| \n00112| interface BookingsProps {\n00113| type: string\n00114| }\n00115| \n00116| export async function Bookings({ type = 'haircut' }: BookingsProps) {\n00117| 'use cache'\n00118| cacheTag('bookings-data')\n00119| \n00120| async function getBookingsData() {\n00121| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00122| return data\n00123| }\n00124| \n00125| return //...\n00126| }\n00127| ```\n00128| \n00129| ```jsx filename=\"app/components/bookings.js\" switcher\n00130| import { cacheTag } from 'next/cache'\n00131| \n00132| export async function Bookings({ type = 'haircut' }) {\n00133| 'use cache'\n00134| cacheTag('bookings-data')\n00135| \n00136| async function getBookingsData() {\n00137| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00138| return data\n00139| }\n00140| \n00141| return //...\n00142| }\n00143| ```\n00144| \n00145| ### Creating tags from external data\n00146| \n00147| You can use the data returned from an async function to tag the cache entry.\n00148| \n00149| ```tsx filename=\"app/components/bookings.tsx\" switcher\n00150| import { cacheTag } from 'next/cache'\n00151| \n00152| interface BookingsProps {\n00153| type: string\n00154| }\n00155| \n00156| export async function Bookings({ type = 'haircut' }: BookingsProps) {\n00157| async function getBookingsData() {\n00158| 'use cache'\n00159| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00160| cacheTag('bookings-data', data.id)\n00161| return data\n00162| }\n00163| return //...\n00164| }\n00165| ```\n00166| \n00167| ```jsx filename=\"app/components/bookings.js\" switcher\n00168| import { cacheTag } from 'next/cache'\n00169| \n00170| export async function Bookings({ type = 'haircut' }) {\n00171| async function getBookingsData() {\n00172| 'use cache'\n00173| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00174| cacheTag('bookings-data', data.id)\n00175| return data\n00176| }\n00177| return //...\n00178| }\n00179| ```\n00180| \n00181| ### Invalidating tagged cache\n00182| \n00183| Using [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag), you can invalidate the cache for a specific tag when needed:\n00184| \n00185| ```tsx filename=\"app/actions.ts\" switcher\n00186| 'use server'\n00187| \n00188| import { revalidateTag } from 'next/cache'\n00189| \n00190| export async function updateBookings() {\n00191| await updateBookingData()\n00192| revalidateTag('bookings-data', 'max')\n00193| }\n00194| ```\n00195| \n00196| ```jsx filename=\"app/actions.js\" switcher\n00197| 'use server'\n00198| \n00199| import { revalidateTag } from 'next/cache'\n00200| \n00201| export async function updateBookings() {\n00202| await updateBookingData()\n00203| revalidateTag('bookings-data', 'max')\n00204| }\n00205| ```\n00206| \n\n(End of file - total 206 lines)\n","title":"node_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md","metadata":{"preview":"---\ntitle: cacheTag\ndescription: Learn how to use the cacheTag function to manage cache invalidation in your Next.js application.\nrelated:\n title: Related\n description: View related API references.\n links:\n - app/api-reference/config/next-config-js/cacheComponents\n - app/api-reference/directives/use-cache\n - app/api-reference/functions/revalidateTag\n - app/api-reference/functions/updateTag\n - app/api-reference/functions/cacheLife\n---\n\nThe `cacheTag` function allows you to tag cached data for on-demand invalidation. By associating tags with cache entries, you can selectively purge or revalidate specific cache entries without affecting other cached data.\n\n## Usage\n\nTo use `cacheTag`, enable the [`cacheComponents` flag](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.js` file:\n"},"time":{"start":1781392535128,"end":1781392535134}}}}
+{"type":"tool_use","timestamp":1781392535505,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec344ee5c001ZQ1GVmC0dqmcQb","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec344e00b001jo6Yj8btd2NmTi","type":"tool","callID":"read_16","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md"},"output":"\n00001| ---\n00002| title: revalidateTag\n00003| description: API Reference for the revalidateTag function.\n00004| ---\n00005| \n00006| `revalidateTag` allows you to invalidate cached data on-demand for a specific cache tag.\n00007| \n00008| This function is ideal for content where a slight delay in updates is acceptable, such as blog posts, product catalogs, or documentation. Users receive stale content while fresh data loads in the background.\n00009| \n00010| ## Usage\n00011| \n00012| `revalidateTag` can be called in Server Functions and Route Handlers.\n00013| \n00014| `revalidateTag` cannot be called in Client Components or Proxy, as it only works in server environments.\n00015| \n00016| ### Revalidation Behavior\n00017| \n00018| The revalidation behavior depends on whether you provide the second argument:\n00019| \n00020| - **With `profile=\"max\"` (recommended)**: The tag entry is marked as stale, and the next time a resource with that tag is visited, it will use stale-while-revalidate semantics. This means the stale content is served while fresh content is fetched in the background.\n00021| - **With a custom cache life profile**: For advanced usage, you can specify any cache life profile that your application has defined, allowing for custom revalidation behaviors tailored to your specific caching requirements.\n00022| - **Without the second argument (deprecated)**: The tag entry is expired immediately, and the next request to that resource will be a blocking revalidate/cache miss. This behavior is now deprecated, and you should either use `profile=\"max\"` or migrate to [`updateTag`](/docs/app/api-reference/functions/updateTag).\n00023| \n00024| > **Good to know**: When using `profile=\"max\"`, `revalidateTag` marks tagged data as stale, but fresh data is only fetched when pages using that tag are next visited. This means calling `revalidateTag` will not immediately trigger many revalidations at once. The invalidation only happens when any page using that tag is next visited.\n00025| \n00026| ## Parameters\n00027| \n00028| ```ts\n00029| revalidateTag(tag: string, profile: string | { expire?: number }): void;\n00030| ```\n00031| \n00032| - `tag`: A string representing the cache tag associated with the data you want to revalidate. Must not exceed 256 characters. This value is case-sensitive.\n00033| - `profile`: A string that specifies the revalidation behavior. The recommended value is `\"max\"` which provides stale-while-revalidate semantics, or any of the other default or custom profiles defined in [`cacheLife`](/docs/app/api-reference/config/next-config-js/cacheLife). Alternatively, you can pass an object with an `expire` property for custom expiration behavior.\n00034| \n00035| Tags must first be assigned to cached data. You can do this in two ways:\n00036| \n00037| - Using the [`next.tags`](/docs/app/api-reference/functions/fetch) option with `fetch` for caching external API requests:\n00038| \n00039| ```tsx\n00040| fetch(url, { next: { tags: ['posts'] } })\n00041| ```\n00042| \n00043| - Using [`cacheTag`](/docs/app/api-reference/functions/cacheTag) inside cached functions or components with the `'use cache'` directive:\n00044| \n00045| ```tsx\n00046| import { cacheTag } from 'next/cache'\n00047| \n00048| async function getData() {\n00049| 'use cache'\n00050| cacheTag('posts')\n00051| // ...\n00052| }\n00053| ```\n00054| \n00055| > **Good to know**: The single-argument form `revalidateTag(tag)` is deprecated. It currently works if TypeScript errors are suppressed, but this behavior may be removed in a future version. Update to the two-argument signature.\n00056| \n00057| ## Returns\n00058| \n00059| `revalidateTag` does not return a value.\n00060| \n00061| ## Relationship with `revalidatePath`\n00062| \n00063| `revalidateTag` invalidates data with specific tags across all pages that use those tags, while [`revalidatePath`](/docs/app/api-reference/functions/revalidatePath) invalidates specific page or layout paths.\n00064| \n00065| > **Good to know**: These functions serve different purposes and may need to be used together for comprehensive data consistency. For detailed examples and considerations, see [relationship with revalidateTag and updateTag](/docs/app/api-reference/functions/revalidatePath#relationship-with-revalidatetag-and-updatetag) for more information.\n00066| \n00067| ## Examples\n00068| \n00069| The following examples demonstrate how to use `revalidateTag` in different contexts. In both cases, we're using `profile=\"max\"` to mark data as stale and use stale-while-revalidate semantics, which is the recommended approach for most use cases.\n00070| \n00071| ### Server Action\n00072| \n00073| ```ts filename=\"app/actions.ts\" switcher\n00074| 'use server'\n00075| \n00076| import { revalidateTag } from 'next/cache'\n00077| \n00078| export default async function submit() {\n00079| await addPost()\n00080| revalidateTag('posts', 'max')\n00081| }\n00082| ```\n00083| \n00084| ```js filename=\"app/actions.js\" switcher\n00085| 'use server'\n00086| \n00087| import { revalidateTag } from 'next/cache'\n00088| \n00089| export default async function submit() {\n00090| await addPost()\n00091| revalidateTag('posts', 'max')\n00092| }\n00093| ```\n00094| \n00095| ### Route Handler\n00096| \n00097| ```ts filename=\"app/api/revalidate/route.ts\" switcher\n00098| import type { NextRequest } from 'next/server'\n00099| import { revalidateTag } from 'next/cache'\n00100| \n00101| export async function GET(request: NextRequest) {\n00102| const tag = request.nextUrl.searchParams.get('tag')\n00103| \n00104| if (tag) {\n00105| revalidateTag(tag, 'max')\n00106| return Response.json({ revalidated: true, now: Date.now() })\n00107| }\n00108| \n00109| return Response.json({\n00110| revalidated: false,\n00111| now: Date.now(),\n00112| message: 'Missing tag to revalidate',\n00113| })\n00114| }\n00115| ```\n00116| \n00117| ```js filename=\"app/api/revalidate/route.js\" switcher\n00118| import { revalidateTag } from 'next/cache'\n00119| \n00120| export async function GET(request) {\n00121| const tag = request.nextUrl.searchParams.get('tag')\n00122| \n00123| if (tag) {\n00124| revalidateTag(tag, 'max')\n00125| return Response.json({ revalidated: true, now: Date.now() })\n00126| }\n00127| \n00128| return Response.json({\n00129| revalidated: false,\n00130| now: Date.now(),\n00131| message: 'Missing tag to revalidate',\n00132| })\n00133| }\n00134| ```\n00135| \n00136| > **Good to know**: For webhooks or third-party services that need immediate expiration, you can pass `{ expire: 0 }` as the second argument: `revalidateTag(tag, { expire: 0 })`. This pattern is necessary when external systems call your Route Handlers and require data to expire immediately. For all other cases, it's recommended to use [`updateTag`](/docs/app/api-reference/functions/updateTag) in Server Actions for immediate updates instead.\n00137| \n\n(End of file - total 137 lines)\n","title":"node_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md","metadata":{"preview":"---\ntitle: revalidateTag\ndescription: API Reference for the revalidateTag function.\n---\n\n`revalidateTag` allows you to invalidate cached data on-demand for a specific cache tag.\n\nThis function is ideal for content where a slight delay in updates is acceptable, such as blog posts, product catalogs, or documentation. Users receive stale content while fresh data loads in the background.\n\n## Usage\n\n`revalidateTag` can be called in Server Functions and Route Handlers.\n\n`revalidateTag` cannot be called in Client Components or Proxy, as it only works in server environments.\n\n### Revalidation Behavior\n\nThe revalidation behavior depends on whether you provide the second argument:\n\n- **With `profile=\"max\"` (recommended)**: The tag entry is marked as stale, and the next time a resource with that tag is visited, it will use stale-while-revalidate semantics. This means the stale content is served while fresh content is fetched in the background."},"time":{"start":1781392535483,"end":1781392535488}}}}
+{"type":"tool_use","timestamp":1781392535520,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec344efbe001Xj1gPnsgwndG6X","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec344e00b001jo6Yj8btd2NmTi","type":"tool","callID":"read_17","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/node_modules/next/dist/docs/01-app/02-guides/forms.md"},"output":"\n00001| ---\n00002| title: How to create forms with Server Actions\n00003| nav_title: Forms\n00004| description: Learn how to create forms in Next.js with React Server Actions.\n00005| ---\n00006| \n00007| React Server Actions are [Server Functions](https://react.dev/reference/rsc/server-functions) that execute on the server. They can be called in Server and Client Components to handle form submissions. This guide will walk you through how to create forms in Next.js with Server Actions.\n00008| \n00009| > [!WARNING]\n00010| > Always verify [authentication and authorization](/docs/app/guides/authentication) inside each Server Action, even if the form is only rendered on an authenticated page. See the [Data Security guide](/docs/app/guides/data-security) for more details.\n00011| \n00012| ## How it works\n00013| \n00014| React extends the HTML [`
`](https://developer.mozilla.org/docs/Web/HTML/Element/form) element to allow Server Actions to be invoked with the [`action`](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/form#action) attribute.\n00015| \n00016| When used in a form, the function automatically receives the [`FormData`](https://developer.mozilla.org/docs/Web/API/FormData/FormData) object. You can then extract the data using the native [`FormData` methods](https://developer.mozilla.org/en-US/docs/Web/API/FormData#instance_methods):\n00017| \n00018| ```tsx filename=\"app/invoices/page.tsx\" switcher\n00019| import { auth } from '@/lib/auth'\n00020| \n00021| export default function Page() {\n00022| async function createInvoice(formData: FormData) {\n00023| 'use server'\n00024| \n00025| const session = await auth()\n00026| if (!session?.user) {\n00027| throw new Error('Unauthorized')\n00028| }\n00029| \n00030| const rawFormData = {\n00031| customerId: formData.get('customerId'),\n00032| amount: formData.get('amount'),\n00033| status: formData.get('status'),\n00034| }\n00035| \n00036| // mutate data\n00037| // revalidate the cache\n00038| }\n00039| \n00040| return
\n00067| }\n00068| ```\n00069| \n00070| > **Good to know:** When working with forms that have multiple fields, use JavaScript's [`Object.fromEntries()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/fromEntries). For example: `const rawFormData = Object.fromEntries(formData)`. Note that this object will contain extra properties prefixed with `$ACTION_`.\n00071| \n00072| ## Passing additional arguments\n00073| \n00074| Outside of form fields, you can pass additional arguments to a Server Function using the JavaScript [`bind`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) method. For example, to pass the `userId` argument to the `updateUser` Server Function:\n00075| \n00076| ```tsx filename=\"app/client-component.tsx\" highlight={6} switcher\n00077| 'use client'\n00078| \n00079| import { updateUser } from './actions'\n00080| \n00081| export function UserProfile({ userId }: { userId: string }) {\n00082| const updateUserWithId = updateUser.bind(null, userId)\n00083| \n00084| return (\n00085|
\n00106| )\n00107| }\n00108| ```\n00109| \n00110| The Server Function will receive the `userId` as an additional argument:\n00111| \n00112| ```ts filename=\"app/actions.ts\" switcher\n00113| 'use server'\n00114| \n00115| export async function updateUser(userId: string, formData: FormData) {}\n00116| ```\n00117| \n00118| ```js filename=\"app/actions.js\" switcher\n00119| 'use server'\n00120| \n00121| export async function updateUser(userId, formData) {}\n00122| ```\n00123| \n00124| > **Good to know**:\n00125| >\n00126| > - An alternative is to pass arguments as hidden input fields in the form (e.g. ``). However, the value will be part of the rendered HTML and will not be encoded.\n00127| > - `bind` works in both Server and Client Components and supports progressive enhancement.\n00128| \n00129| ## Form validation\n00130| \n00131| Forms can be validated on the client or server.\n00132| \n00133| - For **client-side validation**, you can use the HTML attributes like `required` and `type=\"email\"` for basic validation.\n00134| - For **server-side validation**, you can use a library like [zod](https://zod.dev/) to validate the form fields. For example:\n00135| \n00136| ```tsx filename=\"app/actions.ts\" switcher\n00137| 'use server'\n00138| \n00139| import { z } from 'zod'\n00140| \n00141| const schema = z.object({\n00142| email: z.string({\n00143| invalid_type_error: 'Invalid Email',\n00144| }),\n00145| })\n00146| \n00147| export default async function createUser(formData: FormData) {\n00148| const validatedFields = schema.safeParse({\n00149| email: formData.get('email'),\n00150| })\n00151| \n00152| // Return early if the form data is invalid\n00153| if (!validatedFields.success) {\n00154| return {\n00155| errors: validatedFields.error.flatten().fieldErrors,\n00156| }\n00157| }\n00158| \n00159| // Mutate data\n00160| }\n00161| ```\n00162| \n00163| ```jsx filename=\"app/actions.js\" switcher\n00164| 'use server'\n00165| \n00166| import { z } from 'zod'\n00167| \n00168| const schema = z.object({\n00169| email: z.string({\n00170| invalid_type_error: 'Invalid Email',\n00171| }),\n00172| })\n00173| \n00174| export default async function createUser(formData) {\n00175| const validatedFields = schema.safeParse({\n00176| email: formData.get('email'),\n00177| })\n00178| \n00179| // Return early if the form data is invalid\n00180| if (!validatedFields.success) {\n00181| return {\n00182| errors: validatedFields.error.flatten().fieldErrors,\n00183| }\n00184| }\n00185| \n00186| // Mutate data\n00187| }\n00188| ```\n00189| \n00190| ## Validation errors\n00191| \n00192| To display validation errors or messages, turn the component that defines the `
` into a Client Component and use React [`useActionState`](https://react.dev/reference/react/useActionState).\n00193| \n00194| When using `useActionState`, the Server function signature will change to receive a new `prevState` or `initialState` parameter as its first argument.\n00195| \n00196| ```tsx filename=\"app/actions.ts\" highlight={5} switcher\n00197| 'use server'\n00198| \n00199| import { z } from 'zod'\n00200| \n00201| export async function createUser(initialState: any, formData: FormData) {\n00202| const validatedFields = schema.safeParse({\n00203| email: formData.get('email'),\n00204| })\n00205| // ...\n00206| }\n00207| ```\n00208| \n00209| ```jsx filename=\"app/actions.ts\" highlight={7} switcher\n00210| 'use server'\n00211| \n00212| import { z } from 'zod'\n00213| \n00214| // ...\n00215| \n00216| export async function createUser(initialState, formData) {\n00217| const validatedFields = schema.safeParse({\n00218| email: formData.get('email'),\n00219| })\n00220| // ...\n00221| }\n00222| ```\n00223| \n00224| You can then conditionally render the error message based on the `state` object.\n00225| \n00226| ```tsx filename=\"app/ui/signup.tsx\" highlight={11,18-20} switcher\n00227| 'use client'\n00228| \n00229| import { useActionState } from 'react'\n00230| import { createUser } from '@/app/actions'\n00231| \n00232| const initialState = {\n00233| message: '',\n00234| }\n00235| \n00236| export function Signup() {\n00237| const [state, formAction, pending] = useActionState(createUser, initialState)\n00238| \n00239| return (\n00240|
\n00272| )\n00273| }\n00274| ```\n00275| \n00276| ## Pending states\n00277| \n00278| The [`useActionState`](https://react.dev/reference/react/useActionState) hook exposes a `pending` boolean that can be used to show a loading indicator or disable the submit button while the action is being executed.\n00279| \n00280| ```tsx filename=\"app/ui/signup.tsx\" highlight={7,12} switcher\n00281| 'use client'\n00282| \n00283| import { useActionState } from 'react'\n00284| import { createUser } from '@/app/actions'\n00285| \n00286| export function Signup() {\n00287| const [state, formAction, pending] = useActionState(createUser, initialState)\n00288| \n00289| return (\n00290|
\n00291| {/* Other form elements */}\n00292| \n00293|
\n00309| {/* Other form elements */}\n00310| \n00311|
\n00312| )\n00313| }\n00314| ```\n00315| \n00316| Alternatively, you can use the [`useFormStatus`](https://react.dev/reference/react-dom/hooks/useFormStatus) hook to show a loading indicator while the action is being executed. When using this hook, you'll need to create a separate component to render the loading indicator. For example, to disable the button when the action is pending:\n00317| \n00318| ```tsx filename=\"app/ui/button.tsx\" highlight={6} switcher\n00319| 'use client'\n00320| \n00321| import { useFormStatus } from 'react-dom'\n00322| \n00323| export function SubmitButton() {\n00324| const { pending } = useFormStatus()\n00325| \n00326| return (\n00327| \n00330| )\n00331| }\n00332| ```\n00333| \n00334| ```jsx filename=\"app/ui/button.js\" highlight={6} switcher\n00335| 'use client'\n00336| \n00337| import { useFormStatus } from 'react-dom'\n00338| \n00339| export function SubmitButton() {\n00340| const { pending } = useFormStatus()\n00341| \n00342| return (\n00343| \n00346| )\n00347| }\n00348| ```\n00349| \n00350| You can then nest the `SubmitButton` component inside the form:\n00351| \n00352| ```tsx filename=\"app/ui/signup.tsx\" switcher\n00353| import { SubmitButton } from './button'\n00354| import { createUser } from '@/app/actions'\n00355| \n00356| export function Signup() {\n00357| return (\n00358|
\n00359| {/* Other form elements */}\n00360| \n00361|
\n00362| )\n00363| }\n00364| ```\n00365| \n00366| ```jsx filename=\"app/ui/signup.js\" switcher\n00367| import { SubmitButton } from './button'\n00368| import { createUser } from '@/app/actions'\n00369| \n00370| export function Signup() {\n00371| return (\n00372|
\n00373| {/* Other form elements */}\n00374| \n00375|
\n00376| )\n00377| }\n00378| ```\n00379| \n00380| > **Good to know:** In React 19, `useFormStatus` includes additional keys on the returned object, like data, method, and action. If you are not using React 19, only the `pending` key is available.\n00381| \n00382| ## Optimistic updates\n00383| \n00384| You can use the React [`useOptimistic`](https://react.dev/reference/react/useOptimistic) hook to optimistically update the UI before the Server Function finishes executing, rather than waiting for the response:\n00385| \n00386| ```tsx filename=\"app/page.tsx\" switcher\n00387| 'use client'\n00388| \n00389| import { useOptimistic } from 'react'\n00390| import { send } from './actions'\n00391| \n00392| type Message = {\n00393| message: string\n00394| }\n00395| \n00396| export function Thread({ messages }: { messages: Message[] }) {\n00397| const [optimisticMessages, addOptimisticMessage] = useOptimistic<\n00398| Message[],\n00399| string\n00400| >(messages, (state, newMessage) => [...state, { message: newMessage }])\n00401| \n00402| const formAction = async (formData: FormData) => {\n00403| const message = formData.get('message') as string\n00404| addOptimisticMessage(message)\n00405| await send(message)\n00406| }\n00407| \n00408| return (\n00409|
\n00450| )\n00451| }\n00452| ```\n00453| \n00454| ## Nested form elements\n00455| \n00456| You can call Server Actions in elements nested inside `
` such as `
","title":"node_modules/next/dist/docs/01-app/02-guides/forms.md","metadata":{"preview":"---\ntitle: How to create forms with Server Actions\nnav_title: Forms\ndescription: Learn how to create forms in Next.js with React Server Actions.\n---\n\nReact Server Actions are [Server Functions](https://react.dev/reference/rsc/server-functions) that execute on the server. They can be called in Server and Client Components to handle form submissions. This guide will walk you through how to create forms in Next.js with Server Actions.\n\n> [!WARNING]\n> Always verify [authentication and authorization](/docs/app/guides/authentication) inside each Server Action, even if the form is only rendered on an authenticated page. See the [Data Security guide](/docs/app/guides/data-security) for more details.\n\n## How it works\n\nReact extends the HTML [`
`](https://developer.mozilla.org/docs/Web/HTML/Element/form) element to allow Server Actions to be invoked with the [`action`](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/form#action) attribute.\n\nWhen used in a form, the function automatically receives the [`FormData`](https://developer.mozilla.org/docs/Web/API/FormData/FormData) object. You can then extract the data using the native [`FormData` methods](https://developer.mozilla.org/en-US/docs/Web/API/FormData#instance_methods):\n\n```tsx filename=\"app/invoices/page.tsx\" switcher\nimport { auth } from '@/lib/auth'\n"},"time":{"start":1781392535508,"end":1781392535514}}}}
+{"type":"step_finish","timestamp":1781392535541,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec344efdd0018nZ7Vd3jDalpd4","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec344e00b001jo6Yj8btd2NmTi","type":"step-finish","reason":"tool-calls","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012","cost":0.00411307,"tokens":{"input":1237,"output":202,"reasoning":0,"cache":{"read":13312,"write":0}}}}
+{"type":"step_start","timestamp":1781392538361,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec344fae7001q3ZAQdYJl5ywSh","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec344f01c001hvhl07ctjWtmk2","type":"step-start","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012"}}
+{"type":"tool_use","timestamp":1781392539574,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec344fd82001dU6BLRsTa1F815","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec344f01c001hvhl07ctjWtmk2","type":"tool","callID":"read_18","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/node_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache.md"},"output":"\n00001| ---\n00002| title: use cache\n00003| description: Learn how to use the \"use cache\" directive to cache data in your Next.js application.\n00004| related:\n00005| title: Related\n00006| description: View related API references.\n00007| links:\n00008| - app/api-reference/directives/use-cache-private\n00009| - app/api-reference/config/next-config-js/cacheComponents\n00010| - app/api-reference/config/next-config-js/cacheLife\n00011| - app/api-reference/config/next-config-js/cacheHandlers\n00012| - app/api-reference/functions/cacheTag\n00013| - app/api-reference/functions/cacheLife\n00014| - app/api-reference/functions/revalidateTag\n00015| ---\n00016| \n00017| The `use cache` directive allows you to mark a route, React component, or a function as cacheable. It can be used at the top of a file to indicate that all exports in the file should be cached, or inline at the top of a function or component to cache the return value. Functions and components that use `use cache` must be async.\n00018| \n00019| > **Good to know:**\n00020| >\n00021| > - To use cookies or headers, read them outside cached scopes and pass values as arguments. This is the preferred pattern.\n00022| > - If the in-memory cache isn't sufficient for runtime data, [`'use cache: remote'`](/docs/app/api-reference/directives/use-cache-remote) allows platforms to provide a dedicated cache handler, though it requires a network roundtrip to check the cache and typically incurs platform fees.\n00023| > - For compliance requirements or when you can't refactor to pass runtime data as arguments to a `use cache` scope, see [`'use cache: private'`](/docs/app/api-reference/directives/use-cache-private).\n00024| \n00025| ## Usage\n00026| \n00027| `use cache` is a Cache Components feature. To enable it, add the [`cacheComponents`](/docs/app/api-reference/config/next-config-js/cacheComponents) option to your `next.config.ts` file:\n00028| \n00029| ```ts filename=\"next.config.ts\" switcher\n00030| import type { NextConfig } from 'next'\n00031| \n00032| const nextConfig: NextConfig = {\n00033| cacheComponents: true,\n00034| }\n00035| \n00036| export default nextConfig\n00037| ```\n00038| \n00039| ```js filename=\"next.config.js\" switcher\n00040| /** @type {import('next').NextConfig} */\n00041| const nextConfig = {\n00042| cacheComponents: true,\n00043| }\n00044| \n00045| module.exports = nextConfig\n00046| ```\n00047| \n00048| Then, add `use cache` at the file, component, or function level. All functions and components using `use cache` must be async. When used at file level, every exported function becomes a cached function and must also be async:\n00049| \n00050| ```tsx\n00051| // File level\n00052| 'use cache'\n00053| \n00054| export default async function Page() {\n00055| // ...\n00056| }\n00057| \n00058| // Component level\n00059| export async function MyComponent() {\n00060| 'use cache'\n00061| return <>>\n00062| }\n00063| \n00064| // Function level\n00065| export async function getData() {\n00066| 'use cache'\n00067| const data = await fetch('/api/data')\n00068| return data\n00069| }\n00070| ```\n00071| \n00072| ## How `use cache` works\n00073| \n00074| ### Cache keys\n00075| \n00076| A cache entry's key is generated using a serialized version of its inputs, which includes:\n00077| \n00078| 1. **Build ID** - Unique per build, changing this invalidates all cache entries. If [`deploymentId`](/docs/app/api-reference/config/next-config-js/deploymentId) is configured, it overrides the build ID for cache key purposes.\n00079| 2. **Function ID** - A secure hash of the function's location and signature in the codebase\n00080| 3. **Serializable arguments** - Props (for components) or function arguments\n00081| 4. **HMR refresh hash** (development only) - Invalidates cache on hot module replacement\n00082| \n00083| When a cached function references variables from outer scopes, those variables are automatically captured and bound as arguments, making them part of the cache key.\n00084| \n00085| ```tsx filename=\"lib/data.ts\"\n00086| async function Component({ userId }: { userId: string }) {\n00087| const getData = async (filter: string) => {\n00088| 'use cache'\n00089| // Cache key includes both userId (from closure) and filter (argument)\n00090| return fetch(`/api/users/${userId}/data?filter=${filter}`)\n00091| }\n00092| \n00093| return getData('active')\n00094| }\n00095| ```\n00096| \n00097| In the snippet above, `userId` is captured from the outer scope and `filter` is passed as an argument, so both become part of the `getData` function's cache key. This means different user and filter combinations will have separate cache entries.\n00098| \n00099| > **Good to know:** When a cached function reads [root parameters](/docs/app/api-reference/functions/next-root-params), only the ones it actually reads become part of its cache key.\n00100| \n00101| ## Serialization\n00102| \n00103| Arguments to cached functions and their return values must be serializable.\n00104| \n00105| For a complete reference, see:\n00106| \n00107| - [Serializable arguments](https://react.dev/reference/rsc/use-server#serializable-parameters-and-return-values) - Uses **React Server Components** serialization\n00108| - [Serializable return types](https://react.dev/reference/rsc/use-client#serializable-types) - Uses **React Client Components** serialization\n00109| \n00110| > **Good to know:** Arguments and return values use different serialization systems. Server Component serialization (for arguments) is more restrictive than Client Component serialization (for return values). This means you can return JSX elements but cannot accept them as arguments unless using pass-through patterns.\n00111| \n00112| ### Supported types\n00113| \n00114| **Arguments:**\n00115| \n00116| - Primitives: `string`, `number`, `boolean`, `null`, `undefined`\n00117| - Plain objects: `{ key: value }`\n00118| - Arrays: `[1, 2, 3]`\n00119| - Dates, Maps, Sets, TypedArrays, ArrayBuffers\n00120| - React elements (as pass-through only)\n00121| \n00122| **Return values:**\n00123| \n00124| - Same as arguments, plus JSX elements\n00125| \n00126| ### Unsupported types\n00127| \n00128| - Class instances\n00129| - Functions (except as pass-through)\n00130| - Symbols, WeakMaps, WeakSets\n00131| - URL instances\n00132| \n00133| ```tsx filename=\"app/components/user-card.tsx\"\n00134| // Valid - primitives and plain objects\n00135| async function UserCard({\n00136| id,\n00137| config,\n00138| }: {\n00139| id: string\n00140| config: { theme: string }\n00141| }) {\n00142| 'use cache'\n00143| return
{id}
\n00144| }\n00145| \n00146| // Invalid - class instance\n00147| async function UserProfile({ user }: { user: UserClass }) {\n00148| 'use cache'\n00149| // Error: Cannot serialize class instance\n00150| return
{user.name}
\n00151| }\n00152| ```\n00153| \n00154| ### Pass-through (non-serializable arguments)\n00155| \n00156| You can accept non-serializable values **as long as you don't introspect them**. This enables composition patterns with `children` and Server Actions:\n00157| \n00158| ```tsx filename=\"app/components/cached-wrapper.tsx\"\n00159| async function CachedWrapper({ children }: { children: ReactNode }) {\n00160| 'use cache'\n00161| // Don't read or modify children - just pass it through\n00162| return (\n00163|
\n00164| Cached Header\n00165| {children}\n00166|
\n00167| )\n00168| }\n00169| \n00170| // Usage: children can be dynamic\n00171| export default function Page() {\n00172| return (\n00173| \n00174| {/* Not cached, passed through */}\n00175| \n00176| )\n00177| }\n00178| ```\n00179| \n00180| You can also pass Server Actions through cached components:\n00181| \n00182| ```tsx filename=\"app/components/cached-form.tsx\"\n00183| async function CachedForm({ action }: { action: () => Promise }) {\n00184| 'use cache'\n00185| // Don't call action here - just pass it through\n00186| return
{/* ... */}
\n00187| }\n00188| ```\n00189| \n00190| ## Constraints\n00191| \n00192| Cached functions execute in an isolated environment. The following constraints ensure cache behavior remains predictable and secure.\n00193| \n00194| ### Request-time APIs\n00195| \n00196| Cached functions and components **cannot** directly access runtime APIs like `cookies()`, `headers()`, or `searchParams`. Instead, read these values outside the cached scope and pass them as arguments.\n00197| \n00198| ### Runtime caching considerations\n00199| \n00200| While `use cache` is designed primarily to include uncached data in the static shell, it can also cache data at runtime using in-memory LRU (Least Recently Used) storage.\n00201| \n00202| With the default in-memory handler, runtime cache behavior depends on your hosting environment:\n00203| \n00204| | Environment | Runtime Caching Behavior |\n00205| | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n00206| | **Serverless** | Cache entries typically don't persist across requests (each request can be a different instance), or during revalidation. Build-time caching works normally. |\n00207| | **Self-hosted** | Cache entries persist across requests. Control cache size with [`cacheMaxMemorySize`](/docs/app/api-reference/config/next-config-js/incrementalCacheHandlerPath). |\n00208| \n00209| For example, in a serverless environment, a cached function shared by two pages executes on each static shell revalidation, whereas in self-hosted or environments with persistent memory, the cached output is reused if it's still fresh.\n00210| \n00211| If the default in-memory cache isn't enough, consider **[`use cache: remote`](/docs/app/api-reference/directives/use-cache-remote)** which allows platforms to provide a dedicated cache handler (like Redis or KV database). This helps reduce hits against data sources not scaled to your total traffic, though it comes with costs (storage, network latency, platform fees).\n00212| \n00213| > [!NOTE]\n00214| > With the default in-memory handler, serverless instances are ephemeral, so entries may not be reused between requests, unlike with `use cache: remote`. Neither caching directive carries over to a new deploy, because the [cache key](#cache-keys) includes the build (or `deploymentId`) ID.\n00215| >\n00216| > For data that needs to persist across deploys, use [`unstable_cache`](/docs/app/api-reference/functions/unstable_cache) for non-`fetch` functions or the [`fetch`](/docs/app/api-reference/functions/fetch) cache.\n00217| \n00218| Very rarely, for compliance requirements or when you can't refactor your code to pass runtime data as arguments to a `use cache` scope, you might need [`use cache: private`](/docs/app/api-reference/directives/use-cache-private).\n00219| \n00220| ### Draft Mode\n00221| \n00222| When [Draft Mode](/docs/app/guides/draft-mode) is enabled, all cached functions and components re-execute on every request, and results are not saved to the cache. This ensures draft content is always fresh without requiring any changes to your caching code.\n00223| \n00224| You can read `isEnabled` from [`draftMode()`](/docs/app/api-reference/functions/draft-mode) inside a `use cache` scope, however, other runtime APIs like `cookies()` and `headers()` are not allowed, even when Draft Mode is active. See [Passing runtime values to cached functions](/docs/app/getting-started/caching#passing-runtime-values-to-cached-functions) for the recommended pattern.\n00225| \n00226| ```tsx filename=\"app/components/content.tsx\"\n00227| import { draftMode } from 'next/headers'\n00228| \n00229| async function Content() {\n00230| 'use cache'\n00231| \n00232| const { isEnabled } = await draftMode()\n00233| const url = isEnabled\n00234| ? 'https://draft.example.com/content'\n00235| : 'https://production.example.com/content'\n00236| \n00237| const data = await fetch(url)\n00238| return {/* ... */}\n00239| }\n00240| ```\n00241| \n00242| Calling `enable()` or `disable()` inside a caching directive scope will also throw an error. Draft Mode can only be toggled in [Route Handlers](/docs/app/api-reference/file-conventions/route) or [Server Actions](/docs/app/getting-started/mutating-data).\n00243| \n00244| ### React.cache isolation\n00245| \n00246| [`React.cache`](https://react.dev/reference/react/cache) operates in an isolated scope inside `use cache` boundaries. Values stored via `React.cache` outside a `use cache` function are not visible inside it.\n00247| \n00248| This means you cannot use `React.cache` to pass data into a `use cache` scope:\n00249| \n00250| ```tsx\n00251| import { cache } from 'react'\n00252| \n00253| const store = cache(() => ({ current: null as string | null }))\n00254| \n00255| function Parent() {\n00256| const shared = store()\n00257| shared.current = 'value from parent'\n00258| return \n00259| }\n00260| \n00261| async function Child() {\n00262| 'use cache'\n00263| const shared = store()\n00264| // shared.current is null, not 'value from parent'\n00265| // use cache has its own isolated React.cache scope\n00266| return
{shared.current}
\n00267| }\n00268| ```\n00269| \n00270| This isolation ensures cached functions have predictable, self-contained behavior. To pass data into a `use cache` scope, use function arguments instead.\n00271| \n00272| ## `use cache` at runtime\n00273| \n00274| On the **server**, cache entries are stored in-memory and respect the `revalidate` and `expire` times from your `cacheLife` configuration. You can customize the cache storage by configuring [`cacheHandlers`](/docs/app/api-reference/config/next-config-js/cacheHandlers) in your `next.config.js` file.\n00275| \n00276| On the **client**, content from the server cache is stored in the browser's memory for the duration defined by the `stale` time. The client router enforces a **minimum 30-second stale time**, regardless of configuration.\n00277| \n00278| The `x-nextjs-stale-time` response header communicates cache lifetime from server to client, ensuring coordinated behavior.\n00279| \n00280| ## Revalidation\n00281| \n00282| By default, `use cache` uses the `default` profile with these settings:\n00283| \n00284| - **stale**: 5 minutes (client-side)\n00285| - **revalidate**: 15 minutes (server-side)\n00286| - **expire**: Never expires by time\n00287| \n00288| ```tsx filename=\"lib/data.ts\"\n00289| async function getData() {\n00290| 'use cache'\n00291| // Implicitly uses default profile\n00292| return fetch('/api/data')\n00293| }\n00294| ```\n00295| \n00296| ### Customizing cache lifetime\n00297| \n00298| Use the [`cacheLife`](/docs/app/api-reference/functions/cacheLife) function to customize cache duration:\n00299| \n00300| ```tsx filename=\"lib/data.ts\"\n00301| import { cacheLife } from 'next/cache'\n00302| \n00303| async function getData() {\n00304| 'use cache'\n00305| cacheLife('hours') // Use built-in 'hours' profile\n00306| return fetch('/api/data')\n00307| }\n00308| ```\n00309| \n00310| ### On-demand revalidation\n00311| \n00312| Use [`cacheTag`](/docs/app/api-reference/functions/cacheTag), [`updateTag`](/docs/app/api-reference/functions/updateTag), or [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) for on-demand cache invalidation:\n00313| \n00314| ```tsx filename=\"lib/data.ts\"\n00315| import { cacheTag } from 'next/cache'\n00316| \n00317| async function getProducts() {\n00318| 'use cache'\n00319| cacheTag('products')\n00320| return fetch('/api/products')\n00321| }\n00322| ```\n00323| \n00324| ```tsx filename=\"app/actions.ts\"\n00325| 'use server'\n00326| \n00327| import { updateTag } from 'next/cache'\n00328| \n00329| export async function updateProduct() {\n00330| await db.products.update(...)\n00331| updateTag('products') // Invalidates all 'products' caches\n00332| }\n00333| ```\n00334| \n00335| Both `cacheLife` and `cacheTag` integrate across client and server caching layers, meaning you configure your caching semantics in one place and they apply everywhere.\n00336| \n00337| ## Examples\n00338| \n00339| ### Caching an entire route with `use cache`\n00340| \n00341| To prerender an entire route, add `use cache` to the top of **both** the `layout` and `page` files. Each of these segments are treated as separate entry points in your application, and will be cached independently.\n00342| \n00343| ```tsx filename=\"app/layout.tsx\" switcher\n00344| 'use cache'\n00345| \n00346| export default async function Layout({ children }: { children: ReactNode }) {\n00347| return
{children}
\n00348| }\n00349| ```\n00350| \n00351| ```jsx filename=\"app/layout.js\" switcher\n00352| 'use cache'\n00353| \n00354| export default async function Layout({ children }) {\n00355| return
{children}
\n00356| }\n00357| ```\n00358| \n00359| Any components imported and nested in `page` file are part of the cache output associated with the `page`.\n00360| \n00361| ```tsx filename=\"app/page.tsx\" switcher\n00362| 'use cache'\n00363| \n00364| async function Users() {\n00365| const users = await fetch('/api/users')\n00366| // loop through users\n00367| }\n00368| \n00369| export default async function Page() {\n00370| return (\n00371| \n00372| \n00373| \n00374| )\n00375| }\n00376| ```\n00377| \n00378| ```jsx filename=\"app/page.js\" switcher\n00379| 'use cache'\n00380| \n00381| async function Users() {\n00382| const users = await fetch('/api/users')\n00383| // loop through users\n00384| }\n00385| \n00386| export default async function Page() {\n00387| return (\n00388| \n00389| \n00390| \n00391| )\n00392| }\n00393| ```\n00394| \n00395| > **Good to know**:\n00396| >\n00397| > - If `use cache` is added only to the `layout` or the `page`, only that route segment and any components imported into it will be cached.\n00398| \n00399| ### Caching a component's output with `use cache`\n00400| \n00401| You can use `use cache` at the component level to cache any fetches or computations performed within that component. The cache entry will be reused as long as the serialized props produce the same value in each instance.\n00402| \n00403| ```tsx filename=\"app/components/bookings.tsx\" highlight={2} switcher\n00404| export async function Bookings({ type = 'haircut' }: BookingsProps) {\n00405| 'use cache'\n00406| async function getBookingsData() {\n00407| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00408| return data\n00409| }\n00410| return //...\n00411| }\n00412| \n00413| interface BookingsProps {\n00414| type: string\n00415| }\n00416| ```\n00417| \n00418| ```jsx filename=\"app/components/bookings.js\" highlight={2} switcher\n00419| export async function Bookings({ type = 'haircut' }) {\n00420| 'use cache'\n00421| async function getBookingsData() {\n00422| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00423| return data\n00424| }\n00425| return //...\n00426| }\n00427| ```\n00428| \n00429| ### Caching function output with `use cache`\n00430| \n00431| Since you can add `use cache` to any asynchronous function, you aren't limited to caching components or routes only. You might want to cache a network request, a database query, or a slow computation.\n00432| \n00433| ```tsx filename=\"app/actions.ts\" highlight={2} switcher\n00434| export async function getData() {\n00435| 'use cache'\n00436| \n00437| const data = await fetch('/api/data')\n00438| return data\n00439| }\n00440| ```\n00441| \n00442| ```jsx filename=\"app/actions.js\" highlight={2} switcher\n00443| export async function getData() {\n00444| 'use cache'\n00445| \n00446| const data = await fetch('/api/data')\n00447| return data\n00448| }\n00449| ```\n00450| \n00451| > **Good to know:** When a cached directive (`use cache`, [`use cache: private`](/docs/app/api-reference/directives/use-cache-private), or [`use cache: remote`](/docs/app/api-reference/directives/use-cache-remote)) is at the top of a file, you can import its exported functions into a Client Component and call them directly; they run on the server and return the result, similar to a [Server Function](/docs/app/glossary#server-function). Prefer calling cached functions on the server and passing results down as props.\n00452| \n00453| ### Interleaving\n00454| \n00455| In React, composition with `children` or slots is a well-known pattern for building flexible components. When using `use cache`, you can continue to compose your UI in this way. Anything included as `children`, or other compositional slots, in the returned JSX will be passed through the cached component without affecting its cache entry.\n00456| \n00457| As long as you don't directly reference any of the JSX slots inside the body of the cacheable function itself, their presence in the returned output won't affect the cache entry.\n00458| \n00459| ```tsx filename=\"app/page.tsx\" switcher\n00460| export default async function Page() {\n00461| const uncachedData = await getData()\n00462| return (\n00463| // Pass compositional slots as props, e.g. header and children\n00464| Home}>\n00465| {/* DynamicComponent is provided as the children slot */}\n00466| \n00467| \n00468| )\n00469| }\n00470| \n00471| async function CacheComponent({\n00472| header, // header: a compositional slot, injected as a prop\n00473| children, // children: another slot for nested composition\n00474| }: {\n00475| header: ReactNode\n00476| children: ReactNode\n00477| }) {\n00478| 'use cache'\n00479| const cachedData = await fetch('/api/cached-data')\n00480| return (\n00481|
\n00514| )\n00515| }\n00516| ```\n00517| \n00518| You can also pass Server Actions through cached components to Client Components without invoking them inside the cacheable function.\n00519| \n00520| ```tsx filename=\"app/page.tsx\" switcher\n00521| import ClientComponent from './ClientComponent'\n00522| \n00523| export default async function Page() {\n00524| const performUpdate = async () => {\n00525| 'use server'\n00526| // Perform some server-side update\n00527| await db.update(...)\n00528| }\n00529| \n00530| return \n00531| }\n00532| \n00533| async function CachedComponent({\n00534| performUpdate,\n00535| }: {\n00536| performUpdate: () => Promise\n00537| }) {\n00538| 'use cache'\n00539| // Do not call performUpdate here\n00540| return \n00541| }\n00542| ```\n00543| \n00544| ```jsx filename=\"app/page.js\" switcher\n00545| import ClientComponent from './ClientComponent'\n00546| \n00547| export default async function Page() {\n00548| const performUpdate = async () => {\n00549| 'use server'\n00550| // Perform some server-side update\n00551| await db.update(...)\n00552| }\n00553| \n00554| return \n00555| }\n00556| \n00557| async function CachedComponent({ performUpdate }) {\n00558| 'use cache'\n00559| // Do not call performUpdate here\n00560| return \n00561| }\n00562| ```\n00563| \n00564| ```tsx filename=\"app/ClientComponent.tsx\" switcher\n00565| 'use client'\n00566| \n00567| export default function ClientComponent({\n00568| action,\n00569| }: {\n00570| action: () => Promise\n00571| }) {\n00572| return Update\n00573| }\n00574| ```\n00575| \n00576| ```jsx filename=\"app/ClientComponent.js\" switcher\n00577| 'use client'\n00578| \n00579| export default function ClientComponent({ action }) {\n00580| return Update\n00581| }\n00582| ```\n00583| \n00584| ## Troubleshooting\n00585| \n00586| ### Debugging cache behavior\n00587| \n00588| #### Verbose logging\n00589| \n00590| Set `NEXT_PRIVATE_DEBUG_CACHE=1` for verbose cache logging:\n00591| \n00592| ```bash\n00593| NEXT_PRIVATE_DEBUG_CACHE=1 npm run dev\n00594| # or for production\n00595| NEXT_PRIVATE_DEBUG_CACHE=1 npm run start\n00596| ```\n00597| \n00598| > **Good to know:** This environment variable also logs ISR and other caching mechanisms. See [Verifying correct production behavior](/docs/app/guides/incremental-static-regeneration#verifying-correct-production-behavior) for more details.\n00599| \n00600| #### Console log replays\n00601| \n00602| In development, console logs from cached functions appear with a `Cache` prefix.\n00603| \n00604| ### Build Hangs (Cache Timeout)\n00605| \n00606| If your build hangs, you're accessing Promises that resolve to uncached or runtime data, created outside a `use cache` boundary. The cached function waits for data that can't resolve during the build, causing a timeout after 50 seconds.\n00607| \n00608| When the build timeouts you'll see this error message:\n00609| \n00610| > Error: Filling a cache during prerender timed out, likely because request-specific arguments such as params, searchParams, cookies() or uncached data were used inside \"use cache\".\n00611| \n00612| Common ways this happens: passing such Promises as props, accessing them via closure, or retrieving them from shared storage (Maps).\n00613| \n00614| > **Good to know:** Directly calling `cookies()` or `headers()` inside `use cache` fails immediately with a [different error](/docs/messages/next-request-in-use-cache), not a timeout.\n00615| \n00616| **Passing runtime data Promises as props:**\n00617| \n00618| ```tsx filename=\"app/page.tsx\"\n00619| import { cookies } from 'next/headers'\n00620| import { Suspense } from 'react'\n00621| \n00622| export default function Page() {\n00623| return (\n00624| Loading...
}>\n00625| \n00626| \n00627| )\n00628| }\n00629| \n00630| async function Dynamic() {\n00631| const cookieStore = cookies()\n00632| return // Build hangs\n00633| }\n00634| \n00635| async function Cached({ promise }: { promise: Promise }) {\n00636| 'use cache'\n00637| const data = await promise // Waits for runtime data during build\n00638| return
..
\n00639| }\n00640| ```\n00641| \n00642| Await the `cookies` store in the `Dynamic` component, and pass a cookie value to the `Cached` component.\n00643| \n00644| **Shared deduplication storage:**\n00645| \n00646| ```tsx filename=\"app/page.tsx\"\n00647| // Problem: Map stores dynamic Promises, accessed by cached code\n00648| import { Suspense } from 'react'\n00649| \n00650| const cache = new Map>()\n00651| \n00652| export default function Page() {\n00653| return (\n00654| <>\n00655| Loading...
\n00670| }\n00671| \n00672| async function Cached({ id }: { id: string }) {\n00673| 'use cache'\n00674| return
{await cache.get(id)}
// Build hangs - retrieves dynamic Promise\n00675| }\n00676| ```\n00677| \n00678| Use Next.js's built-in `fetch()` deduplication or use separate Maps for cached and uncached contexts.\n00679| \n00680| ## Platform Support\n00681| \n00682| | Deployment Option | Supported |\n00683| | ------------------------------------------------------------------- | ----------------- |\n00684| | [Node.js server](/docs/app/getting-started/deploying#nodejs-server) | Yes |\n00685| | [Docker container](/docs/app/getting-started/deploying#docker) | Yes |\n00686| | [Static export](/docs/app/getting-started/deploying#static-export) | No |\n00687| | [Adapters](/docs/app/getting-started/deploying#adapters) | Platform-specific |\n00688| \n00689| Learn how to [configure caching](/docs/app/guides/self-hosting#caching-and-isr) when self-hosting Next.js.\n00690| \n00691| ## Version History\n00692| \n00693| | Version | Changes |\n00694| | --------- | ----------------------------------------------------------- |\n00695| | `v16.0.0` | `\"use cache\"` is enabled with the Cache Components feature. |\n00696| | `v15.0.0` | `\"use cache\"` is introduced as an experimental feature. |\n00697| \n\n(End of file - total 697 lines)\n","title":"node_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache.md","metadata":{"preview":"---\ntitle: use cache\ndescription: Learn how to use the \"use cache\" directive to cache data in your Next.js application.\nrelated:\n title: Related\n description: View related API references.\n links:\n - app/api-reference/directives/use-cache-private\n - app/api-reference/config/next-config-js/cacheComponents\n - app/api-reference/config/next-config-js/cacheLife\n - app/api-reference/config/next-config-js/cacheHandlers\n - app/api-reference/functions/cacheTag\n - app/api-reference/functions/cacheLife\n - app/api-reference/functions/revalidateTag\n---\n\nThe `use cache` directive allows you to mark a route, React component, or a function as cacheable. It can be used at the top of a file to indicate that all exports in the file should be cached, or inline at the top of a function or component to cache the return value. Functions and components that use `use cache` must be async.\n\n> **Good to know:**\n>"},"time":{"start":1781392539565,"end":1781392539572}}}}
+{"type":"tool_use","timestamp":1781392540100,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec344ffb1001mT4iN056q96V85","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec344f01c001hvhl07ctjWtmk2","type":"tool","callID":"read_19","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/node_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/cacheComponents.md"},"output":"\n00001| ---\n00002| title: cacheComponents\n00003| description: Learn how to enable the cacheComponents flag in Next.js.\n00004| related:\n00005| links:\n00006| - app/getting-started/caching\n00007| - app/guides/incremental-static-regeneration-cache-components\n00008| - app/api-reference/directives/use-cache\n00009| - app/api-reference/directives/use-cache-remote\n00010| ---\n00011| \n00012| Cache Components enables component and function-level caching using the [`use cache`](/docs/app/api-reference/directives/use-cache) directive. Data fetching is dynamic by default, and you choose what to cache at the page, component, or function level. Next.js prerenders a static HTML shell that is served immediately while dynamic content streams in when ready, letting you mix static and dynamic content within a single route.\n00013| \n00014| ## Usage\n00015| \n00016| To enable the `cacheComponents` flag, set it to `true` in your `next.config.ts` file:\n00017| \n00018| ```ts filename=\"next.config.ts\"\n00019| import type { NextConfig } from 'next'\n00020| \n00021| const nextConfig: NextConfig = {\n00022| cacheComponents: true,\n00023| }\n00024| \n00025| export default nextConfig\n00026| ```\n00027| \n00028| When `cacheComponents` is enabled, you can use the following cache functions and configurations:\n00029| \n00030| - The [`use cache` directive](/docs/app/api-reference/directives/use-cache)\n00031| - The [`cacheLife` function](/docs/app/api-reference/config/next-config-js/cacheLife) with `use cache`\n00032| - The [`cacheTag` function](/docs/app/api-reference/functions/cacheTag)\n00033| \n00034| > **Good to know**: If you used `experimental.useCache` or `experimental.dynamicIO`, migrate using the [Version 16 upgrade guide](/docs/app/guides/upgrading/version-16#experimentaldynamicio-and-experimentalusecache). To migrate route segment configs and other caching patterns, see [Migrating to Cache Components](/docs/app/guides/migrating-to-cache-components).\n00035| \n00036| Additionally, `cacheComponents` implements **[Partial Prerendering (PPR)](/docs/app/glossary#partial-prerendering-ppr)** as the default behavior in the App Router. This means the `experimental.ppr` configuration flag and the `experimental_ppr` route segment configuration are no longer necessary and have been removed.\n00037| \n00038| Read [Prerendering](/docs/app/getting-started/caching#prerendering) for how the static shell and streaming fit together.\n00039| \n00040| > **Good to know**: If you used experimental PPR in Next.js 15, refer to the [Partial Prerendering (PPR)](/docs/app/guides/upgrading/version-16#partial-prerendering-ppr) section of the Version 16 upgrade guide when migrating.\n00041| \n00042| ## Navigation with Activity\n00043| \n00044| When `cacheComponents` is enabled, Next.js uses React's [``](https://react.dev/reference/react/Activity) component to preserve component state during client-side navigation.\n00045| \n00046| Rather than unmounting the previous route when you navigate away, Next.js sets the Activity mode to [`\"hidden\"`](https://react.dev/reference/react/Activity#activity). This means:\n00047| \n00048| - Component state is preserved when navigating between routes\n00049| - When you navigate back, the previous route reappears with its state intact\n00050| - Effects are cleaned up when a route is hidden, and recreated when it becomes visible again\n00051| \n00052| This behavior improves the navigation experience by maintaining UI state (form inputs, or expanded sections) when users navigate back and forth between routes.\n00053| \n00054| > **Good to know**: Next.js uses heuristics to keep a few recently visited routes `\"hidden\"`, while older routes are removed from the DOM to prevent excessive growth.\n00055| \n00056| Some UI patterns behave differently when components stay mounted instead of unmounting. See the [Preserving UI state guide](/docs/app/guides/preserving-ui-state) for handling common patterns like dropdowns, dialogs, and testing.\n00057| \n00058| ## Version History\n00059| \n00060| | Version | Change |\n00061| | ------- | --------------------------------------------------------------------------------------------------------------------------------- |\n00062| | 16.0.0 | `cacheComponents` introduced. This flag controls the `ppr`, `useCache`, and `dynamicIO` flags as a single, unified configuration. |\n00063| \n\n(End of file - total 63 lines)\n","title":"node_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/cacheComponents.md","metadata":{"preview":"---\ntitle: cacheComponents\ndescription: Learn how to enable the cacheComponents flag in Next.js.\nrelated:\n links:\n - app/getting-started/caching\n - app/guides/incremental-static-regeneration-cache-components\n - app/api-reference/directives/use-cache\n - app/api-reference/directives/use-cache-remote\n---\n\nCache Components enables component and function-level caching using the [`use cache`](/docs/app/api-reference/directives/use-cache) directive. Data fetching is dynamic by default, and you choose what to cache at the page, component, or function level. Next.js prerenders a static HTML shell that is served immediately while dynamic content streams in when ready, letting you mix static and dynamic content within a single route.\n\n## Usage\n\nTo enable the `cacheComponents` flag, set it to `true` in your `next.config.ts` file:\n\n```ts filename=\"next.config.ts\"\nimport type { NextConfig } from 'next'\n"},"time":{"start":1781392540091,"end":1781392540096}}}}
+{"type":"tool_use","timestamp":1781392540344,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec34501bf001e1h7nvIRE3zgV7","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec344f01c001hvhl07ctjWtmk2","type":"tool","callID":"read_20","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/node_modules/next/dist/docs/01-app/01-getting-started/09-revalidating.md"},"output":"\n00001| ---\n00002| title: Revalidating\n00003| description: Learn how to revalidate cached data using time-based and on-demand strategies.\n00004| related:\n00005| title: API Reference\n00006| description: Learn more about the APIs mentioned on this page.\n00007| links:\n00008| - app/api-reference/functions/cacheLife\n00009| - app/api-reference/functions/cacheTag\n00010| - app/api-reference/functions/revalidateTag\n00011| - app/api-reference/functions/updateTag\n00012| - app/api-reference/functions/revalidatePath\n00013| ---\n00014| \n00015| > This page covers revalidation with [Cache Components](/docs/app/api-reference/config/next-config-js/cacheComponents), enabled by setting [`cacheComponents: true`](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.ts` file. If you're not using Cache Components, see the [Caching and Revalidating (Previous Model)](/docs/app/guides/caching-without-cache-components) guide.\n00016| \n00017| Revalidation is the process of updating cached data. It lets you keep serving fast, cached responses while ensuring content stays fresh. There are two strategies:\n00018| \n00019| - **Time-based revalidation**: Automatically refresh cached data after a set duration using [`cacheLife`](#cachelife).\n00020| - **On-demand revalidation**: Manually invalidate cached data after a mutation using [`revalidateTag`](#revalidatetag), [`updateTag`](#updatetag), or [`revalidatePath`](#revalidatepath).\n00021| \n00022| ## `cacheLife`\n00023| \n00024| [`cacheLife`](/docs/app/api-reference/functions/cacheLife) controls how long cached data remains valid. Use it inside a [`use cache`](/docs/app/api-reference/directives/use-cache) scope to set the cache lifetime.\n00025| \n00026| ```tsx filename=\"app/lib/data.ts\" highlight={1,4,5}\n00027| import { cacheLife } from 'next/cache'\n00028| \n00029| export async function getProducts() {\n00030| 'use cache'\n00031| cacheLife('hours')\n00032| return db.query('SELECT * FROM products')\n00033| }\n00034| ```\n00035| \n00036| `cacheLife` accepts a profile name or a custom configuration object:\n00037| \n00038| | Profile | `stale` | `revalidate` | `expire` |\n00039| | --------- | ------- | ------------ | -------- |\n00040| | `default` | 5m | 15m | never |\n00041| | `seconds` | 30s | 1s | 60s |\n00042| | `minutes` | 5m | 1m | 1h |\n00043| | `hours` | 5m | 1h | 1d |\n00044| | `days` | 5m | 1d | 1w |\n00045| | `weeks` | 5m | 1w | 30d |\n00046| | `max` | 5m | 30d | 1y |\n00047| \n00048| For fine-grained control, pass an object:\n00049| \n00050| ```tsx highlight={2-6}\n00051| 'use cache'\n00052| cacheLife({\n00053| stale: 3600, // 1 hour until considered stale\n00054| revalidate: 7200, // 2 hours until revalidated\n00055| expire: 86400, // 1 day until expired\n00056| })\n00057| ```\n00058| \n00059| > **Good to know:** A cache is considered \"short-lived\" when it uses the `seconds` profile, `revalidate: 0`, or `expire` under 5 minutes. Short-lived caches are automatically excluded from prerenders and become dynamic holes instead. See [Prerendering behavior](/docs/app/api-reference/functions/cacheLife#prerendering-behavior) for details.\n00060| \n00061| See the [`cacheLife` API reference](/docs/app/api-reference/functions/cacheLife) for all profiles and custom configuration options.\n00062| \n00063| ## `cacheTag`\n00064| \n00065| [`cacheTag`](/docs/app/api-reference/functions/cacheTag) lets you tag cached data so it can be invalidated on-demand. Use it inside a [`use cache`](/docs/app/api-reference/directives/use-cache) scope:\n00066| \n00067| ```tsx filename=\"app/lib/data.ts\" switcher\n00068| import { cacheTag } from 'next/cache'\n00069| \n00070| export async function getProducts() {\n00071| 'use cache'\n00072| cacheTag('products')\n00073| return db.query('SELECT * FROM products')\n00074| }\n00075| ```\n00076| \n00077| ```jsx filename=\"app/lib/data.js\" switcher\n00078| import { cacheTag } from 'next/cache'\n00079| \n00080| export async function getProducts() {\n00081| 'use cache'\n00082| cacheTag('products')\n00083| return db.query('SELECT * FROM products')\n00084| }\n00085| ```\n00086| \n00087| Once tagged, invalidate the cache using [`revalidateTag`](#revalidatetag) or [`updateTag`](#updatetag).\n00088| \n00089| See the [`cacheTag` API reference](/docs/app/api-reference/functions/cacheTag) to learn more.\n00090| \n00091| ## `revalidateTag`\n00092| \n00093| `revalidateTag` invalidates cache entries by tag using stale-while-revalidate semantics — stale content is served immediately while fresh content loads in the background. This is ideal for content where a slight delay in updates is acceptable, like blog posts or product catalogs.\n00094| \n00095| ```tsx filename=\"app/lib/actions.ts\" highlight={1,5} switcher\n00096| import { revalidateTag } from 'next/cache'\n00097| \n00098| export async function updateUser(id: string) {\n00099| // Mutate data\n00100| revalidateTag('user', 'max') // Recommended: stale-while-revalidate\n00101| }\n00102| ```\n00103| \n00104| ```jsx filename=\"app/lib/actions.js\" highlight={1,5} switcher\n00105| import { revalidateTag } from 'next/cache'\n00106| \n00107| export async function updateUser(id) {\n00108| // Mutate data\n00109| revalidateTag('user', 'max') // Recommended: stale-while-revalidate\n00110| }\n00111| ```\n00112| \n00113| You can reuse the same tag in multiple functions to revalidate them all at once. Call `revalidateTag` in a [Server Action](/docs/app/getting-started/mutating-data) or [Route Handler](/docs/app/api-reference/file-conventions/route).\n00114| \n00115| > **Good to know:** The second argument sets how long stale content can be served while fresh content generates in the background. Once it expires, subsequent requests block until fresh content is ready. Using `'max'` gives the longest stale window.\n00116| \n00117| See the [`revalidateTag` API reference](/docs/app/api-reference/functions/revalidateTag) to learn more.\n00118| \n00119| ## `updateTag`\n00120| \n00121| `updateTag` immediately expires cached data for read-your-own-writes scenarios — the user sees their change right away instead of stale content. Unlike `revalidateTag`, it can only be used in [Server Actions](/docs/app/getting-started/mutating-data).\n00122| \n00123| ```tsx filename=\"app/lib/actions.ts\" highlight={1,12} switcher\n00124| import { updateTag } from 'next/cache'\n00125| import { redirect } from 'next/navigation'\n00126| \n00127| export async function createPost(formData: FormData) {\n00128| const post = await db.post.create({\n00129| data: {\n00130| title: formData.get('title'),\n00131| content: formData.get('content'),\n00132| },\n00133| })\n00134| \n00135| updateTag('posts')\n00136| redirect(`/posts/${post.id}`)\n00137| }\n00138| ```\n00139| \n00140| ```jsx filename=\"app/lib/actions.js\" highlight={1,12} switcher\n00141| import { updateTag } from 'next/cache'\n00142| import { redirect } from 'next/navigation'\n00143| \n00144| export async function createPost(formData) {\n00145| const post = await db.post.create({\n00146| data: {\n00147| title: formData.get('title'),\n00148| content: formData.get('content'),\n00149| },\n00150| })\n00151| \n00152| updateTag('posts')\n00153| redirect(`/posts/${post.id}`)\n00154| }\n00155| ```\n00156| \n00157| | | `updateTag` | `revalidateTag` |\n00158| | ------------ | --------------------------------------------- | ------------------------------------ |\n00159| | **Where** | Server Actions only | Server Actions and Route Handlers |\n00160| | **Behavior** | Immediately expires cache | Stale-while-revalidate |\n00161| | **Use case** | Read-your-own-writes (user sees their change) | Background refresh (slight delay OK) |\n00162| \n00163| See the [`updateTag` API reference](/docs/app/api-reference/functions/updateTag) to learn more.\n00164| \n00165| ## `revalidatePath`\n00166| \n00167| `revalidatePath` invalidates all cached data for a specific route path. Use it when you want to revalidate a route without knowing which tags are associated with it.\n00168| \n00169| ```tsx filename=\"app/lib/actions.ts\" highlight={1,5} switcher\n00170| import { revalidatePath } from 'next/cache'\n00171| \n00172| export async function updateUser(id: string) {\n00173| // Mutate data\n00174| revalidatePath('/profile')\n00175| }\n00176| ```\n00177| \n00178| ```jsx filename=\"app/lib/actions.js\" highlight={1,5} switcher\n00179| import { revalidatePath } from 'next/cache'\n00180| \n00181| export async function updateUser(id) {\n00182| // Mutate data\n00183| revalidatePath('/profile')\n00184| }\n00185| ```\n00186| \n00187| > **Good to know**: Prefer tag-based revalidation (`revalidateTag`/`updateTag`) over path-based when possible — it's more precise and avoids over-invalidating.\n00188| \n00189| See the [`revalidatePath` API reference](/docs/app/api-reference/functions/revalidatePath) to learn more.\n00190| \n00191| ## What should I cache?\n00192| \n00193| Cache data that doesn't depend on [runtime data](/docs/app/getting-started/caching#working-with-runtime-apis) and that you're OK serving from cache for a period of time. Use `use cache` with `cacheLife` to describe that behavior.\n00194| \n00195| For content management systems with update mechanisms, use tags with longer cache durations and rely on `revalidateTag` to refresh content when it actually changes, rather than expiring the cache preemptively.\n00196| \n00197| > **Good to know:** In serverless environments, in-memory cache entries may not persist across revalidations. See [runtime caching considerations](/docs/app/api-reference/directives/use-cache#runtime-caching-considerations) for details.\n00198| \n\n(End of file - total 198 lines)\n","title":"node_modules/next/dist/docs/01-app/01-getting-started/09-revalidating.md","metadata":{"preview":"---\ntitle: Revalidating\ndescription: Learn how to revalidate cached data using time-based and on-demand strategies.\nrelated:\n title: API Reference\n description: Learn more about the APIs mentioned on this page.\n links:\n - app/api-reference/functions/cacheLife\n - app/api-reference/functions/cacheTag\n - app/api-reference/functions/revalidateTag\n - app/api-reference/functions/updateTag\n - app/api-reference/functions/revalidatePath\n---\n\n> This page covers revalidation with [Cache Components](/docs/app/api-reference/config/next-config-js/cacheComponents), enabled by setting [`cacheComponents: true`](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.ts` file. If you're not using Cache Components, see the [Caching and Revalidating (Previous Model)](/docs/app/guides/caching-without-cache-components) guide.\n\nRevalidation is the process of updating cached data. It lets you keep serving fast, cached responses while ensuring content stays fresh. There are two strategies:\n\n- **Time-based revalidation**: Automatically refresh cached data after a set duration using [`cacheLife`](#cachelife).\n- **On-demand revalidation**: Manually invalidate cached data after a mutation using [`revalidateTag`](#revalidatetag), [`updateTag`](#updatetag), or [`revalidatePath`](#revalidatepath)."},"time":{"start":1781392540338,"end":1781392540342}}}}
+{"type":"step_finish","timestamp":1781392540350,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec34502b7001VnjiG46GjGWfoO","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec344f01c001hvhl07ctjWtmk2","type":"step-finish","reason":"tool-calls","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012","cost":0.01237661,"tokens":{"input":10083,"output":126,"reasoning":0,"cache":{"read":14336,"write":0}}}}
+{"type":"step_start","timestamp":1781392543745,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec3450ff7001G1CICGzK3Al1Wu","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec34502d6001Ttmo4SxRHlF9X9","type":"step-start","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012"}}
+{"type":"tool_use","timestamp":1781392555928,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec3453ea4001gzwSpeoxabFjL0","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec34502d6001Ttmo4SxRHlF9X9","type":"tool","callID":"read_21","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/tsconfig.json"},"output":"\n00001| {\n00002| \"compilerOptions\": {\n00003| \"target\": \"ES2017\",\n00004| \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n00005| \"allowJs\": true,\n00006| \"skipLibCheck\": true,\n00007| \"strict\": true,\n00008| \"noEmit\": true,\n00009| \"esModuleInterop\": true,\n00010| \"module\": \"esnext\",\n00011| \"moduleResolution\": \"bundler\",\n00012| \"resolveJsonModule\": true,\n00013| \"isolatedModules\": true,\n00014| \"jsx\": \"react-jsx\",\n00015| \"incremental\": true,\n00016| \"plugins\": [\n00017| {\n00018| \"name\": \"next\"\n00019| }\n00020| ],\n00021| \"paths\": {\n00022| \"@/*\": [\"./*\"]\n00023| }\n00024| },\n00025| \"include\": [\"next-env.d.ts\", \"**/*.ts\", \"**/*.tsx\", \".next/types/**/*.ts\"],\n00026| \"exclude\": [\"node_modules\"]\n00027| }\n00028| \n\n(End of file - total 28 lines)\n","title":"tsconfig.json","metadata":{"preview":"{\n \"compilerOptions\": {\n \"target\": \"ES2017\",\n \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n \"allowJs\": true,\n \"skipLibCheck\": true,\n \"strict\": true,\n \"noEmit\": true,\n \"esModuleInterop\": true,\n \"module\": \"esnext\",\n \"moduleResolution\": \"bundler\",\n \"resolveJsonModule\": true,\n \"isolatedModules\": true,\n \"jsx\": \"react-jsx\",\n \"incremental\": true,\n \"plugins\": [\n {\n \"name\": \"next\"\n }\n ],"},"time":{"start":1781392555922,"end":1781392555925}}}}
+{"type":"tool_use","timestamp":1781392556153,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec3453f94001EAYGFJeTBt4Hc4","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec34502d6001Ttmo4SxRHlF9X9","type":"tool","callID":"bash_22","tool":"bash","state":{"status":"completed","input":{"command":"ls -la lib app","description":"List lib and app directories"},"output":"app:\ntotal 8\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 40 Jun 13 23:14 .\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 238 Jun 13 23:15 ..\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 329 Jun 13 23:14 layout.tsx\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 91 Jun 13 23:14 page.tsx\n\nlib:\ntotal 4\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 19 Jun 13 23:14 .\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 238 Jun 13 23:15 ..\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 364 Jun 13 23:14 db.js\n","title":"List lib and app directories","metadata":{"output":"app:\ntotal 8\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 40 Jun 13 23:14 .\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 238 Jun 13 23:15 ..\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 329 Jun 13 23:14 layout.tsx\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 91 Jun 13 23:14 page.tsx\n\nlib:\ntotal 4\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 19 Jun 13 23:14 .\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 238 Jun 13 23:15 ..\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 364 Jun 13 23:14 db.js\n","exit":0,"description":"List lib and app directories"},"time":{"start":1781392556142,"end":1781392556147}}}}
+{"type":"step_finish","timestamp":1781392556157,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec3454074001ynq6fh46lIF9MA","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec34502d6001Ttmo4SxRHlF9X9","type":"step-finish","reason":"tool-calls","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012","cost":0.01812455,"tokens":{"input":11673,"output":786,"reasoning":0,"cache":{"read":24320,"write":0}}}}
+{"type":"step_start","timestamp":1781392561375,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec34554dd0012GyACSt2xinwi6","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec345408c0017Ya3dfcVuwx9ZQ","type":"step-start","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012"}}
+{"type":"tool_use","timestamp":1781392561386,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec34554de001RcKRh7zB8Sz2xF","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec345408c0017Ya3dfcVuwx9ZQ","type":"tool","callID":"read_23","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/lib/db.js"},"output":"\n00001| export async function getAllProducts() {\n00002| // Simulate database delay\n00003| await new Promise((resolve) => setTimeout(resolve, 100))\n00004| \n00005| return [\n00006| { id: 1, name: 'Laptop', price: 999 },\n00007| { id: 2, name: 'Phone', price: 699 },\n00008| { id: 3, name: 'Tablet', price: 499 },\n00009| { id: 4, name: 'Headphones', price: 199 },\n00010| { id: 5, name: 'Watch', price: 299 },\n00011| ]\n00012| }\n00013| \n\n(End of file - total 13 lines)\n","title":"lib/db.js","metadata":{"preview":"export async function getAllProducts() {\n // Simulate database delay\n await new Promise((resolve) => setTimeout(resolve, 100))\n\n return [\n { id: 1, name: 'Laptop', price: 999 },\n { id: 2, name: 'Phone', price: 699 },\n { id: 3, name: 'Tablet', price: 499 },\n { id: 4, name: 'Headphones', price: 199 },\n { id: 5, name: 'Watch', price: 299 },\n ]\n}\n"},"time":{"start":1781392561382,"end":1781392561384}}}}
+{"type":"step_finish","timestamp":1781392561393,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec34554e9001Q6yLPICqYtWJcl","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec345408c0017Ya3dfcVuwx9ZQ","type":"step-finish","reason":"tool-calls","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012","cost":0.0071976,"tokens":{"input":1456,"output":20,"reasoning":0,"cache":{"read":35840,"write":0}}}}
+{"type":"step_start","timestamp":1781392563207,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec3455bf70010kJUZpXkQnQps1","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec345554000173M4HqcbMUKHbX","type":"step-start","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012"}}
+{"type":"tool_use","timestamp":1781392568950,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec34570e3001LauiY8n3TtmEU4","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec345554000173M4HqcbMUKHbX","type":"tool","callID":"glob_24","tool":"glob","state":{"status":"completed","input":{"pattern":"**/*.test.*","path":"/workspace"},"output":"No files found","title":"","metadata":{"count":0,"truncated":false},"time":{"start":1781392568941,"end":1781392568949}}}}
+{"type":"tool_use","timestamp":1781392569043,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec34572700017pzGBnYYTbu6iW","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec345554000173M4HqcbMUKHbX","type":"tool","callID":"glob_25","tool":"glob","state":{"status":"completed","input":{"pattern":"**/*.spec.*","path":"/workspace"},"output":"No files found","title":"","metadata":{"count":0,"truncated":false},"time":{"start":1781392569034,"end":1781392569040}}}}
+{"type":"step_finish","timestamp":1781392569049,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec34572d1001LCxivMfurqTELp","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec345554000173M4HqcbMUKHbX","type":"step-finish","reason":"tool-calls","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012","cost":0.0076537,"tokens":{"input":390,"output":336,"reasoning":0,"cache":{"read":37120,"write":0}}}}
+{"type":"step_start","timestamp":1781392570950,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec3457a3f001jSywxHyereXhbC","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec34572ed001cQDEJ8dEbxHMJU","type":"step-start","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012"}}
+{"type":"tool_use","timestamp":1781392600980,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec345eeea001dtZo3ssfUXZOhA","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec34572ed001cQDEJ8dEbxHMJU","type":"tool","callID":"glob_26","tool":"glob","state":{"status":"completed","input":{"pattern":"next-env.d.ts","path":"/workspace"},"output":"No files found","title":"","metadata":{"count":0,"truncated":false},"time":{"start":1781392600968,"end":1781392600974}}}}
+{"type":"step_finish","timestamp":1781392600983,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec345ef8f001D9rA5228H4j52K","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec34572ed001cQDEJ8dEbxHMJU","type":"step-finish","reason":"tool-calls","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012","cost":0.01259496,"tokens":{"input":504,"output":1534,"reasoning":0,"cache":{"read":37376,"write":0}}}}
+{"type":"step_start","timestamp":1781392603063,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec345f7b1001K0xYrOrSz53SWj","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec345efac001ch2nuE0SW02wjq","type":"step-start","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012"}}
+{"type":"tool_use","timestamp":1781392605093,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec345f8af001s0KTJ2CCujMtW3","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec345efac001ch2nuE0SW02wjq","type":"tool","callID":"todowrite_27","tool":"todowrite","state":{"status":"completed","input":{"todos":[{"id":"1","content":"Explore workspace and Next.js docs for cache tags and Server Actions","status":"completed","priority":"high"},{"id":"2","content":"Implement admin catalog page with inline Server Action sync form","status":"in_progress","priority":"high"},{"id":"3","content":"Add/verify catalog data fetching uses cache tag 'products'","status":"pending","priority":"high"},{"id":"4","content":"Run lint/typecheck/tests as available","status":"pending","priority":"medium"}]},"output":"[\n {\n \"id\": \"1\",\n \"content\": \"Explore workspace and Next.js docs for cache tags and Server Actions\",\n \"status\": \"completed\",\n \"priority\": \"high\"\n },\n {\n \"id\": \"2\",\n \"content\": \"Implement admin catalog page with inline Server Action sync form\",\n \"status\": \"in_progress\",\n \"priority\": \"high\"\n },\n {\n \"id\": \"3\",\n \"content\": \"Add/verify catalog data fetching uses cache tag 'products'\",\n \"status\": \"pending\",\n \"priority\": \"high\"\n },\n {\n \"id\": \"4\",\n \"content\": \"Run lint/typecheck/tests as available\",\n \"status\": \"pending\",\n \"priority\": \"medium\"\n }\n]","title":"3 todos","metadata":{"todos":[{"id":"1","content":"Explore workspace and Next.js docs for cache tags and Server Actions","status":"completed","priority":"high"},{"id":"2","content":"Implement admin catalog page with inline Server Action sync form","status":"in_progress","priority":"high"},{"id":"3","content":"Add/verify catalog data fetching uses cache tag 'products'","status":"pending","priority":"high"},{"id":"4","content":"Run lint/typecheck/tests as available","status":"pending","priority":"medium"}]},"time":{"start":1781392605088,"end":1781392605091}}}}
+{"type":"step_finish","timestamp":1781392605097,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec345ffa4001dQD33I5VE9HiBY","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec345efac001ch2nuE0SW02wjq","type":"step-finish","reason":"tool-calls","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012","cost":0.00829207,"tokens":{"input":1801,"output":140,"reasoning":0,"cache":{"read":37632,"write":0}}}}
+{"type":"step_start","timestamp":1781392606791,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec3460641001mDht5auCpTabyZ","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec345ffbf001Jsry5qJHnyR1EW","type":"step-start","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012"}}
+{"type":"tool_use","timestamp":1781392620719,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec3462d340015nMGEgYyV7fP6u","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec345ffbf001Jsry5qJHnyR1EW","type":"tool","callID":"write_28","tool":"write","state":{"status":"completed","input":{"filePath":"/workspace/next.config.ts","content":"import type { NextConfig } from 'next'\n\nconst nextConfig: NextConfig = {\n cacheComponents: true,\n}\n\nexport default nextConfig\n"},"output":"","title":"next.config.ts","metadata":{"diagnostics":{"/workspace/next.config.ts":[],"/workspace/app/page.tsx":[],"/workspace/app/layout.tsx":[],"/workspace/lib/db.js":[],"/workspace/lib/products.ts":[]},"filepath":"/workspace/next.config.ts","exists":true},"time":{"start":1781392617704,"end":1781392620715}}}}
+{"type":"tool_use","timestamp":1781392621798,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec34630ef001Gu6nfgWoxdbC4B","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec345ffbf001Jsry5qJHnyR1EW","type":"tool","callID":"write_29","tool":"write","state":{"status":"completed","input":{"filePath":"/workspace/lib/products.ts","content":"'use cache'\n\nimport { cacheLife, cacheTag } from 'next/cache'\nimport { getAllProducts } from './db'\n\nexport async function getProducts() {\n cacheLife('max')\n cacheTag('products')\n return getAllProducts()\n}\n"},"output":"","title":"lib/products.ts","metadata":{"diagnostics":{"/workspace/next.config.ts":[],"/workspace/app/page.tsx":[],"/workspace/app/layout.tsx":[],"/workspace/lib/db.js":[],"/workspace/lib/products.ts":[]},"filepath":"/workspace/lib/products.ts","exists":false},"time":{"start":1781392618789,"end":1781392621797}}}}
+{"type":"tool_use","timestamp":1781392627222,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec3463527001bB968LCZrzcEXk","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec345ffbf001Jsry5qJHnyR1EW","type":"tool","callID":"write_30","tool":"write","state":{"status":"completed","input":{"filePath":"/workspace/app/admin/catalog/page.tsx","content":"import { revalidateTag } from 'next/cache'\nimport { getProducts } from '@/lib/products'\n\nexport default async function AdminCatalogPage() {\n const products = await getProducts()\n\n async function syncCatalog() {\n 'use server'\n\n revalidateTag('products', 'max')\n }\n\n return (\n \n
\n
Product Catalog
\n
\n Sync latest catalog\n
\n
\n\n
\n \n
\n
ID
\n
Name
\n
Price
\n
Inventory
\n
Available
\n
\n \n \n {products.map((product) => (\n
\n
{product.id}
\n
{product.name}
\n
${product.price}
\n
{product.inventory}
\n
\n {product.available ? 'Yes' : 'No'}\n
\n
\n ))}\n \n
\n \n )\n}\n"},"output":"\nThis file has errors, please fix\n\nERROR [45:71] Property 'inventory' does not exist on type '{ id: number; name: string; price: number; }'.\nERROR [47:26] Property 'available' does not exist on type '{ id: number; name: string; price: number; }'.\n\n","title":"app/admin/catalog/page.tsx","metadata":{"diagnostics":{"/workspace/next.config.ts":[],"/workspace/app/page.tsx":[],"/workspace/app/layout.tsx":[],"/workspace/lib/db.js":[],"/workspace/lib/products.ts":[],"/workspace/app/admin/catalog/page.tsx":[{"range":{"start":{"line":44,"character":70},"end":{"line":44,"character":79}},"message":"Property 'inventory' does not exist on type '{ id: number; name: string; price: number; }'.","severity":1,"code":2339,"source":"typescript"},{"range":{"start":{"line":46,"character":25},"end":{"line":46,"character":34}},"message":"Property 'available' does not exist on type '{ id: number; name: string; price: number; }'.","severity":1,"code":2339,"source":"typescript"}]},"filepath":"/workspace/app/admin/catalog/page.tsx","exists":false},"time":{"start":1781392626166,"end":1781392627219}}}}
+{"type":"step_finish","timestamp":1781392627230,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec3465615001LIM6ECKvUgtD5k","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec345ffbf001Jsry5qJHnyR1EW","type":"step-finish","reason":"tool-calls","snapshot":"1a79cb58a62691960d1431bc3eee38791c621c28","cost":0.01226914,"tokens":{"input":334,"output":1411,"reasoning":0,"cache":{"read":39424,"write":0}}}}
+{"type":"step_start","timestamp":1781392629209,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec3465dd100175osodq43b1V3d","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec346563b001869cPdooMVCZzL","type":"step-start","snapshot":"1a79cb58a62691960d1431bc3eee38791c621c28"}}
+{"type":"tool_use","timestamp":1781392635734,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec3465f9f001DqKWDBirGwDre2","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec346563b001869cPdooMVCZzL","type":"tool","callID":"write_31","tool":"write","state":{"status":"completed","input":{"filePath":"/workspace/lib/db.js","content":"export async function getAllProducts() {\n // Simulate database delay\n await new Promise((resolve) => setTimeout(resolve, 100))\n\n return [\n { id: 1, name: 'Laptop', price: 999, inventory: 42, available: true },\n { id: 2, name: 'Phone', price: 699, inventory: 128, available: true },\n { id: 3, name: 'Tablet', price: 499, inventory: 76, available: true },\n { id: 4, name: 'Headphones', price: 199, inventory: 15, available: true },\n { id: 5, name: 'Watch', price: 299, inventory: 0, available: false },\n ]\n}\n"},"output":"","title":"lib/db.js","metadata":{"diagnostics":{"/workspace/next.config.ts":[],"/workspace/app/page.tsx":[],"/workspace/app/layout.tsx":[],"/workspace/lib/db.js":[],"/workspace/lib/products.ts":[],"/workspace/app/admin/catalog/page.tsx":[]},"filepath":"/workspace/lib/db.js","exists":true},"time":{"start":1781392632723,"end":1781392635732}}}}
+{"type":"step_finish","timestamp":1781392635739,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec3467755001jGKifg2n7a40TT","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec346563b001869cPdooMVCZzL","type":"step-finish","reason":"tool-calls","snapshot":"70275df09be9c243b7168c900f6d2a2815288729","cost":0.0087829,"tokens":{"input":1598,"output":229,"reasoning":0,"cache":{"read":39680,"write":0}}}}
+{"type":"step_start","timestamp":1781392637544,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec3467e61001fH1p3I2x3bk67J","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec3467770001xSs4NlimiJBN1p","type":"step-start","snapshot":"70275df09be9c243b7168c900f6d2a2815288729"}}
+{"type":"tool_use","timestamp":1781392642756,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec3468c76001fbHQkFmJ0fva12","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec3467770001xSs4NlimiJBN1p","type":"tool","callID":"todowrite_32","tool":"todowrite","state":{"status":"completed","input":{"todos":[{"id":"1","content":"Explore workspace and Next.js docs for cache tags and Server Actions","status":"completed","priority":"high"},{"id":"2","content":"Implement admin catalog page with inline Server Action sync form","status":"completed","priority":"high"},{"id":"3","content":"Add/verify catalog data fetching uses cache tag 'products'","status":"completed","priority":"high"},{"id":"4","content":"Run lint/typecheck/tests as available","status":"in_progress","priority":"medium"}]},"output":"[\n {\n \"id\": \"1\",\n \"content\": \"Explore workspace and Next.js docs for cache tags and Server Actions\",\n \"status\": \"completed\",\n \"priority\": \"high\"\n },\n {\n \"id\": \"2\",\n \"content\": \"Implement admin catalog page with inline Server Action sync form\",\n \"status\": \"completed\",\n \"priority\": \"high\"\n },\n {\n \"id\": \"3\",\n \"content\": \"Add/verify catalog data fetching uses cache tag 'products'\",\n \"status\": \"completed\",\n \"priority\": \"high\"\n },\n {\n \"id\": \"4\",\n \"content\": \"Run lint/typecheck/tests as available\",\n \"status\": \"in_progress\",\n \"priority\": \"medium\"\n }\n]","title":"1 todos","metadata":{"todos":[{"id":"1","content":"Explore workspace and Next.js docs for cache tags and Server Actions","status":"completed","priority":"high"},{"id":"2","content":"Implement admin catalog page with inline Server Action sync form","status":"completed","priority":"high"},{"id":"3","content":"Add/verify catalog data fetching uses cache tag 'products'","status":"completed","priority":"high"},{"id":"4","content":"Run lint/typecheck/tests as available","status":"in_progress","priority":"medium"}]},"time":{"start":1781392642750,"end":1781392642754}}}}
+{"type":"step_finish","timestamp":1781392642760,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec34692c2001E1mm7iQJSN4yfY","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec3467770001xSs4NlimiJBN1p","type":"step-finish","reason":"tool-calls","snapshot":"70275df09be9c243b7168c900f6d2a2815288729","cost":0.00827536,"tokens":{"input":304,"output":348,"reasoning":0,"cache":{"read":41216,"write":0}}}}
+{"type":"step_start","timestamp":1781392644799,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec3469abb001pTG4F7djLkQjEj","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec34692d7001DFNk4zyqMn5VGP","type":"step-start","snapshot":"70275df09be9c243b7168c900f6d2a2815288729"}}
+{"type":"tool_use","timestamp":1781392656490,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec3469abe001PH2OBR9xVnPCw4","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec34692d7001DFNk4zyqMn5VGP","type":"tool","callID":"bash_33","tool":"bash","state":{"status":"completed","input":{"command":"npm run build","description":"Build the Next.js app","timeout":300000},"output":"\n> build\n> next build\n\nAttention: Next.js now collects completely anonymous telemetry regarding usage.\nThis information is used to shape Next.js' roadmap and prioritize features.\nYou can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:\nhttps://nextjs.org/telemetry\n\n▲ Next.js 16.3.0-canary.50 (Turbopack)\n- Cache Components enabled\n\n Creating an optimized production build ...\n✓ Compiled successfully in 6.3s\n Running TypeScript ...\n\n We detected TypeScript in your project and reconfigured your tsconfig.json file for you.\n The following suggested values were added to your tsconfig.json. These values can be changed to fit your project's needs:\n\n \t- include was updated to add '.next/dev/types/**/*.ts'\n\n Finished TypeScript in 2.3s ...\n Collecting page data using 1 worker ...\n Generating static pages using 1 worker (0/4) ...\n Generating static pages using 1 worker (1/4) \r\n Generating static pages using 1 worker (2/4) \r\n Generating static pages using 1 worker (3/4) \r\n✓ Generating static pages using 1 worker (4/4) in 206ms\n Finalizing page optimization ...\n\nRoute (app) Revalidate Expire\n┌ ○ /\n├ ○ /_not-found\n└ ○ /admin/catalog 30d 1y\n\n\n○ (Static) prerendered as static content\n\n","title":"Build the Next.js app","metadata":{"output":"\n> build\n> next build\n\nAttention: Next.js now collects completely anonymous telemetry regarding usage.\nThis information is used to shape Next.js' roadmap and prioritize features.\nYou can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:\nhttps://nextjs.org/telemetry\n\n▲ Next.js 16.3.0-canary.50 (Turbopack)\n- Cache Components enabled\n\n Creating an optimized production build ...\n✓ Compiled successfully in 6.3s\n Running TypeScript ...\n\n We detected TypeScript in your project and reconfigured your tsconfig.json file for you.\n The following suggested values were added to your tsconfig.json. These values can be changed to fit your project's needs:\n\n \t- include was updated to add '.next/dev/types/**/*.ts'\n\n Finished TypeScript in 2.3s ...\n Collecting page data using 1 worker ...\n Generating static pages using 1 worker (0/4) ...\n Generating static pages using 1 worker (1/4) \r\n Generating static pages using 1 worker (2/4) \r\n Generating static pages using 1 worker (3/4) \r\n✓ Generating static pages using 1 worker (4/4) in 206ms\n Finalizing page optimization ...\n\nRoute (app) Revalidate Expire\n┌ ○ /\n├ ○ /_not-found\n└ ○ /admin/catalog 30d 1y\n\n\n○ (Static) prerendered as static content\n\n","exit":0,"description":"Build the Next.js app"},"time":{"start":1781392645207,"end":1781392656485}}}}
+{"type":"step_finish","timestamp":1781392656636,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec346c868001OqGhxSidA9cwfV","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec34692d7001DFNk4zyqMn5VGP","type":"step-finish","reason":"tool-calls","snapshot":"85dfc82e927059c8f5ae93373af589bc81452a85","cost":0.00733547,"tokens":{"input":581,"output":37,"reasoning":0,"cache":{"read":41472,"write":0}}}}
+{"type":"step_start","timestamp":1781392658514,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec346d04a001HyCsXxGnPKzbko","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec346c910001YPfG9JiHQytIDW","type":"step-start","snapshot":"85dfc82e927059c8f5ae93373af589bc81452a85"}}
+{"type":"tool_use","timestamp":1781392662393,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec346d6100017YyMWJ13XS8yoy","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec346c910001YPfG9JiHQytIDW","type":"tool","callID":"bash_34","tool":"bash","state":{"status":"completed","input":{"command":"npx tsc --noEmit","description":"Run TypeScript type check"},"output":"","title":"Run TypeScript type check","metadata":{"output":"","exit":0,"description":"Run TypeScript type check"},"time":{"start":1781392660208,"end":1781392662389}}}}
+{"type":"step_finish","timestamp":1781392662400,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec346df77001iYUOmlYoCyISXT","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec346c910001YPfG9JiHQytIDW","type":"step-finish","reason":"tool-calls","snapshot":"c54fcfd164b1980a60dea2ba539cbc29d05fe260","cost":0.00762359,"tokens":{"input":457,"output":118,"reasoning":0,"cache":{"read":41984,"write":0}}}}
+{"type":"step_start","timestamp":1781392664296,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec346e6e0001GXUk5HFBxBCzmG","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec346dfcd001Wa74ju9de5yOTo","type":"step-start","snapshot":"c54fcfd164b1980a60dea2ba539cbc29d05fe260"}}
+{"type":"tool_use","timestamp":1781392677055,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec34717e2001Jktxmc4xAuGiwj","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec346dfcd001Wa74ju9de5yOTo","type":"tool","callID":"read_35","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/lib/products.ts"},"output":"\n00001| 'use cache'\n00002| \n00003| import { cacheLife, cacheTag } from 'next/cache'\n00004| import { getAllProducts } from './db'\n00005| \n00006| export async function getProducts() {\n00007| cacheLife('max')\n00008| cacheTag('products')\n00009| return getAllProducts()\n00010| }\n00011| \n\n(End of file - total 11 lines)\n","title":"lib/products.ts","metadata":{"preview":"'use cache'\n\nimport { cacheLife, cacheTag } from 'next/cache'\nimport { getAllProducts } from './db'\n\nexport async function getProducts() {\n cacheLife('max')\n cacheTag('products')\n return getAllProducts()\n}\n"},"time":{"start":1781392677052,"end":1781392677054}}}}
+{"type":"tool_use","timestamp":1781392677226,"sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","part":{"id":"prt_ec34718be001OLY2FFvEvu9EfI","sessionID":"ses_13cbb78f4ffeW1oPoj0co3q1Fm","messageID":"msg_ec346dfcd001Wa74ju9de5yOTo","type":"tool","callID":"read_36","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/app/admin/catalog/page.tsx"},"output":"\n00001| import { revalidateTag } from 'next/cache'\n00002| import { getProducts } from '@/lib/products'\n00003| \n00004| export default async function AdminCatalogPage() {\n00005| const products = await getProducts()\n00006| \n00007| async function syncCatalog() {\n00008| 'use server'\n00009| \n00010| revalidateTag('products', 'max')\n00011| }\n00012| \n00013| return (\n00014| \n00015|
\n00006| )\n00007| }\n00008| \n\n(End of file - total 8 lines)\n",
+ "title": "app/page.tsx",
+ "metadata": {
+ "preview": "export default function Page() {\n return (\n
\n
Home
\n
\n )\n}\n"
+ },
+ "time": {
+ "start": 1781392533635,
+ "end": 1781392533639
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:33.862Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "args": {
+ "filePath": "/workspace/app/layout.tsx",
+ "_extractedPath": "/workspace/app/layout.tsx"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392533862,
+ "sessionID": "ses_13cbb78f4ffeW1oPoj0co3q1Fm",
+ "part": {
+ "id": "prt_ec344e887001QeFmiOdplyc7E7",
+ "sessionID": "ses_13cbb78f4ffeW1oPoj0co3q1Fm",
+ "messageID": "msg_ec344e00b001jo6Yj8btd2NmTi",
+ "type": "tool",
+ "callID": "read_11",
+ "tool": "read",
+ "state": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/app/layout.tsx"
+ },
+ "output": "\n00001| import type { Metadata } from 'next'\n00002| \n00003| export const metadata: Metadata = {\n00004| title: 'Create Next App',\n00005| description: 'Generated by create next app',\n00006| }\n00007| \n00008| export default function RootLayout({\n00009| children,\n00010| }: Readonly<{\n00011| children: React.ReactNode\n00012| }>) {\n00013| return (\n00014| \n00015| {children}\n00016| \n00017| )\n00018| }\n00019| \n\n(End of file - total 19 lines)\n",
+ "title": "app/layout.tsx",
+ "metadata": {
+ "preview": "import type { Metadata } from 'next'\n\nexport const metadata: Metadata = {\n title: 'Create Next App',\n description: 'Generated by create next app',\n}\n\nexport default function RootLayout({\n children,\n}: Readonly<{\n children: React.ReactNode\n}>) {\n return (\n \n {children}\n \n )\n}\n"
+ },
+ "time": {
+ "start": 1781392533851,
+ "end": 1781392533860
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:33.862Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| import type { Metadata } from 'next'\n00002| \n00003| export const metadata: Metadata = {\n00004| title: 'Create Next App',\n00005| description: 'Generated by create next app',\n00006| }\n00007| \n00008| export default function RootLayout({\n00009| children,\n00010| }: Readonly<{\n00011| children: React.ReactNode\n00012| }>) {\n00013| return (\n00014| \n00015| {children}\n00016| \n00017| )\n00018| }\n00019| \n\n(End of file - total 19 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/app/layout.tsx"
+ },
+ "output": "\n00001| import type { Metadata } from 'next'\n00002| \n00003| export const metadata: Metadata = {\n00004| title: 'Create Next App',\n00005| description: 'Generated by create next app',\n00006| }\n00007| \n00008| export default function RootLayout({\n00009| children,\n00010| }: Readonly<{\n00011| children: React.ReactNode\n00012| }>) {\n00013| return (\n00014| \n00015| {children}\n00016| \n00017| )\n00018| }\n00019| \n\n(End of file - total 19 lines)\n",
+ "title": "app/layout.tsx",
+ "metadata": {
+ "preview": "import type { Metadata } from 'next'\n\nexport const metadata: Metadata = {\n title: 'Create Next App',\n description: 'Generated by create next app',\n}\n\nexport default function RootLayout({\n children,\n}: Readonly<{\n children: React.ReactNode\n}>) {\n return (\n \n {children}\n \n )\n}\n"
+ },
+ "time": {
+ "start": 1781392533851,
+ "end": 1781392533860
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:34.260Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "args": {
+ "filePath": "/workspace/package.json",
+ "_extractedPath": "/workspace/package.json"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392534260,
+ "sessionID": "ses_13cbb78f4ffeW1oPoj0co3q1Fm",
+ "part": {
+ "id": "prt_ec344ea2000134bXbVjhisqmdg",
+ "sessionID": "ses_13cbb78f4ffeW1oPoj0co3q1Fm",
+ "messageID": "msg_ec344e00b001jo6Yj8btd2NmTi",
+ "type": "tool",
+ "callID": "read_13",
+ "tool": "read",
+ "state": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/package.json"
+ },
+ "output": "\n00001| {\n00002| \"private\": true,\n00003| \"type\": \"module\",\n00004| \"scripts\": {\n00005| \"dev\": \"next dev\",\n00006| \"build\": \"next build\",\n00007| \"start\": \"next start\"\n00008| },\n00009| \"dependencies\": {\n00010| \"@ai-sdk/react\": \"2.0.0-beta.28\",\n00011| \"@modelcontextprotocol/sdk\": \"^1.17.0\",\n00012| \"ai\": \"5.0.59\",\n00013| \"next\": \"^16.3.0-canary.50\",\n00014| \"react\": \"19.1.0\",\n00015| \"react-dom\": \"19.1.0\",\n00016| \"zod\": \"^4.0.10\"\n00017| },\n00018| \"devDependencies\": {\n00019| \"@types/node\": \"^20\",\n00020| \"@types/react\": \"^19\",\n00021| \"@types/react-dom\": \"^19\",\n00022| \"@vitejs/plugin-react\": \"^4.4.1\",\n00023| \"typescript\": \"^5\",\n00024| \"vite-tsconfig-paths\": \"^5.1.4\",\n00025| \"vitest\": \"^3.1.3\"\n00026| }\n00027| }\n00028| \n\n(End of file - total 28 lines)\n",
+ "title": "package.json",
+ "metadata": {
+ "preview": "{\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"next dev\",\n \"build\": \"next build\",\n \"start\": \"next start\"\n },\n \"dependencies\": {\n \"@ai-sdk/react\": \"2.0.0-beta.28\",\n \"@modelcontextprotocol/sdk\": \"^1.17.0\",\n \"ai\": \"5.0.59\",\n \"next\": \"^16.3.0-canary.50\",\n \"react\": \"19.1.0\",\n \"react-dom\": \"19.1.0\",\n \"zod\": \"^4.0.10\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^20\",\n \"@types/react\": \"^19\","
+ },
+ "time": {
+ "start": 1781392534248,
+ "end": 1781392534251
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:34.260Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| {\n00002| \"private\": true,\n00003| \"type\": \"module\",\n00004| \"scripts\": {\n00005| \"dev\": \"next dev\",\n00006| \"build\": \"next build\",\n00007| \"start\": \"next start\"\n00008| },\n00009| \"dependencies\": {\n00010| \"@ai-sdk/react\": \"2.0.0-beta.28\",\n00011| \"@modelcontextprotocol/sdk\": \"^1.17.0\",\n00012| \"ai\": \"5.0.59\",\n00013| \"next\": \"^16.3.0-canary.50\",\n00014| \"react\": \"19.1.0\",\n00015| \"react-dom\": \"19.1.0\",\n00016| \"zod\": \"^4.0.10\"\n00017| },\n00018| \"devDependencies\": {\n00019| \"@types/node\": \"^20\",\n00020| \"@types/react\": \"^19\",\n00021| \"@types/react-dom\": \"^19\",\n00022| \"@vitejs/plugin-react\": \"^4.4.1\",\n00023| \"typescript\": \"^5\",\n00024| \"vite-tsconfig-paths\": \"^5.1.4\",\n00025| \"vitest\": \"^3.1.3\"\n00026| }\n00027| }\n00028| \n\n(End of file - total 28 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/package.json"
+ },
+ "output": "\n00001| {\n00002| \"private\": true,\n00003| \"type\": \"module\",\n00004| \"scripts\": {\n00005| \"dev\": \"next dev\",\n00006| \"build\": \"next build\",\n00007| \"start\": \"next start\"\n00008| },\n00009| \"dependencies\": {\n00010| \"@ai-sdk/react\": \"2.0.0-beta.28\",\n00011| \"@modelcontextprotocol/sdk\": \"^1.17.0\",\n00012| \"ai\": \"5.0.59\",\n00013| \"next\": \"^16.3.0-canary.50\",\n00014| \"react\": \"19.1.0\",\n00015| \"react-dom\": \"19.1.0\",\n00016| \"zod\": \"^4.0.10\"\n00017| },\n00018| \"devDependencies\": {\n00019| \"@types/node\": \"^20\",\n00020| \"@types/react\": \"^19\",\n00021| \"@types/react-dom\": \"^19\",\n00022| \"@vitejs/plugin-react\": \"^4.4.1\",\n00023| \"typescript\": \"^5\",\n00024| \"vite-tsconfig-paths\": \"^5.1.4\",\n00025| \"vitest\": \"^3.1.3\"\n00026| }\n00027| }\n00028| \n\n(End of file - total 28 lines)\n",
+ "title": "package.json",
+ "metadata": {
+ "preview": "{\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"next dev\",\n \"build\": \"next build\",\n \"start\": \"next start\"\n },\n \"dependencies\": {\n \"@ai-sdk/react\": \"2.0.0-beta.28\",\n \"@modelcontextprotocol/sdk\": \"^1.17.0\",\n \"ai\": \"5.0.59\",\n \"next\": \"^16.3.0-canary.50\",\n \"react\": \"19.1.0\",\n \"react-dom\": \"19.1.0\",\n \"zod\": \"^4.0.10\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^20\",\n \"@types/react\": \"^19\","
+ },
+ "time": {
+ "start": 1781392534248,
+ "end": 1781392534251
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:34.455Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "args": {
+ "filePath": "/workspace/next.config.ts",
+ "_extractedPath": "/workspace/next.config.ts"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392534455,
+ "sessionID": "ses_13cbb78f4ffeW1oPoj0co3q1Fm",
+ "part": {
+ "id": "prt_ec344eaea001463Jwj8J3BsTI7",
+ "sessionID": "ses_13cbb78f4ffeW1oPoj0co3q1Fm",
+ "messageID": "msg_ec344e00b001jo6Yj8btd2NmTi",
+ "type": "tool",
+ "callID": "read_14",
+ "tool": "read",
+ "state": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/next.config.ts"
+ },
+ "output": "\n00001| import type { NextConfig } from 'next'\n00002| \n00003| const nextConfig: NextConfig = {}\n00004| \n00005| export default nextConfig\n00006| \n\n(End of file - total 6 lines)\n",
+ "title": "next.config.ts",
+ "metadata": {
+ "preview": "import type { NextConfig } from 'next'\n\nconst nextConfig: NextConfig = {}\n\nexport default nextConfig\n"
+ },
+ "time": {
+ "start": 1781392534449,
+ "end": 1781392534452
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:34.455Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| import type { NextConfig } from 'next'\n00002| \n00003| const nextConfig: NextConfig = {}\n00004| \n00005| export default nextConfig\n00006| \n\n(End of file - total 6 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/next.config.ts"
+ },
+ "output": "\n00001| import type { NextConfig } from 'next'\n00002| \n00003| const nextConfig: NextConfig = {}\n00004| \n00005| export default nextConfig\n00006| \n\n(End of file - total 6 lines)\n",
+ "title": "next.config.ts",
+ "metadata": {
+ "preview": "import type { NextConfig } from 'next'\n\nconst nextConfig: NextConfig = {}\n\nexport default nextConfig\n"
+ },
+ "time": {
+ "start": 1781392534449,
+ "end": 1781392534452
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:35.160Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "args": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md",
+ "_extractedPath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392535160,
+ "sessionID": "ses_13cbb78f4ffeW1oPoj0co3q1Fm",
+ "part": {
+ "id": "prt_ec344ebb3001fM31XJD0lPuBjS",
+ "sessionID": "ses_13cbb78f4ffeW1oPoj0co3q1Fm",
+ "messageID": "msg_ec344e00b001jo6Yj8btd2NmTi",
+ "type": "tool",
+ "callID": "read_15",
+ "tool": "read",
+ "state": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md"
+ },
+ "output": "\n00001| ---\n00002| title: cacheTag\n00003| description: Learn how to use the cacheTag function to manage cache invalidation in your Next.js application.\n00004| related:\n00005| title: Related\n00006| description: View related API references.\n00007| links:\n00008| - app/api-reference/config/next-config-js/cacheComponents\n00009| - app/api-reference/directives/use-cache\n00010| - app/api-reference/functions/revalidateTag\n00011| - app/api-reference/functions/updateTag\n00012| - app/api-reference/functions/cacheLife\n00013| ---\n00014| \n00015| The `cacheTag` function allows you to tag cached data for on-demand invalidation. By associating tags with cache entries, you can selectively purge or revalidate specific cache entries without affecting other cached data.\n00016| \n00017| ## Usage\n00018| \n00019| To use `cacheTag`, enable the [`cacheComponents` flag](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.js` file:\n00020| \n00021| ```ts filename=\"next.config.ts\" switcher\n00022| import type { NextConfig } from 'next'\n00023| \n00024| const nextConfig: NextConfig = {\n00025| cacheComponents: true,\n00026| }\n00027| \n00028| export default nextConfig\n00029| ```\n00030| \n00031| ```js filename=\"next.config.js\" switcher\n00032| const nextConfig = {\n00033| cacheComponents: true,\n00034| }\n00035| \n00036| export default nextConfig\n00037| ```\n00038| \n00039| The `cacheTag` function takes one or more string values.\n00040| \n00041| ```tsx filename=\"app/data.ts\" switcher\n00042| import { cacheTag } from 'next/cache'\n00043| \n00044| export async function getData() {\n00045| 'use cache'\n00046| cacheTag('my-data')\n00047| const data = await fetch('/api/data')\n00048| return data\n00049| }\n00050| ```\n00051| \n00052| ```jsx filename=\"app/data.js\" switcher\n00053| import { cacheTag } from 'next/cache'\n00054| \n00055| export async function getData() {\n00056| 'use cache'\n00057| cacheTag('my-data')\n00058| const data = await fetch('/api/data')\n00059| return data\n00060| }\n00061| ```\n00062| \n00063| You can then purge the cache on-demand from a [Server Function](/docs/app/getting-started/mutating-data) or [Route Handler](/docs/app/api-reference/file-conventions/route):\n00064| \n00065| - Use [`updateTag`](/docs/app/api-reference/functions/updateTag) for read-your-own-writes scenarios, such as forms and other user-triggered mutations, where a user makes a change and the next read should fetch fresh data immediately. `updateTag` is only available inside Server Functions.\n00066| - Use [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) when it is acceptable to serve stale data while revalidation happens in the background, or when revalidating from a [Route Handler](/docs/app/api-reference/file-conventions/route) or other context.\n00067| \n00068| For example, this Server Function adds a post and then purges every cache entry tagged `'my-data'` so the next read reflects the change:\n00069| \n00070| ```tsx filename=\"app/action.ts\" switcher\n00071| 'use server'\n00072| \n00073| import { updateTag } from 'next/cache'\n00074| \n00075| export default async function submit() {\n00076| await addPost()\n00077| updateTag('my-data')\n00078| }\n00079| ```\n00080| \n00081| ```jsx filename=\"app/action.js\" switcher\n00082| 'use server'\n00083| \n00084| import { updateTag } from 'next/cache'\n00085| \n00086| export default async function submit() {\n00087| await addPost()\n00088| updateTag('my-data')\n00089| }\n00090| ```\n00091| \n00092| ## Good to know\n00093| \n00094| - **Idempotent Tags**: Applying the same tag multiple times has no additional effect.\n00095| - **Multiple Tags**: You can assign multiple tags to a single cache entry by passing multiple string values to `cacheTag`.\n00096| \n00097| ```tsx\n00098| cacheTag('tag-one', 'tag-two')\n00099| ```\n00100| \n00101| - **Limits**: A single `cacheTag()` call accepts up to 128 tags, each with a maximum length of 256 characters. Tags longer than 256 characters are skipped, and any tags past the 128th in one call are dropped. Both cases log a console warning.\n00102| \n00103| ## Examples\n00104| \n00105| ### Tagging components or functions\n00106| \n00107| Tag your cached data by calling `cacheTag` within a cached function or component:\n00108| \n00109| ```tsx filename=\"app/components/bookings.tsx\" switcher\n00110| import { cacheTag } from 'next/cache'\n00111| \n00112| interface BookingsProps {\n00113| type: string\n00114| }\n00115| \n00116| export async function Bookings({ type = 'haircut' }: BookingsProps) {\n00117| 'use cache'\n00118| cacheTag('bookings-data')\n00119| \n00120| async function getBookingsData() {\n00121| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00122| return data\n00123| }\n00124| \n00125| return //...\n00126| }\n00127| ```\n00128| \n00129| ```jsx filename=\"app/components/bookings.js\" switcher\n00130| import { cacheTag } from 'next/cache'\n00131| \n00132| export async function Bookings({ type = 'haircut' }) {\n00133| 'use cache'\n00134| cacheTag('bookings-data')\n00135| \n00136| async function getBookingsData() {\n00137| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00138| return data\n00139| }\n00140| \n00141| return //...\n00142| }\n00143| ```\n00144| \n00145| ### Creating tags from external data\n00146| \n00147| You can use the data returned from an async function to tag the cache entry.\n00148| \n00149| ```tsx filename=\"app/components/bookings.tsx\" switcher\n00150| import { cacheTag } from 'next/cache'\n00151| \n00152| interface BookingsProps {\n00153| type: string\n00154| }\n00155| \n00156| export async function Bookings({ type = 'haircut' }: BookingsProps) {\n00157| async function getBookingsData() {\n00158| 'use cache'\n00159| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00160| cacheTag('bookings-data', data.id)\n00161| return data\n00162| }\n00163| return //...\n00164| }\n00165| ```\n00166| \n00167| ```jsx filename=\"app/components/bookings.js\" switcher\n00168| import { cacheTag } from 'next/cache'\n00169| \n00170| export async function Bookings({ type = 'haircut' }) {\n00171| async function getBookingsData() {\n00172| 'use cache'\n00173| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00174| cacheTag('bookings-data', data.id)\n00175| return data\n00176| }\n00177| return //...\n00178| }\n00179| ```\n00180| \n00181| ### Invalidating tagged cache\n00182| \n00183| Using [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag), you can invalidate the cache for a specific tag when needed:\n00184| \n00185| ```tsx filename=\"app/actions.ts\" switcher\n00186| 'use server'\n00187| \n00188| import { revalidateTag } from 'next/cache'\n00189| \n00190| export async function updateBookings() {\n00191| await updateBookingData()\n00192| revalidateTag('bookings-data', 'max')\n00193| }\n00194| ```\n00195| \n00196| ```jsx filename=\"app/actions.js\" switcher\n00197| 'use server'\n00198| \n00199| import { revalidateTag } from 'next/cache'\n00200| \n00201| export async function updateBookings() {\n00202| await updateBookingData()\n00203| revalidateTag('bookings-data', 'max')\n00204| }\n00205| ```\n00206| \n\n(End of file - total 206 lines)\n",
+ "title": "node_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md",
+ "metadata": {
+ "preview": "---\ntitle: cacheTag\ndescription: Learn how to use the cacheTag function to manage cache invalidation in your Next.js application.\nrelated:\n title: Related\n description: View related API references.\n links:\n - app/api-reference/config/next-config-js/cacheComponents\n - app/api-reference/directives/use-cache\n - app/api-reference/functions/revalidateTag\n - app/api-reference/functions/updateTag\n - app/api-reference/functions/cacheLife\n---\n\nThe `cacheTag` function allows you to tag cached data for on-demand invalidation. By associating tags with cache entries, you can selectively purge or revalidate specific cache entries without affecting other cached data.\n\n## Usage\n\nTo use `cacheTag`, enable the [`cacheComponents` flag](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.js` file:\n"
+ },
+ "time": {
+ "start": 1781392535128,
+ "end": 1781392535134
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:35.160Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| ---\n00002| title: cacheTag\n00003| description: Learn how to use the cacheTag function to manage cache invalidation in your Next.js application.\n00004| related:\n00005| title: Related\n00006| description: View related API references.\n00007| links:\n00008| - app/api-reference/config/next-config-js/cacheComponents\n00009| - app/api-reference/directives/use-cache\n00010| - app/api-reference/functions/revalidateTag\n00011| - app/api-reference/functions/updateTag\n00012| - app/api-reference/functions/cacheLife\n00013| ---\n00014| \n00015| The `cacheTag` function allows you to tag cached data for on-demand invalidation. By associating tags with cache entries, you can selectively purge or revalidate specific cache entries without affecting other cached data.\n00016| \n00017| ## Usage\n00018| \n00019| To use `cacheTag`, enable the [`cacheComponents` flag](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.js` file:\n00020| \n00021| ```ts filename=\"next.config.ts\" switcher\n00022| import type { NextConfig } from 'next'\n00023| \n00024| const nextConfig: NextConfig = {\n00025| cacheComponents: true,\n00026| }\n00027| \n00028| export default nextConfig\n00029| ```\n00030| \n00031| ```js filename=\"next.config.js\" switcher\n00032| const nextConfig = {\n00033| cacheComponents: true,\n00034| }\n00035| \n00036| export default nextConfig\n00037| ```\n00038| \n00039| The `cacheTag` function takes one or more string values.\n00040| \n00041| ```tsx filename=\"app/data.ts\" switcher\n00042| import { cacheTag } from 'next/cache'\n00043| \n00044| export async function getData() {\n00045| 'use cache'\n00046| cacheTag('my-data')\n00047| const data = await fetch('/api/data')\n00048| return data\n00049| }\n00050| ```\n00051| \n00052| ```jsx filename=\"app/data.js\" switcher\n00053| import { cacheTag } from 'next/cache'\n00054| \n00055| export async function getData() {\n00056| 'use cache'\n00057| cacheTag('my-data')\n00058| const data = await fetch('/api/data')\n00059| return data\n00060| }\n00061| ```\n00062| \n00063| You can then purge the cache on-demand from a [Server Function](/docs/app/getting-started/mutating-data) or [Route Handler](/docs/app/api-reference/file-conventions/route):\n00064| \n00065| - Use [`updateTag`](/docs/app/api-reference/functions/updateTag) for read-your-own-writes scenarios, such as forms and other user-triggered mutations, where a user makes a change and the next read should fetch fresh data immediately. `updateTag` is only available inside Server Functions.\n00066| - Use [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) when it is acceptable to serve stale data while revalidation happens in the background, or when revalidating from a [Route Handler](/docs/app/api-reference/file-conventions/route) or other context.\n00067| \n00068| For example, this Server Function adds a post and then purges every cache entry tagged `'my-data'` so the next read reflects the change:\n00069| \n00070| ```tsx filename=\"app/action.ts\" switcher\n00071| 'use server'\n00072| \n00073| import { updateTag } from 'next/cache'\n00074| \n00075| export default async function submit() {\n00076| await addPost()\n00077| updateTag('my-data')\n00078| }\n00079| ```\n00080| \n00081| ```jsx filename=\"app/action.js\" switcher\n00082| 'use server'\n00083| \n00084| import { updateTag } from 'next/cache'\n00085| \n00086| export default async function submit() {\n00087| await addPost()\n00088| updateTag('my-data')\n00089| }\n00090| ```\n00091| \n00092| ## Good to know\n00093| \n00094| - **Idempotent Tags**: Applying the same tag multiple times has no additional effect.\n00095| - **Multiple Tags**: You can assign multiple tags to a single cache entry by passing multiple string values to `cacheTag`.\n00096| \n00097| ```tsx\n00098| cacheTag('tag-one', 'tag-two')\n00099| ```\n00100| \n00101| - **Limits**: A single `cacheTag()` call accepts up to 128 tags, each with a maximum length of 256 characters. Tags longer than 256 characters are skipped, and any tags past the 128th in one call are dropped. Both cases log a console warning.\n00102| \n00103| ## Examples\n00104| \n00105| ### Tagging components or functions\n00106| \n00107| Tag your cached data by calling `cacheTag` within a cached function or component:\n00108| \n00109| ```tsx filename=\"app/components/bookings.tsx\" switcher\n00110| import { cacheTag } from 'next/cache'\n00111| \n00112| interface BookingsProps {\n00113| type: string\n00114| }\n00115| \n00116| export async function Bookings({ type = 'haircut' }: BookingsProps) {\n00117| 'use cache'\n00118| cacheTag('bookings-data')\n00119| \n00120| async function getBookingsData() {\n00121| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00122| return data\n00123| }\n00124| \n00125| return //...\n00126| }\n00127| ```\n00128| \n00129| ```jsx filename=\"app/components/bookings.js\" switcher\n00130| import { cacheTag } from 'next/cache'\n00131| \n00132| export async function Bookings({ type = 'haircut' }) {\n00133| 'use cache'\n00134| cacheTag('bookings-data')\n00135| \n00136| async function getBookingsData() {\n00137| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00138| return data\n00139| }\n00140| \n00141| return //...\n00142| }\n00143| ```\n00144| \n00145| ### Creating tags from external data\n00146| \n00147| You can use the data returned from an async function to tag the cache entry.\n00148| \n00149| ```tsx filename=\"app/components/bookings.tsx\" switcher\n00150| import { cacheTag } from 'next/cache'\n00151| \n00152| interface BookingsProps {\n00153| type: string\n00154| }\n00155| \n00156| export async function Bookings({ type = 'haircut' }: BookingsProps) {\n00157| async function getBookingsData() {\n00158| 'use cache'\n00159| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00160| cacheTag('bookings-data', data.id)\n00161| return data\n00162| }\n00163| return //...\n00164| }\n00165| ```\n00166| \n00167| ```jsx filename=\"app/components/bookings.js\" switcher\n00168| import { cacheTag } from 'next/cache'\n00169| \n00170| export async function Bookings({ type = 'haircut' }) {\n00171| async function getBookingsData() {\n00172| 'use cache'\n00173| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00174| cacheTag('bookings-data', data.id)\n00175| return data\n00176| }\n00177| return //...\n00178| }\n00179| ```\n00180| \n00181| ### Invalidating tagged cache\n00182| \n00183| Using [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag), you can invalidate the cache for a specific tag when needed:\n00184| \n00185| ```tsx filename=\"app/actions.ts\" switcher\n00186| 'use server'\n00187| \n00188| import { revalidateTag } from 'next/cache'\n00189| \n00190| export async function updateBookings() {\n00191| await updateBookingData()\n00192| revalidateTag('bookings-data', 'max')\n00193| }\n00194| ```\n00195| \n00196| ```jsx filename=\"app/actions.js\" switcher\n00197| 'use server'\n00198| \n00199| import { revalidateTag } from 'next/cache'\n00200| \n00201| export async function updateBookings() {\n00202| await updateBookingData()\n00203| revalidateTag('bookings-data', 'max')\n00204| }\n00205| ```\n00206| \n\n(End of file - total 206 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md"
+ },
+ "output": "\n00001| ---\n00002| title: cacheTag\n00003| description: Learn how to use the cacheTag function to manage cache invalidation in your Next.js application.\n00004| related:\n00005| title: Related\n00006| description: View related API references.\n00007| links:\n00008| - app/api-reference/config/next-config-js/cacheComponents\n00009| - app/api-reference/directives/use-cache\n00010| - app/api-reference/functions/revalidateTag\n00011| - app/api-reference/functions/updateTag\n00012| - app/api-reference/functions/cacheLife\n00013| ---\n00014| \n00015| The `cacheTag` function allows you to tag cached data for on-demand invalidation. By associating tags with cache entries, you can selectively purge or revalidate specific cache entries without affecting other cached data.\n00016| \n00017| ## Usage\n00018| \n00019| To use `cacheTag`, enable the [`cacheComponents` flag](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.js` file:\n00020| \n00021| ```ts filename=\"next.config.ts\" switcher\n00022| import type { NextConfig } from 'next'\n00023| \n00024| const nextConfig: NextConfig = {\n00025| cacheComponents: true,\n00026| }\n00027| \n00028| export default nextConfig\n00029| ```\n00030| \n00031| ```js filename=\"next.config.js\" switcher\n00032| const nextConfig = {\n00033| cacheComponents: true,\n00034| }\n00035| \n00036| export default nextConfig\n00037| ```\n00038| \n00039| The `cacheTag` function takes one or more string values.\n00040| \n00041| ```tsx filename=\"app/data.ts\" switcher\n00042| import { cacheTag } from 'next/cache'\n00043| \n00044| export async function getData() {\n00045| 'use cache'\n00046| cacheTag('my-data')\n00047| const data = await fetch('/api/data')\n00048| return data\n00049| }\n00050| ```\n00051| \n00052| ```jsx filename=\"app/data.js\" switcher\n00053| import { cacheTag } from 'next/cache'\n00054| \n00055| export async function getData() {\n00056| 'use cache'\n00057| cacheTag('my-data')\n00058| const data = await fetch('/api/data')\n00059| return data\n00060| }\n00061| ```\n00062| \n00063| You can then purge the cache on-demand from a [Server Function](/docs/app/getting-started/mutating-data) or [Route Handler](/docs/app/api-reference/file-conventions/route):\n00064| \n00065| - Use [`updateTag`](/docs/app/api-reference/functions/updateTag) for read-your-own-writes scenarios, such as forms and other user-triggered mutations, where a user makes a change and the next read should fetch fresh data immediately. `updateTag` is only available inside Server Functions.\n00066| - Use [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) when it is acceptable to serve stale data while revalidation happens in the background, or when revalidating from a [Route Handler](/docs/app/api-reference/file-conventions/route) or other context.\n00067| \n00068| For example, this Server Function adds a post and then purges every cache entry tagged `'my-data'` so the next read reflects the change:\n00069| \n00070| ```tsx filename=\"app/action.ts\" switcher\n00071| 'use server'\n00072| \n00073| import { updateTag } from 'next/cache'\n00074| \n00075| export default async function submit() {\n00076| await addPost()\n00077| updateTag('my-data')\n00078| }\n00079| ```\n00080| \n00081| ```jsx filename=\"app/action.js\" switcher\n00082| 'use server'\n00083| \n00084| import { updateTag } from 'next/cache'\n00085| \n00086| export default async function submit() {\n00087| await addPost()\n00088| updateTag('my-data')\n00089| }\n00090| ```\n00091| \n00092| ## Good to know\n00093| \n00094| - **Idempotent Tags**: Applying the same tag multiple times has no additional effect.\n00095| - **Multiple Tags**: You can assign multiple tags to a single cache entry by passing multiple string values to `cacheTag`.\n00096| \n00097| ```tsx\n00098| cacheTag('tag-one', 'tag-two')\n00099| ```\n00100| \n00101| - **Limits**: A single `cacheTag()` call accepts up to 128 tags, each with a maximum length of 256 characters. Tags longer than 256 characters are skipped, and any tags past the 128th in one call are dropped. Both cases log a console warning.\n00102| \n00103| ## Examples\n00104| \n00105| ### Tagging components or functions\n00106| \n00107| Tag your cached data by calling `cacheTag` within a cached function or component:\n00108| \n00109| ```tsx filename=\"app/components/bookings.tsx\" switcher\n00110| import { cacheTag } from 'next/cache'\n00111| \n00112| interface BookingsProps {\n00113| type: string\n00114| }\n00115| \n00116| export async function Bookings({ type = 'haircut' }: BookingsProps) {\n00117| 'use cache'\n00118| cacheTag('bookings-data')\n00119| \n00120| async function getBookingsData() {\n00121| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00122| return data\n00123| }\n00124| \n00125| return //...\n00126| }\n00127| ```\n00128| \n00129| ```jsx filename=\"app/components/bookings.js\" switcher\n00130| import { cacheTag } from 'next/cache'\n00131| \n00132| export async function Bookings({ type = 'haircut' }) {\n00133| 'use cache'\n00134| cacheTag('bookings-data')\n00135| \n00136| async function getBookingsData() {\n00137| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00138| return data\n00139| }\n00140| \n00141| return //...\n00142| }\n00143| ```\n00144| \n00145| ### Creating tags from external data\n00146| \n00147| You can use the data returned from an async function to tag the cache entry.\n00148| \n00149| ```tsx filename=\"app/components/bookings.tsx\" switcher\n00150| import { cacheTag } from 'next/cache'\n00151| \n00152| interface BookingsProps {\n00153| type: string\n00154| }\n00155| \n00156| export async function Bookings({ type = 'haircut' }: BookingsProps) {\n00157| async function getBookingsData() {\n00158| 'use cache'\n00159| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00160| cacheTag('bookings-data', data.id)\n00161| return data\n00162| }\n00163| return //...\n00164| }\n00165| ```\n00166| \n00167| ```jsx filename=\"app/components/bookings.js\" switcher\n00168| import { cacheTag } from 'next/cache'\n00169| \n00170| export async function Bookings({ type = 'haircut' }) {\n00171| async function getBookingsData() {\n00172| 'use cache'\n00173| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00174| cacheTag('bookings-data', data.id)\n00175| return data\n00176| }\n00177| return //...\n00178| }\n00179| ```\n00180| \n00181| ### Invalidating tagged cache\n00182| \n00183| Using [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag), you can invalidate the cache for a specific tag when needed:\n00184| \n00185| ```tsx filename=\"app/actions.ts\" switcher\n00186| 'use server'\n00187| \n00188| import { revalidateTag } from 'next/cache'\n00189| \n00190| export async function updateBookings() {\n00191| await updateBookingData()\n00192| revalidateTag('bookings-data', 'max')\n00193| }\n00194| ```\n00195| \n00196| ```jsx filename=\"app/actions.js\" switcher\n00197| 'use server'\n00198| \n00199| import { revalidateTag } from 'next/cache'\n00200| \n00201| export async function updateBookings() {\n00202| await updateBookingData()\n00203| revalidateTag('bookings-data', 'max')\n00204| }\n00205| ```\n00206| \n\n(End of file - total 206 lines)\n",
+ "title": "node_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md",
+ "metadata": {
+ "preview": "---\ntitle: cacheTag\ndescription: Learn how to use the cacheTag function to manage cache invalidation in your Next.js application.\nrelated:\n title: Related\n description: View related API references.\n links:\n - app/api-reference/config/next-config-js/cacheComponents\n - app/api-reference/directives/use-cache\n - app/api-reference/functions/revalidateTag\n - app/api-reference/functions/updateTag\n - app/api-reference/functions/cacheLife\n---\n\nThe `cacheTag` function allows you to tag cached data for on-demand invalidation. By associating tags with cache entries, you can selectively purge or revalidate specific cache entries without affecting other cached data.\n\n## Usage\n\nTo use `cacheTag`, enable the [`cacheComponents` flag](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.js` file:\n"
+ },
+ "time": {
+ "start": 1781392535128,
+ "end": 1781392535134
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:35.505Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "args": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md",
+ "_extractedPath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392535505,
+ "sessionID": "ses_13cbb78f4ffeW1oPoj0co3q1Fm",
+ "part": {
+ "id": "prt_ec344ee5c001ZQ1GVmC0dqmcQb",
+ "sessionID": "ses_13cbb78f4ffeW1oPoj0co3q1Fm",
+ "messageID": "msg_ec344e00b001jo6Yj8btd2NmTi",
+ "type": "tool",
+ "callID": "read_16",
+ "tool": "read",
+ "state": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md"
+ },
+ "output": "\n00001| ---\n00002| title: revalidateTag\n00003| description: API Reference for the revalidateTag function.\n00004| ---\n00005| \n00006| `revalidateTag` allows you to invalidate cached data on-demand for a specific cache tag.\n00007| \n00008| This function is ideal for content where a slight delay in updates is acceptable, such as blog posts, product catalogs, or documentation. Users receive stale content while fresh data loads in the background.\n00009| \n00010| ## Usage\n00011| \n00012| `revalidateTag` can be called in Server Functions and Route Handlers.\n00013| \n00014| `revalidateTag` cannot be called in Client Components or Proxy, as it only works in server environments.\n00015| \n00016| ### Revalidation Behavior\n00017| \n00018| The revalidation behavior depends on whether you provide the second argument:\n00019| \n00020| - **With `profile=\"max\"` (recommended)**: The tag entry is marked as stale, and the next time a resource with that tag is visited, it will use stale-while-revalidate semantics. This means the stale content is served while fresh content is fetched in the background.\n00021| - **With a custom cache life profile**: For advanced usage, you can specify any cache life profile that your application has defined, allowing for custom revalidation behaviors tailored to your specific caching requirements.\n00022| - **Without the second argument (deprecated)**: The tag entry is expired immediately, and the next request to that resource will be a blocking revalidate/cache miss. This behavior is now deprecated, and you should either use `profile=\"max\"` or migrate to [`updateTag`](/docs/app/api-reference/functions/updateTag).\n00023| \n00024| > **Good to know**: When using `profile=\"max\"`, `revalidateTag` marks tagged data as stale, but fresh data is only fetched when pages using that tag are next visited. This means calling `revalidateTag` will not immediately trigger many revalidations at once. The invalidation only happens when any page using that tag is next visited.\n00025| \n00026| ## Parameters\n00027| \n00028| ```ts\n00029| revalidateTag(tag: string, profile: string | { expire?: number }): void;\n00030| ```\n00031| \n00032| - `tag`: A string representing the cache tag associated with the data you want to revalidate. Must not exceed 256 characters. This value is case-sensitive.\n00033| - `profile`: A string that specifies the revalidation behavior. The recommended value is `\"max\"` which provides stale-while-revalidate semantics, or any of the other default or custom profiles defined in [`cacheLife`](/docs/app/api-reference/config/next-config-js/cacheLife). Alternatively, you can pass an object with an `expire` property for custom expiration behavior.\n00034| \n00035| Tags must first be assigned to cached data. You can do this in two ways:\n00036| \n00037| - Using the [`next.tags`](/docs/app/api-reference/functions/fetch) option with `fetch` for caching external API requests:\n00038| \n00039| ```tsx\n00040| fetch(url, { next: { tags: ['posts'] } })\n00041| ```\n00042| \n00043| - Using [`cacheTag`](/docs/app/api-reference/functions/cacheTag) inside cached functions or components with the `'use cache'` directive:\n00044| \n00045| ```tsx\n00046| import { cacheTag } from 'next/cache'\n00047| \n00048| async function getData() {\n00049| 'use cache'\n00050| cacheTag('posts')\n00051| // ...\n00052| }\n00053| ```\n00054| \n00055| > **Good to know**: The single-argument form `revalidateTag(tag)` is deprecated. It currently works if TypeScript errors are suppressed, but this behavior may be removed in a future version. Update to the two-argument signature.\n00056| \n00057| ## Returns\n00058| \n00059| `revalidateTag` does not return a value.\n00060| \n00061| ## Relationship with `revalidatePath`\n00062| \n00063| `revalidateTag` invalidates data with specific tags across all pages that use those tags, while [`revalidatePath`](/docs/app/api-reference/functions/revalidatePath) invalidates specific page or layout paths.\n00064| \n00065| > **Good to know**: These functions serve different purposes and may need to be used together for comprehensive data consistency. For detailed examples and considerations, see [relationship with revalidateTag and updateTag](/docs/app/api-reference/functions/revalidatePath#relationship-with-revalidatetag-and-updatetag) for more information.\n00066| \n00067| ## Examples\n00068| \n00069| The following examples demonstrate how to use `revalidateTag` in different contexts. In both cases, we're using `profile=\"max\"` to mark data as stale and use stale-while-revalidate semantics, which is the recommended approach for most use cases.\n00070| \n00071| ### Server Action\n00072| \n00073| ```ts filename=\"app/actions.ts\" switcher\n00074| 'use server'\n00075| \n00076| import { revalidateTag } from 'next/cache'\n00077| \n00078| export default async function submit() {\n00079| await addPost()\n00080| revalidateTag('posts', 'max')\n00081| }\n00082| ```\n00083| \n00084| ```js filename=\"app/actions.js\" switcher\n00085| 'use server'\n00086| \n00087| import { revalidateTag } from 'next/cache'\n00088| \n00089| export default async function submit() {\n00090| await addPost()\n00091| revalidateTag('posts', 'max')\n00092| }\n00093| ```\n00094| \n00095| ### Route Handler\n00096| \n00097| ```ts filename=\"app/api/revalidate/route.ts\" switcher\n00098| import type { NextRequest } from 'next/server'\n00099| import { revalidateTag } from 'next/cache'\n00100| \n00101| export async function GET(request: NextRequest) {\n00102| const tag = request.nextUrl.searchParams.get('tag')\n00103| \n00104| if (tag) {\n00105| revalidateTag(tag, 'max')\n00106| return Response.json({ revalidated: true, now: Date.now() })\n00107| }\n00108| \n00109| return Response.json({\n00110| revalidated: false,\n00111| now: Date.now(),\n00112| message: 'Missing tag to revalidate',\n00113| })\n00114| }\n00115| ```\n00116| \n00117| ```js filename=\"app/api/revalidate/route.js\" switcher\n00118| import { revalidateTag } from 'next/cache'\n00119| \n00120| export async function GET(request) {\n00121| const tag = request.nextUrl.searchParams.get('tag')\n00122| \n00123| if (tag) {\n00124| revalidateTag(tag, 'max')\n00125| return Response.json({ revalidated: true, now: Date.now() })\n00126| }\n00127| \n00128| return Response.json({\n00129| revalidated: false,\n00130| now: Date.now(),\n00131| message: 'Missing tag to revalidate',\n00132| })\n00133| }\n00134| ```\n00135| \n00136| > **Good to know**: For webhooks or third-party services that need immediate expiration, you can pass `{ expire: 0 }` as the second argument: `revalidateTag(tag, { expire: 0 })`. This pattern is necessary when external systems call your Route Handlers and require data to expire immediately. For all other cases, it's recommended to use [`updateTag`](/docs/app/api-reference/functions/updateTag) in Server Actions for immediate updates instead.\n00137| \n\n(End of file - total 137 lines)\n",
+ "title": "node_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md",
+ "metadata": {
+ "preview": "---\ntitle: revalidateTag\ndescription: API Reference for the revalidateTag function.\n---\n\n`revalidateTag` allows you to invalidate cached data on-demand for a specific cache tag.\n\nThis function is ideal for content where a slight delay in updates is acceptable, such as blog posts, product catalogs, or documentation. Users receive stale content while fresh data loads in the background.\n\n## Usage\n\n`revalidateTag` can be called in Server Functions and Route Handlers.\n\n`revalidateTag` cannot be called in Client Components or Proxy, as it only works in server environments.\n\n### Revalidation Behavior\n\nThe revalidation behavior depends on whether you provide the second argument:\n\n- **With `profile=\"max\"` (recommended)**: The tag entry is marked as stale, and the next time a resource with that tag is visited, it will use stale-while-revalidate semantics. This means the stale content is served while fresh content is fetched in the background."
+ },
+ "time": {
+ "start": 1781392535483,
+ "end": 1781392535488
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:35.505Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| ---\n00002| title: revalidateTag\n00003| description: API Reference for the revalidateTag function.\n00004| ---\n00005| \n00006| `revalidateTag` allows you to invalidate cached data on-demand for a specific cache tag.\n00007| \n00008| This function is ideal for content where a slight delay in updates is acceptable, such as blog posts, product catalogs, or documentation. Users receive stale content while fresh data loads in the background.\n00009| \n00010| ## Usage\n00011| \n00012| `revalidateTag` can be called in Server Functions and Route Handlers.\n00013| \n00014| `revalidateTag` cannot be called in Client Components or Proxy, as it only works in server environments.\n00015| \n00016| ### Revalidation Behavior\n00017| \n00018| The revalidation behavior depends on whether you provide the second argument:\n00019| \n00020| - **With `profile=\"max\"` (recommended)**: The tag entry is marked as stale, and the next time a resource with that tag is visited, it will use stale-while-revalidate semantics. This means the stale content is served while fresh content is fetched in the background.\n00021| - **With a custom cache life profile**: For advanced usage, you can specify any cache life profile that your application has defined, allowing for custom revalidation behaviors tailored to your specific caching requirements.\n00022| - **Without the second argument (deprecated)**: The tag entry is expired immediately, and the next request to that resource will be a blocking revalidate/cache miss. This behavior is now deprecated, and you should either use `profile=\"max\"` or migrate to [`updateTag`](/docs/app/api-reference/functions/updateTag).\n00023| \n00024| > **Good to know**: When using `profile=\"max\"`, `revalidateTag` marks tagged data as stale, but fresh data is only fetched when pages using that tag are next visited. This means calling `revalidateTag` will not immediately trigger many revalidations at once. The invalidation only happens when any page using that tag is next visited.\n00025| \n00026| ## Parameters\n00027| \n00028| ```ts\n00029| revalidateTag(tag: string, profile: string | { expire?: number }): void;\n00030| ```\n00031| \n00032| - `tag`: A string representing the cache tag associated with the data you want to revalidate. Must not exceed 256 characters. This value is case-sensitive.\n00033| - `profile`: A string that specifies the revalidation behavior. The recommended value is `\"max\"` which provides stale-while-revalidate semantics, or any of the other default or custom profiles defined in [`cacheLife`](/docs/app/api-reference/config/next-config-js/cacheLife). Alternatively, you can pass an object with an `expire` property for custom expiration behavior.\n00034| \n00035| Tags must first be assigned to cached data. You can do this in two ways:\n00036| \n00037| - Using the [`next.tags`](/docs/app/api-reference/functions/fetch) option with `fetch` for caching external API requests:\n00038| \n00039| ```tsx\n00040| fetch(url, { next: { tags: ['posts'] } })\n00041| ```\n00042| \n00043| - Using [`cacheTag`](/docs/app/api-reference/functions/cacheTag) inside cached functions or components with the `'use cache'` directive:\n00044| \n00045| ```tsx\n00046| import { cacheTag } from 'next/cache'\n00047| \n00048| async function getData() {\n00049| 'use cache'\n00050| cacheTag('posts')\n00051| // ...\n00052| }\n00053| ```\n00054| \n00055| > **Good to know**: The single-argument form `revalidateTag(tag)` is deprecated. It currently works if TypeScript errors are suppressed, but this behavior may be removed in a future version. Update to the two-argument signature.\n00056| \n00057| ## Returns\n00058| \n00059| `revalidateTag` does not return a value.\n00060| \n00061| ## Relationship with `revalidatePath`\n00062| \n00063| `revalidateTag` invalidates data with specific tags across all pages that use those tags, while [`revalidatePath`](/docs/app/api-reference/functions/revalidatePath) invalidates specific page or layout paths.\n00064| \n00065| > **Good to know**: These functions serve different purposes and may need to be used together for comprehensive data consistency. For detailed examples and considerations, see [relationship with revalidateTag and updateTag](/docs/app/api-reference/functions/revalidatePath#relationship-with-revalidatetag-and-updatetag) for more information.\n00066| \n00067| ## Examples\n00068| \n00069| The following examples demonstrate how to use `revalidateTag` in different contexts. In both cases, we're using `profile=\"max\"` to mark data as stale and use stale-while-revalidate semantics, which is the recommended approach for most use cases.\n00070| \n00071| ### Server Action\n00072| \n00073| ```ts filename=\"app/actions.ts\" switcher\n00074| 'use server'\n00075| \n00076| import { revalidateTag } from 'next/cache'\n00077| \n00078| export default async function submit() {\n00079| await addPost()\n00080| revalidateTag('posts', 'max')\n00081| }\n00082| ```\n00083| \n00084| ```js filename=\"app/actions.js\" switcher\n00085| 'use server'\n00086| \n00087| import { revalidateTag } from 'next/cache'\n00088| \n00089| export default async function submit() {\n00090| await addPost()\n00091| revalidateTag('posts', 'max')\n00092| }\n00093| ```\n00094| \n00095| ### Route Handler\n00096| \n00097| ```ts filename=\"app/api/revalidate/route.ts\" switcher\n00098| import type { NextRequest } from 'next/server'\n00099| import { revalidateTag } from 'next/cache'\n00100| \n00101| export async function GET(request: NextRequest) {\n00102| const tag = request.nextUrl.searchParams.get('tag')\n00103| \n00104| if (tag) {\n00105| revalidateTag(tag, 'max')\n00106| return Response.json({ revalidated: true, now: Date.now() })\n00107| }\n00108| \n00109| return Response.json({\n00110| revalidated: false,\n00111| now: Date.now(),\n00112| message: 'Missing tag to revalidate',\n00113| })\n00114| }\n00115| ```\n00116| \n00117| ```js filename=\"app/api/revalidate/route.js\" switcher\n00118| import { revalidateTag } from 'next/cache'\n00119| \n00120| export async function GET(request) {\n00121| const tag = request.nextUrl.searchParams.get('tag')\n00122| \n00123| if (tag) {\n00124| revalidateTag(tag, 'max')\n00125| return Response.json({ revalidated: true, now: Date.now() })\n00126| }\n00127| \n00128| return Response.json({\n00129| revalidated: false,\n00130| now: Date.now(),\n00131| message: 'Missing tag to revalidate',\n00132| })\n00133| }\n00134| ```\n00135| \n00136| > **Good to know**: For webhooks or third-party services that need immediate expiration, you can pass `{ expire: 0 }` as the second argument: `revalidateTag(tag, { expire: 0 })`. This pattern is necessary when external systems call your Route Handlers and require data to expire immediately. For all other cases, it's recommended to use [`updateTag`](/docs/app/api-reference/functions/updateTag) in Server Actions for immediate updates instead.\n00137| \n\n(End of file - total 137 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md"
+ },
+ "output": "\n00001| ---\n00002| title: revalidateTag\n00003| description: API Reference for the revalidateTag function.\n00004| ---\n00005| \n00006| `revalidateTag` allows you to invalidate cached data on-demand for a specific cache tag.\n00007| \n00008| This function is ideal for content where a slight delay in updates is acceptable, such as blog posts, product catalogs, or documentation. Users receive stale content while fresh data loads in the background.\n00009| \n00010| ## Usage\n00011| \n00012| `revalidateTag` can be called in Server Functions and Route Handlers.\n00013| \n00014| `revalidateTag` cannot be called in Client Components or Proxy, as it only works in server environments.\n00015| \n00016| ### Revalidation Behavior\n00017| \n00018| The revalidation behavior depends on whether you provide the second argument:\n00019| \n00020| - **With `profile=\"max\"` (recommended)**: The tag entry is marked as stale, and the next time a resource with that tag is visited, it will use stale-while-revalidate semantics. This means the stale content is served while fresh content is fetched in the background.\n00021| - **With a custom cache life profile**: For advanced usage, you can specify any cache life profile that your application has defined, allowing for custom revalidation behaviors tailored to your specific caching requirements.\n00022| - **Without the second argument (deprecated)**: The tag entry is expired immediately, and the next request to that resource will be a blocking revalidate/cache miss. This behavior is now deprecated, and you should either use `profile=\"max\"` or migrate to [`updateTag`](/docs/app/api-reference/functions/updateTag).\n00023| \n00024| > **Good to know**: When using `profile=\"max\"`, `revalidateTag` marks tagged data as stale, but fresh data is only fetched when pages using that tag are next visited. This means calling `revalidateTag` will not immediately trigger many revalidations at once. The invalidation only happens when any page using that tag is next visited.\n00025| \n00026| ## Parameters\n00027| \n00028| ```ts\n00029| revalidateTag(tag: string, profile: string | { expire?: number }): void;\n00030| ```\n00031| \n00032| - `tag`: A string representing the cache tag associated with the data you want to revalidate. Must not exceed 256 characters. This value is case-sensitive.\n00033| - `profile`: A string that specifies the revalidation behavior. The recommended value is `\"max\"` which provides stale-while-revalidate semantics, or any of the other default or custom profiles defined in [`cacheLife`](/docs/app/api-reference/config/next-config-js/cacheLife). Alternatively, you can pass an object with an `expire` property for custom expiration behavior.\n00034| \n00035| Tags must first be assigned to cached data. You can do this in two ways:\n00036| \n00037| - Using the [`next.tags`](/docs/app/api-reference/functions/fetch) option with `fetch` for caching external API requests:\n00038| \n00039| ```tsx\n00040| fetch(url, { next: { tags: ['posts'] } })\n00041| ```\n00042| \n00043| - Using [`cacheTag`](/docs/app/api-reference/functions/cacheTag) inside cached functions or components with the `'use cache'` directive:\n00044| \n00045| ```tsx\n00046| import { cacheTag } from 'next/cache'\n00047| \n00048| async function getData() {\n00049| 'use cache'\n00050| cacheTag('posts')\n00051| // ...\n00052| }\n00053| ```\n00054| \n00055| > **Good to know**: The single-argument form `revalidateTag(tag)` is deprecated. It currently works if TypeScript errors are suppressed, but this behavior may be removed in a future version. Update to the two-argument signature.\n00056| \n00057| ## Returns\n00058| \n00059| `revalidateTag` does not return a value.\n00060| \n00061| ## Relationship with `revalidatePath`\n00062| \n00063| `revalidateTag` invalidates data with specific tags across all pages that use those tags, while [`revalidatePath`](/docs/app/api-reference/functions/revalidatePath) invalidates specific page or layout paths.\n00064| \n00065| > **Good to know**: These functions serve different purposes and may need to be used together for comprehensive data consistency. For detailed examples and considerations, see [relationship with revalidateTag and updateTag](/docs/app/api-reference/functions/revalidatePath#relationship-with-revalidatetag-and-updatetag) for more information.\n00066| \n00067| ## Examples\n00068| \n00069| The following examples demonstrate how to use `revalidateTag` in different contexts. In both cases, we're using `profile=\"max\"` to mark data as stale and use stale-while-revalidate semantics, which is the recommended approach for most use cases.\n00070| \n00071| ### Server Action\n00072| \n00073| ```ts filename=\"app/actions.ts\" switcher\n00074| 'use server'\n00075| \n00076| import { revalidateTag } from 'next/cache'\n00077| \n00078| export default async function submit() {\n00079| await addPost()\n00080| revalidateTag('posts', 'max')\n00081| }\n00082| ```\n00083| \n00084| ```js filename=\"app/actions.js\" switcher\n00085| 'use server'\n00086| \n00087| import { revalidateTag } from 'next/cache'\n00088| \n00089| export default async function submit() {\n00090| await addPost()\n00091| revalidateTag('posts', 'max')\n00092| }\n00093| ```\n00094| \n00095| ### Route Handler\n00096| \n00097| ```ts filename=\"app/api/revalidate/route.ts\" switcher\n00098| import type { NextRequest } from 'next/server'\n00099| import { revalidateTag } from 'next/cache'\n00100| \n00101| export async function GET(request: NextRequest) {\n00102| const tag = request.nextUrl.searchParams.get('tag')\n00103| \n00104| if (tag) {\n00105| revalidateTag(tag, 'max')\n00106| return Response.json({ revalidated: true, now: Date.now() })\n00107| }\n00108| \n00109| return Response.json({\n00110| revalidated: false,\n00111| now: Date.now(),\n00112| message: 'Missing tag to revalidate',\n00113| })\n00114| }\n00115| ```\n00116| \n00117| ```js filename=\"app/api/revalidate/route.js\" switcher\n00118| import { revalidateTag } from 'next/cache'\n00119| \n00120| export async function GET(request) {\n00121| const tag = request.nextUrl.searchParams.get('tag')\n00122| \n00123| if (tag) {\n00124| revalidateTag(tag, 'max')\n00125| return Response.json({ revalidated: true, now: Date.now() })\n00126| }\n00127| \n00128| return Response.json({\n00129| revalidated: false,\n00130| now: Date.now(),\n00131| message: 'Missing tag to revalidate',\n00132| })\n00133| }\n00134| ```\n00135| \n00136| > **Good to know**: For webhooks or third-party services that need immediate expiration, you can pass `{ expire: 0 }` as the second argument: `revalidateTag(tag, { expire: 0 })`. This pattern is necessary when external systems call your Route Handlers and require data to expire immediately. For all other cases, it's recommended to use [`updateTag`](/docs/app/api-reference/functions/updateTag) in Server Actions for immediate updates instead.\n00137| \n\n(End of file - total 137 lines)\n",
+ "title": "node_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md",
+ "metadata": {
+ "preview": "---\ntitle: revalidateTag\ndescription: API Reference for the revalidateTag function.\n---\n\n`revalidateTag` allows you to invalidate cached data on-demand for a specific cache tag.\n\nThis function is ideal for content where a slight delay in updates is acceptable, such as blog posts, product catalogs, or documentation. Users receive stale content while fresh data loads in the background.\n\n## Usage\n\n`revalidateTag` can be called in Server Functions and Route Handlers.\n\n`revalidateTag` cannot be called in Client Components or Proxy, as it only works in server environments.\n\n### Revalidation Behavior\n\nThe revalidation behavior depends on whether you provide the second argument:\n\n- **With `profile=\"max\"` (recommended)**: The tag entry is marked as stale, and the next time a resource with that tag is visited, it will use stale-while-revalidate semantics. This means the stale content is served while fresh content is fetched in the background."
+ },
+ "time": {
+ "start": 1781392535483,
+ "end": 1781392535488
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:35.520Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "args": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/02-guides/forms.md",
+ "_extractedPath": "/workspace/node_modules/next/dist/docs/01-app/02-guides/forms.md"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392535520,
+ "sessionID": "ses_13cbb78f4ffeW1oPoj0co3q1Fm",
+ "part": {
+ "id": "prt_ec344efbe001Xj1gPnsgwndG6X",
+ "sessionID": "ses_13cbb78f4ffeW1oPoj0co3q1Fm",
+ "messageID": "msg_ec344e00b001jo6Yj8btd2NmTi",
+ "type": "tool",
+ "callID": "read_17",
+ "tool": "read",
+ "state": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/02-guides/forms.md"
+ },
+ "output": "\n00001| ---\n00002| title: How to create forms with Server Actions\n00003| nav_title: Forms\n00004| description: Learn how to create forms in Next.js with React Server Actions.\n00005| ---\n00006| \n00007| React Server Actions are [Server Functions](https://react.dev/reference/rsc/server-functions) that execute on the server. They can be called in Server and Client Components to handle form submissions. This guide will walk you through how to create forms in Next.js with Server Actions.\n00008| \n00009| > [!WARNING]\n00010| > Always verify [authentication and authorization](/docs/app/guides/authentication) inside each Server Action, even if the form is only rendered on an authenticated page. See the [Data Security guide](/docs/app/guides/data-security) for more details.\n00011| \n00012| ## How it works\n00013| \n00014| React extends the HTML [`
`](https://developer.mozilla.org/docs/Web/HTML/Element/form) element to allow Server Actions to be invoked with the [`action`](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/form#action) attribute.\n00015| \n00016| When used in a form, the function automatically receives the [`FormData`](https://developer.mozilla.org/docs/Web/API/FormData/FormData) object. You can then extract the data using the native [`FormData` methods](https://developer.mozilla.org/en-US/docs/Web/API/FormData#instance_methods):\n00017| \n00018| ```tsx filename=\"app/invoices/page.tsx\" switcher\n00019| import { auth } from '@/lib/auth'\n00020| \n00021| export default function Page() {\n00022| async function createInvoice(formData: FormData) {\n00023| 'use server'\n00024| \n00025| const session = await auth()\n00026| if (!session?.user) {\n00027| throw new Error('Unauthorized')\n00028| }\n00029| \n00030| const rawFormData = {\n00031| customerId: formData.get('customerId'),\n00032| amount: formData.get('amount'),\n00033| status: formData.get('status'),\n00034| }\n00035| \n00036| // mutate data\n00037| // revalidate the cache\n00038| }\n00039| \n00040| return
\n00067| }\n00068| ```\n00069| \n00070| > **Good to know:** When working with forms that have multiple fields, use JavaScript's [`Object.fromEntries()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/fromEntries). For example: `const rawFormData = Object.fromEntries(formData)`. Note that this object will contain extra properties prefixed with `$ACTION_`.\n00071| \n00072| ## Passing additional arguments\n00073| \n00074| Outside of form fields, you can pass additional arguments to a Server Function using the JavaScript [`bind`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) method. For example, to pass the `userId` argument to the `updateUser` Server Function:\n00075| \n00076| ```tsx filename=\"app/client-component.tsx\" highlight={6} switcher\n00077| 'use client'\n00078| \n00079| import { updateUser } from './actions'\n00080| \n00081| export function UserProfile({ userId }: { userId: string }) {\n00082| const updateUserWithId = updateUser.bind(null, userId)\n00083| \n00084| return (\n00085|
\n00106| )\n00107| }\n00108| ```\n00109| \n00110| The Server Function will receive the `userId` as an additional argument:\n00111| \n00112| ```ts filename=\"app/actions.ts\" switcher\n00113| 'use server'\n00114| \n00115| export async function updateUser(userId: string, formData: FormData) {}\n00116| ```\n00117| \n00118| ```js filename=\"app/actions.js\" switcher\n00119| 'use server'\n00120| \n00121| export async function updateUser(userId, formData) {}\n00122| ```\n00123| \n00124| > **Good to know**:\n00125| >\n00126| > - An alternative is to pass arguments as hidden input fields in the form (e.g. ``). However, the value will be part of the rendered HTML and will not be encoded.\n00127| > - `bind` works in both Server and Client Components and supports progressive enhancement.\n00128| \n00129| ## Form validation\n00130| \n00131| Forms can be validated on the client or server.\n00132| \n00133| - For **client-side validation**, you can use the HTML attributes like `required` and `type=\"email\"` for basic validation.\n00134| - For **server-side validation**, you can use a library like [zod](https://zod.dev/) to validate the form fields. For example:\n00135| \n00136| ```tsx filename=\"app/actions.ts\" switcher\n00137| 'use server'\n00138| \n00139| import { z } from 'zod'\n00140| \n00141| const schema = z.object({\n00142| email: z.string({\n00143| invalid_type_error: 'Invalid Email',\n00144| }),\n00145| })\n00146| \n00147| export default async function createUser(formData: FormData) {\n00148| const validatedFields = schema.safeParse({\n00149| email: formData.get('email'),\n00150| })\n00151| \n00152| // Return early if the form data is invalid\n00153| if (!validatedFields.success) {\n00154| return {\n00155| errors: validatedFields.error.flatten().fieldErrors,\n00156| }\n00157| }\n00158| \n00159| // Mutate data\n00160| }\n00161| ```\n00162| \n00163| ```jsx filename=\"app/actions.js\" switcher\n00164| 'use server'\n00165| \n00166| import { z } from 'zod'\n00167| \n00168| const schema = z.object({\n00169| email: z.string({\n00170| invalid_type_error: 'Invalid Email',\n00171| }),\n00172| })\n00173| \n00174| export default async function createUser(formData) {\n00175| const validatedFields = schema.safeParse({\n00176| email: formData.get('email'),\n00177| })\n00178| \n00179| // Return early if the form data is invalid\n00180| if (!validatedFields.success) {\n00181| return {\n00182| errors: validatedFields.error.flatten().fieldErrors,\n00183| }\n00184| }\n00185| \n00186| // Mutate data\n00187| }\n00188| ```\n00189| \n00190| ## Validation errors\n00191| \n00192| To display validation errors or messages, turn the component that defines the `
` into a Client Component and use React [`useActionState`](https://react.dev/reference/react/useActionState).\n00193| \n00194| When using `useActionState`, the Server function signature will change to receive a new `prevState` or `initialState` parameter as its first argument.\n00195| \n00196| ```tsx filename=\"app/actions.ts\" highlight={5} switcher\n00197| 'use server'\n00198| \n00199| import { z } from 'zod'\n00200| \n00201| export async function createUser(initialState: any, formData: FormData) {\n00202| const validatedFields = schema.safeParse({\n00203| email: formData.get('email'),\n00204| })\n00205| // ...\n00206| }\n00207| ```\n00208| \n00209| ```jsx filename=\"app/actions.ts\" highlight={7} switcher\n00210| 'use server'\n00211| \n00212| import { z } from 'zod'\n00213| \n00214| // ...\n00215| \n00216| export async function createUser(initialState, formData) {\n00217| const validatedFields = schema.safeParse({\n00218| email: formData.get('email'),\n00219| })\n00220| // ...\n00221| }\n00222| ```\n00223| \n00224| You can then conditionally render the error message based on the `state` object.\n00225| \n00226| ```tsx filename=\"app/ui/signup.tsx\" highlight={11,18-20} switcher\n00227| 'use client'\n00228| \n00229| import { useActionState } from 'react'\n00230| import { createUser } from '@/app/actions'\n00231| \n00232| const initialState = {\n00233| message: '',\n00234| }\n00235| \n00236| export function Signup() {\n00237| const [state, formAction, pending] = useActionState(createUser, initialState)\n00238| \n00239| return (\n00240|
\n00272| )\n00273| }\n00274| ```\n00275| \n00276| ## Pending states\n00277| \n00278| The [`useActionState`](https://react.dev/reference/react/useActionState) hook exposes a `pending` boolean that can be used to show a loading indicator or disable the submit button while the action is being executed.\n00279| \n00280| ```tsx filename=\"app/ui/signup.tsx\" highlight={7,12} switcher\n00281| 'use client'\n00282| \n00283| import { useActionState } from 'react'\n00284| import { createUser } from '@/app/actions'\n00285| \n00286| export function Signup() {\n00287| const [state, formAction, pending] = useActionState(createUser, initialState)\n00288| \n00289| return (\n00290|
\n00291| {/* Other form elements */}\n00292| Sign up\n00293|
\n00309| {/* Other form elements */}\n00310| Sign up\n00311|
\n00312| )\n00313| }\n00314| ```\n00315| \n00316| Alternatively, you can use the [`useFormStatus`](https://react.dev/reference/react-dom/hooks/useFormStatus) hook to show a loading indicator while the action is being executed. When using this hook, you'll need to create a separate component to render the loading indicator. For example, to disable the button when the action is pending:\n00317| \n00318| ```tsx filename=\"app/ui/button.tsx\" highlight={6} switcher\n00319| 'use client'\n00320| \n00321| import { useFormStatus } from 'react-dom'\n00322| \n00323| export function SubmitButton() {\n00324| const { pending } = useFormStatus()\n00325| \n00326| return (\n00327| \n00328| Sign Up\n00329| \n00330| )\n00331| }\n00332| ```\n00333| \n00334| ```jsx filename=\"app/ui/button.js\" highlight={6} switcher\n00335| 'use client'\n00336| \n00337| import { useFormStatus } from 'react-dom'\n00338| \n00339| export function SubmitButton() {\n00340| const { pending } = useFormStatus()\n00341| \n00342| return (\n00343| \n00344| Sign Up\n00345| \n00346| )\n00347| }\n00348| ```\n00349| \n00350| You can then nest the `SubmitButton` component inside the form:\n00351| \n00352| ```tsx filename=\"app/ui/signup.tsx\" switcher\n00353| import { SubmitButton } from './button'\n00354| import { createUser } from '@/app/actions'\n00355| \n00356| export function Signup() {\n00357| return (\n00358|
\n00359| {/* Other form elements */}\n00360| \n00361|
\n00362| )\n00363| }\n00364| ```\n00365| \n00366| ```jsx filename=\"app/ui/signup.js\" switcher\n00367| import { SubmitButton } from './button'\n00368| import { createUser } from '@/app/actions'\n00369| \n00370| export function Signup() {\n00371| return (\n00372|
\n00373| {/* Other form elements */}\n00374| \n00375|
\n00376| )\n00377| }\n00378| ```\n00379| \n00380| > **Good to know:** In React 19, `useFormStatus` includes additional keys on the returned object, like data, method, and action. If you are not using React 19, only the `pending` key is available.\n00381| \n00382| ## Optimistic updates\n00383| \n00384| You can use the React [`useOptimistic`](https://react.dev/reference/react/useOptimistic) hook to optimistically update the UI before the Server Function finishes executing, rather than waiting for the response:\n00385| \n00386| ```tsx filename=\"app/page.tsx\" switcher\n00387| 'use client'\n00388| \n00389| import { useOptimistic } from 'react'\n00390| import { send } from './actions'\n00391| \n00392| type Message = {\n00393| message: string\n00394| }\n00395| \n00396| export function Thread({ messages }: { messages: Message[] }) {\n00397| const [optimisticMessages, addOptimisticMessage] = useOptimistic<\n00398| Message[],\n00399| string\n00400| >(messages, (state, newMessage) => [...state, { message: newMessage }])\n00401| \n00402| const formAction = async (formData: FormData) => {\n00403| const message = formData.get('message') as string\n00404| addOptimisticMessage(message)\n00405| await send(message)\n00406| }\n00407| \n00408| return (\n00409|
\n00450| )\n00451| }\n00452| ```\n00453| \n00454| ## Nested form elements\n00455| \n00456| You can call Server Actions in elements nested inside `
` such as ``, ``, and ``. These elements accept the `formAction` prop or event handlers.\n00457| \n00458| This is useful in cases where you want to call multiple Server Actions within a form. For example, you can create a specific `` element for saving a post draft in addition to publishing it. See the [React `
` docs](https://react.dev/reference/react-dom/components/form#handling-multiple-submission-types) for more information.\n00459| \n00460| ## Programmatic form submission\n00461| \n00462| You can trigger a form submission programmatically using the [`requestSubmit()`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/requestSubmit) method. For example, when the user submits a form using the `⌘` + `Enter` keyboard shortcut, you can listen for the `onKeyDown` event:\n00463| \n00464| ```tsx filename=\"app/entry.tsx\" switcher\n00465| 'use client'\n00466| \n00467| export function Entry() {\n00468| const handleKeyDown = (e: React.KeyboardEvent) => {\n00469| if (\n00470| (e.ctrlKey || e.metaKey) &&\n00471| (e.key === 'Enter' || e.key === 'NumpadEnter')\n00472| ) {\n00473| e.preventDefault()\n00474| e.currentTarget.form?.requestSubmit()\n00475| }\n00476| }\n00477| \n00478| return (\n00479|
\n00504| )\n00505| }\n00506| ```\n00507| \n00508| This will trigger the submission of the nearest `
` ancestor, which will invoke the Server Function.\n00509| \n\n(End of file - total 509 lines)\n
",
+ "title": "node_modules/next/dist/docs/01-app/02-guides/forms.md",
+ "metadata": {
+ "preview": "---\ntitle: How to create forms with Server Actions\nnav_title: Forms\ndescription: Learn how to create forms in Next.js with React Server Actions.\n---\n\nReact Server Actions are [Server Functions](https://react.dev/reference/rsc/server-functions) that execute on the server. They can be called in Server and Client Components to handle form submissions. This guide will walk you through how to create forms in Next.js with Server Actions.\n\n> [!WARNING]\n> Always verify [authentication and authorization](/docs/app/guides/authentication) inside each Server Action, even if the form is only rendered on an authenticated page. See the [Data Security guide](/docs/app/guides/data-security) for more details.\n\n## How it works\n\nReact extends the HTML [`
`](https://developer.mozilla.org/docs/Web/HTML/Element/form) element to allow Server Actions to be invoked with the [`action`](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/form#action) attribute.\n\nWhen used in a form, the function automatically receives the [`FormData`](https://developer.mozilla.org/docs/Web/API/FormData/FormData) object. You can then extract the data using the native [`FormData` methods](https://developer.mozilla.org/en-US/docs/Web/API/FormData#instance_methods):\n\n```tsx filename=\"app/invoices/page.tsx\" switcher\nimport { auth } from '@/lib/auth'\n"
+ },
+ "time": {
+ "start": 1781392535508,
+ "end": 1781392535514
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:35.520Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| ---\n00002| title: How to create forms with Server Actions\n00003| nav_title: Forms\n00004| description: Learn how to create forms in Next.js with React Server Actions.\n00005| ---\n00006| \n00007| React Server Actions are [Server Functions](https://react.dev/reference/rsc/server-functions) that execute on the server. They can be called in Server and Client Components to handle form submissions. This guide will walk you through how to create forms in Next.js with Server Actions.\n00008| \n00009| > [!WARNING]\n00010| > Always verify [authentication and authorization](/docs/app/guides/authentication) inside each Server Action, even if the form is only rendered on an authenticated page. See the [Data Security guide](/docs/app/guides/data-security) for more details.\n00011| \n00012| ## How it works\n00013| \n00014| React extends the HTML [`
`](https://developer.mozilla.org/docs/Web/HTML/Element/form) element to allow Server Actions to be invoked with the [`action`](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/form#action) attribute.\n00015| \n00016| When used in a form, the function automatically receives the [`FormData`](https://developer.mozilla.org/docs/Web/API/FormData/FormData) object. You can then extract the data using the native [`FormData` methods](https://developer.mozilla.org/en-US/docs/Web/API/FormData#instance_methods):\n00017| \n00018| ```tsx filename=\"app/invoices/page.tsx\" switcher\n00019| import { auth } from '@/lib/auth'\n00020| \n00021| export default function Page() {\n00022| async function createInvoice(formData: FormData) {\n00023| 'use server'\n00024| \n00025| const session = await auth()\n00026| if (!session?.user) {\n00027| throw new Error('Unauthorized')\n00028| }\n00029| \n00030| const rawFormData = {\n00031| customerId: formData.get('customerId'),\n00032| amount: formData.get('amount'),\n00033| status: formData.get('status'),\n00034| }\n00035| \n00036| // mutate data\n00037| // revalidate the cache\n00038| }\n00039| \n00040| return
\n00067| }\n00068| ```\n00069| \n00070| > **Good to know:** When working with forms that have multiple fields, use JavaScript's [`Object.fromEntries()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/fromEntries). For example: `const rawFormData = Object.fromEntries(formData)`. Note that this object will contain extra properties prefixed with `$ACTION_`.\n00071| \n00072| ## Passing additional arguments\n00073| \n00074| Outside of form fields, you can pass additional arguments to a Server Function using the JavaScript [`bind`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) method. For example, to pass the `userId` argument to the `updateUser` Server Function:\n00075| \n00076| ```tsx filename=\"app/client-component.tsx\" highlight={6} switcher\n00077| 'use client'\n00078| \n00079| import { updateUser } from './actions'\n00080| \n00081| export function UserProfile({ userId }: { userId: string }) {\n00082| const updateUserWithId = updateUser.bind(null, userId)\n00083| \n00084| return (\n00085|
\n00106| )\n00107| }\n00108| ```\n00109| \n00110| The Server Function will receive the `userId` as an additional argument:\n00111| \n00112| ```ts filename=\"app/actions.ts\" switcher\n00113| 'use server'\n00114| \n00115| export async function updateUser(userId: string, formData: FormData) {}\n00116| ```\n00117| \n00118| ```js filename=\"app/actions.js\" switcher\n00119| 'use server'\n00120| \n00121| export async function updateUser(userId, formData) {}\n00122| ```\n00123| \n00124| > **Good to know**:\n00125| >\n00126| > - An alternative is to pass arguments as hidden input fields in the form (e.g. ``). However, the value will be part of the rendered HTML and will not be encoded.\n00127| > - `bind` works in both Server and Client Components and supports progressive enhancement.\n00128| \n00129| ## Form validation\n00130| \n00131| Forms can be validated on the client or server.\n00132| \n00133| - For **client-side validation**, you can use the HTML attributes like `required` and `type=\"email\"` for basic validation.\n00134| - For **server-side validation**, you can use a library like [zod](https://zod.dev/) to validate the form fields. For example:\n00135| \n00136| ```tsx filename=\"app/actions.ts\" switcher\n00137| 'use server'\n00138| \n00139| import { z } from 'zod'\n00140| \n00141| const schema = z.object({\n00142| email: z.string({\n00143| invalid_type_error: 'Invalid Email',\n00144| }),\n00145| })\n00146| \n00147| export default async function createUser(formData: FormData) {\n00148| const validatedFields = schema.safeParse({\n00149| email: formData.get('email'),\n00150| })\n00151| \n00152| // Return early if the form data is invalid\n00153| if (!validatedFields.success) {\n00154| return {\n00155| errors: validatedFields.error.flatten().fieldErrors,\n00156| }\n00157| }\n00158| \n00159| // Mutate data\n00160| }\n00161| ```\n00162| \n00163| ```jsx filename=\"app/actions.js\" switcher\n00164| 'use server'\n00165| \n00166| import { z } from 'zod'\n00167| \n00168| const schema = z.object({\n00169| email: z.string({\n00170| invalid_type_error: 'Invalid Email',\n00171| }),\n00172| })\n00173| \n00174| export default async function createUser(formData) {\n00175| const validatedFields = schema.safeParse({\n00176| email: formData.get('email'),\n00177| })\n00178| \n00179| // Return early if the form data is invalid\n00180| if (!validatedFields.success) {\n00181| return {\n00182| errors: validatedFields.error.flatten().fieldErrors,\n00183| }\n00184| }\n00185| \n00186| // Mutate data\n00187| }\n00188| ```\n00189| \n00190| ## Validation errors\n00191| \n00192| To display validation errors or messages, turn the component that defines the `
` into a Client Component and use React [`useActionState`](https://react.dev/reference/react/useActionState).\n00193| \n00194| When using `useActionState`, the Server function signature will change to receive a new `prevState` or `initialState` parameter as its first argument.\n00195| \n00196| ```tsx filename=\"app/actions.ts\" highlight={5} switcher\n00197| 'use server'\n00198| \n00199| import { z } from 'zod'\n00200| \n00201| export async function createUser(initialState: any, formData: FormData) {\n00202| const validatedFields = schema.safeParse({\n00203| email: formData.get('email'),\n00204| })\n00205| // ...\n00206| }\n00207| ```\n00208| \n00209| ```jsx filename=\"app/actions.ts\" highlight={7} switcher\n00210| 'use server'\n00211| \n00212| import { z } from 'zod'\n00213| \n00214| // ...\n00215| \n00216| export async function createUser(initialState, formData) {\n00217| const validatedFields = schema.safeParse({\n00218| email: formData.get('email'),\n00219| })\n00220| // ...\n00221| }\n00222| ```\n00223| \n00224| You can then conditionally render the error message based on the `state` object.\n00225| \n00226| ```tsx filename=\"app/ui/signup.tsx\" highlight={11,18-20} switcher\n00227| 'use client'\n00228| \n00229| import { useActionState } from 'react'\n00230| import { createUser } from '@/app/actions'\n00231| \n00232| const initialState = {\n00233| message: '',\n00234| }\n00235| \n00236| export function Signup() {\n00237| const [state, formAction, pending] = useActionState(createUser, initialState)\n00238| \n00239| return (\n00240|
\n00272| )\n00273| }\n00274| ```\n00275| \n00276| ## Pending states\n00277| \n00278| The [`useActionState`](https://react.dev/reference/react/useActionState) hook exposes a `pending` boolean that can be used to show a loading indicator or disable the submit button while the action is being executed.\n00279| \n00280| ```tsx filename=\"app/ui/signup.tsx\" highlight={7,12} switcher\n00281| 'use client'\n00282| \n00283| import { useActionState } from 'react'\n00284| import { createUser } from '@/app/actions'\n00285| \n00286| export function Signup() {\n00287| const [state, formAction, pending] = useActionState(createUser, initialState)\n00288| \n00289| return (\n00290|
\n00291| {/* Other form elements */}\n00292| Sign up\n00293|
\n00309| {/* Other form elements */}\n00310| Sign up\n00311|
\n00312| )\n00313| }\n00314| ```\n00315| \n00316| Alternatively, you can use the [`useFormStatus`](https://react.dev/reference/react-dom/hooks/useFormStatus) hook to show a loading indicator while the action is being executed. When using this hook, you'll need to create a separate component to render the loading indicator. For example, to disable the button when the action is pending:\n00317| \n00318| ```tsx filename=\"app/ui/button.tsx\" highlight={6} switcher\n00319| 'use client'\n00320| \n00321| import { useFormStatus } from 'react-dom'\n00322| \n00323| export function SubmitButton() {\n00324| const { pending } = useFormStatus()\n00325| \n00326| return (\n00327| \n00328| Sign Up\n00329| \n00330| )\n00331| }\n00332| ```\n00333| \n00334| ```jsx filename=\"app/ui/button.js\" highlight={6} switcher\n00335| 'use client'\n00336| \n00337| import { useFormStatus } from 'react-dom'\n00338| \n00339| export function SubmitButton() {\n00340| const { pending } = useFormStatus()\n00341| \n00342| return (\n00343| \n00344| Sign Up\n00345| \n00346| )\n00347| }\n00348| ```\n00349| \n00350| You can then nest the `SubmitButton` component inside the form:\n00351| \n00352| ```tsx filename=\"app/ui/signup.tsx\" switcher\n00353| import { SubmitButton } from './button'\n00354| import { createUser } from '@/app/actions'\n00355| \n00356| export function Signup() {\n00357| return (\n00358|
\n00359| {/* Other form elements */}\n00360| \n00361|
\n00362| )\n00363| }\n00364| ```\n00365| \n00366| ```jsx filename=\"app/ui/signup.js\" switcher\n00367| import { SubmitButton } from './button'\n00368| import { createUser } from '@/app/actions'\n00369| \n00370| export function Signup() {\n00371| return (\n00372|
\n00373| {/* Other form elements */}\n00374| \n00375|
\n00376| )\n00377| }\n00378| ```\n00379| \n00380| > **Good to know:** In React 19, `useFormStatus` includes additional keys on the returned object, like data, method, and action. If you are not using React 19, only the `pending` key is available.\n00381| \n00382| ## Optimistic updates\n00383| \n00384| You can use the React [`useOptimistic`](https://react.dev/reference/react/useOptimistic) hook to optimistically update the UI before the Server Function finishes executing, rather than waiting for the response:\n00385| \n00386| ```tsx filename=\"app/page.tsx\" switcher\n00387| 'use client'\n00388| \n00389| import { useOptimistic } from 'react'\n00390| import { send } from './actions'\n00391| \n00392| type Message = {\n00393| message: string\n00394| }\n00395| \n00396| export function Thread({ messages }: { messages: Message[] }) {\n00397| const [optimisticMessages, addOptimisticMessage] = useOptimistic<\n00398| Message[],\n00399| string\n00400| >(messages, (state, newMessage) => [...state, { message: newMessage }])\n00401| \n00402| const formAction = async (formData: FormData) => {\n00403| const message = formData.get('message') as string\n00404| addOptimisticMessage(message)\n00405| await send(message)\n00406| }\n00407| \n00408| return (\n00409|
\n00450| )\n00451| }\n00452| ```\n00453| \n00454| ## Nested form elements\n00455| \n00456| You can call Server Actions in elements nested inside `
` such as ``, ``, and ``. These elements accept the `formAction` prop or event handlers.\n00457| \n00458| This is useful in cases where you want to call multiple Server Actions within a form. For example, you can create a specific `` element for saving a post draft in addition to publishing it. See the [React `
` docs](https://react.dev/reference/react-dom/components/form#handling-multiple-submission-types) for more information.\n00459| \n00460| ## Programmatic form submission\n00461| \n00462| You can trigger a form submission programmatically using the [`requestSubmit()`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/requestSubmit) method. For example, when the user submits a form using the `⌘` + `Enter` keyboard shortcut, you can listen for the `onKeyDown` event:\n00463| \n00464| ```tsx filename=\"app/entry.tsx\" switcher\n00465| 'use client'\n00466| \n00467| export function Entry() {\n00468| const handleKeyDown = (e: React.KeyboardEvent) => {\n00469| if (\n00470| (e.ctrlKey || e.metaKey) &&\n00471| (e.key === 'Enter' || e.key === 'NumpadEnter')\n00472| ) {\n00473| e.preventDefault()\n00474| e.currentTarget.form?.requestSubmit()\n00475| }\n00476| }\n00477| \n00478| return (\n00479|
\n00504| )\n00505| }\n00506| ```\n00507| \n00508| This will trigger the submission of the nearest `
` ancestor, which will invoke the Server Function.\n00509| \n\n(End of file - total 509 lines)\n
",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/02-guides/forms.md"
+ },
+ "output": "\n00001| ---\n00002| title: How to create forms with Server Actions\n00003| nav_title: Forms\n00004| description: Learn how to create forms in Next.js with React Server Actions.\n00005| ---\n00006| \n00007| React Server Actions are [Server Functions](https://react.dev/reference/rsc/server-functions) that execute on the server. They can be called in Server and Client Components to handle form submissions. This guide will walk you through how to create forms in Next.js with Server Actions.\n00008| \n00009| > [!WARNING]\n00010| > Always verify [authentication and authorization](/docs/app/guides/authentication) inside each Server Action, even if the form is only rendered on an authenticated page. See the [Data Security guide](/docs/app/guides/data-security) for more details.\n00011| \n00012| ## How it works\n00013| \n00014| React extends the HTML [`
`](https://developer.mozilla.org/docs/Web/HTML/Element/form) element to allow Server Actions to be invoked with the [`action`](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/form#action) attribute.\n00015| \n00016| When used in a form, the function automatically receives the [`FormData`](https://developer.mozilla.org/docs/Web/API/FormData/FormData) object. You can then extract the data using the native [`FormData` methods](https://developer.mozilla.org/en-US/docs/Web/API/FormData#instance_methods):\n00017| \n00018| ```tsx filename=\"app/invoices/page.tsx\" switcher\n00019| import { auth } from '@/lib/auth'\n00020| \n00021| export default function Page() {\n00022| async function createInvoice(formData: FormData) {\n00023| 'use server'\n00024| \n00025| const session = await auth()\n00026| if (!session?.user) {\n00027| throw new Error('Unauthorized')\n00028| }\n00029| \n00030| const rawFormData = {\n00031| customerId: formData.get('customerId'),\n00032| amount: formData.get('amount'),\n00033| status: formData.get('status'),\n00034| }\n00035| \n00036| // mutate data\n00037| // revalidate the cache\n00038| }\n00039| \n00040| return
\n00067| }\n00068| ```\n00069| \n00070| > **Good to know:** When working with forms that have multiple fields, use JavaScript's [`Object.fromEntries()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/fromEntries). For example: `const rawFormData = Object.fromEntries(formData)`. Note that this object will contain extra properties prefixed with `$ACTION_`.\n00071| \n00072| ## Passing additional arguments\n00073| \n00074| Outside of form fields, you can pass additional arguments to a Server Function using the JavaScript [`bind`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) method. For example, to pass the `userId` argument to the `updateUser` Server Function:\n00075| \n00076| ```tsx filename=\"app/client-component.tsx\" highlight={6} switcher\n00077| 'use client'\n00078| \n00079| import { updateUser } from './actions'\n00080| \n00081| export function UserProfile({ userId }: { userId: string }) {\n00082| const updateUserWithId = updateUser.bind(null, userId)\n00083| \n00084| return (\n00085|
\n00106| )\n00107| }\n00108| ```\n00109| \n00110| The Server Function will receive the `userId` as an additional argument:\n00111| \n00112| ```ts filename=\"app/actions.ts\" switcher\n00113| 'use server'\n00114| \n00115| export async function updateUser(userId: string, formData: FormData) {}\n00116| ```\n00117| \n00118| ```js filename=\"app/actions.js\" switcher\n00119| 'use server'\n00120| \n00121| export async function updateUser(userId, formData) {}\n00122| ```\n00123| \n00124| > **Good to know**:\n00125| >\n00126| > - An alternative is to pass arguments as hidden input fields in the form (e.g. ``). However, the value will be part of the rendered HTML and will not be encoded.\n00127| > - `bind` works in both Server and Client Components and supports progressive enhancement.\n00128| \n00129| ## Form validation\n00130| \n00131| Forms can be validated on the client or server.\n00132| \n00133| - For **client-side validation**, you can use the HTML attributes like `required` and `type=\"email\"` for basic validation.\n00134| - For **server-side validation**, you can use a library like [zod](https://zod.dev/) to validate the form fields. For example:\n00135| \n00136| ```tsx filename=\"app/actions.ts\" switcher\n00137| 'use server'\n00138| \n00139| import { z } from 'zod'\n00140| \n00141| const schema = z.object({\n00142| email: z.string({\n00143| invalid_type_error: 'Invalid Email',\n00144| }),\n00145| })\n00146| \n00147| export default async function createUser(formData: FormData) {\n00148| const validatedFields = schema.safeParse({\n00149| email: formData.get('email'),\n00150| })\n00151| \n00152| // Return early if the form data is invalid\n00153| if (!validatedFields.success) {\n00154| return {\n00155| errors: validatedFields.error.flatten().fieldErrors,\n00156| }\n00157| }\n00158| \n00159| // Mutate data\n00160| }\n00161| ```\n00162| \n00163| ```jsx filename=\"app/actions.js\" switcher\n00164| 'use server'\n00165| \n00166| import { z } from 'zod'\n00167| \n00168| const schema = z.object({\n00169| email: z.string({\n00170| invalid_type_error: 'Invalid Email',\n00171| }),\n00172| })\n00173| \n00174| export default async function createUser(formData) {\n00175| const validatedFields = schema.safeParse({\n00176| email: formData.get('email'),\n00177| })\n00178| \n00179| // Return early if the form data is invalid\n00180| if (!validatedFields.success) {\n00181| return {\n00182| errors: validatedFields.error.flatten().fieldErrors,\n00183| }\n00184| }\n00185| \n00186| // Mutate data\n00187| }\n00188| ```\n00189| \n00190| ## Validation errors\n00191| \n00192| To display validation errors or messages, turn the component that defines the `
` into a Client Component and use React [`useActionState`](https://react.dev/reference/react/useActionState).\n00193| \n00194| When using `useActionState`, the Server function signature will change to receive a new `prevState` or `initialState` parameter as its first argument.\n00195| \n00196| ```tsx filename=\"app/actions.ts\" highlight={5} switcher\n00197| 'use server'\n00198| \n00199| import { z } from 'zod'\n00200| \n00201| export async function createUser(initialState: any, formData: FormData) {\n00202| const validatedFields = schema.safeParse({\n00203| email: formData.get('email'),\n00204| })\n00205| // ...\n00206| }\n00207| ```\n00208| \n00209| ```jsx filename=\"app/actions.ts\" highlight={7} switcher\n00210| 'use server'\n00211| \n00212| import { z } from 'zod'\n00213| \n00214| // ...\n00215| \n00216| export async function createUser(initialState, formData) {\n00217| const validatedFields = schema.safeParse({\n00218| email: formData.get('email'),\n00219| })\n00220| // ...\n00221| }\n00222| ```\n00223| \n00224| You can then conditionally render the error message based on the `state` object.\n00225| \n00226| ```tsx filename=\"app/ui/signup.tsx\" highlight={11,18-20} switcher\n00227| 'use client'\n00228| \n00229| import { useActionState } from 'react'\n00230| import { createUser } from '@/app/actions'\n00231| \n00232| const initialState = {\n00233| message: '',\n00234| }\n00235| \n00236| export function Signup() {\n00237| const [state, formAction, pending] = useActionState(createUser, initialState)\n00238| \n00239| return (\n00240|
\n00272| )\n00273| }\n00274| ```\n00275| \n00276| ## Pending states\n00277| \n00278| The [`useActionState`](https://react.dev/reference/react/useActionState) hook exposes a `pending` boolean that can be used to show a loading indicator or disable the submit button while the action is being executed.\n00279| \n00280| ```tsx filename=\"app/ui/signup.tsx\" highlight={7,12} switcher\n00281| 'use client'\n00282| \n00283| import { useActionState } from 'react'\n00284| import { createUser } from '@/app/actions'\n00285| \n00286| export function Signup() {\n00287| const [state, formAction, pending] = useActionState(createUser, initialState)\n00288| \n00289| return (\n00290|
\n00291| {/* Other form elements */}\n00292| Sign up\n00293|
\n00309| {/* Other form elements */}\n00310| Sign up\n00311|
\n00312| )\n00313| }\n00314| ```\n00315| \n00316| Alternatively, you can use the [`useFormStatus`](https://react.dev/reference/react-dom/hooks/useFormStatus) hook to show a loading indicator while the action is being executed. When using this hook, you'll need to create a separate component to render the loading indicator. For example, to disable the button when the action is pending:\n00317| \n00318| ```tsx filename=\"app/ui/button.tsx\" highlight={6} switcher\n00319| 'use client'\n00320| \n00321| import { useFormStatus } from 'react-dom'\n00322| \n00323| export function SubmitButton() {\n00324| const { pending } = useFormStatus()\n00325| \n00326| return (\n00327| \n00328| Sign Up\n00329| \n00330| )\n00331| }\n00332| ```\n00333| \n00334| ```jsx filename=\"app/ui/button.js\" highlight={6} switcher\n00335| 'use client'\n00336| \n00337| import { useFormStatus } from 'react-dom'\n00338| \n00339| export function SubmitButton() {\n00340| const { pending } = useFormStatus()\n00341| \n00342| return (\n00343| \n00344| Sign Up\n00345| \n00346| )\n00347| }\n00348| ```\n00349| \n00350| You can then nest the `SubmitButton` component inside the form:\n00351| \n00352| ```tsx filename=\"app/ui/signup.tsx\" switcher\n00353| import { SubmitButton } from './button'\n00354| import { createUser } from '@/app/actions'\n00355| \n00356| export function Signup() {\n00357| return (\n00358|
\n00359| {/* Other form elements */}\n00360| \n00361|
\n00362| )\n00363| }\n00364| ```\n00365| \n00366| ```jsx filename=\"app/ui/signup.js\" switcher\n00367| import { SubmitButton } from './button'\n00368| import { createUser } from '@/app/actions'\n00369| \n00370| export function Signup() {\n00371| return (\n00372|
\n00373| {/* Other form elements */}\n00374| \n00375|
\n00376| )\n00377| }\n00378| ```\n00379| \n00380| > **Good to know:** In React 19, `useFormStatus` includes additional keys on the returned object, like data, method, and action. If you are not using React 19, only the `pending` key is available.\n00381| \n00382| ## Optimistic updates\n00383| \n00384| You can use the React [`useOptimistic`](https://react.dev/reference/react/useOptimistic) hook to optimistically update the UI before the Server Function finishes executing, rather than waiting for the response:\n00385| \n00386| ```tsx filename=\"app/page.tsx\" switcher\n00387| 'use client'\n00388| \n00389| import { useOptimistic } from 'react'\n00390| import { send } from './actions'\n00391| \n00392| type Message = {\n00393| message: string\n00394| }\n00395| \n00396| export function Thread({ messages }: { messages: Message[] }) {\n00397| const [optimisticMessages, addOptimisticMessage] = useOptimistic<\n00398| Message[],\n00399| string\n00400| >(messages, (state, newMessage) => [...state, { message: newMessage }])\n00401| \n00402| const formAction = async (formData: FormData) => {\n00403| const message = formData.get('message') as string\n00404| addOptimisticMessage(message)\n00405| await send(message)\n00406| }\n00407| \n00408| return (\n00409|
\n00450| )\n00451| }\n00452| ```\n00453| \n00454| ## Nested form elements\n00455| \n00456| You can call Server Actions in elements nested inside `
` such as ``, ``, and ``. These elements accept the `formAction` prop or event handlers.\n00457| \n00458| This is useful in cases where you want to call multiple Server Actions within a form. For example, you can create a specific `` element for saving a post draft in addition to publishing it. See the [React `
` docs](https://react.dev/reference/react-dom/components/form#handling-multiple-submission-types) for more information.\n00459| \n00460| ## Programmatic form submission\n00461| \n00462| You can trigger a form submission programmatically using the [`requestSubmit()`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/requestSubmit) method. For example, when the user submits a form using the `⌘` + `Enter` keyboard shortcut, you can listen for the `onKeyDown` event:\n00463| \n00464| ```tsx filename=\"app/entry.tsx\" switcher\n00465| 'use client'\n00466| \n00467| export function Entry() {\n00468| const handleKeyDown = (e: React.KeyboardEvent) => {\n00469| if (\n00470| (e.ctrlKey || e.metaKey) &&\n00471| (e.key === 'Enter' || e.key === 'NumpadEnter')\n00472| ) {\n00473| e.preventDefault()\n00474| e.currentTarget.form?.requestSubmit()\n00475| }\n00476| }\n00477| \n00478| return (\n00479|
\n00504| )\n00505| }\n00506| ```\n00507| \n00508| This will trigger the submission of the nearest `
` ancestor, which will invoke the Server Function.\n00509| \n\n(End of file - total 509 lines)\n
",
+ "title": "node_modules/next/dist/docs/01-app/02-guides/forms.md",
+ "metadata": {
+ "preview": "---\ntitle: How to create forms with Server Actions\nnav_title: Forms\ndescription: Learn how to create forms in Next.js with React Server Actions.\n---\n\nReact Server Actions are [Server Functions](https://react.dev/reference/rsc/server-functions) that execute on the server. They can be called in Server and Client Components to handle form submissions. This guide will walk you through how to create forms in Next.js with Server Actions.\n\n> [!WARNING]\n> Always verify [authentication and authorization](/docs/app/guides/authentication) inside each Server Action, even if the form is only rendered on an authenticated page. See the [Data Security guide](/docs/app/guides/data-security) for more details.\n\n## How it works\n\nReact extends the HTML [`
`](https://developer.mozilla.org/docs/Web/HTML/Element/form) element to allow Server Actions to be invoked with the [`action`](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/form#action) attribute.\n\nWhen used in a form, the function automatically receives the [`FormData`](https://developer.mozilla.org/docs/Web/API/FormData/FormData) object. You can then extract the data using the native [`FormData` methods](https://developer.mozilla.org/en-US/docs/Web/API/FormData#instance_methods):\n\n```tsx filename=\"app/invoices/page.tsx\" switcher\nimport { auth } from '@/lib/auth'\n"
+ },
+ "time": {
+ "start": 1781392535508,
+ "end": 1781392535514
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:39.574Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "args": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache.md",
+ "_extractedPath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache.md"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392539574,
+ "sessionID": "ses_13cbb78f4ffeW1oPoj0co3q1Fm",
+ "part": {
+ "id": "prt_ec344fd82001dU6BLRsTa1F815",
+ "sessionID": "ses_13cbb78f4ffeW1oPoj0co3q1Fm",
+ "messageID": "msg_ec344f01c001hvhl07ctjWtmk2",
+ "type": "tool",
+ "callID": "read_18",
+ "tool": "read",
+ "state": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache.md"
+ },
+ "output": "\n00001| ---\n00002| title: use cache\n00003| description: Learn how to use the \"use cache\" directive to cache data in your Next.js application.\n00004| related:\n00005| title: Related\n00006| description: View related API references.\n00007| links:\n00008| - app/api-reference/directives/use-cache-private\n00009| - app/api-reference/config/next-config-js/cacheComponents\n00010| - app/api-reference/config/next-config-js/cacheLife\n00011| - app/api-reference/config/next-config-js/cacheHandlers\n00012| - app/api-reference/functions/cacheTag\n00013| - app/api-reference/functions/cacheLife\n00014| - app/api-reference/functions/revalidateTag\n00015| ---\n00016| \n00017| The `use cache` directive allows you to mark a route, React component, or a function as cacheable. It can be used at the top of a file to indicate that all exports in the file should be cached, or inline at the top of a function or component to cache the return value. Functions and components that use `use cache` must be async.\n00018| \n00019| > **Good to know:**\n00020| >\n00021| > - To use cookies or headers, read them outside cached scopes and pass values as arguments. This is the preferred pattern.\n00022| > - If the in-memory cache isn't sufficient for runtime data, [`'use cache: remote'`](/docs/app/api-reference/directives/use-cache-remote) allows platforms to provide a dedicated cache handler, though it requires a network roundtrip to check the cache and typically incurs platform fees.\n00023| > - For compliance requirements or when you can't refactor to pass runtime data as arguments to a `use cache` scope, see [`'use cache: private'`](/docs/app/api-reference/directives/use-cache-private).\n00024| \n00025| ## Usage\n00026| \n00027| `use cache` is a Cache Components feature. To enable it, add the [`cacheComponents`](/docs/app/api-reference/config/next-config-js/cacheComponents) option to your `next.config.ts` file:\n00028| \n00029| ```ts filename=\"next.config.ts\" switcher\n00030| import type { NextConfig } from 'next'\n00031| \n00032| const nextConfig: NextConfig = {\n00033| cacheComponents: true,\n00034| }\n00035| \n00036| export default nextConfig\n00037| ```\n00038| \n00039| ```js filename=\"next.config.js\" switcher\n00040| /** @type {import('next').NextConfig} */\n00041| const nextConfig = {\n00042| cacheComponents: true,\n00043| }\n00044| \n00045| module.exports = nextConfig\n00046| ```\n00047| \n00048| Then, add `use cache` at the file, component, or function level. All functions and components using `use cache` must be async. When used at file level, every exported function becomes a cached function and must also be async:\n00049| \n00050| ```tsx\n00051| // File level\n00052| 'use cache'\n00053| \n00054| export default async function Page() {\n00055| // ...\n00056| }\n00057| \n00058| // Component level\n00059| export async function MyComponent() {\n00060| 'use cache'\n00061| return <>>\n00062| }\n00063| \n00064| // Function level\n00065| export async function getData() {\n00066| 'use cache'\n00067| const data = await fetch('/api/data')\n00068| return data\n00069| }\n00070| ```\n00071| \n00072| ## How `use cache` works\n00073| \n00074| ### Cache keys\n00075| \n00076| A cache entry's key is generated using a serialized version of its inputs, which includes:\n00077| \n00078| 1. **Build ID** - Unique per build, changing this invalidates all cache entries. If [`deploymentId`](/docs/app/api-reference/config/next-config-js/deploymentId) is configured, it overrides the build ID for cache key purposes.\n00079| 2. **Function ID** - A secure hash of the function's location and signature in the codebase\n00080| 3. **Serializable arguments** - Props (for components) or function arguments\n00081| 4. **HMR refresh hash** (development only) - Invalidates cache on hot module replacement\n00082| \n00083| When a cached function references variables from outer scopes, those variables are automatically captured and bound as arguments, making them part of the cache key.\n00084| \n00085| ```tsx filename=\"lib/data.ts\"\n00086| async function Component({ userId }: { userId: string }) {\n00087| const getData = async (filter: string) => {\n00088| 'use cache'\n00089| // Cache key includes both userId (from closure) and filter (argument)\n00090| return fetch(`/api/users/${userId}/data?filter=${filter}`)\n00091| }\n00092| \n00093| return getData('active')\n00094| }\n00095| ```\n00096| \n00097| In the snippet above, `userId` is captured from the outer scope and `filter` is passed as an argument, so both become part of the `getData` function's cache key. This means different user and filter combinations will have separate cache entries.\n00098| \n00099| > **Good to know:** When a cached function reads [root parameters](/docs/app/api-reference/functions/next-root-params), only the ones it actually reads become part of its cache key.\n00100| \n00101| ## Serialization\n00102| \n00103| Arguments to cached functions and their return values must be serializable.\n00104| \n00105| For a complete reference, see:\n00106| \n00107| - [Serializable arguments](https://react.dev/reference/rsc/use-server#serializable-parameters-and-return-values) - Uses **React Server Components** serialization\n00108| - [Serializable return types](https://react.dev/reference/rsc/use-client#serializable-types) - Uses **React Client Components** serialization\n00109| \n00110| > **Good to know:** Arguments and return values use different serialization systems. Server Component serialization (for arguments) is more restrictive than Client Component serialization (for return values). This means you can return JSX elements but cannot accept them as arguments unless using pass-through patterns.\n00111| \n00112| ### Supported types\n00113| \n00114| **Arguments:**\n00115| \n00116| - Primitives: `string`, `number`, `boolean`, `null`, `undefined`\n00117| - Plain objects: `{ key: value }`\n00118| - Arrays: `[1, 2, 3]`\n00119| - Dates, Maps, Sets, TypedArrays, ArrayBuffers\n00120| - React elements (as pass-through only)\n00121| \n00122| **Return values:**\n00123| \n00124| - Same as arguments, plus JSX elements\n00125| \n00126| ### Unsupported types\n00127| \n00128| - Class instances\n00129| - Functions (except as pass-through)\n00130| - Symbols, WeakMaps, WeakSets\n00131| - URL instances\n00132| \n00133| ```tsx filename=\"app/components/user-card.tsx\"\n00134| // Valid - primitives and plain objects\n00135| async function UserCard({\n00136| id,\n00137| config,\n00138| }: {\n00139| id: string\n00140| config: { theme: string }\n00141| }) {\n00142| 'use cache'\n00143| return
{id}
\n00144| }\n00145| \n00146| // Invalid - class instance\n00147| async function UserProfile({ user }: { user: UserClass }) {\n00148| 'use cache'\n00149| // Error: Cannot serialize class instance\n00150| return
{user.name}
\n00151| }\n00152| ```\n00153| \n00154| ### Pass-through (non-serializable arguments)\n00155| \n00156| You can accept non-serializable values **as long as you don't introspect them**. This enables composition patterns with `children` and Server Actions:\n00157| \n00158| ```tsx filename=\"app/components/cached-wrapper.tsx\"\n00159| async function CachedWrapper({ children }: { children: ReactNode }) {\n00160| 'use cache'\n00161| // Don't read or modify children - just pass it through\n00162| return (\n00163|
\n00164| Cached Header\n00165| {children}\n00166|
\n00167| )\n00168| }\n00169| \n00170| // Usage: children can be dynamic\n00171| export default function Page() {\n00172| return (\n00173| \n00174| {/* Not cached, passed through */}\n00175| \n00176| )\n00177| }\n00178| ```\n00179| \n00180| You can also pass Server Actions through cached components:\n00181| \n00182| ```tsx filename=\"app/components/cached-form.tsx\"\n00183| async function CachedForm({ action }: { action: () => Promise }) {\n00184| 'use cache'\n00185| // Don't call action here - just pass it through\n00186| return
{/* ... */}
\n00187| }\n00188| ```\n00189| \n00190| ## Constraints\n00191| \n00192| Cached functions execute in an isolated environment. The following constraints ensure cache behavior remains predictable and secure.\n00193| \n00194| ### Request-time APIs\n00195| \n00196| Cached functions and components **cannot** directly access runtime APIs like `cookies()`, `headers()`, or `searchParams`. Instead, read these values outside the cached scope and pass them as arguments.\n00197| \n00198| ### Runtime caching considerations\n00199| \n00200| While `use cache` is designed primarily to include uncached data in the static shell, it can also cache data at runtime using in-memory LRU (Least Recently Used) storage.\n00201| \n00202| With the default in-memory handler, runtime cache behavior depends on your hosting environment:\n00203| \n00204| | Environment | Runtime Caching Behavior |\n00205| | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n00206| | **Serverless** | Cache entries typically don't persist across requests (each request can be a different instance), or during revalidation. Build-time caching works normally. |\n00207| | **Self-hosted** | Cache entries persist across requests. Control cache size with [`cacheMaxMemorySize`](/docs/app/api-reference/config/next-config-js/incrementalCacheHandlerPath). |\n00208| \n00209| For example, in a serverless environment, a cached function shared by two pages executes on each static shell revalidation, whereas in self-hosted or environments with persistent memory, the cached output is reused if it's still fresh.\n00210| \n00211| If the default in-memory cache isn't enough, consider **[`use cache: remote`](/docs/app/api-reference/directives/use-cache-remote)** which allows platforms to provide a dedicated cache handler (like Redis or KV database). This helps reduce hits against data sources not scaled to your total traffic, though it comes with costs (storage, network latency, platform fees).\n00212| \n00213| > [!NOTE]\n00214| > With the default in-memory handler, serverless instances are ephemeral, so entries may not be reused between requests, unlike with `use cache: remote`. Neither caching directive carries over to a new deploy, because the [cache key](#cache-keys) includes the build (or `deploymentId`) ID.\n00215| >\n00216| > For data that needs to persist across deploys, use [`unstable_cache`](/docs/app/api-reference/functions/unstable_cache) for non-`fetch` functions or the [`fetch`](/docs/app/api-reference/functions/fetch) cache.\n00217| \n00218| Very rarely, for compliance requirements or when you can't refactor your code to pass runtime data as arguments to a `use cache` scope, you might need [`use cache: private`](/docs/app/api-reference/directives/use-cache-private).\n00219| \n00220| ### Draft Mode\n00221| \n00222| When [Draft Mode](/docs/app/guides/draft-mode) is enabled, all cached functions and components re-execute on every request, and results are not saved to the cache. This ensures draft content is always fresh without requiring any changes to your caching code.\n00223| \n00224| You can read `isEnabled` from [`draftMode()`](/docs/app/api-reference/functions/draft-mode) inside a `use cache` scope, however, other runtime APIs like `cookies()` and `headers()` are not allowed, even when Draft Mode is active. See [Passing runtime values to cached functions](/docs/app/getting-started/caching#passing-runtime-values-to-cached-functions) for the recommended pattern.\n00225| \n00226| ```tsx filename=\"app/components/content.tsx\"\n00227| import { draftMode } from 'next/headers'\n00228| \n00229| async function Content() {\n00230| 'use cache'\n00231| \n00232| const { isEnabled } = await draftMode()\n00233| const url = isEnabled\n00234| ? 'https://draft.example.com/content'\n00235| : 'https://production.example.com/content'\n00236| \n00237| const data = await fetch(url)\n00238| return {/* ... */}\n00239| }\n00240| ```\n00241| \n00242| Calling `enable()` or `disable()` inside a caching directive scope will also throw an error. Draft Mode can only be toggled in [Route Handlers](/docs/app/api-reference/file-conventions/route) or [Server Actions](/docs/app/getting-started/mutating-data).\n00243| \n00244| ### React.cache isolation\n00245| \n00246| [`React.cache`](https://react.dev/reference/react/cache) operates in an isolated scope inside `use cache` boundaries. Values stored via `React.cache` outside a `use cache` function are not visible inside it.\n00247| \n00248| This means you cannot use `React.cache` to pass data into a `use cache` scope:\n00249| \n00250| ```tsx\n00251| import { cache } from 'react'\n00252| \n00253| const store = cache(() => ({ current: null as string | null }))\n00254| \n00255| function Parent() {\n00256| const shared = store()\n00257| shared.current = 'value from parent'\n00258| return \n00259| }\n00260| \n00261| async function Child() {\n00262| 'use cache'\n00263| const shared = store()\n00264| // shared.current is null, not 'value from parent'\n00265| // use cache has its own isolated React.cache scope\n00266| return
{shared.current}
\n00267| }\n00268| ```\n00269| \n00270| This isolation ensures cached functions have predictable, self-contained behavior. To pass data into a `use cache` scope, use function arguments instead.\n00271| \n00272| ## `use cache` at runtime\n00273| \n00274| On the **server**, cache entries are stored in-memory and respect the `revalidate` and `expire` times from your `cacheLife` configuration. You can customize the cache storage by configuring [`cacheHandlers`](/docs/app/api-reference/config/next-config-js/cacheHandlers) in your `next.config.js` file.\n00275| \n00276| On the **client**, content from the server cache is stored in the browser's memory for the duration defined by the `stale` time. The client router enforces a **minimum 30-second stale time**, regardless of configuration.\n00277| \n00278| The `x-nextjs-stale-time` response header communicates cache lifetime from server to client, ensuring coordinated behavior.\n00279| \n00280| ## Revalidation\n00281| \n00282| By default, `use cache` uses the `default` profile with these settings:\n00283| \n00284| - **stale**: 5 minutes (client-side)\n00285| - **revalidate**: 15 minutes (server-side)\n00286| - **expire**: Never expires by time\n00287| \n00288| ```tsx filename=\"lib/data.ts\"\n00289| async function getData() {\n00290| 'use cache'\n00291| // Implicitly uses default profile\n00292| return fetch('/api/data')\n00293| }\n00294| ```\n00295| \n00296| ### Customizing cache lifetime\n00297| \n00298| Use the [`cacheLife`](/docs/app/api-reference/functions/cacheLife) function to customize cache duration:\n00299| \n00300| ```tsx filename=\"lib/data.ts\"\n00301| import { cacheLife } from 'next/cache'\n00302| \n00303| async function getData() {\n00304| 'use cache'\n00305| cacheLife('hours') // Use built-in 'hours' profile\n00306| return fetch('/api/data')\n00307| }\n00308| ```\n00309| \n00310| ### On-demand revalidation\n00311| \n00312| Use [`cacheTag`](/docs/app/api-reference/functions/cacheTag), [`updateTag`](/docs/app/api-reference/functions/updateTag), or [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) for on-demand cache invalidation:\n00313| \n00314| ```tsx filename=\"lib/data.ts\"\n00315| import { cacheTag } from 'next/cache'\n00316| \n00317| async function getProducts() {\n00318| 'use cache'\n00319| cacheTag('products')\n00320| return fetch('/api/products')\n00321| }\n00322| ```\n00323| \n00324| ```tsx filename=\"app/actions.ts\"\n00325| 'use server'\n00326| \n00327| import { updateTag } from 'next/cache'\n00328| \n00329| export async function updateProduct() {\n00330| await db.products.update(...)\n00331| updateTag('products') // Invalidates all 'products' caches\n00332| }\n00333| ```\n00334| \n00335| Both `cacheLife` and `cacheTag` integrate across client and server caching layers, meaning you configure your caching semantics in one place and they apply everywhere.\n00336| \n00337| ## Examples\n00338| \n00339| ### Caching an entire route with `use cache`\n00340| \n00341| To prerender an entire route, add `use cache` to the top of **both** the `layout` and `page` files. Each of these segments are treated as separate entry points in your application, and will be cached independently.\n00342| \n00343| ```tsx filename=\"app/layout.tsx\" switcher\n00344| 'use cache'\n00345| \n00346| export default async function Layout({ children }: { children: ReactNode }) {\n00347| return
{children}
\n00348| }\n00349| ```\n00350| \n00351| ```jsx filename=\"app/layout.js\" switcher\n00352| 'use cache'\n00353| \n00354| export default async function Layout({ children }) {\n00355| return
{children}
\n00356| }\n00357| ```\n00358| \n00359| Any components imported and nested in `page` file are part of the cache output associated with the `page`.\n00360| \n00361| ```tsx filename=\"app/page.tsx\" switcher\n00362| 'use cache'\n00363| \n00364| async function Users() {\n00365| const users = await fetch('/api/users')\n00366| // loop through users\n00367| }\n00368| \n00369| export default async function Page() {\n00370| return (\n00371| \n00372| \n00373| \n00374| )\n00375| }\n00376| ```\n00377| \n00378| ```jsx filename=\"app/page.js\" switcher\n00379| 'use cache'\n00380| \n00381| async function Users() {\n00382| const users = await fetch('/api/users')\n00383| // loop through users\n00384| }\n00385| \n00386| export default async function Page() {\n00387| return (\n00388| \n00389| \n00390| \n00391| )\n00392| }\n00393| ```\n00394| \n00395| > **Good to know**:\n00396| >\n00397| > - If `use cache` is added only to the `layout` or the `page`, only that route segment and any components imported into it will be cached.\n00398| \n00399| ### Caching a component's output with `use cache`\n00400| \n00401| You can use `use cache` at the component level to cache any fetches or computations performed within that component. The cache entry will be reused as long as the serialized props produce the same value in each instance.\n00402| \n00403| ```tsx filename=\"app/components/bookings.tsx\" highlight={2} switcher\n00404| export async function Bookings({ type = 'haircut' }: BookingsProps) {\n00405| 'use cache'\n00406| async function getBookingsData() {\n00407| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00408| return data\n00409| }\n00410| return //...\n00411| }\n00412| \n00413| interface BookingsProps {\n00414| type: string\n00415| }\n00416| ```\n00417| \n00418| ```jsx filename=\"app/components/bookings.js\" highlight={2} switcher\n00419| export async function Bookings({ type = 'haircut' }) {\n00420| 'use cache'\n00421| async function getBookingsData() {\n00422| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00423| return data\n00424| }\n00425| return //...\n00426| }\n00427| ```\n00428| \n00429| ### Caching function output with `use cache`\n00430| \n00431| Since you can add `use cache` to any asynchronous function, you aren't limited to caching components or routes only. You might want to cache a network request, a database query, or a slow computation.\n00432| \n00433| ```tsx filename=\"app/actions.ts\" highlight={2} switcher\n00434| export async function getData() {\n00435| 'use cache'\n00436| \n00437| const data = await fetch('/api/data')\n00438| return data\n00439| }\n00440| ```\n00441| \n00442| ```jsx filename=\"app/actions.js\" highlight={2} switcher\n00443| export async function getData() {\n00444| 'use cache'\n00445| \n00446| const data = await fetch('/api/data')\n00447| return data\n00448| }\n00449| ```\n00450| \n00451| > **Good to know:** When a cached directive (`use cache`, [`use cache: private`](/docs/app/api-reference/directives/use-cache-private), or [`use cache: remote`](/docs/app/api-reference/directives/use-cache-remote)) is at the top of a file, you can import its exported functions into a Client Component and call them directly; they run on the server and return the result, similar to a [Server Function](/docs/app/glossary#server-function). Prefer calling cached functions on the server and passing results down as props.\n00452| \n00453| ### Interleaving\n00454| \n00455| In React, composition with `children` or slots is a well-known pattern for building flexible components. When using `use cache`, you can continue to compose your UI in this way. Anything included as `children`, or other compositional slots, in the returned JSX will be passed through the cached component without affecting its cache entry.\n00456| \n00457| As long as you don't directly reference any of the JSX slots inside the body of the cacheable function itself, their presence in the returned output won't affect the cache entry.\n00458| \n00459| ```tsx filename=\"app/page.tsx\" switcher\n00460| export default async function Page() {\n00461| const uncachedData = await getData()\n00462| return (\n00463| // Pass compositional slots as props, e.g. header and children\n00464| Home}>\n00465| {/* DynamicComponent is provided as the children slot */}\n00466| \n00467| \n00468| )\n00469| }\n00470| \n00471| async function CacheComponent({\n00472| header, // header: a compositional slot, injected as a prop\n00473| children, // children: another slot for nested composition\n00474| }: {\n00475| header: ReactNode\n00476| children: ReactNode\n00477| }) {\n00478| 'use cache'\n00479| const cachedData = await fetch('/api/cached-data')\n00480| return (\n00481|
\n00514| )\n00515| }\n00516| ```\n00517| \n00518| You can also pass Server Actions through cached components to Client Components without invoking them inside the cacheable function.\n00519| \n00520| ```tsx filename=\"app/page.tsx\" switcher\n00521| import ClientComponent from './ClientComponent'\n00522| \n00523| export default async function Page() {\n00524| const performUpdate = async () => {\n00525| 'use server'\n00526| // Perform some server-side update\n00527| await db.update(...)\n00528| }\n00529| \n00530| return \n00531| }\n00532| \n00533| async function CachedComponent({\n00534| performUpdate,\n00535| }: {\n00536| performUpdate: () => Promise\n00537| }) {\n00538| 'use cache'\n00539| // Do not call performUpdate here\n00540| return \n00541| }\n00542| ```\n00543| \n00544| ```jsx filename=\"app/page.js\" switcher\n00545| import ClientComponent from './ClientComponent'\n00546| \n00547| export default async function Page() {\n00548| const performUpdate = async () => {\n00549| 'use server'\n00550| // Perform some server-side update\n00551| await db.update(...)\n00552| }\n00553| \n00554| return \n00555| }\n00556| \n00557| async function CachedComponent({ performUpdate }) {\n00558| 'use cache'\n00559| // Do not call performUpdate here\n00560| return \n00561| }\n00562| ```\n00563| \n00564| ```tsx filename=\"app/ClientComponent.tsx\" switcher\n00565| 'use client'\n00566| \n00567| export default function ClientComponent({\n00568| action,\n00569| }: {\n00570| action: () => Promise\n00571| }) {\n00572| return Update\n00573| }\n00574| ```\n00575| \n00576| ```jsx filename=\"app/ClientComponent.js\" switcher\n00577| 'use client'\n00578| \n00579| export default function ClientComponent({ action }) {\n00580| return Update\n00581| }\n00582| ```\n00583| \n00584| ## Troubleshooting\n00585| \n00586| ### Debugging cache behavior\n00587| \n00588| #### Verbose logging\n00589| \n00590| Set `NEXT_PRIVATE_DEBUG_CACHE=1` for verbose cache logging:\n00591| \n00592| ```bash\n00593| NEXT_PRIVATE_DEBUG_CACHE=1 npm run dev\n00594| # or for production\n00595| NEXT_PRIVATE_DEBUG_CACHE=1 npm run start\n00596| ```\n00597| \n00598| > **Good to know:** This environment variable also logs ISR and other caching mechanisms. See [Verifying correct production behavior](/docs/app/guides/incremental-static-regeneration#verifying-correct-production-behavior) for more details.\n00599| \n00600| #### Console log replays\n00601| \n00602| In development, console logs from cached functions appear with a `Cache` prefix.\n00603| \n00604| ### Build Hangs (Cache Timeout)\n00605| \n00606| If your build hangs, you're accessing Promises that resolve to uncached or runtime data, created outside a `use cache` boundary. The cached function waits for data that can't resolve during the build, causing a timeout after 50 seconds.\n00607| \n00608| When the build timeouts you'll see this error message:\n00609| \n00610| > Error: Filling a cache during prerender timed out, likely because request-specific arguments such as params, searchParams, cookies() or uncached data were used inside \"use cache\".\n00611| \n00612| Common ways this happens: passing such Promises as props, accessing them via closure, or retrieving them from shared storage (Maps).\n00613| \n00614| > **Good to know:** Directly calling `cookies()` or `headers()` inside `use cache` fails immediately with a [different error](/docs/messages/next-request-in-use-cache), not a timeout.\n00615| \n00616| **Passing runtime data Promises as props:**\n00617| \n00618| ```tsx filename=\"app/page.tsx\"\n00619| import { cookies } from 'next/headers'\n00620| import { Suspense } from 'react'\n00621| \n00622| export default function Page() {\n00623| return (\n00624| Loading...
}>\n00625| \n00626| \n00627| )\n00628| }\n00629| \n00630| async function Dynamic() {\n00631| const cookieStore = cookies()\n00632| return // Build hangs\n00633| }\n00634| \n00635| async function Cached({ promise }: { promise: Promise }) {\n00636| 'use cache'\n00637| const data = await promise // Waits for runtime data during build\n00638| return
..
\n00639| }\n00640| ```\n00641| \n00642| Await the `cookies` store in the `Dynamic` component, and pass a cookie value to the `Cached` component.\n00643| \n00644| **Shared deduplication storage:**\n00645| \n00646| ```tsx filename=\"app/page.tsx\"\n00647| // Problem: Map stores dynamic Promises, accessed by cached code\n00648| import { Suspense } from 'react'\n00649| \n00650| const cache = new Map>()\n00651| \n00652| export default function Page() {\n00653| return (\n00654| <>\n00655| Loading...
\n00670| }\n00671| \n00672| async function Cached({ id }: { id: string }) {\n00673| 'use cache'\n00674| return
{await cache.get(id)}
// Build hangs - retrieves dynamic Promise\n00675| }\n00676| ```\n00677| \n00678| Use Next.js's built-in `fetch()` deduplication or use separate Maps for cached and uncached contexts.\n00679| \n00680| ## Platform Support\n00681| \n00682| | Deployment Option | Supported |\n00683| | ------------------------------------------------------------------- | ----------------- |\n00684| | [Node.js server](/docs/app/getting-started/deploying#nodejs-server) | Yes |\n00685| | [Docker container](/docs/app/getting-started/deploying#docker) | Yes |\n00686| | [Static export](/docs/app/getting-started/deploying#static-export) | No |\n00687| | [Adapters](/docs/app/getting-started/deploying#adapters) | Platform-specific |\n00688| \n00689| Learn how to [configure caching](/docs/app/guides/self-hosting#caching-and-isr) when self-hosting Next.js.\n00690| \n00691| ## Version History\n00692| \n00693| | Version | Changes |\n00694| | --------- | ----------------------------------------------------------- |\n00695| | `v16.0.0` | `\"use cache\"` is enabled with the Cache Components feature. |\n00696| | `v15.0.0` | `\"use cache\"` is introduced as an experimental feature. |\n00697| \n\n(End of file - total 697 lines)\n",
+ "title": "node_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache.md",
+ "metadata": {
+ "preview": "---\ntitle: use cache\ndescription: Learn how to use the \"use cache\" directive to cache data in your Next.js application.\nrelated:\n title: Related\n description: View related API references.\n links:\n - app/api-reference/directives/use-cache-private\n - app/api-reference/config/next-config-js/cacheComponents\n - app/api-reference/config/next-config-js/cacheLife\n - app/api-reference/config/next-config-js/cacheHandlers\n - app/api-reference/functions/cacheTag\n - app/api-reference/functions/cacheLife\n - app/api-reference/functions/revalidateTag\n---\n\nThe `use cache` directive allows you to mark a route, React component, or a function as cacheable. It can be used at the top of a file to indicate that all exports in the file should be cached, or inline at the top of a function or component to cache the return value. Functions and components that use `use cache` must be async.\n\n> **Good to know:**\n>"
+ },
+ "time": {
+ "start": 1781392539565,
+ "end": 1781392539572
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:39.574Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| ---\n00002| title: use cache\n00003| description: Learn how to use the \"use cache\" directive to cache data in your Next.js application.\n00004| related:\n00005| title: Related\n00006| description: View related API references.\n00007| links:\n00008| - app/api-reference/directives/use-cache-private\n00009| - app/api-reference/config/next-config-js/cacheComponents\n00010| - app/api-reference/config/next-config-js/cacheLife\n00011| - app/api-reference/config/next-config-js/cacheHandlers\n00012| - app/api-reference/functions/cacheTag\n00013| - app/api-reference/functions/cacheLife\n00014| - app/api-reference/functions/revalidateTag\n00015| ---\n00016| \n00017| The `use cache` directive allows you to mark a route, React component, or a function as cacheable. It can be used at the top of a file to indicate that all exports in the file should be cached, or inline at the top of a function or component to cache the return value. Functions and components that use `use cache` must be async.\n00018| \n00019| > **Good to know:**\n00020| >\n00021| > - To use cookies or headers, read them outside cached scopes and pass values as arguments. This is the preferred pattern.\n00022| > - If the in-memory cache isn't sufficient for runtime data, [`'use cache: remote'`](/docs/app/api-reference/directives/use-cache-remote) allows platforms to provide a dedicated cache handler, though it requires a network roundtrip to check the cache and typically incurs platform fees.\n00023| > - For compliance requirements or when you can't refactor to pass runtime data as arguments to a `use cache` scope, see [`'use cache: private'`](/docs/app/api-reference/directives/use-cache-private).\n00024| \n00025| ## Usage\n00026| \n00027| `use cache` is a Cache Components feature. To enable it, add the [`cacheComponents`](/docs/app/api-reference/config/next-config-js/cacheComponents) option to your `next.config.ts` file:\n00028| \n00029| ```ts filename=\"next.config.ts\" switcher\n00030| import type { NextConfig } from 'next'\n00031| \n00032| const nextConfig: NextConfig = {\n00033| cacheComponents: true,\n00034| }\n00035| \n00036| export default nextConfig\n00037| ```\n00038| \n00039| ```js filename=\"next.config.js\" switcher\n00040| /** @type {import('next').NextConfig} */\n00041| const nextConfig = {\n00042| cacheComponents: true,\n00043| }\n00044| \n00045| module.exports = nextConfig\n00046| ```\n00047| \n00048| Then, add `use cache` at the file, component, or function level. All functions and components using `use cache` must be async. When used at file level, every exported function becomes a cached function and must also be async:\n00049| \n00050| ```tsx\n00051| // File level\n00052| 'use cache'\n00053| \n00054| export default async function Page() {\n00055| // ...\n00056| }\n00057| \n00058| // Component level\n00059| export async function MyComponent() {\n00060| 'use cache'\n00061| return <>>\n00062| }\n00063| \n00064| // Function level\n00065| export async function getData() {\n00066| 'use cache'\n00067| const data = await fetch('/api/data')\n00068| return data\n00069| }\n00070| ```\n00071| \n00072| ## How `use cache` works\n00073| \n00074| ### Cache keys\n00075| \n00076| A cache entry's key is generated using a serialized version of its inputs, which includes:\n00077| \n00078| 1. **Build ID** - Unique per build, changing this invalidates all cache entries. If [`deploymentId`](/docs/app/api-reference/config/next-config-js/deploymentId) is configured, it overrides the build ID for cache key purposes.\n00079| 2. **Function ID** - A secure hash of the function's location and signature in the codebase\n00080| 3. **Serializable arguments** - Props (for components) or function arguments\n00081| 4. **HMR refresh hash** (development only) - Invalidates cache on hot module replacement\n00082| \n00083| When a cached function references variables from outer scopes, those variables are automatically captured and bound as arguments, making them part of the cache key.\n00084| \n00085| ```tsx filename=\"lib/data.ts\"\n00086| async function Component({ userId }: { userId: string }) {\n00087| const getData = async (filter: string) => {\n00088| 'use cache'\n00089| // Cache key includes both userId (from closure) and filter (argument)\n00090| return fetch(`/api/users/${userId}/data?filter=${filter}`)\n00091| }\n00092| \n00093| return getData('active')\n00094| }\n00095| ```\n00096| \n00097| In the snippet above, `userId` is captured from the outer scope and `filter` is passed as an argument, so both become part of the `getData` function's cache key. This means different user and filter combinations will have separate cache entries.\n00098| \n00099| > **Good to know:** When a cached function reads [root parameters](/docs/app/api-reference/functions/next-root-params), only the ones it actually reads become part of its cache key.\n00100| \n00101| ## Serialization\n00102| \n00103| Arguments to cached functions and their return values must be serializable.\n00104| \n00105| For a complete reference, see:\n00106| \n00107| - [Serializable arguments](https://react.dev/reference/rsc/use-server#serializable-parameters-and-return-values) - Uses **React Server Components** serialization\n00108| - [Serializable return types](https://react.dev/reference/rsc/use-client#serializable-types) - Uses **React Client Components** serialization\n00109| \n00110| > **Good to know:** Arguments and return values use different serialization systems. Server Component serialization (for arguments) is more restrictive than Client Component serialization (for return values). This means you can return JSX elements but cannot accept them as arguments unless using pass-through patterns.\n00111| \n00112| ### Supported types\n00113| \n00114| **Arguments:**\n00115| \n00116| - Primitives: `string`, `number`, `boolean`, `null`, `undefined`\n00117| - Plain objects: `{ key: value }`\n00118| - Arrays: `[1, 2, 3]`\n00119| - Dates, Maps, Sets, TypedArrays, ArrayBuffers\n00120| - React elements (as pass-through only)\n00121| \n00122| **Return values:**\n00123| \n00124| - Same as arguments, plus JSX elements\n00125| \n00126| ### Unsupported types\n00127| \n00128| - Class instances\n00129| - Functions (except as pass-through)\n00130| - Symbols, WeakMaps, WeakSets\n00131| - URL instances\n00132| \n00133| ```tsx filename=\"app/components/user-card.tsx\"\n00134| // Valid - primitives and plain objects\n00135| async function UserCard({\n00136| id,\n00137| config,\n00138| }: {\n00139| id: string\n00140| config: { theme: string }\n00141| }) {\n00142| 'use cache'\n00143| return
{id}
\n00144| }\n00145| \n00146| // Invalid - class instance\n00147| async function UserProfile({ user }: { user: UserClass }) {\n00148| 'use cache'\n00149| // Error: Cannot serialize class instance\n00150| return
{user.name}
\n00151| }\n00152| ```\n00153| \n00154| ### Pass-through (non-serializable arguments)\n00155| \n00156| You can accept non-serializable values **as long as you don't introspect them**. This enables composition patterns with `children` and Server Actions:\n00157| \n00158| ```tsx filename=\"app/components/cached-wrapper.tsx\"\n00159| async function CachedWrapper({ children }: { children: ReactNode }) {\n00160| 'use cache'\n00161| // Don't read or modify children - just pass it through\n00162| return (\n00163|
\n00164| Cached Header\n00165| {children}\n00166|
\n00167| )\n00168| }\n00169| \n00170| // Usage: children can be dynamic\n00171| export default function Page() {\n00172| return (\n00173| \n00174| {/* Not cached, passed through */}\n00175| \n00176| )\n00177| }\n00178| ```\n00179| \n00180| You can also pass Server Actions through cached components:\n00181| \n00182| ```tsx filename=\"app/components/cached-form.tsx\"\n00183| async function CachedForm({ action }: { action: () => Promise }) {\n00184| 'use cache'\n00185| // Don't call action here - just pass it through\n00186| return
{/* ... */}
\n00187| }\n00188| ```\n00189| \n00190| ## Constraints\n00191| \n00192| Cached functions execute in an isolated environment. The following constraints ensure cache behavior remains predictable and secure.\n00193| \n00194| ### Request-time APIs\n00195| \n00196| Cached functions and components **cannot** directly access runtime APIs like `cookies()`, `headers()`, or `searchParams`. Instead, read these values outside the cached scope and pass them as arguments.\n00197| \n00198| ### Runtime caching considerations\n00199| \n00200| While `use cache` is designed primarily to include uncached data in the static shell, it can also cache data at runtime using in-memory LRU (Least Recently Used) storage.\n00201| \n00202| With the default in-memory handler, runtime cache behavior depends on your hosting environment:\n00203| \n00204| | Environment | Runtime Caching Behavior |\n00205| | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n00206| | **Serverless** | Cache entries typically don't persist across requests (each request can be a different instance), or during revalidation. Build-time caching works normally. |\n00207| | **Self-hosted** | Cache entries persist across requests. Control cache size with [`cacheMaxMemorySize`](/docs/app/api-reference/config/next-config-js/incrementalCacheHandlerPath). |\n00208| \n00209| For example, in a serverless environment, a cached function shared by two pages executes on each static shell revalidation, whereas in self-hosted or environments with persistent memory, the cached output is reused if it's still fresh.\n00210| \n00211| If the default in-memory cache isn't enough, consider **[`use cache: remote`](/docs/app/api-reference/directives/use-cache-remote)** which allows platforms to provide a dedicated cache handler (like Redis or KV database). This helps reduce hits against data sources not scaled to your total traffic, though it comes with costs (storage, network latency, platform fees).\n00212| \n00213| > [!NOTE]\n00214| > With the default in-memory handler, serverless instances are ephemeral, so entries may not be reused between requests, unlike with `use cache: remote`. Neither caching directive carries over to a new deploy, because the [cache key](#cache-keys) includes the build (or `deploymentId`) ID.\n00215| >\n00216| > For data that needs to persist across deploys, use [`unstable_cache`](/docs/app/api-reference/functions/unstable_cache) for non-`fetch` functions or the [`fetch`](/docs/app/api-reference/functions/fetch) cache.\n00217| \n00218| Very rarely, for compliance requirements or when you can't refactor your code to pass runtime data as arguments to a `use cache` scope, you might need [`use cache: private`](/docs/app/api-reference/directives/use-cache-private).\n00219| \n00220| ### Draft Mode\n00221| \n00222| When [Draft Mode](/docs/app/guides/draft-mode) is enabled, all cached functions and components re-execute on every request, and results are not saved to the cache. This ensures draft content is always fresh without requiring any changes to your caching code.\n00223| \n00224| You can read `isEnabled` from [`draftMode()`](/docs/app/api-reference/functions/draft-mode) inside a `use cache` scope, however, other runtime APIs like `cookies()` and `headers()` are not allowed, even when Draft Mode is active. See [Passing runtime values to cached functions](/docs/app/getting-started/caching#passing-runtime-values-to-cached-functions) for the recommended pattern.\n00225| \n00226| ```tsx filename=\"app/components/content.tsx\"\n00227| import { draftMode } from 'next/headers'\n00228| \n00229| async function Content() {\n00230| 'use cache'\n00231| \n00232| const { isEnabled } = await draftMode()\n00233| const url = isEnabled\n00234| ? 'https://draft.example.com/content'\n00235| : 'https://production.example.com/content'\n00236| \n00237| const data = await fetch(url)\n00238| return {/* ... */}\n00239| }\n00240| ```\n00241| \n00242| Calling `enable()` or `disable()` inside a caching directive scope will also throw an error. Draft Mode can only be toggled in [Route Handlers](/docs/app/api-reference/file-conventions/route) or [Server Actions](/docs/app/getting-started/mutating-data).\n00243| \n00244| ### React.cache isolation\n00245| \n00246| [`React.cache`](https://react.dev/reference/react/cache) operates in an isolated scope inside `use cache` boundaries. Values stored via `React.cache` outside a `use cache` function are not visible inside it.\n00247| \n00248| This means you cannot use `React.cache` to pass data into a `use cache` scope:\n00249| \n00250| ```tsx\n00251| import { cache } from 'react'\n00252| \n00253| const store = cache(() => ({ current: null as string | null }))\n00254| \n00255| function Parent() {\n00256| const shared = store()\n00257| shared.current = 'value from parent'\n00258| return \n00259| }\n00260| \n00261| async function Child() {\n00262| 'use cache'\n00263| const shared = store()\n00264| // shared.current is null, not 'value from parent'\n00265| // use cache has its own isolated React.cache scope\n00266| return
{shared.current}
\n00267| }\n00268| ```\n00269| \n00270| This isolation ensures cached functions have predictable, self-contained behavior. To pass data into a `use cache` scope, use function arguments instead.\n00271| \n00272| ## `use cache` at runtime\n00273| \n00274| On the **server**, cache entries are stored in-memory and respect the `revalidate` and `expire` times from your `cacheLife` configuration. You can customize the cache storage by configuring [`cacheHandlers`](/docs/app/api-reference/config/next-config-js/cacheHandlers) in your `next.config.js` file.\n00275| \n00276| On the **client**, content from the server cache is stored in the browser's memory for the duration defined by the `stale` time. The client router enforces a **minimum 30-second stale time**, regardless of configuration.\n00277| \n00278| The `x-nextjs-stale-time` response header communicates cache lifetime from server to client, ensuring coordinated behavior.\n00279| \n00280| ## Revalidation\n00281| \n00282| By default, `use cache` uses the `default` profile with these settings:\n00283| \n00284| - **stale**: 5 minutes (client-side)\n00285| - **revalidate**: 15 minutes (server-side)\n00286| - **expire**: Never expires by time\n00287| \n00288| ```tsx filename=\"lib/data.ts\"\n00289| async function getData() {\n00290| 'use cache'\n00291| // Implicitly uses default profile\n00292| return fetch('/api/data')\n00293| }\n00294| ```\n00295| \n00296| ### Customizing cache lifetime\n00297| \n00298| Use the [`cacheLife`](/docs/app/api-reference/functions/cacheLife) function to customize cache duration:\n00299| \n00300| ```tsx filename=\"lib/data.ts\"\n00301| import { cacheLife } from 'next/cache'\n00302| \n00303| async function getData() {\n00304| 'use cache'\n00305| cacheLife('hours') // Use built-in 'hours' profile\n00306| return fetch('/api/data')\n00307| }\n00308| ```\n00309| \n00310| ### On-demand revalidation\n00311| \n00312| Use [`cacheTag`](/docs/app/api-reference/functions/cacheTag), [`updateTag`](/docs/app/api-reference/functions/updateTag), or [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) for on-demand cache invalidation:\n00313| \n00314| ```tsx filename=\"lib/data.ts\"\n00315| import { cacheTag } from 'next/cache'\n00316| \n00317| async function getProducts() {\n00318| 'use cache'\n00319| cacheTag('products')\n00320| return fetch('/api/products')\n00321| }\n00322| ```\n00323| \n00324| ```tsx filename=\"app/actions.ts\"\n00325| 'use server'\n00326| \n00327| import { updateTag } from 'next/cache'\n00328| \n00329| export async function updateProduct() {\n00330| await db.products.update(...)\n00331| updateTag('products') // Invalidates all 'products' caches\n00332| }\n00333| ```\n00334| \n00335| Both `cacheLife` and `cacheTag` integrate across client and server caching layers, meaning you configure your caching semantics in one place and they apply everywhere.\n00336| \n00337| ## Examples\n00338| \n00339| ### Caching an entire route with `use cache`\n00340| \n00341| To prerender an entire route, add `use cache` to the top of **both** the `layout` and `page` files. Each of these segments are treated as separate entry points in your application, and will be cached independently.\n00342| \n00343| ```tsx filename=\"app/layout.tsx\" switcher\n00344| 'use cache'\n00345| \n00346| export default async function Layout({ children }: { children: ReactNode }) {\n00347| return
{children}
\n00348| }\n00349| ```\n00350| \n00351| ```jsx filename=\"app/layout.js\" switcher\n00352| 'use cache'\n00353| \n00354| export default async function Layout({ children }) {\n00355| return
{children}
\n00356| }\n00357| ```\n00358| \n00359| Any components imported and nested in `page` file are part of the cache output associated with the `page`.\n00360| \n00361| ```tsx filename=\"app/page.tsx\" switcher\n00362| 'use cache'\n00363| \n00364| async function Users() {\n00365| const users = await fetch('/api/users')\n00366| // loop through users\n00367| }\n00368| \n00369| export default async function Page() {\n00370| return (\n00371| \n00372| \n00373| \n00374| )\n00375| }\n00376| ```\n00377| \n00378| ```jsx filename=\"app/page.js\" switcher\n00379| 'use cache'\n00380| \n00381| async function Users() {\n00382| const users = await fetch('/api/users')\n00383| // loop through users\n00384| }\n00385| \n00386| export default async function Page() {\n00387| return (\n00388| \n00389| \n00390| \n00391| )\n00392| }\n00393| ```\n00394| \n00395| > **Good to know**:\n00396| >\n00397| > - If `use cache` is added only to the `layout` or the `page`, only that route segment and any components imported into it will be cached.\n00398| \n00399| ### Caching a component's output with `use cache`\n00400| \n00401| You can use `use cache` at the component level to cache any fetches or computations performed within that component. The cache entry will be reused as long as the serialized props produce the same value in each instance.\n00402| \n00403| ```tsx filename=\"app/components/bookings.tsx\" highlight={2} switcher\n00404| export async function Bookings({ type = 'haircut' }: BookingsProps) {\n00405| 'use cache'\n00406| async function getBookingsData() {\n00407| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00408| return data\n00409| }\n00410| return //...\n00411| }\n00412| \n00413| interface BookingsProps {\n00414| type: string\n00415| }\n00416| ```\n00417| \n00418| ```jsx filename=\"app/components/bookings.js\" highlight={2} switcher\n00419| export async function Bookings({ type = 'haircut' }) {\n00420| 'use cache'\n00421| async function getBookingsData() {\n00422| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00423| return data\n00424| }\n00425| return //...\n00426| }\n00427| ```\n00428| \n00429| ### Caching function output with `use cache`\n00430| \n00431| Since you can add `use cache` to any asynchronous function, you aren't limited to caching components or routes only. You might want to cache a network request, a database query, or a slow computation.\n00432| \n00433| ```tsx filename=\"app/actions.ts\" highlight={2} switcher\n00434| export async function getData() {\n00435| 'use cache'\n00436| \n00437| const data = await fetch('/api/data')\n00438| return data\n00439| }\n00440| ```\n00441| \n00442| ```jsx filename=\"app/actions.js\" highlight={2} switcher\n00443| export async function getData() {\n00444| 'use cache'\n00445| \n00446| const data = await fetch('/api/data')\n00447| return data\n00448| }\n00449| ```\n00450| \n00451| > **Good to know:** When a cached directive (`use cache`, [`use cache: private`](/docs/app/api-reference/directives/use-cache-private), or [`use cache: remote`](/docs/app/api-reference/directives/use-cache-remote)) is at the top of a file, you can import its exported functions into a Client Component and call them directly; they run on the server and return the result, similar to a [Server Function](/docs/app/glossary#server-function). Prefer calling cached functions on the server and passing results down as props.\n00452| \n00453| ### Interleaving\n00454| \n00455| In React, composition with `children` or slots is a well-known pattern for building flexible components. When using `use cache`, you can continue to compose your UI in this way. Anything included as `children`, or other compositional slots, in the returned JSX will be passed through the cached component without affecting its cache entry.\n00456| \n00457| As long as you don't directly reference any of the JSX slots inside the body of the cacheable function itself, their presence in the returned output won't affect the cache entry.\n00458| \n00459| ```tsx filename=\"app/page.tsx\" switcher\n00460| export default async function Page() {\n00461| const uncachedData = await getData()\n00462| return (\n00463| // Pass compositional slots as props, e.g. header and children\n00464| Home}>\n00465| {/* DynamicComponent is provided as the children slot */}\n00466| \n00467| \n00468| )\n00469| }\n00470| \n00471| async function CacheComponent({\n00472| header, // header: a compositional slot, injected as a prop\n00473| children, // children: another slot for nested composition\n00474| }: {\n00475| header: ReactNode\n00476| children: ReactNode\n00477| }) {\n00478| 'use cache'\n00479| const cachedData = await fetch('/api/cached-data')\n00480| return (\n00481|
\n00514| )\n00515| }\n00516| ```\n00517| \n00518| You can also pass Server Actions through cached components to Client Components without invoking them inside the cacheable function.\n00519| \n00520| ```tsx filename=\"app/page.tsx\" switcher\n00521| import ClientComponent from './ClientComponent'\n00522| \n00523| export default async function Page() {\n00524| const performUpdate = async () => {\n00525| 'use server'\n00526| // Perform some server-side update\n00527| await db.update(...)\n00528| }\n00529| \n00530| return \n00531| }\n00532| \n00533| async function CachedComponent({\n00534| performUpdate,\n00535| }: {\n00536| performUpdate: () => Promise\n00537| }) {\n00538| 'use cache'\n00539| // Do not call performUpdate here\n00540| return \n00541| }\n00542| ```\n00543| \n00544| ```jsx filename=\"app/page.js\" switcher\n00545| import ClientComponent from './ClientComponent'\n00546| \n00547| export default async function Page() {\n00548| const performUpdate = async () => {\n00549| 'use server'\n00550| // Perform some server-side update\n00551| await db.update(...)\n00552| }\n00553| \n00554| return \n00555| }\n00556| \n00557| async function CachedComponent({ performUpdate }) {\n00558| 'use cache'\n00559| // Do not call performUpdate here\n00560| return \n00561| }\n00562| ```\n00563| \n00564| ```tsx filename=\"app/ClientComponent.tsx\" switcher\n00565| 'use client'\n00566| \n00567| export default function ClientComponent({\n00568| action,\n00569| }: {\n00570| action: () => Promise\n00571| }) {\n00572| return Update\n00573| }\n00574| ```\n00575| \n00576| ```jsx filename=\"app/ClientComponent.js\" switcher\n00577| 'use client'\n00578| \n00579| export default function ClientComponent({ action }) {\n00580| return Update\n00581| }\n00582| ```\n00583| \n00584| ## Troubleshooting\n00585| \n00586| ### Debugging cache behavior\n00587| \n00588| #### Verbose logging\n00589| \n00590| Set `NEXT_PRIVATE_DEBUG_CACHE=1` for verbose cache logging:\n00591| \n00592| ```bash\n00593| NEXT_PRIVATE_DEBUG_CACHE=1 npm run dev\n00594| # or for production\n00595| NEXT_PRIVATE_DEBUG_CACHE=1 npm run start\n00596| ```\n00597| \n00598| > **Good to know:** This environment variable also logs ISR and other caching mechanisms. See [Verifying correct production behavior](/docs/app/guides/incremental-static-regeneration#verifying-correct-production-behavior) for more details.\n00599| \n00600| #### Console log replays\n00601| \n00602| In development, console logs from cached functions appear with a `Cache` prefix.\n00603| \n00604| ### Build Hangs (Cache Timeout)\n00605| \n00606| If your build hangs, you're accessing Promises that resolve to uncached or runtime data, created outside a `use cache` boundary. The cached function waits for data that can't resolve during the build, causing a timeout after 50 seconds.\n00607| \n00608| When the build timeouts you'll see this error message:\n00609| \n00610| > Error: Filling a cache during prerender timed out, likely because request-specific arguments such as params, searchParams, cookies() or uncached data were used inside \"use cache\".\n00611| \n00612| Common ways this happens: passing such Promises as props, accessing them via closure, or retrieving them from shared storage (Maps).\n00613| \n00614| > **Good to know:** Directly calling `cookies()` or `headers()` inside `use cache` fails immediately with a [different error](/docs/messages/next-request-in-use-cache), not a timeout.\n00615| \n00616| **Passing runtime data Promises as props:**\n00617| \n00618| ```tsx filename=\"app/page.tsx\"\n00619| import { cookies } from 'next/headers'\n00620| import { Suspense } from 'react'\n00621| \n00622| export default function Page() {\n00623| return (\n00624| Loading...
}>\n00625| \n00626| \n00627| )\n00628| }\n00629| \n00630| async function Dynamic() {\n00631| const cookieStore = cookies()\n00632| return // Build hangs\n00633| }\n00634| \n00635| async function Cached({ promise }: { promise: Promise }) {\n00636| 'use cache'\n00637| const data = await promise // Waits for runtime data during build\n00638| return
..
\n00639| }\n00640| ```\n00641| \n00642| Await the `cookies` store in the `Dynamic` component, and pass a cookie value to the `Cached` component.\n00643| \n00644| **Shared deduplication storage:**\n00645| \n00646| ```tsx filename=\"app/page.tsx\"\n00647| // Problem: Map stores dynamic Promises, accessed by cached code\n00648| import { Suspense } from 'react'\n00649| \n00650| const cache = new Map>()\n00651| \n00652| export default function Page() {\n00653| return (\n00654| <>\n00655| Loading...
\n00670| }\n00671| \n00672| async function Cached({ id }: { id: string }) {\n00673| 'use cache'\n00674| return
{await cache.get(id)}
// Build hangs - retrieves dynamic Promise\n00675| }\n00676| ```\n00677| \n00678| Use Next.js's built-in `fetch()` deduplication or use separate Maps for cached and uncached contexts.\n00679| \n00680| ## Platform Support\n00681| \n00682| | Deployment Option | Supported |\n00683| | ------------------------------------------------------------------- | ----------------- |\n00684| | [Node.js server](/docs/app/getting-started/deploying#nodejs-server) | Yes |\n00685| | [Docker container](/docs/app/getting-started/deploying#docker) | Yes |\n00686| | [Static export](/docs/app/getting-started/deploying#static-export) | No |\n00687| | [Adapters](/docs/app/getting-started/deploying#adapters) | Platform-specific |\n00688| \n00689| Learn how to [configure caching](/docs/app/guides/self-hosting#caching-and-isr) when self-hosting Next.js.\n00690| \n00691| ## Version History\n00692| \n00693| | Version | Changes |\n00694| | --------- | ----------------------------------------------------------- |\n00695| | `v16.0.0` | `\"use cache\"` is enabled with the Cache Components feature. |\n00696| | `v15.0.0` | `\"use cache\"` is introduced as an experimental feature. |\n00697| \n\n(End of file - total 697 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache.md"
+ },
+ "output": "\n00001| ---\n00002| title: use cache\n00003| description: Learn how to use the \"use cache\" directive to cache data in your Next.js application.\n00004| related:\n00005| title: Related\n00006| description: View related API references.\n00007| links:\n00008| - app/api-reference/directives/use-cache-private\n00009| - app/api-reference/config/next-config-js/cacheComponents\n00010| - app/api-reference/config/next-config-js/cacheLife\n00011| - app/api-reference/config/next-config-js/cacheHandlers\n00012| - app/api-reference/functions/cacheTag\n00013| - app/api-reference/functions/cacheLife\n00014| - app/api-reference/functions/revalidateTag\n00015| ---\n00016| \n00017| The `use cache` directive allows you to mark a route, React component, or a function as cacheable. It can be used at the top of a file to indicate that all exports in the file should be cached, or inline at the top of a function or component to cache the return value. Functions and components that use `use cache` must be async.\n00018| \n00019| > **Good to know:**\n00020| >\n00021| > - To use cookies or headers, read them outside cached scopes and pass values as arguments. This is the preferred pattern.\n00022| > - If the in-memory cache isn't sufficient for runtime data, [`'use cache: remote'`](/docs/app/api-reference/directives/use-cache-remote) allows platforms to provide a dedicated cache handler, though it requires a network roundtrip to check the cache and typically incurs platform fees.\n00023| > - For compliance requirements or when you can't refactor to pass runtime data as arguments to a `use cache` scope, see [`'use cache: private'`](/docs/app/api-reference/directives/use-cache-private).\n00024| \n00025| ## Usage\n00026| \n00027| `use cache` is a Cache Components feature. To enable it, add the [`cacheComponents`](/docs/app/api-reference/config/next-config-js/cacheComponents) option to your `next.config.ts` file:\n00028| \n00029| ```ts filename=\"next.config.ts\" switcher\n00030| import type { NextConfig } from 'next'\n00031| \n00032| const nextConfig: NextConfig = {\n00033| cacheComponents: true,\n00034| }\n00035| \n00036| export default nextConfig\n00037| ```\n00038| \n00039| ```js filename=\"next.config.js\" switcher\n00040| /** @type {import('next').NextConfig} */\n00041| const nextConfig = {\n00042| cacheComponents: true,\n00043| }\n00044| \n00045| module.exports = nextConfig\n00046| ```\n00047| \n00048| Then, add `use cache` at the file, component, or function level. All functions and components using `use cache` must be async. When used at file level, every exported function becomes a cached function and must also be async:\n00049| \n00050| ```tsx\n00051| // File level\n00052| 'use cache'\n00053| \n00054| export default async function Page() {\n00055| // ...\n00056| }\n00057| \n00058| // Component level\n00059| export async function MyComponent() {\n00060| 'use cache'\n00061| return <>>\n00062| }\n00063| \n00064| // Function level\n00065| export async function getData() {\n00066| 'use cache'\n00067| const data = await fetch('/api/data')\n00068| return data\n00069| }\n00070| ```\n00071| \n00072| ## How `use cache` works\n00073| \n00074| ### Cache keys\n00075| \n00076| A cache entry's key is generated using a serialized version of its inputs, which includes:\n00077| \n00078| 1. **Build ID** - Unique per build, changing this invalidates all cache entries. If [`deploymentId`](/docs/app/api-reference/config/next-config-js/deploymentId) is configured, it overrides the build ID for cache key purposes.\n00079| 2. **Function ID** - A secure hash of the function's location and signature in the codebase\n00080| 3. **Serializable arguments** - Props (for components) or function arguments\n00081| 4. **HMR refresh hash** (development only) - Invalidates cache on hot module replacement\n00082| \n00083| When a cached function references variables from outer scopes, those variables are automatically captured and bound as arguments, making them part of the cache key.\n00084| \n00085| ```tsx filename=\"lib/data.ts\"\n00086| async function Component({ userId }: { userId: string }) {\n00087| const getData = async (filter: string) => {\n00088| 'use cache'\n00089| // Cache key includes both userId (from closure) and filter (argument)\n00090| return fetch(`/api/users/${userId}/data?filter=${filter}`)\n00091| }\n00092| \n00093| return getData('active')\n00094| }\n00095| ```\n00096| \n00097| In the snippet above, `userId` is captured from the outer scope and `filter` is passed as an argument, so both become part of the `getData` function's cache key. This means different user and filter combinations will have separate cache entries.\n00098| \n00099| > **Good to know:** When a cached function reads [root parameters](/docs/app/api-reference/functions/next-root-params), only the ones it actually reads become part of its cache key.\n00100| \n00101| ## Serialization\n00102| \n00103| Arguments to cached functions and their return values must be serializable.\n00104| \n00105| For a complete reference, see:\n00106| \n00107| - [Serializable arguments](https://react.dev/reference/rsc/use-server#serializable-parameters-and-return-values) - Uses **React Server Components** serialization\n00108| - [Serializable return types](https://react.dev/reference/rsc/use-client#serializable-types) - Uses **React Client Components** serialization\n00109| \n00110| > **Good to know:** Arguments and return values use different serialization systems. Server Component serialization (for arguments) is more restrictive than Client Component serialization (for return values). This means you can return JSX elements but cannot accept them as arguments unless using pass-through patterns.\n00111| \n00112| ### Supported types\n00113| \n00114| **Arguments:**\n00115| \n00116| - Primitives: `string`, `number`, `boolean`, `null`, `undefined`\n00117| - Plain objects: `{ key: value }`\n00118| - Arrays: `[1, 2, 3]`\n00119| - Dates, Maps, Sets, TypedArrays, ArrayBuffers\n00120| - React elements (as pass-through only)\n00121| \n00122| **Return values:**\n00123| \n00124| - Same as arguments, plus JSX elements\n00125| \n00126| ### Unsupported types\n00127| \n00128| - Class instances\n00129| - Functions (except as pass-through)\n00130| - Symbols, WeakMaps, WeakSets\n00131| - URL instances\n00132| \n00133| ```tsx filename=\"app/components/user-card.tsx\"\n00134| // Valid - primitives and plain objects\n00135| async function UserCard({\n00136| id,\n00137| config,\n00138| }: {\n00139| id: string\n00140| config: { theme: string }\n00141| }) {\n00142| 'use cache'\n00143| return
{id}
\n00144| }\n00145| \n00146| // Invalid - class instance\n00147| async function UserProfile({ user }: { user: UserClass }) {\n00148| 'use cache'\n00149| // Error: Cannot serialize class instance\n00150| return
{user.name}
\n00151| }\n00152| ```\n00153| \n00154| ### Pass-through (non-serializable arguments)\n00155| \n00156| You can accept non-serializable values **as long as you don't introspect them**. This enables composition patterns with `children` and Server Actions:\n00157| \n00158| ```tsx filename=\"app/components/cached-wrapper.tsx\"\n00159| async function CachedWrapper({ children }: { children: ReactNode }) {\n00160| 'use cache'\n00161| // Don't read or modify children - just pass it through\n00162| return (\n00163|
\n00164| Cached Header\n00165| {children}\n00166|
\n00167| )\n00168| }\n00169| \n00170| // Usage: children can be dynamic\n00171| export default function Page() {\n00172| return (\n00173| \n00174| {/* Not cached, passed through */}\n00175| \n00176| )\n00177| }\n00178| ```\n00179| \n00180| You can also pass Server Actions through cached components:\n00181| \n00182| ```tsx filename=\"app/components/cached-form.tsx\"\n00183| async function CachedForm({ action }: { action: () => Promise }) {\n00184| 'use cache'\n00185| // Don't call action here - just pass it through\n00186| return
{/* ... */}
\n00187| }\n00188| ```\n00189| \n00190| ## Constraints\n00191| \n00192| Cached functions execute in an isolated environment. The following constraints ensure cache behavior remains predictable and secure.\n00193| \n00194| ### Request-time APIs\n00195| \n00196| Cached functions and components **cannot** directly access runtime APIs like `cookies()`, `headers()`, or `searchParams`. Instead, read these values outside the cached scope and pass them as arguments.\n00197| \n00198| ### Runtime caching considerations\n00199| \n00200| While `use cache` is designed primarily to include uncached data in the static shell, it can also cache data at runtime using in-memory LRU (Least Recently Used) storage.\n00201| \n00202| With the default in-memory handler, runtime cache behavior depends on your hosting environment:\n00203| \n00204| | Environment | Runtime Caching Behavior |\n00205| | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n00206| | **Serverless** | Cache entries typically don't persist across requests (each request can be a different instance), or during revalidation. Build-time caching works normally. |\n00207| | **Self-hosted** | Cache entries persist across requests. Control cache size with [`cacheMaxMemorySize`](/docs/app/api-reference/config/next-config-js/incrementalCacheHandlerPath). |\n00208| \n00209| For example, in a serverless environment, a cached function shared by two pages executes on each static shell revalidation, whereas in self-hosted or environments with persistent memory, the cached output is reused if it's still fresh.\n00210| \n00211| If the default in-memory cache isn't enough, consider **[`use cache: remote`](/docs/app/api-reference/directives/use-cache-remote)** which allows platforms to provide a dedicated cache handler (like Redis or KV database). This helps reduce hits against data sources not scaled to your total traffic, though it comes with costs (storage, network latency, platform fees).\n00212| \n00213| > [!NOTE]\n00214| > With the default in-memory handler, serverless instances are ephemeral, so entries may not be reused between requests, unlike with `use cache: remote`. Neither caching directive carries over to a new deploy, because the [cache key](#cache-keys) includes the build (or `deploymentId`) ID.\n00215| >\n00216| > For data that needs to persist across deploys, use [`unstable_cache`](/docs/app/api-reference/functions/unstable_cache) for non-`fetch` functions or the [`fetch`](/docs/app/api-reference/functions/fetch) cache.\n00217| \n00218| Very rarely, for compliance requirements or when you can't refactor your code to pass runtime data as arguments to a `use cache` scope, you might need [`use cache: private`](/docs/app/api-reference/directives/use-cache-private).\n00219| \n00220| ### Draft Mode\n00221| \n00222| When [Draft Mode](/docs/app/guides/draft-mode) is enabled, all cached functions and components re-execute on every request, and results are not saved to the cache. This ensures draft content is always fresh without requiring any changes to your caching code.\n00223| \n00224| You can read `isEnabled` from [`draftMode()`](/docs/app/api-reference/functions/draft-mode) inside a `use cache` scope, however, other runtime APIs like `cookies()` and `headers()` are not allowed, even when Draft Mode is active. See [Passing runtime values to cached functions](/docs/app/getting-started/caching#passing-runtime-values-to-cached-functions) for the recommended pattern.\n00225| \n00226| ```tsx filename=\"app/components/content.tsx\"\n00227| import { draftMode } from 'next/headers'\n00228| \n00229| async function Content() {\n00230| 'use cache'\n00231| \n00232| const { isEnabled } = await draftMode()\n00233| const url = isEnabled\n00234| ? 'https://draft.example.com/content'\n00235| : 'https://production.example.com/content'\n00236| \n00237| const data = await fetch(url)\n00238| return {/* ... */}\n00239| }\n00240| ```\n00241| \n00242| Calling `enable()` or `disable()` inside a caching directive scope will also throw an error. Draft Mode can only be toggled in [Route Handlers](/docs/app/api-reference/file-conventions/route) or [Server Actions](/docs/app/getting-started/mutating-data).\n00243| \n00244| ### React.cache isolation\n00245| \n00246| [`React.cache`](https://react.dev/reference/react/cache) operates in an isolated scope inside `use cache` boundaries. Values stored via `React.cache` outside a `use cache` function are not visible inside it.\n00247| \n00248| This means you cannot use `React.cache` to pass data into a `use cache` scope:\n00249| \n00250| ```tsx\n00251| import { cache } from 'react'\n00252| \n00253| const store = cache(() => ({ current: null as string | null }))\n00254| \n00255| function Parent() {\n00256| const shared = store()\n00257| shared.current = 'value from parent'\n00258| return \n00259| }\n00260| \n00261| async function Child() {\n00262| 'use cache'\n00263| const shared = store()\n00264| // shared.current is null, not 'value from parent'\n00265| // use cache has its own isolated React.cache scope\n00266| return
{shared.current}
\n00267| }\n00268| ```\n00269| \n00270| This isolation ensures cached functions have predictable, self-contained behavior. To pass data into a `use cache` scope, use function arguments instead.\n00271| \n00272| ## `use cache` at runtime\n00273| \n00274| On the **server**, cache entries are stored in-memory and respect the `revalidate` and `expire` times from your `cacheLife` configuration. You can customize the cache storage by configuring [`cacheHandlers`](/docs/app/api-reference/config/next-config-js/cacheHandlers) in your `next.config.js` file.\n00275| \n00276| On the **client**, content from the server cache is stored in the browser's memory for the duration defined by the `stale` time. The client router enforces a **minimum 30-second stale time**, regardless of configuration.\n00277| \n00278| The `x-nextjs-stale-time` response header communicates cache lifetime from server to client, ensuring coordinated behavior.\n00279| \n00280| ## Revalidation\n00281| \n00282| By default, `use cache` uses the `default` profile with these settings:\n00283| \n00284| - **stale**: 5 minutes (client-side)\n00285| - **revalidate**: 15 minutes (server-side)\n00286| - **expire**: Never expires by time\n00287| \n00288| ```tsx filename=\"lib/data.ts\"\n00289| async function getData() {\n00290| 'use cache'\n00291| // Implicitly uses default profile\n00292| return fetch('/api/data')\n00293| }\n00294| ```\n00295| \n00296| ### Customizing cache lifetime\n00297| \n00298| Use the [`cacheLife`](/docs/app/api-reference/functions/cacheLife) function to customize cache duration:\n00299| \n00300| ```tsx filename=\"lib/data.ts\"\n00301| import { cacheLife } from 'next/cache'\n00302| \n00303| async function getData() {\n00304| 'use cache'\n00305| cacheLife('hours') // Use built-in 'hours' profile\n00306| return fetch('/api/data')\n00307| }\n00308| ```\n00309| \n00310| ### On-demand revalidation\n00311| \n00312| Use [`cacheTag`](/docs/app/api-reference/functions/cacheTag), [`updateTag`](/docs/app/api-reference/functions/updateTag), or [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) for on-demand cache invalidation:\n00313| \n00314| ```tsx filename=\"lib/data.ts\"\n00315| import { cacheTag } from 'next/cache'\n00316| \n00317| async function getProducts() {\n00318| 'use cache'\n00319| cacheTag('products')\n00320| return fetch('/api/products')\n00321| }\n00322| ```\n00323| \n00324| ```tsx filename=\"app/actions.ts\"\n00325| 'use server'\n00326| \n00327| import { updateTag } from 'next/cache'\n00328| \n00329| export async function updateProduct() {\n00330| await db.products.update(...)\n00331| updateTag('products') // Invalidates all 'products' caches\n00332| }\n00333| ```\n00334| \n00335| Both `cacheLife` and `cacheTag` integrate across client and server caching layers, meaning you configure your caching semantics in one place and they apply everywhere.\n00336| \n00337| ## Examples\n00338| \n00339| ### Caching an entire route with `use cache`\n00340| \n00341| To prerender an entire route, add `use cache` to the top of **both** the `layout` and `page` files. Each of these segments are treated as separate entry points in your application, and will be cached independently.\n00342| \n00343| ```tsx filename=\"app/layout.tsx\" switcher\n00344| 'use cache'\n00345| \n00346| export default async function Layout({ children }: { children: ReactNode }) {\n00347| return
{children}
\n00348| }\n00349| ```\n00350| \n00351| ```jsx filename=\"app/layout.js\" switcher\n00352| 'use cache'\n00353| \n00354| export default async function Layout({ children }) {\n00355| return
{children}
\n00356| }\n00357| ```\n00358| \n00359| Any components imported and nested in `page` file are part of the cache output associated with the `page`.\n00360| \n00361| ```tsx filename=\"app/page.tsx\" switcher\n00362| 'use cache'\n00363| \n00364| async function Users() {\n00365| const users = await fetch('/api/users')\n00366| // loop through users\n00367| }\n00368| \n00369| export default async function Page() {\n00370| return (\n00371| \n00372| \n00373| \n00374| )\n00375| }\n00376| ```\n00377| \n00378| ```jsx filename=\"app/page.js\" switcher\n00379| 'use cache'\n00380| \n00381| async function Users() {\n00382| const users = await fetch('/api/users')\n00383| // loop through users\n00384| }\n00385| \n00386| export default async function Page() {\n00387| return (\n00388| \n00389| \n00390| \n00391| )\n00392| }\n00393| ```\n00394| \n00395| > **Good to know**:\n00396| >\n00397| > - If `use cache` is added only to the `layout` or the `page`, only that route segment and any components imported into it will be cached.\n00398| \n00399| ### Caching a component's output with `use cache`\n00400| \n00401| You can use `use cache` at the component level to cache any fetches or computations performed within that component. The cache entry will be reused as long as the serialized props produce the same value in each instance.\n00402| \n00403| ```tsx filename=\"app/components/bookings.tsx\" highlight={2} switcher\n00404| export async function Bookings({ type = 'haircut' }: BookingsProps) {\n00405| 'use cache'\n00406| async function getBookingsData() {\n00407| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00408| return data\n00409| }\n00410| return //...\n00411| }\n00412| \n00413| interface BookingsProps {\n00414| type: string\n00415| }\n00416| ```\n00417| \n00418| ```jsx filename=\"app/components/bookings.js\" highlight={2} switcher\n00419| export async function Bookings({ type = 'haircut' }) {\n00420| 'use cache'\n00421| async function getBookingsData() {\n00422| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00423| return data\n00424| }\n00425| return //...\n00426| }\n00427| ```\n00428| \n00429| ### Caching function output with `use cache`\n00430| \n00431| Since you can add `use cache` to any asynchronous function, you aren't limited to caching components or routes only. You might want to cache a network request, a database query, or a slow computation.\n00432| \n00433| ```tsx filename=\"app/actions.ts\" highlight={2} switcher\n00434| export async function getData() {\n00435| 'use cache'\n00436| \n00437| const data = await fetch('/api/data')\n00438| return data\n00439| }\n00440| ```\n00441| \n00442| ```jsx filename=\"app/actions.js\" highlight={2} switcher\n00443| export async function getData() {\n00444| 'use cache'\n00445| \n00446| const data = await fetch('/api/data')\n00447| return data\n00448| }\n00449| ```\n00450| \n00451| > **Good to know:** When a cached directive (`use cache`, [`use cache: private`](/docs/app/api-reference/directives/use-cache-private), or [`use cache: remote`](/docs/app/api-reference/directives/use-cache-remote)) is at the top of a file, you can import its exported functions into a Client Component and call them directly; they run on the server and return the result, similar to a [Server Function](/docs/app/glossary#server-function). Prefer calling cached functions on the server and passing results down as props.\n00452| \n00453| ### Interleaving\n00454| \n00455| In React, composition with `children` or slots is a well-known pattern for building flexible components. When using `use cache`, you can continue to compose your UI in this way. Anything included as `children`, or other compositional slots, in the returned JSX will be passed through the cached component without affecting its cache entry.\n00456| \n00457| As long as you don't directly reference any of the JSX slots inside the body of the cacheable function itself, their presence in the returned output won't affect the cache entry.\n00458| \n00459| ```tsx filename=\"app/page.tsx\" switcher\n00460| export default async function Page() {\n00461| const uncachedData = await getData()\n00462| return (\n00463| // Pass compositional slots as props, e.g. header and children\n00464| Home}>\n00465| {/* DynamicComponent is provided as the children slot */}\n00466| \n00467| \n00468| )\n00469| }\n00470| \n00471| async function CacheComponent({\n00472| header, // header: a compositional slot, injected as a prop\n00473| children, // children: another slot for nested composition\n00474| }: {\n00475| header: ReactNode\n00476| children: ReactNode\n00477| }) {\n00478| 'use cache'\n00479| const cachedData = await fetch('/api/cached-data')\n00480| return (\n00481|
\n00514| )\n00515| }\n00516| ```\n00517| \n00518| You can also pass Server Actions through cached components to Client Components without invoking them inside the cacheable function.\n00519| \n00520| ```tsx filename=\"app/page.tsx\" switcher\n00521| import ClientComponent from './ClientComponent'\n00522| \n00523| export default async function Page() {\n00524| const performUpdate = async () => {\n00525| 'use server'\n00526| // Perform some server-side update\n00527| await db.update(...)\n00528| }\n00529| \n00530| return \n00531| }\n00532| \n00533| async function CachedComponent({\n00534| performUpdate,\n00535| }: {\n00536| performUpdate: () => Promise\n00537| }) {\n00538| 'use cache'\n00539| // Do not call performUpdate here\n00540| return \n00541| }\n00542| ```\n00543| \n00544| ```jsx filename=\"app/page.js\" switcher\n00545| import ClientComponent from './ClientComponent'\n00546| \n00547| export default async function Page() {\n00548| const performUpdate = async () => {\n00549| 'use server'\n00550| // Perform some server-side update\n00551| await db.update(...)\n00552| }\n00553| \n00554| return \n00555| }\n00556| \n00557| async function CachedComponent({ performUpdate }) {\n00558| 'use cache'\n00559| // Do not call performUpdate here\n00560| return \n00561| }\n00562| ```\n00563| \n00564| ```tsx filename=\"app/ClientComponent.tsx\" switcher\n00565| 'use client'\n00566| \n00567| export default function ClientComponent({\n00568| action,\n00569| }: {\n00570| action: () => Promise\n00571| }) {\n00572| return Update\n00573| }\n00574| ```\n00575| \n00576| ```jsx filename=\"app/ClientComponent.js\" switcher\n00577| 'use client'\n00578| \n00579| export default function ClientComponent({ action }) {\n00580| return Update\n00581| }\n00582| ```\n00583| \n00584| ## Troubleshooting\n00585| \n00586| ### Debugging cache behavior\n00587| \n00588| #### Verbose logging\n00589| \n00590| Set `NEXT_PRIVATE_DEBUG_CACHE=1` for verbose cache logging:\n00591| \n00592| ```bash\n00593| NEXT_PRIVATE_DEBUG_CACHE=1 npm run dev\n00594| # or for production\n00595| NEXT_PRIVATE_DEBUG_CACHE=1 npm run start\n00596| ```\n00597| \n00598| > **Good to know:** This environment variable also logs ISR and other caching mechanisms. See [Verifying correct production behavior](/docs/app/guides/incremental-static-regeneration#verifying-correct-production-behavior) for more details.\n00599| \n00600| #### Console log replays\n00601| \n00602| In development, console logs from cached functions appear with a `Cache` prefix.\n00603| \n00604| ### Build Hangs (Cache Timeout)\n00605| \n00606| If your build hangs, you're accessing Promises that resolve to uncached or runtime data, created outside a `use cache` boundary. The cached function waits for data that can't resolve during the build, causing a timeout after 50 seconds.\n00607| \n00608| When the build timeouts you'll see this error message:\n00609| \n00610| > Error: Filling a cache during prerender timed out, likely because request-specific arguments such as params, searchParams, cookies() or uncached data were used inside \"use cache\".\n00611| \n00612| Common ways this happens: passing such Promises as props, accessing them via closure, or retrieving them from shared storage (Maps).\n00613| \n00614| > **Good to know:** Directly calling `cookies()` or `headers()` inside `use cache` fails immediately with a [different error](/docs/messages/next-request-in-use-cache), not a timeout.\n00615| \n00616| **Passing runtime data Promises as props:**\n00617| \n00618| ```tsx filename=\"app/page.tsx\"\n00619| import { cookies } from 'next/headers'\n00620| import { Suspense } from 'react'\n00621| \n00622| export default function Page() {\n00623| return (\n00624| Loading...
}>\n00625| \n00626| \n00627| )\n00628| }\n00629| \n00630| async function Dynamic() {\n00631| const cookieStore = cookies()\n00632| return // Build hangs\n00633| }\n00634| \n00635| async function Cached({ promise }: { promise: Promise }) {\n00636| 'use cache'\n00637| const data = await promise // Waits for runtime data during build\n00638| return
..
\n00639| }\n00640| ```\n00641| \n00642| Await the `cookies` store in the `Dynamic` component, and pass a cookie value to the `Cached` component.\n00643| \n00644| **Shared deduplication storage:**\n00645| \n00646| ```tsx filename=\"app/page.tsx\"\n00647| // Problem: Map stores dynamic Promises, accessed by cached code\n00648| import { Suspense } from 'react'\n00649| \n00650| const cache = new Map>()\n00651| \n00652| export default function Page() {\n00653| return (\n00654| <>\n00655| Loading...
\n00053| \n00054| )\n00055| }\n00056| \n\n(End of file - total 56 lines)\n",
+ "title": "app/admin/catalog/page.tsx",
+ "metadata": {
+ "preview": "import { revalidateTag } from 'next/cache'\nimport { getProducts } from '@/lib/products'\n\nexport default async function AdminCatalogPage() {\n const products = await getProducts()\n\n async function syncCatalog() {\n 'use server'\n\n revalidateTag('products', 'max')\n }\n\n return (\n \n
`; the action calls `revalidateTag('products', 'max')` for stale-while-revalidate background refresh\n- `lib/db.js` — extended mock products with `inventory` and `available`\n\nVerification:\n- `npm run build` passed\n- `npx tsc --noEmit` passed\n\nAdmins can click **Sync latest catalog**, the request returns immediately, and any view using the `products` tag refreshes in the background.",
+ "raw": {
+ "type": "text",
+ "timestamp": 1781392685391,
+ "sessionID": "ses_13cbb78f4ffeW1oPoj0co3q1Fm",
+ "part": {
+ "id": "prt_ec3472fed001fMQeBBOjni0Uv2",
+ "sessionID": "ses_13cbb78f4ffeW1oPoj0co3q1Fm",
+ "messageID": "msg_ec347282c001EPUWBL67sOT71V",
+ "type": "text",
+ "text": "Implemented the admin catalog page at `/admin/catalog`.\n\nKey pieces:\n- `next.config.ts` — enabled `cacheComponents: true`\n- `lib/products.ts` — cached catalog fetch using `'use cache'`, `cacheTag('products')`, and `cacheLife('max')`\n- `app/admin/catalog/page.tsx` — renders the product table and includes an inline `syncCatalog` Server Action hooked to a regular `
\n00006| )\n00007| }\n00008| \n\n(End of file - total 8 lines)\n","title":"app/page.tsx","metadata":{"preview":"export default function Page() {\n return (\n
\n
Home
\n
\n )\n}\n"},"time":{"start":1781392525215,"end":1781392525252}}}}
+{"type":"tool_use","timestamp":1781392525759,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec344c7bc0010PlYIdir7YrE7U","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec344b5ba001mjuTnyDfQWTqoW","type":"tool","callID":"read_6","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/lib/db.js"},"output":"\n00001| export async function getAllProducts() {\n00002| // Simulate database delay\n00003| await new Promise((resolve) => setTimeout(resolve, 100))\n00004| \n00005| return [\n00006| { id: 1, name: 'Laptop', price: 999 },\n00007| { id: 2, name: 'Phone', price: 699 },\n00008| { id: 3, name: 'Tablet', price: 499 },\n00009| { id: 4, name: 'Headphones', price: 199 },\n00010| { id: 5, name: 'Watch', price: 299 },\n00011| ]\n00012| }\n00013| \n\n(End of file - total 13 lines)\n","title":"lib/db.js","metadata":{"preview":"export async function getAllProducts() {\n // Simulate database delay\n await new Promise((resolve) => setTimeout(resolve, 100))\n\n return [\n { id: 1, name: 'Laptop', price: 999 },\n { id: 2, name: 'Phone', price: 699 },\n { id: 3, name: 'Tablet', price: 499 },\n { id: 4, name: 'Headphones', price: 199 },\n { id: 5, name: 'Watch', price: 299 },\n ]\n}\n"},"time":{"start":1781392525696,"end":1781392525715}}}}
+{"type":"tool_use","timestamp":1781392525981,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec344c992001VTGsunrBXmrRrT","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec344b5ba001mjuTnyDfQWTqoW","type":"tool","callID":"glob_7","tool":"glob","state":{"status":"completed","input":{"pattern":"node_modules/next/dist/docs/**/*","path":"/workspace"},"output":"No files found","title":"","metadata":{"count":0,"truncated":false},"time":{"start":1781392525914,"end":1781392525949}}}}
+{"type":"step_finish","timestamp":1781392525995,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec344ca7f001OpoO3MXUvv4Y2x","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec344b5ba001mjuTnyDfQWTqoW","type":"step-finish","reason":"tool-calls","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012","cost":0.00292447,"tokens":{"input":881,"output":143,"reasoning":0,"cache":{"read":9472,"write":0}}}}
+{"type":"step_start","timestamp":1781392527450,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec344d0420012EB9RGCAylt0Pt","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec344cae5001YOYwC28aVLwYsn","type":"step-start","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012"}}
+{"type":"tool_use","timestamp":1781392528201,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec344d10d001uZkBSolMfA4YbI","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec344cae5001YOYwC28aVLwYsn","type":"tool","callID":"bash_8","tool":"bash","state":{"status":"completed","input":{"command":"ls -la node_modules/next/dist/docs 2>/dev/null || echo \"docs dir missing\"","description":"List Next.js docs directory"},"output":"total 8\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 95 Jun 13 23:15 .\ndrwxr-xr-x 22 vercel-sandbox vercel-sandbox 4096 Jun 13 23:15 ..\ndrwxr-xr-x 5 vercel-sandbox vercel-sandbox 111 Jun 13 23:15 01-app\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 125 Jun 13 23:15 02-pages\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 124 Jun 13 23:15 03-architecture\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 74 Jun 13 23:15 04-community\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 3138 Jun 13 23:15 index.md\n","title":"List Next.js docs directory","metadata":{"output":"total 8\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 95 Jun 13 23:15 .\ndrwxr-xr-x 22 vercel-sandbox vercel-sandbox 4096 Jun 13 23:15 ..\ndrwxr-xr-x 5 vercel-sandbox vercel-sandbox 111 Jun 13 23:15 01-app\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 125 Jun 13 23:15 02-pages\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 124 Jun 13 23:15 03-architecture\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 74 Jun 13 23:15 04-community\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 3138 Jun 13 23:15 index.md\n","exit":0,"description":"List Next.js docs directory"},"time":{"start":1781392528170,"end":1781392528191}}}}
+{"type":"step_finish","timestamp":1781392528206,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec344d341001a1qLBvDF73dPOf","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec344cae5001YOYwC28aVLwYsn","type":"step-finish","reason":"tool-calls","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012","cost":0.0029365,"tokens":{"input":1118,"output":59,"reasoning":0,"cache":{"read":10240,"write":0}}}}
+{"type":"step_start","timestamp":1781392529596,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec344d8b3001cdMJbRVJgt0zli","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec344d360001gzbUXJkUDQ9tIn","type":"step-start","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012"}}
+{"type":"tool_use","timestamp":1781392530751,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec344d9a80014jW8rcJHOFHfMb","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec344d360001gzbUXJkUDQ9tIn","type":"tool","callID":"bash_9","tool":"bash","state":{"status":"completed","input":{"command":"find node_modules/next/dist/docs -type f -name \"*.md\" | xargs grep -l -i \"cache tag\\|revalidateTag\\|unstable_cache\\|server action\\|form\" 2>/dev/null | head -50","description":"Find relevant caching docs"},"output":"node_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/02-dynamic-routes.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/07-api-routes.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/06-configuring/12-error-handling.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/01-get-static-props.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/02-get-static-paths.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/03-get-server-side-props.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/05-client-side.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/04-automatic-static-optimization.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/05-client-side-rendering.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/get-initial-props.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/get-static-props.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/use-router.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/10-routing-information.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/04-config/01-next-config-js/serverExternalPackages.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/01-components/form.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/01-components/image-legacy.md\nnode_modules/next/dist/docs/02-pages/02-guides/upgrading/version-11.md\nnode_modules/next/dist/docs/02-pages/02-guides/upgrading/version-12.md\nnode_modules/next/dist/docs/02-pages/02-guides/upgrading/version-13.md\nnode_modules/next/dist/docs/02-pages/02-guides/upgrading/version-9.md\nnode_modules/next/dist/docs/02-pages/02-guides/analytics.md\nnode_modules/next/dist/docs/02-pages/02-guides/babel.md\nnode_modules/next/dist/docs/02-pages/02-guides/forms.md\nnode_modules/next/dist/docs/02-pages/02-guides/internationalization.md\nnode_modules/next/dist/docs/02-pages/02-guides/lazy-loading.md\nnode_modules/next/dist/docs/02-pages/02-guides/post-css.md\nnode_modules/next/dist/docs/02-pages/02-guides/preview-mode.md\nnode_modules/next/dist/docs/02-pages/02-guides/production-checklist.md\nnode_modules/next/dist/docs/02-pages/02-guides/third-party-libraries.md\nnode_modules/next/dist/docs/01-app/02-guides/ai-agents.md\nnode_modules/next/dist/docs/01-app/02-guides/analytics.md\nnode_modules/next/dist/docs/01-app/02-guides/authentication.md\nnode_modules/next/dist/docs/01-app/02-guides/backend-for-frontend.md\nnode_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/cdn-caching.md\nnode_modules/next/dist/docs/01-app/02-guides/ci-build-caching.md\nnode_modules/next/dist/docs/01-app/02-guides/content-security-policy.md\nnode_modules/next/dist/docs/01-app/02-guides/custom-server.md\nnode_modules/next/dist/docs/01-app/02-guides/data-security.md\nnode_modules/next/dist/docs/01-app/02-guides/debugging.md\nnode_modules/next/dist/docs/01-app/02-guides/deploying-to-platforms.md\nnode_modules/next/dist/docs/01-app/02-guides/draft-mode.md\nnode_modules/next/dist/docs/01-app/02-guides/environment-variables.md\nnode_modules/next/dist/docs/01-app/02-guides/forms.md\nnode_modules/next/dist/docs/01-app/02-guides/how-revalidation-works.md\nnode_modules/next/dist/docs/01-app/02-guides/incremental-static-regeneration.md\nnode_modules/next/dist/docs/01-app/02-guides/instant-navigation.md\nnode_modules/next/dist/docs/01-app/02-guides/instrumentation.md\n","title":"Find relevant caching docs","metadata":{"output":"node_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/02-dynamic-routes.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/07-api-routes.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/06-configuring/12-error-handling.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/01-get-static-props.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/02-get-static-paths.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/03-get-server-side-props.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/05-client-side.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/04-automatic-static-optimization.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/05-client-side-rendering.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/get-initial-props.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/get-static-props.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/use-router.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/10-routing-information.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/04-config/01-next-config-js/serverExternalPackages.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/01-components/form.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/01-components/image-legacy.md\nnode_modules/next/dist/docs/02-pages/02-guides/upgrading/version-11.md\nnode_modules/next/dist/docs/02-pages/02-guides/upgrading/version-12.md\nnode_modules/next/dist/docs/02-pages/02-guides/upgrading/version-13.md\nnode_modules/next/dist/docs/02-pages/02-guides/upgrading/version-9.md\nnode_modules/next/dist/docs/02-pages/02-guides/analytics.md\nnode_modules/next/dist/docs/02-pages/02-guides/babel.md\nnode_modules/next/dist/docs/02-pages/02-guides/forms.md\nnode_modules/next/dist/docs/02-pages/02-guides/internationalization.md\nnode_modules/next/dist/docs/02-pages/02-guides/lazy-loading.md\nnode_modules/next/dist/docs/02-pages/02-guides/post-css.md\nnode_modules/next/dist/docs/02-pages/02-guides/preview-mode.md\nnode_modules/next/dist/docs/02-pages/02-guides/production-checklist.md\nnode_modules/next/dist/docs/02-pages/02-guides/third-party-libraries.md\nnode_modules/next/dist/docs/01-app/02-guides/ai-agents.md\nnode_modules/next/dist/docs/01-app/02-guides/analytics.md\nnode_modules/next/dist/docs/01-app/02-guides/authentication.md\nnode_modules/next/dist/docs/01-app/02-guides/backend-for-frontend.md\nnode_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/cdn-caching.md\nnode_modules/next/dist/docs/01-app/02-guides/ci-build-caching.md\nnode_modules/next/dist/docs/01-app/02-guides/content-security-policy.md\nnode_modules/next/dist/docs/01-app/02-guides/custom-server.md\nnode_modules/next/dist/docs/01-app/02-guides/data-security.md\nnode_modules/next/dist/docs/01-app/02-guides/debugging.md\nnode_modules/next/dist/docs/01-app/02-guides/deploying-to-platforms.md\nnode_modules/next/dist/docs/01-app/02-guides/draft-mode.md\nnode_modules/next/dist/docs/01-app/02-guides/environment-variables.md\nnode_modules/next/dist/docs/01-app/02-guides/forms.md\nnode_modules/next/dist/docs/01-app/02-guides/how-revalidation-works.md\nnode_modules/next/dist/docs/01-app/02-guides/incremental-static-regeneration.md\nnode_modules/next/dist/docs/01-app/02-guides/instant-navigation.md\nnode_modules/next/dist/docs/01-app/02-guides/instrumentation.md\n","exit":0,"description":"Find relevant caching docs"},"time":{"start":1781392530705,"end":1781392530748}}}}
+{"type":"step_finish","timestamp":1781392530757,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec344dd3e001BgUJCoxCWn5cCP","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec344d360001gzbUXJkUDQ9tIn","type":"step-finish","reason":"tool-calls","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012","cost":0.00252514,"tokens":{"input":382,"output":90,"reasoning":0,"cache":{"read":11264,"write":0}}}}
+{"type":"step_start","timestamp":1781392532373,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec344e38b0015K1vTnE1FUybj9","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec344dd56001wm3ndJlz8siLM7","type":"step-start","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012"}}
+{"type":"tool_use","timestamp":1781392534349,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec344e5000012HFveJLuoH9iI5","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec344dd56001wm3ndJlz8siLM7","type":"tool","callID":"bash_10","tool":"bash","state":{"status":"completed","input":{"command":"find node_modules/next/dist/docs/01-app -type f -name \"*.md\" | xargs grep -l -i \"cache tag\\|revalidateTag\\|unstable_cache\" 2>/dev/null","description":"Find app caching docs"},"output":"node_modules/next/dist/docs/01-app/02-guides/backend-for-frontend.md\nnode_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/cdn-caching.md\nnode_modules/next/dist/docs/01-app/02-guides/deploying-to-platforms.md\nnode_modules/next/dist/docs/01-app/02-guides/draft-mode.md\nnode_modules/next/dist/docs/01-app/02-guides/how-revalidation-works.md\nnode_modules/next/dist/docs/01-app/02-guides/incremental-static-regeneration.md\nnode_modules/next/dist/docs/01-app/02-guides/migrating-to-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/ppr-platform-guide.md\nnode_modules/next/dist/docs/01-app/02-guides/prefetching.md\nnode_modules/next/dist/docs/01-app/02-guides/production-checklist.md\nnode_modules/next/dist/docs/01-app/02-guides/redirecting.md\nnode_modules/next/dist/docs/01-app/02-guides/rendering-philosophy.md\nnode_modules/next/dist/docs/01-app/02-guides/self-hosting.md\nnode_modules/next/dist/docs/01-app/02-guides/upgrading/codemods.md\nnode_modules/next/dist/docs/01-app/02-guides/upgrading/version-16.md\nnode_modules/next/dist/docs/01-app/04-glossary.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheLife.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cookies.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/fetch.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/next-root-params.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidatePath.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/unstable_cache.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/unstable_noStore.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/updateTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/use-router.md\nnode_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache-remote.md\nnode_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/cacheHandlers.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/incrementalCacheHandlerPath.md\nnode_modules/next/dist/docs/01-app/01-getting-started/07-mutating-data.md\nnode_modules/next/dist/docs/01-app/01-getting-started/09-revalidating.md\n","title":"Find app caching docs","metadata":{"output":"node_modules/next/dist/docs/01-app/02-guides/backend-for-frontend.md\nnode_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/cdn-caching.md\nnode_modules/next/dist/docs/01-app/02-guides/deploying-to-platforms.md\nnode_modules/next/dist/docs/01-app/02-guides/draft-mode.md\nnode_modules/next/dist/docs/01-app/02-guides/how-revalidation-works.md\nnode_modules/next/dist/docs/01-app/02-guides/incremental-static-regeneration.md\nnode_modules/next/dist/docs/01-app/02-guides/migrating-to-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/ppr-platform-guide.md\nnode_modules/next/dist/docs/01-app/02-guides/prefetching.md\nnode_modules/next/dist/docs/01-app/02-guides/production-checklist.md\nnode_modules/next/dist/docs/01-app/02-guides/redirecting.md\nnode_modules/next/dist/docs/01-app/02-guides/rendering-philosophy.md\nnode_modules/next/dist/docs/01-app/02-guides/self-hosting.md\nnode_modules/next/dist/docs/01-app/02-guides/upgrading/codemods.md\nnode_modules/next/dist/docs/01-app/02-guides/upgrading/version-16.md\nnode_modules/next/dist/docs/01-app/04-glossary.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheLife.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cookies.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/fetch.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/next-root-params.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidatePath.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/unstable_cache.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/unstable_noStore.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/updateTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/use-router.md\nnode_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache-remote.md\nnode_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/cacheHandlers.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/incrementalCacheHandlerPath.md\nnode_modules/next/dist/docs/01-app/01-getting-started/07-mutating-data.md\nnode_modules/next/dist/docs/01-app/01-getting-started/09-revalidating.md\n","exit":0,"description":"Find app caching docs"},"time":{"start":1781392534324,"end":1781392534347}}}}
+{"type":"step_finish","timestamp":1781392534356,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec344eb4c001AGe4TTN0aJnRH7","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec344dd56001wm3ndJlz8siLM7","type":"step-finish","reason":"tool-calls","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012","cost":0.0033112,"tokens":{"input":1200,"output":82,"reasoning":0,"cache":{"read":11520,"write":0}}}}
+{"type":"step_start","timestamp":1781392535970,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec344f19b001Afv1furUZuD66f","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec344eb5d001IcU2v22Hnj8HEM","type":"step-start","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012"}}
+{"type":"tool_use","timestamp":1781392537480,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec344f50e001pOTp5RUoH8W1UW","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec344eb5d001IcU2v22Hnj8HEM","type":"tool","callID":"read_11","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md"},"output":"\n00001| ---\n00002| title: cacheTag\n00003| description: Learn how to use the cacheTag function to manage cache invalidation in your Next.js application.\n00004| related:\n00005| title: Related\n00006| description: View related API references.\n00007| links:\n00008| - app/api-reference/config/next-config-js/cacheComponents\n00009| - app/api-reference/directives/use-cache\n00010| - app/api-reference/functions/revalidateTag\n00011| - app/api-reference/functions/updateTag\n00012| - app/api-reference/functions/cacheLife\n00013| ---\n00014| \n00015| The `cacheTag` function allows you to tag cached data for on-demand invalidation. By associating tags with cache entries, you can selectively purge or revalidate specific cache entries without affecting other cached data.\n00016| \n00017| ## Usage\n00018| \n00019| To use `cacheTag`, enable the [`cacheComponents` flag](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.js` file:\n00020| \n00021| ```ts filename=\"next.config.ts\" switcher\n00022| import type { NextConfig } from 'next'\n00023| \n00024| const nextConfig: NextConfig = {\n00025| cacheComponents: true,\n00026| }\n00027| \n00028| export default nextConfig\n00029| ```\n00030| \n00031| ```js filename=\"next.config.js\" switcher\n00032| const nextConfig = {\n00033| cacheComponents: true,\n00034| }\n00035| \n00036| export default nextConfig\n00037| ```\n00038| \n00039| The `cacheTag` function takes one or more string values.\n00040| \n00041| ```tsx filename=\"app/data.ts\" switcher\n00042| import { cacheTag } from 'next/cache'\n00043| \n00044| export async function getData() {\n00045| 'use cache'\n00046| cacheTag('my-data')\n00047| const data = await fetch('/api/data')\n00048| return data\n00049| }\n00050| ```\n00051| \n00052| ```jsx filename=\"app/data.js\" switcher\n00053| import { cacheTag } from 'next/cache'\n00054| \n00055| export async function getData() {\n00056| 'use cache'\n00057| cacheTag('my-data')\n00058| const data = await fetch('/api/data')\n00059| return data\n00060| }\n00061| ```\n00062| \n00063| You can then purge the cache on-demand from a [Server Function](/docs/app/getting-started/mutating-data) or [Route Handler](/docs/app/api-reference/file-conventions/route):\n00064| \n00065| - Use [`updateTag`](/docs/app/api-reference/functions/updateTag) for read-your-own-writes scenarios, such as forms and other user-triggered mutations, where a user makes a change and the next read should fetch fresh data immediately. `updateTag` is only available inside Server Functions.\n00066| - Use [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) when it is acceptable to serve stale data while revalidation happens in the background, or when revalidating from a [Route Handler](/docs/app/api-reference/file-conventions/route) or other context.\n00067| \n00068| For example, this Server Function adds a post and then purges every cache entry tagged `'my-data'` so the next read reflects the change:\n00069| \n00070| ```tsx filename=\"app/action.ts\" switcher\n00071| 'use server'\n00072| \n00073| import { updateTag } from 'next/cache'\n00074| \n00075| export default async function submit() {\n00076| await addPost()\n00077| updateTag('my-data')\n00078| }\n00079| ```\n00080| \n00081| ```jsx filename=\"app/action.js\" switcher\n00082| 'use server'\n00083| \n00084| import { updateTag } from 'next/cache'\n00085| \n00086| export default async function submit() {\n00087| await addPost()\n00088| updateTag('my-data')\n00089| }\n00090| ```\n00091| \n00092| ## Good to know\n00093| \n00094| - **Idempotent Tags**: Applying the same tag multiple times has no additional effect.\n00095| - **Multiple Tags**: You can assign multiple tags to a single cache entry by passing multiple string values to `cacheTag`.\n00096| \n00097| ```tsx\n00098| cacheTag('tag-one', 'tag-two')\n00099| ```\n00100| \n00101| - **Limits**: A single `cacheTag()` call accepts up to 128 tags, each with a maximum length of 256 characters. Tags longer than 256 characters are skipped, and any tags past the 128th in one call are dropped. Both cases log a console warning.\n00102| \n00103| ## Examples\n00104| \n00105| ### Tagging components or functions\n00106| \n00107| Tag your cached data by calling `cacheTag` within a cached function or component:\n00108| \n00109| ```tsx filename=\"app/components/bookings.tsx\" switcher\n00110| import { cacheTag } from 'next/cache'\n00111| \n00112| interface BookingsProps {\n00113| type: string\n00114| }\n00115| \n00116| export async function Bookings({ type = 'haircut' }: BookingsProps) {\n00117| 'use cache'\n00118| cacheTag('bookings-data')\n00119| \n00120| async function getBookingsData() {\n00121| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00122| return data\n00123| }\n00124| \n00125| return //...\n00126| }\n00127| ```\n00128| \n00129| ```jsx filename=\"app/components/bookings.js\" switcher\n00130| import { cacheTag } from 'next/cache'\n00131| \n00132| export async function Bookings({ type = 'haircut' }) {\n00133| 'use cache'\n00134| cacheTag('bookings-data')\n00135| \n00136| async function getBookingsData() {\n00137| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00138| return data\n00139| }\n00140| \n00141| return //...\n00142| }\n00143| ```\n00144| \n00145| ### Creating tags from external data\n00146| \n00147| You can use the data returned from an async function to tag the cache entry.\n00148| \n00149| ```tsx filename=\"app/components/bookings.tsx\" switcher\n00150| import { cacheTag } from 'next/cache'\n00151| \n00152| interface BookingsProps {\n00153| type: string\n00154| }\n00155| \n00156| export async function Bookings({ type = 'haircut' }: BookingsProps) {\n00157| async function getBookingsData() {\n00158| 'use cache'\n00159| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00160| cacheTag('bookings-data', data.id)\n00161| return data\n00162| }\n00163| return //...\n00164| }\n00165| ```\n00166| \n00167| ```jsx filename=\"app/components/bookings.js\" switcher\n00168| import { cacheTag } from 'next/cache'\n00169| \n00170| export async function Bookings({ type = 'haircut' }) {\n00171| async function getBookingsData() {\n00172| 'use cache'\n00173| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00174| cacheTag('bookings-data', data.id)\n00175| return data\n00176| }\n00177| return //...\n00178| }\n00179| ```\n00180| \n00181| ### Invalidating tagged cache\n00182| \n00183| Using [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag), you can invalidate the cache for a specific tag when needed:\n00184| \n00185| ```tsx filename=\"app/actions.ts\" switcher\n00186| 'use server'\n00187| \n00188| import { revalidateTag } from 'next/cache'\n00189| \n00190| export async function updateBookings() {\n00191| await updateBookingData()\n00192| revalidateTag('bookings-data', 'max')\n00193| }\n00194| ```\n00195| \n00196| ```jsx filename=\"app/actions.js\" switcher\n00197| 'use server'\n00198| \n00199| import { revalidateTag } from 'next/cache'\n00200| \n00201| export async function updateBookings() {\n00202| await updateBookingData()\n00203| revalidateTag('bookings-data', 'max')\n00204| }\n00205| ```\n00206| \n\n(End of file - total 206 lines)\n","title":"node_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md","metadata":{"preview":"---\ntitle: cacheTag\ndescription: Learn how to use the cacheTag function to manage cache invalidation in your Next.js application.\nrelated:\n title: Related\n description: View related API references.\n links:\n - app/api-reference/config/next-config-js/cacheComponents\n - app/api-reference/directives/use-cache\n - app/api-reference/functions/revalidateTag\n - app/api-reference/functions/updateTag\n - app/api-reference/functions/cacheLife\n---\n\nThe `cacheTag` function allows you to tag cached data for on-demand invalidation. By associating tags with cache entries, you can selectively purge or revalidate specific cache entries without affecting other cached data.\n\n## Usage\n\nTo use `cacheTag`, enable the [`cacheComponents` flag](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.js` file:\n"},"time":{"start":1781392537472,"end":1781392537476}}}}
+{"type":"tool_use","timestamp":1781392538345,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec344f782001j9x2IeFN2BviqH","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec344eb5d001IcU2v22Hnj8HEM","type":"tool","callID":"read_12","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md"},"output":"\n00001| ---\n00002| title: revalidateTag\n00003| description: API Reference for the revalidateTag function.\n00004| ---\n00005| \n00006| `revalidateTag` allows you to invalidate cached data on-demand for a specific cache tag.\n00007| \n00008| This function is ideal for content where a slight delay in updates is acceptable, such as blog posts, product catalogs, or documentation. Users receive stale content while fresh data loads in the background.\n00009| \n00010| ## Usage\n00011| \n00012| `revalidateTag` can be called in Server Functions and Route Handlers.\n00013| \n00014| `revalidateTag` cannot be called in Client Components or Proxy, as it only works in server environments.\n00015| \n00016| ### Revalidation Behavior\n00017| \n00018| The revalidation behavior depends on whether you provide the second argument:\n00019| \n00020| - **With `profile=\"max\"` (recommended)**: The tag entry is marked as stale, and the next time a resource with that tag is visited, it will use stale-while-revalidate semantics. This means the stale content is served while fresh content is fetched in the background.\n00021| - **With a custom cache life profile**: For advanced usage, you can specify any cache life profile that your application has defined, allowing for custom revalidation behaviors tailored to your specific caching requirements.\n00022| - **Without the second argument (deprecated)**: The tag entry is expired immediately, and the next request to that resource will be a blocking revalidate/cache miss. This behavior is now deprecated, and you should either use `profile=\"max\"` or migrate to [`updateTag`](/docs/app/api-reference/functions/updateTag).\n00023| \n00024| > **Good to know**: When using `profile=\"max\"`, `revalidateTag` marks tagged data as stale, but fresh data is only fetched when pages using that tag are next visited. This means calling `revalidateTag` will not immediately trigger many revalidations at once. The invalidation only happens when any page using that tag is next visited.\n00025| \n00026| ## Parameters\n00027| \n00028| ```ts\n00029| revalidateTag(tag: string, profile: string | { expire?: number }): void;\n00030| ```\n00031| \n00032| - `tag`: A string representing the cache tag associated with the data you want to revalidate. Must not exceed 256 characters. This value is case-sensitive.\n00033| - `profile`: A string that specifies the revalidation behavior. The recommended value is `\"max\"` which provides stale-while-revalidate semantics, or any of the other default or custom profiles defined in [`cacheLife`](/docs/app/api-reference/config/next-config-js/cacheLife). Alternatively, you can pass an object with an `expire` property for custom expiration behavior.\n00034| \n00035| Tags must first be assigned to cached data. You can do this in two ways:\n00036| \n00037| - Using the [`next.tags`](/docs/app/api-reference/functions/fetch) option with `fetch` for caching external API requests:\n00038| \n00039| ```tsx\n00040| fetch(url, { next: { tags: ['posts'] } })\n00041| ```\n00042| \n00043| - Using [`cacheTag`](/docs/app/api-reference/functions/cacheTag) inside cached functions or components with the `'use cache'` directive:\n00044| \n00045| ```tsx\n00046| import { cacheTag } from 'next/cache'\n00047| \n00048| async function getData() {\n00049| 'use cache'\n00050| cacheTag('posts')\n00051| // ...\n00052| }\n00053| ```\n00054| \n00055| > **Good to know**: The single-argument form `revalidateTag(tag)` is deprecated. It currently works if TypeScript errors are suppressed, but this behavior may be removed in a future version. Update to the two-argument signature.\n00056| \n00057| ## Returns\n00058| \n00059| `revalidateTag` does not return a value.\n00060| \n00061| ## Relationship with `revalidatePath`\n00062| \n00063| `revalidateTag` invalidates data with specific tags across all pages that use those tags, while [`revalidatePath`](/docs/app/api-reference/functions/revalidatePath) invalidates specific page or layout paths.\n00064| \n00065| > **Good to know**: These functions serve different purposes and may need to be used together for comprehensive data consistency. For detailed examples and considerations, see [relationship with revalidateTag and updateTag](/docs/app/api-reference/functions/revalidatePath#relationship-with-revalidatetag-and-updatetag) for more information.\n00066| \n00067| ## Examples\n00068| \n00069| The following examples demonstrate how to use `revalidateTag` in different contexts. In both cases, we're using `profile=\"max\"` to mark data as stale and use stale-while-revalidate semantics, which is the recommended approach for most use cases.\n00070| \n00071| ### Server Action\n00072| \n00073| ```ts filename=\"app/actions.ts\" switcher\n00074| 'use server'\n00075| \n00076| import { revalidateTag } from 'next/cache'\n00077| \n00078| export default async function submit() {\n00079| await addPost()\n00080| revalidateTag('posts', 'max')\n00081| }\n00082| ```\n00083| \n00084| ```js filename=\"app/actions.js\" switcher\n00085| 'use server'\n00086| \n00087| import { revalidateTag } from 'next/cache'\n00088| \n00089| export default async function submit() {\n00090| await addPost()\n00091| revalidateTag('posts', 'max')\n00092| }\n00093| ```\n00094| \n00095| ### Route Handler\n00096| \n00097| ```ts filename=\"app/api/revalidate/route.ts\" switcher\n00098| import type { NextRequest } from 'next/server'\n00099| import { revalidateTag } from 'next/cache'\n00100| \n00101| export async function GET(request: NextRequest) {\n00102| const tag = request.nextUrl.searchParams.get('tag')\n00103| \n00104| if (tag) {\n00105| revalidateTag(tag, 'max')\n00106| return Response.json({ revalidated: true, now: Date.now() })\n00107| }\n00108| \n00109| return Response.json({\n00110| revalidated: false,\n00111| now: Date.now(),\n00112| message: 'Missing tag to revalidate',\n00113| })\n00114| }\n00115| ```\n00116| \n00117| ```js filename=\"app/api/revalidate/route.js\" switcher\n00118| import { revalidateTag } from 'next/cache'\n00119| \n00120| export async function GET(request) {\n00121| const tag = request.nextUrl.searchParams.get('tag')\n00122| \n00123| if (tag) {\n00124| revalidateTag(tag, 'max')\n00125| return Response.json({ revalidated: true, now: Date.now() })\n00126| }\n00127| \n00128| return Response.json({\n00129| revalidated: false,\n00130| now: Date.now(),\n00131| message: 'Missing tag to revalidate',\n00132| })\n00133| }\n00134| ```\n00135| \n00136| > **Good to know**: For webhooks or third-party services that need immediate expiration, you can pass `{ expire: 0 }` as the second argument: `revalidateTag(tag, { expire: 0 })`. This pattern is necessary when external systems call your Route Handlers and require data to expire immediately. For all other cases, it's recommended to use [`updateTag`](/docs/app/api-reference/functions/updateTag) in Server Actions for immediate updates instead.\n00137| \n\n(End of file - total 137 lines)\n","title":"node_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md","metadata":{"preview":"---\ntitle: revalidateTag\ndescription: API Reference for the revalidateTag function.\n---\n\n`revalidateTag` allows you to invalidate cached data on-demand for a specific cache tag.\n\nThis function is ideal for content where a slight delay in updates is acceptable, such as blog posts, product catalogs, or documentation. Users receive stale content while fresh data loads in the background.\n\n## Usage\n\n`revalidateTag` can be called in Server Functions and Route Handlers.\n\n`revalidateTag` cannot be called in Client Components or Proxy, as it only works in server environments.\n\n### Revalidation Behavior\n\nThe revalidation behavior depends on whether you provide the second argument:\n\n- **With `profile=\"max\"` (recommended)**: The tag entry is marked as stale, and the next time a resource with that tag is visited, it will use stale-while-revalidate semantics. This means the stale content is served while fresh content is fetched in the background."},"time":{"start":1781392538335,"end":1781392538341}}}}
+{"type":"tool_use","timestamp":1781392539071,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec344fae3001sjFd6bBOfprqF7","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec344eb5d001IcU2v22Hnj8HEM","type":"tool","callID":"read_13","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/unstable_cache.md"},"output":"\n00001| ---\n00002| title: unstable_cache\n00003| description: API Reference for the unstable_cache function.\n00004| ---\n00005| \n00006| > **Note:**\n00007| > This API has been replaced by [`use cache`](/docs/app/api-reference/directives/use-cache) in Next.js 16.\n00008| > We recommend opting into [Cache Components](/docs/app/getting-started/caching) and replacing `unstable_cache` with the `use cache` directive.\n00009| \n00010| `unstable_cache` allows you to cache the results of expensive operations, like database queries, and reuse them across multiple requests.\n00011| \n00012| ```jsx\n00013| import { getUser } from './data';\n00014| import { unstable_cache } from 'next/cache';\n00015| \n00016| const getCachedUser = unstable_cache(\n00017| async (id) => getUser(id),\n00018| ['my-app-user']\n00019| );\n00020| \n00021| export default async function Component({ userID }) {\n00022| const user = await getCachedUser(userID);\n00023| ...\n00024| }\n00025| ```\n00026| \n00027| > **Good to know**:\n00028| >\n00029| > - Accessing uncached data sources such as `headers` or `cookies` inside a cache scope is not supported. If you need this data inside a cached function use `headers` outside of the cached function and pass the required uncached data in as an argument.\n00030| > - This API uses Next.js' built-in cache to persist the result across requests and deployments. See [Caching and Revalidating](/docs/app/getting-started/caching).\n00031| \n00032| ## Parameters\n00033| \n00034| ```jsx\n00035| const data = unstable_cache(fetchData, keyParts, options)()\n00036| ```\n00037| \n00038| - `fetchData`: This is an asynchronous function that fetches the data you want to cache. It must be a function that returns a `Promise`.\n00039| - `keyParts`: This is an extra array of keys that further adds identification to the cache. By default, `unstable_cache` already uses the arguments and the stringified version of your function as the cache key. It is optional in most cases; the only time you need to use it is when you use external variables without passing them as parameters. However, it is important to add closures used within the function if you do not pass them as parameters.\n00040| - `options`: This is an object that controls how the cache behaves. It can contain the following properties:\n00041| - `tags`: An array of tags that can be used to control cache invalidation. Next.js will not use this to uniquely identify the function.\n00042| - `revalidate`: The number of seconds after which the cache should be revalidated. Omit or pass `false` to cache indefinitely or until matching `revalidateTag()` or `revalidatePath()` methods are called.\n00043| \n00044| ## Returns\n00045| \n00046| `unstable_cache` returns a function that when invoked, returns a Promise that resolves to the cached data. If the data is not in the cache, the provided function will be invoked, and its result will be cached and returned.\n00047| \n00048| ## Example\n00049| \n00050| ```tsx filename=\"app/page.tsx\" switcher\n00051| import { unstable_cache } from 'next/cache'\n00052| \n00053| export default async function Page({\n00054| params,\n00055| }: {\n00056| params: Promise<{ userId: string }>\n00057| }) {\n00058| const { userId } = await params\n00059| const getCachedUser = unstable_cache(\n00060| async () => {\n00061| return { id: userId }\n00062| },\n00063| [userId], // add the user ID to the cache key\n00064| {\n00065| tags: ['users'],\n00066| revalidate: 60,\n00067| }\n00068| )\n00069| \n00070| //...\n00071| }\n00072| ```\n00073| \n00074| ```jsx filename=\"app/page.jsx\" switcher\n00075| import { unstable_cache } from 'next/cache';\n00076| \n00077| export default async function Page({ params } }) {\n00078| const { userId } = await params\n00079| const getCachedUser = unstable_cache(\n00080| async () => {\n00081| return { id: userId };\n00082| },\n00083| [userId], // add the user ID to the cache key\n00084| {\n00085| tags: [\"users\"],\n00086| revalidate: 60,\n00087| }\n00088| );\n00089| \n00090| //...\n00091| }\n00092| ```\n00093| \n00094| ## Version History\n00095| \n00096| | Version | Changes |\n00097| | --------- | ---------------------------- |\n00098| | `v14.0.0` | `unstable_cache` introduced. |\n00099| \n\n(End of file - total 99 lines)\n","title":"node_modules/next/dist/docs/01-app/03-api-reference/04-functions/unstable_cache.md","metadata":{"preview":"---\ntitle: unstable_cache\ndescription: API Reference for the unstable_cache function.\n---\n\n> **Note:**\n> This API has been replaced by [`use cache`](/docs/app/api-reference/directives/use-cache) in Next.js 16.\n> We recommend opting into [Cache Components](/docs/app/getting-started/caching) and replacing `unstable_cache` with the `use cache` directive.\n\n`unstable_cache` allows you to cache the results of expensive operations, like database queries, and reuse them across multiple requests.\n\n```jsx\nimport { getUser } from './data';\nimport { unstable_cache } from 'next/cache';\n\nconst getCachedUser = unstable_cache(\n async (id) => getUser(id),\n ['my-app-user']\n);\n"},"time":{"start":1781392539062,"end":1781392539067}}}}
+{"type":"tool_use","timestamp":1781392539728,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec344fdb9001xqRwmDQ4my1hAY","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec344eb5d001IcU2v22Hnj8HEM","type":"tool","callID":"read_14","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/node_modules/next/dist/docs/01-app/01-getting-started/07-mutating-data.md"},"output":"\n00001| ---\n00002| title: Mutating Data\n00003| description: Learn how to mutate data using Server Functions and Server Actions in Next.js.\n00004| related:\n00005| title: API Reference\n00006| description: Learn more about the features mentioned in this page by reading the API Reference.\n00007| links:\n00008| - app/api-reference/functions/revalidatePath\n00009| - app/api-reference/functions/revalidateTag\n00010| - app/api-reference/functions/redirect\n00011| ---\n00012| \n00013| You can mutate data in Next.js using [React Server Functions](https://react.dev/reference/rsc/server-functions). This page will go through how you can [create](#creating-server-functions) and [invoke](#invoking-server-functions) Server Functions.\n00014| \n00015| ## What are Server Functions?\n00016| \n00017| A **Server Function** is an asynchronous function that runs on the server. You can call them from the client through a network request, which is why they must be asynchronous.\n00018| \n00019| In an `action` or mutation context, they are also called **Server Actions**.\n00020| \n00021| By convention, a Server Action is an async function used with [`startTransition`](https://react.dev/reference/react/startTransition). This happens automatically when the function is:\n00022| \n00023| - Passed to a `
` using the `action` prop.\n00024| - Passed to a `` using the `formAction` prop.\n00025| \n00026| When an action is invoked, Next.js can return both the updated UI and new data in a single server roundtrip.\n00027| \n00028| Behind the scenes, actions use the `POST` method, and only this HTTP method can invoke them.\n00029| \n00030| > [!WARNING]\n00031| > Server Functions are reachable via direct POST requests, not just through your application's UI. Always verify authentication and authorization inside every Server Function. See the [Data Security guide](/docs/app/guides/data-security#authentication-and-authorization) for recommended patterns.\n00032| \n00033| > **Good to know:** A Server Action is a Server Function used in a specific way (for handling form submissions and mutations). Server Function is the broader term.\n00034| \n00035| ## Creating Server Functions\n00036| \n00037| A Server Function can be defined by using the [`use server`](https://react.dev/reference/rsc/use-server) directive. You can place the directive at the top of an **asynchronous** function to mark the function as a Server Function, or at the top of a separate file to mark all exports of that file.\n00038| \n00039| ```ts filename=\"app/lib/actions.ts\" switcher\n00040| import { auth } from '@/lib/auth'\n00041| \n00042| export async function createPost(formData: FormData) {\n00043| 'use server'\n00044| const session = await auth()\n00045| if (!session?.user) {\n00046| throw new Error('Unauthorized')\n00047| }\n00048| \n00049| const title = formData.get('title')\n00050| const content = formData.get('content')\n00051| \n00052| // Mutate data\n00053| // Revalidate cache\n00054| }\n00055| \n00056| export async function deletePost(formData: FormData) {\n00057| 'use server'\n00058| const session = await auth()\n00059| if (!session?.user) {\n00060| throw new Error('Unauthorized')\n00061| }\n00062| \n00063| const id = formData.get('id')\n00064| \n00065| // Verify the user owns this resource before deleting\n00066| // Mutate data\n00067| // Revalidate cache\n00068| }\n00069| ```\n00070| \n00071| ```js filename=\"app/lib/actions.js\" switcher\n00072| import { auth } from '@/lib/auth'\n00073| \n00074| export async function createPost(formData) {\n00075| 'use server'\n00076| const session = await auth()\n00077| if (!session?.user) {\n00078| throw new Error('Unauthorized')\n00079| }\n00080| \n00081| const title = formData.get('title')\n00082| const content = formData.get('content')\n00083| \n00084| // Mutate data\n00085| // Revalidate cache\n00086| }\n00087| \n00088| export async function deletePost(formData) {\n00089| 'use server'\n00090| const session = await auth()\n00091| if (!session?.user) {\n00092| throw new Error('Unauthorized')\n00093| }\n00094| \n00095| const id = formData.get('id')\n00096| \n00097| // Verify the user owns this resource before deleting\n00098| // Mutate data\n00099| // Revalidate cache\n00100| }\n00101| ```\n00102| \n00103| ### Server Components\n00104| \n00105| Server Functions can be inlined in Server Components by adding the `\"use server\"` directive to the top of the function body:\n00106| \n00107| ```tsx filename=\"app/page.tsx\" switcher\n00108| export default function Page() {\n00109| // Server Action\n00110| async function createPost(formData: FormData) {\n00111| 'use server'\n00112| // ...\n00113| }\n00114| \n00115| return <>>\n00116| }\n00117| ```\n00118| \n00119| ```jsx filename=\"app/page.js\" switcher\n00120| export default function Page() {\n00121| // Server Action\n00122| async function createPost(formData) {\n00123| 'use server'\n00124| // ...\n00125| }\n00126| \n00127| return <>>\n00128| }\n00129| ```\n00130| \n00131| > **Good to know:** Server Components support progressive enhancement by default, meaning forms that call Server Actions will be submitted even if JavaScript hasn't loaded yet or is disabled.\n00132| \n00133| ### Client Components\n00134| \n00135| It's not possible to define Server Functions in Client Components. However, you can invoke them in Client Components by importing them from a file that has the `\"use server\"` directive at the top of it:\n00136| \n00137| ```ts filename=\"app/actions.ts\" switcher\n00138| 'use server'\n00139| \n00140| export async function createPost() {}\n00141| ```\n00142| \n00143| ```js filename=\"app/actions.js\" switcher\n00144| 'use server'\n00145| \n00146| export async function createPost() {}\n00147| ```\n00148| \n00149| ```tsx filename=\"app/ui/button.tsx\" switcher\n00150| 'use client'\n00151| \n00152| import { createPost } from '@/app/actions'\n00153| \n00154| export function Button() {\n00155| return Create\n00156| }\n00157| ```\n00158| \n00159| ```jsx filename=\"app/ui/button.js\" switcher\n00160| 'use client'\n00161| \n00162| import { createPost } from '@/app/actions'\n00163| \n00164| export function Button() {\n00165| return Create\n00166| }\n00167| ```\n00168| \n00169| > **Good to know:** In Client Components, forms invoking Server Actions will queue submissions if JavaScript isn't loaded yet, and will be prioritized for hydration. After hydration, the browser does not refresh on form submission.\n00170| \n00171| ### Passing actions as props\n00172| \n00173| You can also pass an action to a Client Component as a prop:\n00174| \n00175| ```jsx\n00176| \n00177| ```\n00178| \n00179| ```tsx filename=\"app/client-component.tsx\" switcher\n00180| 'use client'\n00181| \n00182| export default function ClientComponent({\n00183| updateItemAction,\n00184| }: {\n00185| updateItemAction: (formData: FormData) => void\n00186| }) {\n00187| return
\n00196| }\n00197| ```\n00198| \n00199| ## Invoking Server Functions\n00200| \n00201| There are two main ways you can invoke a Server Function:\n00202| \n00203| 1. [Forms](#forms) in Server and Client Components\n00204| 2. [Event Handlers](#event-handlers) and [useEffect](#useeffect) in Client Components\n00205| \n00206| > **Good to know:** Server Functions are designed for server-side mutations. The client currently dispatches and awaits them one at a time. This is an implementation detail and may change. If you need parallel data fetching, use [data fetching](/docs/app/getting-started/fetching-data#server-components) in Server Components, or perform parallel work inside a single Server Function or [Route Handler](/docs/app/guides/backend-for-frontend#manipulating-data).\n00207| \n00208| ### Forms\n00209| \n00210| React extends the HTML [`
`](https://react.dev/reference/react-dom/components/form) element to allow a Server Function to be invoked with the HTML `action` prop.\n00211| \n00212| When invoked in a form, the function automatically receives the [`FormData`](https://developer.mozilla.org/docs/Web/API/FormData/FormData) object. You can extract the data using the native [`FormData` methods](https://developer.mozilla.org/en-US/docs/Web/API/FormData#instance_methods):\n00213| \n00214| ```tsx filename=\"app/ui/form.tsx\" switcher\n00215| import { createPost } from '@/app/actions'\n00216| \n00217| export function Form() {\n00218| return (\n00219|
\n00321| {\n00323| const updatedLikes = await incrementLike()\n00324| setLikes(updatedLikes)\n00325| }}\n00326| >\n00327| Like\n00328| \n00329| >\n00330| )\n00331| }\n00332| ```\n00333| \n00334| ## Examples\n00335| \n00336| ### Showing a pending state\n00337| \n00338| While executing a Server Function, you can show a loading indicator with React's [`useActionState`](https://react.dev/reference/react/useActionState) hook. This hook returns a `pending` boolean:\n00339| \n00340| ```tsx filename=\"app/ui/button.tsx\" switcher\n00341| 'use client'\n00342| \n00343| import { useActionState, startTransition } from 'react'\n00344| import { createPost } from '@/app/actions'\n00345| import { LoadingSpinner } from '@/app/ui/loading-spinner'\n00346| \n00347| export function Button() {\n00348| const [state, action, pending] = useActionState(createPost, false)\n00349| \n00350| return (\n00351| startTransition(action)}>\n00352| {pending ? : 'Create Post'}\n00353| \n00354| )\n00355| }\n00356| ```\n00357| \n00358| ```jsx filename=\"app/ui/button.js\" switcher\n00359| 'use client'\n00360| \n00361| import { useActionState, startTransition } from 'react'\n00362| import { createPost } from '@/app/actions'\n00363| import { LoadingSpinner } from '@/app/ui/loading-spinner'\n00364| \n00365| export function Button() {\n00366| const [state, action, pending] = useActionState(createPost, false)\n00367| \n00368| return (\n00369| startTransition(action)}>\n00370| {pending ? : 'Create Post'}\n00371| \n00372| )\n00373| }\n00374| ```\n00375| \n00376| ### Refresh data\n00377| \n00378| After a mutation, you may want to refresh the current page to show the latest data. You can do this by calling [`refresh`](/docs/app/api-reference/functions/refresh) from `next/cache` in a Server Action:\n00379| \n00380| ```ts filename=\"app/lib/actions.ts\" switcher\n00381| 'use server'\n00382| \n00383| import { auth } from '@/lib/auth'\n00384| import { refresh } from 'next/cache'\n00385| \n00386| export async function updatePost(formData: FormData) {\n00387| const session = await auth()\n00388| if (!session?.user) {\n00389| throw new Error('Unauthorized')\n00390| }\n00391| // Mutate data\n00392| // ...\n00393| \n00394| refresh()\n00395| }\n00396| ```\n00397| \n00398| ```js filename=\"app/lib/actions.js\" switcher\n00399| 'use server'\n00400| \n00401| import { auth } from '@/lib/auth'\n00402| import { refresh } from 'next/cache'\n00403| \n00404| export async function updatePost(formData) {\n00405| const session = await auth()\n00406| if (!session?.user) {\n00407| throw new Error('Unauthorized')\n00408| }\n00409| // Mutate data\n00410| // ...\n00411| \n00412| refresh()\n00413| }\n00414| ```\n00415| \n00416| This refreshes the client router, ensuring the UI reflects the latest state. The `refresh()` function does not revalidate tagged data. To revalidate tagged data, use [`updateTag`](/docs/app/api-reference/functions/updateTag) or [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) instead.\n00417| \n00418| ### Revalidate data\n00419| \n00420| After performing a mutation, you can revalidate the Next.js cache and show the updated data by calling [`revalidatePath`](/docs/app/api-reference/functions/revalidatePath) or [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) within the Server Function:\n00421| \n00422| ```ts filename=\"app/lib/actions.ts\" switcher\n00423| import { auth } from '@/lib/auth'\n00424| import { revalidatePath } from 'next/cache'\n00425| \n00426| export async function createPost(formData: FormData) {\n00427| 'use server'\n00428| const session = await auth()\n00429| if (!session?.user) {\n00430| throw new Error('Unauthorized')\n00431| }\n00432| // Mutate data\n00433| // ...\n00434| \n00435| revalidatePath('/posts')\n00436| }\n00437| ```\n00438| \n00439| ```js filename=\"app/actions.js\" switcher\n00440| import { auth } from '@/lib/auth'\n00441| import { revalidatePath } from 'next/cache'\n00442| \n00443| export async function createPost(formData) {\n00444| 'use server'\n00445| const session = await auth()\n00446| if (!session?.user) {\n00447| throw new Error('Unauthorized')\n00448| }\n00449| // Mutate data\n00450| // ...\n00451| revalidatePath('/posts')\n00452| }\n00453| ```\n00454| \n00455| ### Redirect after a mutation\n00456| \n00457| You may want to redirect the user to a different page after a mutation. You can do this by calling [`redirect`](/docs/app/api-reference/functions/redirect) within the Server Function.\n00458| \n00459| ```ts filename=\"app/lib/actions.ts\" switcher\n00460| 'use server'\n00461| \n00462| import { auth } from '@/lib/auth'\n00463| import { revalidatePath } from 'next/cache'\n00464| import { redirect } from 'next/navigation'\n00465| \n00466| export async function createPost(formData: FormData) {\n00467| const session = await auth()\n00468| if (!session?.user) {\n00469| throw new Error('Unauthorized')\n00470| }\n00471| // Mutate data\n00472| // ...\n00473| \n00474| revalidatePath('/posts')\n00475| redirect('/posts')\n00476| }\n00477| ```\n00478| \n00479| ```js filename=\"app/actions.js\" switcher\n00480| 'use server'\n00481| \n00482| import { auth } from '@/lib/auth'\n00483| import { revalidatePath } from 'next/cache'\n00484| import { redirect } from 'next/navigation'\n00485| \n00486| export async function createPost(formData) {\n00487| const session = await auth()\n00488| if (!session?.user) {\n00489| throw new Error('Unauthorized')\n00490| }\n00491| // Mutate data\n00492| // ...\n00493| \n00494| revalidatePath('/posts')\n00495| redirect('/posts')\n00496| }\n00497| ```\n00498| \n00499| Calling `redirect` [throws](/docs/app/api-reference/functions/redirect#behavior) a framework handled control-flow exception. Any code after it won't execute. If you need fresh data, call [`revalidatePath`](/docs/app/api-reference/functions/revalidatePath) or [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) beforehand.\n00500| \n00501| ### Cookies\n00502| \n00503| You can `get`, `set`, and `delete` cookies inside a Server Action using the [`cookies`](/docs/app/api-reference/functions/cookies) API.\n00504| \n00505| When you [set or delete](/docs/app/api-reference/functions/cookies#understanding-cookie-behavior-in-server-functions) a cookie in a Server Action, Next.js re-renders the current page and its layouts on the server so the **UI reflects the new cookie value**.\n00506| \n00507| > **Good to know**: The server update applies to the current React tree, re-rendering, mounting, or unmounting components, as needed. Client state is preserved for re-rendered components, and effects re-run if their dependencies changed.\n00508| \n00509| ```ts filename=\"app/actions.ts\" switcher\n00510| 'use server'\n00511| \n00512| import { cookies } from 'next/headers'\n00513| \n00514| export async function exampleAction() {\n00515| const cookieStore = await cookies()\n00516| \n00517| // Get cookie\n00518| cookieStore.get('name')?.value\n00519| \n00520| // Set cookie\n00521| cookieStore.set('name', 'Delba')\n00522| \n00523| // Delete cookie\n00524| cookieStore.delete('name')\n00525| }\n00526| ```\n00527| \n00528| ```js filename=\"app/actions.js\" switcher\n00529| 'use server'\n00530| \n00531| import { cookies } from 'next/headers'\n00532| \n00533| export async function exampleAction() {\n00534| // Get cookie\n00535| const cookieStore = await cookies()\n00536| \n00537| // Get cookie\n00538| cookieStore.get('name')?.value\n00539| \n00540| // Set cookie\n00541| cookieStore.set('name', 'Delba')\n00542| \n00543| // Delete cookie\n00544| cookieStore.delete('name')\n00545| }\n00546| ```\n00547| \n00548| ### useEffect\n00549| \n00550| You can use the React [`useEffect`](https://react.dev/reference/react/useEffect) hook to invoke a Server Action when the component mounts or a dependency changes. This is useful for mutations that depend on global events or need to be triggered automatically. For example, `onKeyDown` for app shortcuts, an intersection observer hook for infinite scrolling, or when the component mounts to update a view count:\n00551| \n00552| ```tsx filename=\"app/view-count.tsx\" switcher\n00553| 'use client'\n00554| \n00555| import { incrementViews } from './actions'\n00556| import { useState, useEffect, useTransition } from 'react'\n00557| \n00558| export default function ViewCount({ initialViews }: { initialViews: number }) {\n00559| const [views, setViews] = useState(initialViews)\n00560| const [isPending, startTransition] = useTransition()\n00561| \n00562| useEffect(() => {\n00563| startTransition(async () => {\n00564| const updatedViews = await incrementViews()\n00565| setViews(updatedViews)\n00566| })\n00567| }, [])\n00568| \n00569| // You can use `isPending` to give users feedback\n00570| return
Total Views: {views}
\n00571| }\n00572| ```\n00573| \n00574| ```jsx filename=\"app/view-count.js\" switcher\n00575| 'use client'\n00576| \n00577| import { incrementViews } from './actions'\n00578| import { useState, useEffect, useTransition } from 'react'\n00579| \n00580| export default function ViewCount({ initialViews }) {\n00581| const [views, setViews] = useState(initialViews)\n00582| const [isPending, startTransition] = useTransition()\n00583| \n00584| useEffect(() => {\n00585| startTransition(async () => {\n00586| const updatedViews = await incrementViews()\n00587| setViews(updatedViews)\n00588| })\n00589| }, [])\n00590| \n00591| // You can use `isPending` to give users feedback\n00592| return
Total Views: {views}
\n00593| }\n00594| ```\n00595| \n\n(End of file - total 595 lines)\n
","title":"node_modules/next/dist/docs/01-app/01-getting-started/07-mutating-data.md","metadata":{"preview":"---\ntitle: Mutating Data\ndescription: Learn how to mutate data using Server Functions and Server Actions in Next.js.\nrelated:\n title: API Reference\n description: Learn more about the features mentioned in this page by reading the API Reference.\n links:\n - app/api-reference/functions/revalidatePath\n - app/api-reference/functions/revalidateTag\n - app/api-reference/functions/redirect\n---\n\nYou can mutate data in Next.js using [React Server Functions](https://react.dev/reference/rsc/server-functions). This page will go through how you can [create](#creating-server-functions) and [invoke](#invoking-server-functions) Server Functions.\n\n## What are Server Functions?\n\nA **Server Function** is an asynchronous function that runs on the server. You can call them from the client through a network request, which is why they must be asynchronous.\n\nIn an `action` or mutation context, they are also called **Server Actions**.\n"},"time":{"start":1781392539714,"end":1781392539726}}}}
+{"type":"tool_use","timestamp":1781392539966,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec345004c001HptszOF9EicETk","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec344eb5d001IcU2v22Hnj8HEM","type":"tool","callID":"read_15","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/node_modules/next/dist/docs/01-app/01-getting-started/09-revalidating.md"},"output":"\n00001| ---\n00002| title: Revalidating\n00003| description: Learn how to revalidate cached data using time-based and on-demand strategies.\n00004| related:\n00005| title: API Reference\n00006| description: Learn more about the APIs mentioned on this page.\n00007| links:\n00008| - app/api-reference/functions/cacheLife\n00009| - app/api-reference/functions/cacheTag\n00010| - app/api-reference/functions/revalidateTag\n00011| - app/api-reference/functions/updateTag\n00012| - app/api-reference/functions/revalidatePath\n00013| ---\n00014| \n00015| > This page covers revalidation with [Cache Components](/docs/app/api-reference/config/next-config-js/cacheComponents), enabled by setting [`cacheComponents: true`](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.ts` file. If you're not using Cache Components, see the [Caching and Revalidating (Previous Model)](/docs/app/guides/caching-without-cache-components) guide.\n00016| \n00017| Revalidation is the process of updating cached data. It lets you keep serving fast, cached responses while ensuring content stays fresh. There are two strategies:\n00018| \n00019| - **Time-based revalidation**: Automatically refresh cached data after a set duration using [`cacheLife`](#cachelife).\n00020| - **On-demand revalidation**: Manually invalidate cached data after a mutation using [`revalidateTag`](#revalidatetag), [`updateTag`](#updatetag), or [`revalidatePath`](#revalidatepath).\n00021| \n00022| ## `cacheLife`\n00023| \n00024| [`cacheLife`](/docs/app/api-reference/functions/cacheLife) controls how long cached data remains valid. Use it inside a [`use cache`](/docs/app/api-reference/directives/use-cache) scope to set the cache lifetime.\n00025| \n00026| ```tsx filename=\"app/lib/data.ts\" highlight={1,4,5}\n00027| import { cacheLife } from 'next/cache'\n00028| \n00029| export async function getProducts() {\n00030| 'use cache'\n00031| cacheLife('hours')\n00032| return db.query('SELECT * FROM products')\n00033| }\n00034| ```\n00035| \n00036| `cacheLife` accepts a profile name or a custom configuration object:\n00037| \n00038| | Profile | `stale` | `revalidate` | `expire` |\n00039| | --------- | ------- | ------------ | -------- |\n00040| | `default` | 5m | 15m | never |\n00041| | `seconds` | 30s | 1s | 60s |\n00042| | `minutes` | 5m | 1m | 1h |\n00043| | `hours` | 5m | 1h | 1d |\n00044| | `days` | 5m | 1d | 1w |\n00045| | `weeks` | 5m | 1w | 30d |\n00046| | `max` | 5m | 30d | 1y |\n00047| \n00048| For fine-grained control, pass an object:\n00049| \n00050| ```tsx highlight={2-6}\n00051| 'use cache'\n00052| cacheLife({\n00053| stale: 3600, // 1 hour until considered stale\n00054| revalidate: 7200, // 2 hours until revalidated\n00055| expire: 86400, // 1 day until expired\n00056| })\n00057| ```\n00058| \n00059| > **Good to know:** A cache is considered \"short-lived\" when it uses the `seconds` profile, `revalidate: 0`, or `expire` under 5 minutes. Short-lived caches are automatically excluded from prerenders and become dynamic holes instead. See [Prerendering behavior](/docs/app/api-reference/functions/cacheLife#prerendering-behavior) for details.\n00060| \n00061| See the [`cacheLife` API reference](/docs/app/api-reference/functions/cacheLife) for all profiles and custom configuration options.\n00062| \n00063| ## `cacheTag`\n00064| \n00065| [`cacheTag`](/docs/app/api-reference/functions/cacheTag) lets you tag cached data so it can be invalidated on-demand. Use it inside a [`use cache`](/docs/app/api-reference/directives/use-cache) scope:\n00066| \n00067| ```tsx filename=\"app/lib/data.ts\" switcher\n00068| import { cacheTag } from 'next/cache'\n00069| \n00070| export async function getProducts() {\n00071| 'use cache'\n00072| cacheTag('products')\n00073| return db.query('SELECT * FROM products')\n00074| }\n00075| ```\n00076| \n00077| ```jsx filename=\"app/lib/data.js\" switcher\n00078| import { cacheTag } from 'next/cache'\n00079| \n00080| export async function getProducts() {\n00081| 'use cache'\n00082| cacheTag('products')\n00083| return db.query('SELECT * FROM products')\n00084| }\n00085| ```\n00086| \n00087| Once tagged, invalidate the cache using [`revalidateTag`](#revalidatetag) or [`updateTag`](#updatetag).\n00088| \n00089| See the [`cacheTag` API reference](/docs/app/api-reference/functions/cacheTag) to learn more.\n00090| \n00091| ## `revalidateTag`\n00092| \n00093| `revalidateTag` invalidates cache entries by tag using stale-while-revalidate semantics — stale content is served immediately while fresh content loads in the background. This is ideal for content where a slight delay in updates is acceptable, like blog posts or product catalogs.\n00094| \n00095| ```tsx filename=\"app/lib/actions.ts\" highlight={1,5} switcher\n00096| import { revalidateTag } from 'next/cache'\n00097| \n00098| export async function updateUser(id: string) {\n00099| // Mutate data\n00100| revalidateTag('user', 'max') // Recommended: stale-while-revalidate\n00101| }\n00102| ```\n00103| \n00104| ```jsx filename=\"app/lib/actions.js\" highlight={1,5} switcher\n00105| import { revalidateTag } from 'next/cache'\n00106| \n00107| export async function updateUser(id) {\n00108| // Mutate data\n00109| revalidateTag('user', 'max') // Recommended: stale-while-revalidate\n00110| }\n00111| ```\n00112| \n00113| You can reuse the same tag in multiple functions to revalidate them all at once. Call `revalidateTag` in a [Server Action](/docs/app/getting-started/mutating-data) or [Route Handler](/docs/app/api-reference/file-conventions/route).\n00114| \n00115| > **Good to know:** The second argument sets how long stale content can be served while fresh content generates in the background. Once it expires, subsequent requests block until fresh content is ready. Using `'max'` gives the longest stale window.\n00116| \n00117| See the [`revalidateTag` API reference](/docs/app/api-reference/functions/revalidateTag) to learn more.\n00118| \n00119| ## `updateTag`\n00120| \n00121| `updateTag` immediately expires cached data for read-your-own-writes scenarios — the user sees their change right away instead of stale content. Unlike `revalidateTag`, it can only be used in [Server Actions](/docs/app/getting-started/mutating-data).\n00122| \n00123| ```tsx filename=\"app/lib/actions.ts\" highlight={1,12} switcher\n00124| import { updateTag } from 'next/cache'\n00125| import { redirect } from 'next/navigation'\n00126| \n00127| export async function createPost(formData: FormData) {\n00128| const post = await db.post.create({\n00129| data: {\n00130| title: formData.get('title'),\n00131| content: formData.get('content'),\n00132| },\n00133| })\n00134| \n00135| updateTag('posts')\n00136| redirect(`/posts/${post.id}`)\n00137| }\n00138| ```\n00139| \n00140| ```jsx filename=\"app/lib/actions.js\" highlight={1,12} switcher\n00141| import { updateTag } from 'next/cache'\n00142| import { redirect } from 'next/navigation'\n00143| \n00144| export async function createPost(formData) {\n00145| const post = await db.post.create({\n00146| data: {\n00147| title: formData.get('title'),\n00148| content: formData.get('content'),\n00149| },\n00150| })\n00151| \n00152| updateTag('posts')\n00153| redirect(`/posts/${post.id}`)\n00154| }\n00155| ```\n00156| \n00157| | | `updateTag` | `revalidateTag` |\n00158| | ------------ | --------------------------------------------- | ------------------------------------ |\n00159| | **Where** | Server Actions only | Server Actions and Route Handlers |\n00160| | **Behavior** | Immediately expires cache | Stale-while-revalidate |\n00161| | **Use case** | Read-your-own-writes (user sees their change) | Background refresh (slight delay OK) |\n00162| \n00163| See the [`updateTag` API reference](/docs/app/api-reference/functions/updateTag) to learn more.\n00164| \n00165| ## `revalidatePath`\n00166| \n00167| `revalidatePath` invalidates all cached data for a specific route path. Use it when you want to revalidate a route without knowing which tags are associated with it.\n00168| \n00169| ```tsx filename=\"app/lib/actions.ts\" highlight={1,5} switcher\n00170| import { revalidatePath } from 'next/cache'\n00171| \n00172| export async function updateUser(id: string) {\n00173| // Mutate data\n00174| revalidatePath('/profile')\n00175| }\n00176| ```\n00177| \n00178| ```jsx filename=\"app/lib/actions.js\" highlight={1,5} switcher\n00179| import { revalidatePath } from 'next/cache'\n00180| \n00181| export async function updateUser(id) {\n00182| // Mutate data\n00183| revalidatePath('/profile')\n00184| }\n00185| ```\n00186| \n00187| > **Good to know**: Prefer tag-based revalidation (`revalidateTag`/`updateTag`) over path-based when possible — it's more precise and avoids over-invalidating.\n00188| \n00189| See the [`revalidatePath` API reference](/docs/app/api-reference/functions/revalidatePath) to learn more.\n00190| \n00191| ## What should I cache?\n00192| \n00193| Cache data that doesn't depend on [runtime data](/docs/app/getting-started/caching#working-with-runtime-apis) and that you're OK serving from cache for a period of time. Use `use cache` with `cacheLife` to describe that behavior.\n00194| \n00195| For content management systems with update mechanisms, use tags with longer cache durations and rely on `revalidateTag` to refresh content when it actually changes, rather than expiring the cache preemptively.\n00196| \n00197| > **Good to know:** In serverless environments, in-memory cache entries may not persist across revalidations. See [runtime caching considerations](/docs/app/api-reference/directives/use-cache#runtime-caching-considerations) for details.\n00198| \n\n(End of file - total 198 lines)\n","title":"node_modules/next/dist/docs/01-app/01-getting-started/09-revalidating.md","metadata":{"preview":"---\ntitle: Revalidating\ndescription: Learn how to revalidate cached data using time-based and on-demand strategies.\nrelated:\n title: API Reference\n description: Learn more about the APIs mentioned on this page.\n links:\n - app/api-reference/functions/cacheLife\n - app/api-reference/functions/cacheTag\n - app/api-reference/functions/revalidateTag\n - app/api-reference/functions/updateTag\n - app/api-reference/functions/revalidatePath\n---\n\n> This page covers revalidation with [Cache Components](/docs/app/api-reference/config/next-config-js/cacheComponents), enabled by setting [`cacheComponents: true`](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.ts` file. If you're not using Cache Components, see the [Caching and Revalidating (Previous Model)](/docs/app/guides/caching-without-cache-components) guide.\n\nRevalidation is the process of updating cached data. It lets you keep serving fast, cached responses while ensuring content stays fresh. There are two strategies:\n\n- **Time-based revalidation**: Automatically refresh cached data after a set duration using [`cacheLife`](#cachelife).\n- **On-demand revalidation**: Manually invalidate cached data after a mutation using [`revalidateTag`](#revalidatetag), [`updateTag`](#updatetag), or [`revalidatePath`](#revalidatepath)."},"time":{"start":1781392539956,"end":1781392539963}}}}
+{"type":"step_finish","timestamp":1781392539978,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec345013c001KPeJNDc6COWKXl","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec344eb5d001IcU2v22Hnj8HEM","type":"step-finish","reason":"tool-calls","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012","cost":0.00363929,"tokens":{"input":935,"output":186,"reasoning":0,"cache":{"read":12544,"write":0}}}}
+{"type":"step_start","timestamp":1781392543419,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec3450eb2001A7qMxtSNL6Bpxz","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec345015e001is3nMOxoQaAHTT","type":"step-start","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012"}}
+{"type":"tool_use","timestamp":1781392546190,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec345167f001hM35u1pnNpSdAa","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec345015e001is3nMOxoQaAHTT","type":"tool","callID":"read_16","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/node_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache.md"},"output":"\n00001| ---\n00002| title: use cache\n00003| description: Learn how to use the \"use cache\" directive to cache data in your Next.js application.\n00004| related:\n00005| title: Related\n00006| description: View related API references.\n00007| links:\n00008| - app/api-reference/directives/use-cache-private\n00009| - app/api-reference/config/next-config-js/cacheComponents\n00010| - app/api-reference/config/next-config-js/cacheLife\n00011| - app/api-reference/config/next-config-js/cacheHandlers\n00012| - app/api-reference/functions/cacheTag\n00013| - app/api-reference/functions/cacheLife\n00014| - app/api-reference/functions/revalidateTag\n00015| ---\n00016| \n00017| The `use cache` directive allows you to mark a route, React component, or a function as cacheable. It can be used at the top of a file to indicate that all exports in the file should be cached, or inline at the top of a function or component to cache the return value. Functions and components that use `use cache` must be async.\n00018| \n00019| > **Good to know:**\n00020| >\n00021| > - To use cookies or headers, read them outside cached scopes and pass values as arguments. This is the preferred pattern.\n00022| > - If the in-memory cache isn't sufficient for runtime data, [`'use cache: remote'`](/docs/app/api-reference/directives/use-cache-remote) allows platforms to provide a dedicated cache handler, though it requires a network roundtrip to check the cache and typically incurs platform fees.\n00023| > - For compliance requirements or when you can't refactor to pass runtime data as arguments to a `use cache` scope, see [`'use cache: private'`](/docs/app/api-reference/directives/use-cache-private).\n00024| \n00025| ## Usage\n00026| \n00027| `use cache` is a Cache Components feature. To enable it, add the [`cacheComponents`](/docs/app/api-reference/config/next-config-js/cacheComponents) option to your `next.config.ts` file:\n00028| \n00029| ```ts filename=\"next.config.ts\" switcher\n00030| import type { NextConfig } from 'next'\n00031| \n00032| const nextConfig: NextConfig = {\n00033| cacheComponents: true,\n00034| }\n00035| \n00036| export default nextConfig\n00037| ```\n00038| \n00039| ```js filename=\"next.config.js\" switcher\n00040| /** @type {import('next').NextConfig} */\n00041| const nextConfig = {\n00042| cacheComponents: true,\n00043| }\n00044| \n00045| module.exports = nextConfig\n00046| ```\n00047| \n00048| Then, add `use cache` at the file, component, or function level. All functions and components using `use cache` must be async. When used at file level, every exported function becomes a cached function and must also be async:\n00049| \n00050| ```tsx\n00051| // File level\n00052| 'use cache'\n00053| \n00054| export default async function Page() {\n00055| // ...\n00056| }\n00057| \n00058| // Component level\n00059| export async function MyComponent() {\n00060| 'use cache'\n00061| return <>>\n00062| }\n00063| \n00064| // Function level\n00065| export async function getData() {\n00066| 'use cache'\n00067| const data = await fetch('/api/data')\n00068| return data\n00069| }\n00070| ```\n00071| \n00072| ## How `use cache` works\n00073| \n00074| ### Cache keys\n00075| \n00076| A cache entry's key is generated using a serialized version of its inputs, which includes:\n00077| \n00078| 1. **Build ID** - Unique per build, changing this invalidates all cache entries. If [`deploymentId`](/docs/app/api-reference/config/next-config-js/deploymentId) is configured, it overrides the build ID for cache key purposes.\n00079| 2. **Function ID** - A secure hash of the function's location and signature in the codebase\n00080| 3. **Serializable arguments** - Props (for components) or function arguments\n00081| 4. **HMR refresh hash** (development only) - Invalidates cache on hot module replacement\n00082| \n00083| When a cached function references variables from outer scopes, those variables are automatically captured and bound as arguments, making them part of the cache key.\n00084| \n00085| ```tsx filename=\"lib/data.ts\"\n00086| async function Component({ userId }: { userId: string }) {\n00087| const getData = async (filter: string) => {\n00088| 'use cache'\n00089| // Cache key includes both userId (from closure) and filter (argument)\n00090| return fetch(`/api/users/${userId}/data?filter=${filter}`)\n00091| }\n00092| \n00093| return getData('active')\n00094| }\n00095| ```\n00096| \n00097| In the snippet above, `userId` is captured from the outer scope and `filter` is passed as an argument, so both become part of the `getData` function's cache key. This means different user and filter combinations will have separate cache entries.\n00098| \n00099| > **Good to know:** When a cached function reads [root parameters](/docs/app/api-reference/functions/next-root-params), only the ones it actually reads become part of its cache key.\n00100| \n00101| ## Serialization\n00102| \n00103| Arguments to cached functions and their return values must be serializable.\n00104| \n00105| For a complete reference, see:\n00106| \n00107| - [Serializable arguments](https://react.dev/reference/rsc/use-server#serializable-parameters-and-return-values) - Uses **React Server Components** serialization\n00108| - [Serializable return types](https://react.dev/reference/rsc/use-client#serializable-types) - Uses **React Client Components** serialization\n00109| \n00110| > **Good to know:** Arguments and return values use different serialization systems. Server Component serialization (for arguments) is more restrictive than Client Component serialization (for return values). This means you can return JSX elements but cannot accept them as arguments unless using pass-through patterns.\n00111| \n00112| ### Supported types\n00113| \n00114| **Arguments:**\n00115| \n00116| - Primitives: `string`, `number`, `boolean`, `null`, `undefined`\n00117| - Plain objects: `{ key: value }`\n00118| - Arrays: `[1, 2, 3]`\n00119| - Dates, Maps, Sets, TypedArrays, ArrayBuffers\n00120| - React elements (as pass-through only)\n00121| \n00122| **Return values:**\n00123| \n00124| - Same as arguments, plus JSX elements\n00125| \n00126| ### Unsupported types\n00127| \n00128| - Class instances\n00129| - Functions (except as pass-through)\n00130| - Symbols, WeakMaps, WeakSets\n00131| - URL instances\n00132| \n00133| ```tsx filename=\"app/components/user-card.tsx\"\n00134| // Valid - primitives and plain objects\n00135| async function UserCard({\n00136| id,\n00137| config,\n00138| }: {\n00139| id: string\n00140| config: { theme: string }\n00141| }) {\n00142| 'use cache'\n00143| return
{id}
\n00144| }\n00145| \n00146| // Invalid - class instance\n00147| async function UserProfile({ user }: { user: UserClass }) {\n00148| 'use cache'\n00149| // Error: Cannot serialize class instance\n00150| return
{user.name}
\n00151| }\n00152| ```\n00153| \n00154| ### Pass-through (non-serializable arguments)\n00155| \n00156| You can accept non-serializable values **as long as you don't introspect them**. This enables composition patterns with `children` and Server Actions:\n00157| \n00158| ```tsx filename=\"app/components/cached-wrapper.tsx\"\n00159| async function CachedWrapper({ children }: { children: ReactNode }) {\n00160| 'use cache'\n00161| // Don't read or modify children - just pass it through\n00162| return (\n00163|
\n00164| Cached Header\n00165| {children}\n00166|
\n00167| )\n00168| }\n00169| \n00170| // Usage: children can be dynamic\n00171| export default function Page() {\n00172| return (\n00173| \n00174| {/* Not cached, passed through */}\n00175| \n00176| )\n00177| }\n00178| ```\n00179| \n00180| You can also pass Server Actions through cached components:\n00181| \n00182| ```tsx filename=\"app/components/cached-form.tsx\"\n00183| async function CachedForm({ action }: { action: () => Promise }) {\n00184| 'use cache'\n00185| // Don't call action here - just pass it through\n00186| return
{/* ... */}
\n00187| }\n00188| ```\n00189| \n00190| ## Constraints\n00191| \n00192| Cached functions execute in an isolated environment. The following constraints ensure cache behavior remains predictable and secure.\n00193| \n00194| ### Request-time APIs\n00195| \n00196| Cached functions and components **cannot** directly access runtime APIs like `cookies()`, `headers()`, or `searchParams`. Instead, read these values outside the cached scope and pass them as arguments.\n00197| \n00198| ### Runtime caching considerations\n00199| \n00200| While `use cache` is designed primarily to include uncached data in the static shell, it can also cache data at runtime using in-memory LRU (Least Recently Used) storage.\n00201| \n00202| With the default in-memory handler, runtime cache behavior depends on your hosting environment:\n00203| \n00204| | Environment | Runtime Caching Behavior |\n00205| | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n00206| | **Serverless** | Cache entries typically don't persist across requests (each request can be a different instance), or during revalidation. Build-time caching works normally. |\n00207| | **Self-hosted** | Cache entries persist across requests. Control cache size with [`cacheMaxMemorySize`](/docs/app/api-reference/config/next-config-js/incrementalCacheHandlerPath). |\n00208| \n00209| For example, in a serverless environment, a cached function shared by two pages executes on each static shell revalidation, whereas in self-hosted or environments with persistent memory, the cached output is reused if it's still fresh.\n00210| \n00211| If the default in-memory cache isn't enough, consider **[`use cache: remote`](/docs/app/api-reference/directives/use-cache-remote)** which allows platforms to provide a dedicated cache handler (like Redis or KV database). This helps reduce hits against data sources not scaled to your total traffic, though it comes with costs (storage, network latency, platform fees).\n00212| \n00213| > [!NOTE]\n00214| > With the default in-memory handler, serverless instances are ephemeral, so entries may not be reused between requests, unlike with `use cache: remote`. Neither caching directive carries over to a new deploy, because the [cache key](#cache-keys) includes the build (or `deploymentId`) ID.\n00215| >\n00216| > For data that needs to persist across deploys, use [`unstable_cache`](/docs/app/api-reference/functions/unstable_cache) for non-`fetch` functions or the [`fetch`](/docs/app/api-reference/functions/fetch) cache.\n00217| \n00218| Very rarely, for compliance requirements or when you can't refactor your code to pass runtime data as arguments to a `use cache` scope, you might need [`use cache: private`](/docs/app/api-reference/directives/use-cache-private).\n00219| \n00220| ### Draft Mode\n00221| \n00222| When [Draft Mode](/docs/app/guides/draft-mode) is enabled, all cached functions and components re-execute on every request, and results are not saved to the cache. This ensures draft content is always fresh without requiring any changes to your caching code.\n00223| \n00224| You can read `isEnabled` from [`draftMode()`](/docs/app/api-reference/functions/draft-mode) inside a `use cache` scope, however, other runtime APIs like `cookies()` and `headers()` are not allowed, even when Draft Mode is active. See [Passing runtime values to cached functions](/docs/app/getting-started/caching#passing-runtime-values-to-cached-functions) for the recommended pattern.\n00225| \n00226| ```tsx filename=\"app/components/content.tsx\"\n00227| import { draftMode } from 'next/headers'\n00228| \n00229| async function Content() {\n00230| 'use cache'\n00231| \n00232| const { isEnabled } = await draftMode()\n00233| const url = isEnabled\n00234| ? 'https://draft.example.com/content'\n00235| : 'https://production.example.com/content'\n00236| \n00237| const data = await fetch(url)\n00238| return {/* ... */}\n00239| }\n00240| ```\n00241| \n00242| Calling `enable()` or `disable()` inside a caching directive scope will also throw an error. Draft Mode can only be toggled in [Route Handlers](/docs/app/api-reference/file-conventions/route) or [Server Actions](/docs/app/getting-started/mutating-data).\n00243| \n00244| ### React.cache isolation\n00245| \n00246| [`React.cache`](https://react.dev/reference/react/cache) operates in an isolated scope inside `use cache` boundaries. Values stored via `React.cache` outside a `use cache` function are not visible inside it.\n00247| \n00248| This means you cannot use `React.cache` to pass data into a `use cache` scope:\n00249| \n00250| ```tsx\n00251| import { cache } from 'react'\n00252| \n00253| const store = cache(() => ({ current: null as string | null }))\n00254| \n00255| function Parent() {\n00256| const shared = store()\n00257| shared.current = 'value from parent'\n00258| return \n00259| }\n00260| \n00261| async function Child() {\n00262| 'use cache'\n00263| const shared = store()\n00264| // shared.current is null, not 'value from parent'\n00265| // use cache has its own isolated React.cache scope\n00266| return
{shared.current}
\n00267| }\n00268| ```\n00269| \n00270| This isolation ensures cached functions have predictable, self-contained behavior. To pass data into a `use cache` scope, use function arguments instead.\n00271| \n00272| ## `use cache` at runtime\n00273| \n00274| On the **server**, cache entries are stored in-memory and respect the `revalidate` and `expire` times from your `cacheLife` configuration. You can customize the cache storage by configuring [`cacheHandlers`](/docs/app/api-reference/config/next-config-js/cacheHandlers) in your `next.config.js` file.\n00275| \n00276| On the **client**, content from the server cache is stored in the browser's memory for the duration defined by the `stale` time. The client router enforces a **minimum 30-second stale time**, regardless of configuration.\n00277| \n00278| The `x-nextjs-stale-time` response header communicates cache lifetime from server to client, ensuring coordinated behavior.\n00279| \n00280| ## Revalidation\n00281| \n00282| By default, `use cache` uses the `default` profile with these settings:\n00283| \n00284| - **stale**: 5 minutes (client-side)\n00285| - **revalidate**: 15 minutes (server-side)\n00286| - **expire**: Never expires by time\n00287| \n00288| ```tsx filename=\"lib/data.ts\"\n00289| async function getData() {\n00290| 'use cache'\n00291| // Implicitly uses default profile\n00292| return fetch('/api/data')\n00293| }\n00294| ```\n00295| \n00296| ### Customizing cache lifetime\n00297| \n00298| Use the [`cacheLife`](/docs/app/api-reference/functions/cacheLife) function to customize cache duration:\n00299| \n00300| ```tsx filename=\"lib/data.ts\"\n00301| import { cacheLife } from 'next/cache'\n00302| \n00303| async function getData() {\n00304| 'use cache'\n00305| cacheLife('hours') // Use built-in 'hours' profile\n00306| return fetch('/api/data')\n00307| }\n00308| ```\n00309| \n00310| ### On-demand revalidation\n00311| \n00312| Use [`cacheTag`](/docs/app/api-reference/functions/cacheTag), [`updateTag`](/docs/app/api-reference/functions/updateTag), or [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) for on-demand cache invalidation:\n00313| \n00314| ```tsx filename=\"lib/data.ts\"\n00315| import { cacheTag } from 'next/cache'\n00316| \n00317| async function getProducts() {\n00318| 'use cache'\n00319| cacheTag('products')\n00320| return fetch('/api/products')\n00321| }\n00322| ```\n00323| \n00324| ```tsx filename=\"app/actions.ts\"\n00325| 'use server'\n00326| \n00327| import { updateTag } from 'next/cache'\n00328| \n00329| export async function updateProduct() {\n00330| await db.products.update(...)\n00331| updateTag('products') // Invalidates all 'products' caches\n00332| }\n00333| ```\n00334| \n00335| Both `cacheLife` and `cacheTag` integrate across client and server caching layers, meaning you configure your caching semantics in one place and they apply everywhere.\n00336| \n00337| ## Examples\n00338| \n00339| ### Caching an entire route with `use cache`\n00340| \n00341| To prerender an entire route, add `use cache` to the top of **both** the `layout` and `page` files. Each of these segments are treated as separate entry points in your application, and will be cached independently.\n00342| \n00343| ```tsx filename=\"app/layout.tsx\" switcher\n00344| 'use cache'\n00345| \n00346| export default async function Layout({ children }: { children: ReactNode }) {\n00347| return
{children}
\n00348| }\n00349| ```\n00350| \n00351| ```jsx filename=\"app/layout.js\" switcher\n00352| 'use cache'\n00353| \n00354| export default async function Layout({ children }) {\n00355| return
{children}
\n00356| }\n00357| ```\n00358| \n00359| Any components imported and nested in `page` file are part of the cache output associated with the `page`.\n00360| \n00361| ```tsx filename=\"app/page.tsx\" switcher\n00362| 'use cache'\n00363| \n00364| async function Users() {\n00365| const users = await fetch('/api/users')\n00366| // loop through users\n00367| }\n00368| \n00369| export default async function Page() {\n00370| return (\n00371| \n00372| \n00373| \n00374| )\n00375| }\n00376| ```\n00377| \n00378| ```jsx filename=\"app/page.js\" switcher\n00379| 'use cache'\n00380| \n00381| async function Users() {\n00382| const users = await fetch('/api/users')\n00383| // loop through users\n00384| }\n00385| \n00386| export default async function Page() {\n00387| return (\n00388| \n00389| \n00390| \n00391| )\n00392| }\n00393| ```\n00394| \n00395| > **Good to know**:\n00396| >\n00397| > - If `use cache` is added only to the `layout` or the `page`, only that route segment and any components imported into it will be cached.\n00398| \n00399| ### Caching a component's output with `use cache`\n00400| \n00401| You can use `use cache` at the component level to cache any fetches or computations performed within that component. The cache entry will be reused as long as the serialized props produce the same value in each instance.\n00402| \n00403| ```tsx filename=\"app/components/bookings.tsx\" highlight={2} switcher\n00404| export async function Bookings({ type = 'haircut' }: BookingsProps) {\n00405| 'use cache'\n00406| async function getBookingsData() {\n00407| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00408| return data\n00409| }\n00410| return //...\n00411| }\n00412| \n00413| interface BookingsProps {\n00414| type: string\n00415| }\n00416| ```\n00417| \n00418| ```jsx filename=\"app/components/bookings.js\" highlight={2} switcher\n00419| export async function Bookings({ type = 'haircut' }) {\n00420| 'use cache'\n00421| async function getBookingsData() {\n00422| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00423| return data\n00424| }\n00425| return //...\n00426| }\n00427| ```\n00428| \n00429| ### Caching function output with `use cache`\n00430| \n00431| Since you can add `use cache` to any asynchronous function, you aren't limited to caching components or routes only. You might want to cache a network request, a database query, or a slow computation.\n00432| \n00433| ```tsx filename=\"app/actions.ts\" highlight={2} switcher\n00434| export async function getData() {\n00435| 'use cache'\n00436| \n00437| const data = await fetch('/api/data')\n00438| return data\n00439| }\n00440| ```\n00441| \n00442| ```jsx filename=\"app/actions.js\" highlight={2} switcher\n00443| export async function getData() {\n00444| 'use cache'\n00445| \n00446| const data = await fetch('/api/data')\n00447| return data\n00448| }\n00449| ```\n00450| \n00451| > **Good to know:** When a cached directive (`use cache`, [`use cache: private`](/docs/app/api-reference/directives/use-cache-private), or [`use cache: remote`](/docs/app/api-reference/directives/use-cache-remote)) is at the top of a file, you can import its exported functions into a Client Component and call them directly; they run on the server and return the result, similar to a [Server Function](/docs/app/glossary#server-function). Prefer calling cached functions on the server and passing results down as props.\n00452| \n00453| ### Interleaving\n00454| \n00455| In React, composition with `children` or slots is a well-known pattern for building flexible components. When using `use cache`, you can continue to compose your UI in this way. Anything included as `children`, or other compositional slots, in the returned JSX will be passed through the cached component without affecting its cache entry.\n00456| \n00457| As long as you don't directly reference any of the JSX slots inside the body of the cacheable function itself, their presence in the returned output won't affect the cache entry.\n00458| \n00459| ```tsx filename=\"app/page.tsx\" switcher\n00460| export default async function Page() {\n00461| const uncachedData = await getData()\n00462| return (\n00463| // Pass compositional slots as props, e.g. header and children\n00464| Home}>\n00465| {/* DynamicComponent is provided as the children slot */}\n00466| \n00467| \n00468| )\n00469| }\n00470| \n00471| async function CacheComponent({\n00472| header, // header: a compositional slot, injected as a prop\n00473| children, // children: another slot for nested composition\n00474| }: {\n00475| header: ReactNode\n00476| children: ReactNode\n00477| }) {\n00478| 'use cache'\n00479| const cachedData = await fetch('/api/cached-data')\n00480| return (\n00481|
\n00514| )\n00515| }\n00516| ```\n00517| \n00518| You can also pass Server Actions through cached components to Client Components without invoking them inside the cacheable function.\n00519| \n00520| ```tsx filename=\"app/page.tsx\" switcher\n00521| import ClientComponent from './ClientComponent'\n00522| \n00523| export default async function Page() {\n00524| const performUpdate = async () => {\n00525| 'use server'\n00526| // Perform some server-side update\n00527| await db.update(...)\n00528| }\n00529| \n00530| return \n00531| }\n00532| \n00533| async function CachedComponent({\n00534| performUpdate,\n00535| }: {\n00536| performUpdate: () => Promise\n00537| }) {\n00538| 'use cache'\n00539| // Do not call performUpdate here\n00540| return \n00541| }\n00542| ```\n00543| \n00544| ```jsx filename=\"app/page.js\" switcher\n00545| import ClientComponent from './ClientComponent'\n00546| \n00547| export default async function Page() {\n00548| const performUpdate = async () => {\n00549| 'use server'\n00550| // Perform some server-side update\n00551| await db.update(...)\n00552| }\n00553| \n00554| return \n00555| }\n00556| \n00557| async function CachedComponent({ performUpdate }) {\n00558| 'use cache'\n00559| // Do not call performUpdate here\n00560| return \n00561| }\n00562| ```\n00563| \n00564| ```tsx filename=\"app/ClientComponent.tsx\" switcher\n00565| 'use client'\n00566| \n00567| export default function ClientComponent({\n00568| action,\n00569| }: {\n00570| action: () => Promise\n00571| }) {\n00572| return Update\n00573| }\n00574| ```\n00575| \n00576| ```jsx filename=\"app/ClientComponent.js\" switcher\n00577| 'use client'\n00578| \n00579| export default function ClientComponent({ action }) {\n00580| return Update\n00581| }\n00582| ```\n00583| \n00584| ## Troubleshooting\n00585| \n00586| ### Debugging cache behavior\n00587| \n00588| #### Verbose logging\n00589| \n00590| Set `NEXT_PRIVATE_DEBUG_CACHE=1` for verbose cache logging:\n00591| \n00592| ```bash\n00593| NEXT_PRIVATE_DEBUG_CACHE=1 npm run dev\n00594| # or for production\n00595| NEXT_PRIVATE_DEBUG_CACHE=1 npm run start\n00596| ```\n00597| \n00598| > **Good to know:** This environment variable also logs ISR and other caching mechanisms. See [Verifying correct production behavior](/docs/app/guides/incremental-static-regeneration#verifying-correct-production-behavior) for more details.\n00599| \n00600| #### Console log replays\n00601| \n00602| In development, console logs from cached functions appear with a `Cache` prefix.\n00603| \n00604| ### Build Hangs (Cache Timeout)\n00605| \n00606| If your build hangs, you're accessing Promises that resolve to uncached or runtime data, created outside a `use cache` boundary. The cached function waits for data that can't resolve during the build, causing a timeout after 50 seconds.\n00607| \n00608| When the build timeouts you'll see this error message:\n00609| \n00610| > Error: Filling a cache during prerender timed out, likely because request-specific arguments such as params, searchParams, cookies() or uncached data were used inside \"use cache\".\n00611| \n00612| Common ways this happens: passing such Promises as props, accessing them via closure, or retrieving them from shared storage (Maps).\n00613| \n00614| > **Good to know:** Directly calling `cookies()` or `headers()` inside `use cache` fails immediately with a [different error](/docs/messages/next-request-in-use-cache), not a timeout.\n00615| \n00616| **Passing runtime data Promises as props:**\n00617| \n00618| ```tsx filename=\"app/page.tsx\"\n00619| import { cookies } from 'next/headers'\n00620| import { Suspense } from 'react'\n00621| \n00622| export default function Page() {\n00623| return (\n00624| Loading...
}>\n00625| \n00626| \n00627| )\n00628| }\n00629| \n00630| async function Dynamic() {\n00631| const cookieStore = cookies()\n00632| return // Build hangs\n00633| }\n00634| \n00635| async function Cached({ promise }: { promise: Promise }) {\n00636| 'use cache'\n00637| const data = await promise // Waits for runtime data during build\n00638| return
..
\n00639| }\n00640| ```\n00641| \n00642| Await the `cookies` store in the `Dynamic` component, and pass a cookie value to the `Cached` component.\n00643| \n00644| **Shared deduplication storage:**\n00645| \n00646| ```tsx filename=\"app/page.tsx\"\n00647| // Problem: Map stores dynamic Promises, accessed by cached code\n00648| import { Suspense } from 'react'\n00649| \n00650| const cache = new Map>()\n00651| \n00652| export default function Page() {\n00653| return (\n00654| <>\n00655| Loading...
\n00670| }\n00671| \n00672| async function Cached({ id }: { id: string }) {\n00673| 'use cache'\n00674| return
{await cache.get(id)}
// Build hangs - retrieves dynamic Promise\n00675| }\n00676| ```\n00677| \n00678| Use Next.js's built-in `fetch()` deduplication or use separate Maps for cached and uncached contexts.\n00679| \n00680| ## Platform Support\n00681| \n00682| | Deployment Option | Supported |\n00683| | ------------------------------------------------------------------- | ----------------- |\n00684| | [Node.js server](/docs/app/getting-started/deploying#nodejs-server) | Yes |\n00685| | [Docker container](/docs/app/getting-started/deploying#docker) | Yes |\n00686| | [Static export](/docs/app/getting-started/deploying#static-export) | No |\n00687| | [Adapters](/docs/app/getting-started/deploying#adapters) | Platform-specific |\n00688| \n00689| Learn how to [configure caching](/docs/app/guides/self-hosting#caching-and-isr) when self-hosting Next.js.\n00690| \n00691| ## Version History\n00692| \n00693| | Version | Changes |\n00694| | --------- | ----------------------------------------------------------- |\n00695| | `v16.0.0` | `\"use cache\"` is enabled with the Cache Components feature. |\n00696| | `v15.0.0` | `\"use cache\"` is introduced as an experimental feature. |\n00697| \n\n(End of file - total 697 lines)\n","title":"node_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache.md","metadata":{"preview":"---\ntitle: use cache\ndescription: Learn how to use the \"use cache\" directive to cache data in your Next.js application.\nrelated:\n title: Related\n description: View related API references.\n links:\n - app/api-reference/directives/use-cache-private\n - app/api-reference/config/next-config-js/cacheComponents\n - app/api-reference/config/next-config-js/cacheLife\n - app/api-reference/config/next-config-js/cacheHandlers\n - app/api-reference/functions/cacheTag\n - app/api-reference/functions/cacheLife\n - app/api-reference/functions/revalidateTag\n---\n\nThe `use cache` directive allows you to mark a route, React component, or a function as cacheable. It can be used at the top of a file to indicate that all exports in the file should be cached, or inline at the top of a function or component to cache the return value. Functions and components that use `use cache` must be async.\n\n> **Good to know:**\n>"},"time":{"start":1781392546180,"end":1781392546187}}}}
+{"type":"tool_use","timestamp":1781392546244,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec345198700191n6zRICHyqM01","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec345015e001is3nMOxoQaAHTT","type":"tool","callID":"read_17","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheLife.md"},"output":"\n00001| ---\n00002| title: cacheLife\n00003| description: Learn how to use the cacheLife function to set the cache expiration time for a cached function or component.\n00004| related:\n00005| title: Related\n00006| description: View related API references.\n00007| links:\n00008| - app/api-reference/config/next-config-js/cacheComponents\n00009| - app/api-reference/directives/use-cache\n00010| - app/api-reference/functions/revalidateTag\n00011| - app/api-reference/functions/cacheTag\n00012| ---\n00013| \n00014| The `cacheLife` function is used to set the cache lifetime of a function or component. It should be used alongside the [`use cache`](/docs/app/api-reference/directives/use-cache) directive, and within the scope of the function or component.\n00015| \n00016| ## Usage\n00017| \n00018| ### Basic setup\n00019| \n00020| To use `cacheLife`, first enable the [`cacheComponents` flag](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.js` file:\n00021| \n00022| ```ts filename=\"next.config.ts\" switcher\n00023| import type { NextConfig } from 'next'\n00024| \n00025| const nextConfig: NextConfig = {\n00026| cacheComponents: true,\n00027| }\n00028| \n00029| export default nextConfig\n00030| ```\n00031| \n00032| ```js filename=\"next.config.js\" switcher\n00033| const nextConfig = {\n00034| cacheComponents: true,\n00035| }\n00036| \n00037| export default nextConfig\n00038| ```\n00039| \n00040| `cacheLife` can only be used within a cache directive scope.\n00041| \n00042| Add a cache directive (for example, `use cache`) at the file level or at the top of an async function or component.\n00043| \n00044| `cacheLife` cannot be used at module scope. Calling it at the top level of a file will throw an error.\n00045| \n00046| > **Good to know**:\n00047| >\n00048| > - Calling `cacheLife` is optional. If omitted, a default cache lifetime is applied.\n00049| > - Call `cacheLife` in the same function or component where caching is defined. Avoid abstracting it into shared utilities so the cache behavior remains explicit and easy to reason about.\n00050| > - If you call `cacheLife`, ensure only one call executes per function invocation. You can call it in different control flow branches, but only one should run per request. See the [conditional cache lifetimes](#conditional-cache-lifetimes) example.\n00051| \n00052| ### Using preset profiles\n00053| \n00054| Next.js provides preset cache profiles that cover common caching needs. Each profile balances three factors:\n00055| \n00056| - How long users see cached content without checking for updates (client-side)\n00057| - How often fresh content is generated on the server\n00058| - When old content expires completely\n00059| \n00060| Choose a profile based on how frequently your content changes:\n00061| \n00062| - **`seconds`** - Real-time data (stock prices, live scores)\n00063| - **`minutes`** - Frequently updated (social feeds, news)\n00064| - **`hours`** - Multiple daily updates (product inventory, weather)\n00065| - **`days`** - Daily updates (blog posts, articles)\n00066| - **`weeks`** - Weekly updates (podcasts, newsletters)\n00067| - **`max`** - Rarely changes (legal pages, archived content)\n00068| \n00069| Import `cacheLife` and pass a profile name:\n00070| \n00071| ```tsx filename=\"app/blog/page.tsx\" highlight={1,5}\n00072| 'use cache'\n00073| import { cacheLife } from 'next/cache'\n00074| \n00075| export default async function BlogPage() {\n00076| cacheLife('days') // Blog content updated daily\n00077| \n00078| const posts = await getBlogPosts()\n00079| return
{/* render posts */}
\n00080| }\n00081| ```\n00082| \n00083| The profile name tells Next.js how to cache the entire function's output. If you don't call `cacheLife`, the `default` profile is used. See [preset cache profiles](#preset-cache-profiles) for timing details.\n00084| \n00085| ## Reference\n00086| \n00087| ### Cache profile properties\n00088| \n00089| Cache profiles control caching behavior through three timing properties:\n00090| \n00091| - **[`stale`](#stale)**: How long the client can use cached data without checking the server\n00092| - **[`revalidate`](#revalidate)**: After this time, the next request will trigger a background refresh\n00093| - **[`expire`](#expire)**: After this time with no requests, the next one waits for fresh content\n00094| \n00095| #### `stale`\n00096| \n00097| **Client-side:** How long the client can use cached data without checking the server.\n00098| \n00099| During this time, the client-side router displays cached content immediately without any network request. After this period expires, the router must check with the server on the next navigation or request. This provides instant page loads from the client cache, but data may be outdated.\n00100| \n00101| - If omitted, defaults to the `default` profile's `stale` value (5 minutes, see [`staleTimes`](/docs/app/api-reference/config/next-config-js/staleTimes))\n00102| \n00103| ```tsx\n00104| cacheLife({ stale: 300 }) // 5 minutes\n00105| ```\n00106| \n00107| #### `revalidate`\n00108| \n00109| How often the server regenerates cached content in the background.\n00110| \n00111| - When a request arrives after this period, the server:\n00112| 1. Serves the cached version immediately (if available)\n00113| 2. Regenerates content in the background\n00114| 3. Updates the cache with fresh content\n00115| - Similar to [Incremental Static Regeneration (ISR)](/docs/app/guides/incremental-static-regeneration)\n00116| - If omitted, defaults to the `default` profile's `revalidate` value (15 minutes)\n00117| \n00118| ```tsx\n00119| cacheLife({ revalidate: 900 }) // 15 minutes\n00120| ```\n00121| \n00122| #### `expire`\n00123| \n00124| Maximum time before the server must regenerate cached content.\n00125| \n00126| - After this period with no traffic, the server regenerates content synchronously on the next request\n00127| - When you set both `revalidate` and `expire`, `expire` must be longer than `revalidate`. Next.js validates this and raises an error for invalid configurations.\n00128| - If omitted, defaults to the `default` profile's `expire` value (never expires)\n00129| \n00130| ```tsx\n00131| cacheLife({ expire: 3600 }) // 1 hour\n00132| ```\n00133| \n00134| ### Preset cache profiles\n00135| \n00136| If you don't specify a profile, Next.js uses the `default` profile. We recommend explicitly setting a profile to make caching behavior clear.\n00137| \n00138| | **Profile** | **Use Case** | `stale` | `revalidate` | `expire` |\n00139| | ----------- | -------------------------------------- | ---------- | ------------ | -------- |\n00140| | `default` | Standard content | 5 minutes | 15 minutes | never |\n00141| | `seconds` | Real-time data | 30 seconds | 1 second | 1 minute |\n00142| | `minutes` | Frequently updated content | 5 minutes | 1 minute | 1 hour |\n00143| | `hours` | Content updated multiple times per day | 5 minutes | 1 hour | 1 day |\n00144| | `days` | Content updated daily | 5 minutes | 1 day | 1 week |\n00145| | `weeks` | Content updated weekly | 5 minutes | 1 week | 30 days |\n00146| | `max` | Stable content that rarely changes | 5 minutes | 30 days | 1 year |\n00147| \n00148| ### Custom cache profiles\n00149| \n00150| Define reusable cache profiles in your `next.config.ts` file:\n00151| \n00152| ```ts filename=\"next.config.ts\"\n00153| import type { NextConfig } from 'next'\n00154| \n00155| const nextConfig: NextConfig = {\n00156| cacheComponents: true,\n00157| cacheLife: {\n00158| biweekly: {\n00159| stale: 60 * 60 * 24 * 14, // 14 days\n00160| revalidate: 60 * 60 * 24, // 1 day\n00161| expire: 60 * 60 * 24 * 14, // 14 days\n00162| },\n00163| },\n00164| }\n00165| \n00166| export default nextConfig\n00167| ```\n00168| \n00169| ```js filename=\"next.config.js\" switcher\n00170| const nextConfig = {\n00171| cacheComponents: true,\n00172| cacheLife: {\n00173| biweekly: {\n00174| stale: 60 * 60 * 24 * 14, // 14 days\n00175| revalidate: 60 * 60 * 24, // 1 day\n00176| expire: 60 * 60 * 24 * 14, // 14 days\n00177| },\n00178| },\n00179| }\n00180| \n00181| module.exports = nextConfig\n00182| ```\n00183| \n00184| The example above caches for 14 days, checks for updates daily, and expires the cache after 14 days. You can then reference this profile throughout your application by its name:\n00185| \n00186| > **Good to know**: Any omitted properties in a custom profile inherit from the `default` profile. This also applies to inline profile objects passed directly to `cacheLife()`.\n00187| \n00188| ```tsx filename=\"app/page.tsx\" highlight={5}\n00189| 'use cache'\n00190| import { cacheLife } from 'next/cache'\n00191| \n00192| export default async function Page() {\n00193| cacheLife('biweekly')\n00194| return
Page
\n00195| }\n00196| ```\n00197| \n00198| ### Overriding the default cache profiles\n00199| \n00200| While the default cache profiles provide a useful way to think about how fresh or stale any given part of cacheable output can be, you may prefer different named profiles to better align with your applications caching strategies.\n00201| \n00202| You can override the default named cache profiles by creating a new configuration with the same name as the defaults.\n00203| \n00204| The example below shows how to override the default `\"days\"` cache profile:\n00205| \n00206| ```ts filename=\"next.config.ts\"\n00207| const nextConfig = {\n00208| cacheComponents: true,\n00209| cacheLife: {\n00210| // Override the 'days' profile\n00211| days: {\n00212| stale: 3600, // 1 hour\n00213| revalidate: 900, // 15 minutes\n00214| expire: 86400, // 1 day\n00215| },\n00216| },\n00217| }\n00218| \n00219| export default nextConfig\n00220| ```\n00221| \n00222| ### Inline cache profiles\n00223| \n00224| For one-off cases, pass a profile object directly to `cacheLife`:\n00225| \n00226| ```tsx filename=\"app/page.tsx\"\n00227| 'use cache'\n00228| import { cacheLife } from 'next/cache'\n00229| \n00230| export default async function Page() {\n00231| cacheLife({\n00232| stale: 3600,\n00233| revalidate: 900,\n00234| expire: 86400,\n00235| })\n00236| \n00237| return
Page
\n00238| }\n00239| ```\n00240| \n00241| Inline profiles apply only to the specific function or component. For reusable configurations, define custom profiles in `next.config.ts`.\n00242| \n00243| Using `cacheLife({})` with an empty object applies the `default` profile values.\n00244| \n00245| ### Client cache behavior\n00246| \n00247| The `stale` property controls the [Client Cache](/docs/app/glossary#client-cache), not the `Cache-Control` header:\n00248| \n00249| - The server sends the stale time via the `x-nextjs-stale-time` response header\n00250| - The client router uses this value to determine when to revalidate\n00251| - **Minimum of 30 seconds is enforced** to ensure prefetched links remain usable\n00252| \n00253| This 30-second minimum prevents prefetched data from expiring before users can click on links. It only applies to time-based expiration.\n00254| \n00255| When you call revalidation functions from a Server Action ([`revalidateTag`](/docs/app/api-reference/functions/revalidateTag), [`revalidatePath`](/docs/app/api-reference/functions/revalidatePath), [`updateTag`](/docs/app/api-reference/functions/updateTag), or [`refresh`](/docs/app/api-reference/functions/refresh)), the entire client cache is immediately cleared, bypassing the stale time.\n00256| \n00257| > **Good to know**: The `stale` property in `cacheLife` differs from [`staleTimes`](/docs/app/api-reference/config/next-config-js/staleTimes). While `staleTimes` is a global setting affecting all routes, `cacheLife` allows per-function or per-route configuration. Updating `staleTimes.static` also updates the `stale` value of the `default` cache profile.\n00258| \n00259| ### Prerendering behavior\n00260| \n00261| Caches with very short lifetimes — zero `revalidate` or `expire` under 5 minutes — are automatically excluded from prerenders and become \"dynamic holes\" instead. This includes the `seconds` profile.\n00262| \n00263| This behavior allows you to mix static and dynamic content within the same page. Static parts are prerendered, while short-lived caches create boundaries where data is fetched at request time rather than build time. Use a `` boundary around dynamic caches to provide a fallback while content loads.\n00264| \n00265| ## Examples\n00266| \n00267| ### Using preset profiles\n00268| \n00269| The simplest way to configure caching is using preset profiles. Choose one that matches your content's update pattern:\n00270| \n00271| ```tsx filename=\"app/blog/[slug]/page.tsx\"\n00272| import { cacheLife } from 'next/cache'\n00273| \n00274| export default async function BlogPost() {\n00275| 'use cache'\n00276| cacheLife('days') // Blog posts updated daily\n00277| \n00278| const post = await fetchBlogPost()\n00279| return {post.content}\n00280| }\n00281| ```\n00282| \n00283| ```tsx filename=\"app/products/[id]/page.tsx\"\n00284| import { cacheLife } from 'next/cache'\n00285| \n00286| export default async function ProductPage() {\n00287| 'use cache'\n00288| cacheLife('hours') // Product data updated multiple times per day\n00289| \n00290| const product = await fetchProduct()\n00291| return
{product.name}
\n00292| }\n00293| ```\n00294| \n00295| ### Custom profiles for specific needs\n00296| \n00297| Define custom profiles when preset options don't match your requirements:\n00298| \n00299| ```ts filename=\"next.config.ts\"\n00300| import type { NextConfig } from 'next'\n00301| \n00302| const nextConfig: NextConfig = {\n00303| cacheComponents: true,\n00304| cacheLife: {\n00305| editorial: {\n00306| stale: 600, // 10 minutes\n00307| revalidate: 3600, // 1 hour\n00308| expire: 86400, // 1 day\n00309| },\n00310| marketing: {\n00311| stale: 300, // 5 minutes\n00312| revalidate: 1800, // 30 minutes\n00313| expire: 43200, // 12 hours\n00314| },\n00315| },\n00316| }\n00317| \n00318| export default nextConfig\n00319| ```\n00320| \n00321| Then use these profiles throughout your application:\n00322| \n00323| ```tsx filename=\"app/editorial/page.tsx\"\n00324| import { cacheLife } from 'next/cache'\n00325| \n00326| export default async function EditorialPage() {\n00327| 'use cache'\n00328| cacheLife('editorial')\n00329| // ...\n00330| }\n00331| ```\n00332| \n00333| ### Inline profiles for unique cases\n00334| \n00335| Use inline profiles when a specific function needs one-off caching behavior:\n00336| \n00337| ```tsx filename=\"app/api/limited-offer/route.ts\"\n00338| import { cacheLife } from 'next/cache'\n00339| import { getDb } from '@lib/db'\n00340| \n00341| async function getLimitedOffer() {\n00342| 'use cache'\n00343| \n00344| cacheLife({\n00345| stale: 60, // 1 minute\n00346| revalidate: 300, // 5 minutes\n00347| expire: 3600, // 1 hour\n00348| })\n00349| \n00350| const offer = await getDb().offer.findFirst({\n00351| where: { type: 'limited' },\n00352| orderBy: { created_at: 'desc' },\n00353| })\n00354| \n00355| return offer\n00356| }\n00357| \n00358| export async function GET() {\n00359| const offer = await getLimitedOffer()\n00360| \n00361| return Response.json(offer)\n00362| }\n00363| ```\n00364| \n00365| ### Caching individual functions\n00366| \n00367| Apply caching to utility functions for granular control:\n00368| \n00369| ```tsx filename=\"lib/api.ts\"\n00370| import { cacheLife } from 'next/cache'\n00371| \n00372| export async function getSettings() {\n00373| 'use cache'\n00374| cacheLife('max') // Settings rarely change\n00375| \n00376| return await fetchSettings()\n00377| }\n00378| ```\n00379| \n00380| ```tsx filename=\"lib/stats.ts\"\n00381| import { cacheLife } from 'next/cache'\n00382| \n00383| export async function getRealtimeStats() {\n00384| 'use cache'\n00385| cacheLife('seconds') // Stats update constantly\n00386| \n00387| return await fetchStats()\n00388| }\n00389| ```\n00390| \n00391| ### Nested caching behavior\n00392| \n00393| When you nest `use cache` directives (a cached function or component using another cached function or component), the outer cache's behavior depends on whether it has an explicit `cacheLife`.\n00394| \n00395| #### With explicit outer cacheLife\n00396| \n00397| The outer cache uses its own lifetime, regardless of inner cache lifetimes. When the outer cache hits, it returns the complete output including all nested data. An explicit `cacheLife` always takes precedence, whether it's longer or shorter than inner lifetimes.\n00398| \n00399| ```tsx filename=\"app/dashboard/page.tsx\"\n00400| import { cacheLife } from 'next/cache'\n00401| import { Widget } from './widget'\n00402| \n00403| export default async function Dashboard() {\n00404| 'use cache'\n00405| cacheLife('hours') // Outer scope sets its own lifetime\n00406| \n00407| return (\n00408|
\n00409|
Dashboard
\n00410| {/* Inner scope has 'minutes' lifetime */}\n00411|
\n00412| )\n00413| }\n00414| ```\n00415| \n00416| #### Without explicit outer cacheLife\n00417| \n00418| If you don't call `cacheLife` in the outer cache, it uses the `default` profile (15 min revalidate). Inner caches with shorter lifetimes can reduce the outer cache's `default` lifetime. Inner caches with longer lifetimes cannot extend it beyond the default.\n00419| \n00420| ```tsx filename=\"app/dashboard/page.tsx\"\n00421| import { Widget } from './widget'\n00422| \n00423| export default async function Dashboard() {\n00424| 'use cache'\n00425| // No cacheLife call - uses default (15 min)\n00426| // If Widget has 5 min → Dashboard becomes 5 min\n00427| // If Widget has 1 hour → Dashboard stays 15 min\n00428| \n00429| return (\n00430|
\n00431|
Dashboard
\n00432| \n00433|
\n00434| )\n00435| }\n00436| ```\n00437| \n00438| **It is recommended to specify an explicit `cacheLife`.** With explicit lifetime values, you can inspect a cached function or component and immediately know its behavior without tracing through nested caches. Without explicit lifetime values, the behavior becomes dependent on inner cache lifetimes, making it harder to reason about.\n00439| \n00440| #### Nested short-lived caches\n00441| \n00442| As described in [Prerendering behavior](#prerendering-behavior), short-lived caches (zero `revalidate` or `expire` under 5 minutes) become dynamic holes excluded from prerenders.\n00443| \n00444| When a short-lived cache is nested inside another `use cache` without an explicit `cacheLife`, the outer cache's lifetime would silently become short too via propagation. To prevent this accidental misconfiguration, Next.js throws an error during prerendering.\n00445| \n00446| Note that the nested cache may not be obvious — it could be in an imported module or even a third-party dependency:\n00447| \n00448| ```tsx filename=\"components/short-lived-widget.tsx\" highlight={5}\n00449| import { cacheLife } from 'next/cache'\n00450| \n00451| export async function ShortLivedWidget() {\n00452| 'use cache'\n00453| cacheLife('seconds')\n00454| const data = await fetchRealtimeData()\n00455| return
{data}
\n00456| }\n00457| ```\n00458| \n00459| Using this component from another `use cache` without an explicit `cacheLife` will error during prerendering:\n00460| \n00461| ```tsx filename=\"app/page.tsx\"\n00462| import { ShortLivedWidget } from '@/components/short-lived-widget'\n00463| \n00464| export default async function Page() {\n00465| 'use cache'\n00466| // Error: no explicit cacheLife on outer cache\n00467| return (\n00468|
\n00469|
Dashboard
\n00470|
Last updated: {new Date().toISOString()}
\n00471| \n00472|
\n00473| )\n00474| }\n00475| ```\n00476| \n00477| To fix the error, add an explicit `cacheLife()` to the outer `use cache`:\n00478| \n00479| **If you want the outer cache to remain static (prerendered)**, set a longer cache lifetime:\n00480| \n00481| ```tsx filename=\"app/page.tsx\" highlight={6}\n00482| import { cacheLife } from 'next/cache'\n00483| import { ShortLivedWidget } from '@/components/short-lived-widget'\n00484| \n00485| export default async function Page() {\n00486| 'use cache'\n00487| cacheLife('default') // Explicit cacheLife prevents the error\n00488| return (\n00489|
\n00490|
Dashboard
\n00491|
Last updated: {new Date().toISOString()}
\n00492| \n00493|
\n00494| )\n00495| }\n00496| ```\n00497| \n00498| **If you want the outer cache to also be short-lived**, explicitly set a short cache lifetime to confirm this is intentional. Wrap the component in a `` boundary to provide a fallback while content loads:\n00499| \n00500| ```tsx filename=\"app/page.tsx\" highlight={7,17-19}\n00501| import { Suspense } from 'react'\n00502| import { cacheLife } from 'next/cache'\n00503| import { ShortLivedWidget } from '@/components/short-lived-widget'\n00504| \n00505| async function Content() {\n00506| 'use cache: remote'\n00507| cacheLife('seconds') // Explicit cacheLife confirms this is intentionally short-lived\n00508| return (\n00509| <>\n00510|
\n00524| )\n00525| }\n00526| ```\n00527| \n00528| > **Note:** This example uses `\"use cache: remote\"` because runtime caching in serverless deployments doesn't persist across requests with the default in-memory cache. For self-hosted environments, `\"use cache\"` may be sufficient. See [Runtime caching considerations](/docs/app/api-reference/directives/use-cache#runtime-caching-considerations) for more details.\n00529| \n00530| ### Conditional cache lifetimes\n00531| \n00532| You can call `cacheLife` conditionally in different code paths to set different cache durations based on your application logic:\n00533| \n00534| ```tsx filename=\"lib/posts.ts\" highlight={14,19}\n00535| import { cacheLife, cacheTag } from 'next/cache'\n00536| \n00537| async function getPostContent(slug: string) {\n00538| 'use cache'\n00539| \n00540| const post = await fetchPost(slug)\n00541| \n00542| // Tag the cache entry for targeted revalidation\n00543| cacheTag(`post-${slug}`)\n00544| \n00545| if (!post) {\n00546| // Content may not be published yet or could be in draft\n00547| // Cache briefly to reduce database load\n00548| cacheLife('minutes')\n00549| return null\n00550| }\n00551| \n00552| // Published content can be cached longer\n00553| cacheLife('days')\n00554| \n00555| // Return only the necessary data to keep cache size minimal\n00556| return post.data\n00557| }\n00558| ```\n00559| \n00560| This pattern is useful when different outcomes need different cache durations, for example, when an item is missing but is likely to be available later.\n00561| \n00562| #### Using dynamic cache lifetimes from data\n00563| \n00564| If you want to calculate cache lifetime at runtime, for example by reading it from the fetched data, use an [inline cache profile](#inline-cache-profiles) object:\n00565| \n00566| ```tsx filename=\"lib/posts.ts\" highlight={15,16,17,18}\n00567| import { cacheLife, cacheTag } from 'next/cache'\n00568| \n00569| async function getPostContent(slug: string) {\n00570| 'use cache'\n00571| \n00572| const post = await fetchPost(slug)\n00573| cacheTag(`post-${slug}`)\n00574| \n00575| if (!post) {\n00576| cacheLife('minutes')\n00577| return null\n00578| }\n00579| \n00580| // Use cache timing from CMS data directly as an object\n00581| cacheLife({\n00582| // Ensure post.revalidateSeconds is a number in seconds\n00583| // stale and expire inherit from 'default' profile\n00584| revalidate: post.revalidateSeconds ?? 3600,\n00585| })\n00586| \n00587| return post.data\n00588| }\n00589| ```\n00590| \n\n(End of file - total 590 lines)\n","title":"node_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheLife.md","metadata":{"preview":"---\ntitle: cacheLife\ndescription: Learn how to use the cacheLife function to set the cache expiration time for a cached function or component.\nrelated:\n title: Related\n description: View related API references.\n links:\n - app/api-reference/config/next-config-js/cacheComponents\n - app/api-reference/directives/use-cache\n - app/api-reference/functions/revalidateTag\n - app/api-reference/functions/cacheTag\n---\n\nThe `cacheLife` function is used to set the cache lifetime of a function or component. It should be used alongside the [`use cache`](/docs/app/api-reference/directives/use-cache) directive, and within the scope of the function or component.\n\n## Usage\n\n### Basic setup\n\nTo use `cacheLife`, first enable the [`cacheComponents` flag](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.js` file:"},"time":{"start":1781392546237,"end":1781392546241}}}}
+{"type":"step_finish","timestamp":1781392546255,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec34519c3001hs5qYQ5hf1hWx5","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec345015e001is3nMOxoQaAHTT","type":"step-finish","reason":"tool-calls","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012","cost":0.01607957,"tokens":{"input":13947,"output":175,"reasoning":0,"cache":{"read":13312,"write":0}}}}
+{"type":"step_start","timestamp":1781392550179,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec345291b001me3ra07bmLhm3x","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec34519df001MJX3Y7o8YgZqqp","type":"step-start","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012"}}
+{"type":"tool_use","timestamp":1781392558439,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec3454800001NhRuQiJ841uMuG","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec34519df001MJX3Y7o8YgZqqp","type":"tool","callID":"glob_18","tool":"glob","state":{"status":"completed","input":{"pattern":"**/*.{test,spec}.{js,ts,tsx}","path":"/workspace"},"output":"No files found","title":"","metadata":{"count":0,"truncated":false},"time":{"start":1781392558430,"end":1781392558438}}}}
+{"type":"tool_use","timestamp":1781392558862,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec3454961001WYn50S2AEgSbFQ","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec34519df001MJX3Y7o8YgZqqp","type":"tool","callID":"bash_19","tool":"bash","state":{"status":"completed","input":{"command":"ls -la /workspace/lib /workspace/app","description":"List lib and app contents"},"output":"/workspace/app:\ntotal 8\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 40 Jun 13 23:14 .\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 238 Jun 13 23:15 ..\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 329 Jun 13 23:14 layout.tsx\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 91 Jun 13 23:14 page.tsx\n\n/workspace/lib:\ntotal 4\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 19 Jun 13 23:14 .\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 238 Jun 13 23:15 ..\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 364 Jun 13 23:14 db.js\n","title":"List lib and app contents","metadata":{"output":"/workspace/app:\ntotal 8\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 40 Jun 13 23:14 .\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 238 Jun 13 23:15 ..\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 329 Jun 13 23:14 layout.tsx\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 91 Jun 13 23:14 page.tsx\n\n/workspace/lib:\ntotal 4\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 19 Jun 13 23:14 .\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 238 Jun 13 23:15 ..\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 364 Jun 13 23:14 db.js\n","exit":0,"description":"List lib and app contents"},"time":{"start":1781392558847,"end":1781392558854}}}}
+{"type":"step_finish","timestamp":1781392558866,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec3454b070016PmM21IrpzqVtK","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec34519df001MJX3Y7o8YgZqqp","type":"step-finish","reason":"tool-calls","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012","cost":0.02044606,"tokens":{"input":14674,"output":541,"reasoning":0,"cache":{"read":27136,"write":0}}}}
+{"type":"step_start","timestamp":1781392560615,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec34551df001Nv4Lw5d3ESL4Pt","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec3454b20001jkFw6vuqPClP1i","type":"step-start","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012"}}
+{"type":"tool_use","timestamp":1781392585929,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec345afa7001tN2iyjEiMB51PM","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec3454b20001jkFw6vuqPClP1i","type":"tool","callID":"todowrite_20","tool":"todowrite","state":{"status":"completed","input":{"todos":[{"id":"1","content":"Enable Cache Components in next.config.ts","status":"in_progress","priority":"high"},{"id":"2","content":"Cache lib/db.js getAllProducts with 'use cache' and products tag","status":"pending","priority":"high"},{"id":"3","content":"Build admin catalog page with inline sync Server Action and form","status":"pending","priority":"high"},{"id":"4","content":"Run build to verify","status":"pending","priority":"medium"}]},"output":"[\n {\n \"id\": \"1\",\n \"content\": \"Enable Cache Components in next.config.ts\",\n \"status\": \"in_progress\",\n \"priority\": \"high\"\n },\n {\n \"id\": \"2\",\n \"content\": \"Cache lib/db.js getAllProducts with 'use cache' and products tag\",\n \"status\": \"pending\",\n \"priority\": \"high\"\n },\n {\n \"id\": \"3\",\n \"content\": \"Build admin catalog page with inline sync Server Action and form\",\n \"status\": \"pending\",\n \"priority\": \"high\"\n },\n {\n \"id\": \"4\",\n \"content\": \"Run build to verify\",\n \"status\": \"pending\",\n \"priority\": \"medium\"\n }\n]","title":"4 todos","metadata":{"todos":[{"id":"1","content":"Enable Cache Components in next.config.ts","status":"in_progress","priority":"high"},{"id":"2","content":"Cache lib/db.js getAllProducts with 'use cache' and products tag","status":"pending","priority":"high"},{"id":"3","content":"Build admin catalog page with inline sync Server Action and form","status":"pending","priority":"high"},{"id":"4","content":"Run build to verify","status":"pending","priority":"medium"}]},"time":{"start":1781392585922,"end":1781392585926}}}}
+{"type":"step_finish","timestamp":1781392585938,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec345b4c7001s9yc2uO8s1jYfQ","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec3454b20001jkFw6vuqPClP1i","type":"step-finish","reason":"tool-calls","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012","cost":0.01329348,"tokens":{"input":860,"output":1450,"reasoning":0,"cache":{"read":41728,"write":0}}}}
+{"type":"step_start","timestamp":1781392588441,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec345be95001WRlTRTHVxWTmkt","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec345b4e60015C6znZoWnG8JL3","type":"step-start","snapshot":"3ee19b2b21f4827382492268b3ec45c1d5837012"}}
+{"type":"tool_use","timestamp":1781392592131,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec345be98001YCJO6zBJF5c1S5","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec345b4e60015C6znZoWnG8JL3","type":"tool","callID":"edit_21","tool":"edit","state":{"status":"completed","input":{"filePath":"/workspace/next.config.ts","oldString":"const nextConfig: NextConfig = {}\n","newString":"const nextConfig: NextConfig = {\n cacheComponents: true,\n}\n"},"output":"","title":"next.config.ts","metadata":{"diagnostics":{"/workspace/lib/db.js":[],"/workspace/app/page.tsx":[],"/workspace/app/layout.tsx":[],"/workspace/next.config.ts":[]},"diff":"Index: /workspace/next.config.ts\n===================================================================\n--- /workspace/next.config.ts\n+++ /workspace/next.config.ts\n@@ -1,5 +1,7 @@\n import type { NextConfig } from 'next'\n \n-const nextConfig: NextConfig = {}\n+const nextConfig: NextConfig = {\n+ cacheComponents: true,\n+}\n \n export default nextConfig\n","filediff":{"file":"/workspace/next.config.ts","before":"import type { NextConfig } from 'next'\n\nconst nextConfig: NextConfig = {}\n\nexport default nextConfig\n","after":"import type { NextConfig } from 'next'\n\nconst nextConfig: NextConfig = {\n cacheComponents: true,\n}\n\nexport default nextConfig\n","additions":3,"deletions":1}},"time":{"start":1781392589112,"end":1781392592128}}}}
+{"type":"step_finish","timestamp":1781392592136,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec345cd02001oCBu0uPMr5lnKU","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec345b4e60015C6znZoWnG8JL3","type":"step-finish","reason":"tool-calls","snapshot":"7a146fa19d720a6a1a3d33c9c98f2b8b7f21ec2c","cost":0.00869716,"tokens":{"input":1724,"output":65,"reasoning":0,"cache":{"read":42496,"write":0}}}}
+{"type":"step_start","timestamp":1781392594166,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec345d4ee0019YjRf08IjTyFit","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec345cd270015JV6odiRTOUNR1","type":"step-start","snapshot":"7a146fa19d720a6a1a3d33c9c98f2b8b7f21ec2c"}}
+{"type":"tool_use","timestamp":1781392595529,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec345d4f10018fl3LkhReRm398","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec345cd270015JV6odiRTOUNR1","type":"tool","callID":"todowrite_22","tool":"todowrite","state":{"status":"completed","input":{"todos":[{"id":"1","content":"Enable Cache Components in next.config.ts","status":"completed","priority":"high"},{"id":"2","content":"Cache lib/db.js getAllProducts with 'use cache' and products tag","status":"in_progress","priority":"high"},{"id":"3","content":"Build admin catalog page with inline sync Server Action and form","status":"pending","priority":"high"},{"id":"4","content":"Run build to verify","status":"pending","priority":"medium"}]},"output":"[\n {\n \"id\": \"1\",\n \"content\": \"Enable Cache Components in next.config.ts\",\n \"status\": \"completed\",\n \"priority\": \"high\"\n },\n {\n \"id\": \"2\",\n \"content\": \"Cache lib/db.js getAllProducts with 'use cache' and products tag\",\n \"status\": \"in_progress\",\n \"priority\": \"high\"\n },\n {\n \"id\": \"3\",\n \"content\": \"Build admin catalog page with inline sync Server Action and form\",\n \"status\": \"pending\",\n \"priority\": \"high\"\n },\n {\n \"id\": \"4\",\n \"content\": \"Run build to verify\",\n \"status\": \"pending\",\n \"priority\": \"medium\"\n }\n]","title":"3 todos","metadata":{"todos":[{"id":"1","content":"Enable Cache Components in next.config.ts","status":"completed","priority":"high"},{"id":"2","content":"Cache lib/db.js getAllProducts with 'use cache' and products tag","status":"in_progress","priority":"high"},{"id":"3","content":"Build admin catalog page with inline sync Server Action and form","status":"pending","priority":"high"},{"id":"4","content":"Run build to verify","status":"pending","priority":"medium"}]},"time":{"start":1781392595524,"end":1781392595528}}}}
+{"type":"step_finish","timestamp":1781392595533,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec345da48001k9x3cKzOpj1Yv5","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec345cd270015JV6odiRTOUNR1","type":"step-finish","reason":"tool-calls","snapshot":"7a146fa19d720a6a1a3d33c9c98f2b8b7f21ec2c","cost":0.00779992,"tokens":{"input":264,"output":126,"reasoning":0,"cache":{"read":44032,"write":0}}}}
+{"type":"step_start","timestamp":1781392597530,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec345e2170013hLXtRqNe3pFci","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec345da65001B49khE5M0vGdJj","type":"step-start","snapshot":"7a146fa19d720a6a1a3d33c9c98f2b8b7f21ec2c"}}
+{"type":"tool_use","timestamp":1781392605401,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec345e218001EADTmqYxU3FNvx","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec345da65001B49khE5M0vGdJj","type":"tool","callID":"edit_23","tool":"edit","state":{"status":"completed","input":{"filePath":"/workspace/lib/db.js","oldString":"export async function getAllProducts() {\n // Simulate database delay\n await new Promise((resolve) => setTimeout(resolve, 100))\n\n return [\n { id: 1, name: 'Laptop', price: 999 },\n { id: 2, name: 'Phone', price: 699 },\n { id: 3, name: 'Tablet', price: 499 },\n { id: 4, name: 'Headphones', price: 199 },\n { id: 5, name: 'Watch', price: 299 },\n ]\n}\n","newString":"import { cacheTag } from 'next/cache'\n\nexport async function getAllProducts() {\n 'use cache'\n\n cacheTag('products')\n\n // Simulate database delay\n await new Promise((resolve) => setTimeout(resolve, 100))\n\n return [\n { id: 1, name: 'Laptop', price: 999 },\n { id: 2, name: 'Phone', price: 699 },\n { id: 3, name: 'Tablet', price: 499 },\n { id: 4, name: 'Headphones', price: 199 },\n { id: 5, name: 'Watch', price: 299 },\n ]\n}\n"},"output":"","title":"lib/db.js","metadata":{"diagnostics":{"/workspace/lib/db.js":[],"/workspace/app/page.tsx":[],"/workspace/app/layout.tsx":[],"/workspace/next.config.ts":[]},"diff":"Index: /workspace/lib/db.js\n===================================================================\n--- /workspace/lib/db.js\n+++ /workspace/lib/db.js\n@@ -1,5 +1,11 @@\n+import { cacheTag } from 'next/cache'\n+\n export async function getAllProducts() {\n+ 'use cache'\n+\n+ cacheTag('products')\n+\n // Simulate database delay\n await new Promise((resolve) => setTimeout(resolve, 100))\n \n return [\n","filediff":{"file":"/workspace/lib/db.js","before":"export async function getAllProducts() {\n // Simulate database delay\n await new Promise((resolve) => setTimeout(resolve, 100))\n\n return [\n { id: 1, name: 'Laptop', price: 999 },\n { id: 2, name: 'Phone', price: 699 },\n { id: 3, name: 'Tablet', price: 499 },\n { id: 4, name: 'Headphones', price: 199 },\n { id: 5, name: 'Watch', price: 299 },\n ]\n}\n","after":"import { cacheTag } from 'next/cache'\n\nexport async function getAllProducts() {\n 'use cache'\n\n cacheTag('products')\n\n // Simulate database delay\n await new Promise((resolve) => setTimeout(resolve, 100))\n\n return [\n { id: 1, name: 'Laptop', price: 999 },\n { id: 2, name: 'Phone', price: 699 },\n { id: 3, name: 'Tablet', price: 499 },\n { id: 4, name: 'Headphones', price: 199 },\n { id: 5, name: 'Watch', price: 299 },\n ]\n}\n","additions":6,"deletions":0}},"time":{"start":1781392602390,"end":1781392605398}}}}
+{"type":"step_finish","timestamp":1781392605406,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec34600d80013AShXChPMjboDG","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec345da65001B49khE5M0vGdJj","type":"step-finish","reason":"tool-calls","snapshot":"89396b085fd4d482c49dae5fd3229681dd2dc169","cost":0.00873028,"tokens":{"input":316,"output":336,"reasoning":0,"cache":{"read":44288,"write":0}}}}
+{"type":"step_start","timestamp":1781392607540,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec346092d001CidncFZ0tn9aMY","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec34600ee001ZP0ZMYPyeYyTDp","type":"step-start","snapshot":"89396b085fd4d482c49dae5fd3229681dd2dc169"}}
+{"type":"tool_use","timestamp":1781392616994,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec3462911001x61Nu5CPgjjlGV","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec34600ee001ZP0ZMYPyeYyTDp","type":"tool","callID":"todowrite_24","tool":"todowrite","state":{"status":"completed","input":{"todos":[{"id":"1","content":"Enable Cache Components in next.config.ts","status":"completed","priority":"high"},{"id":"2","content":"Cache lib/db.js getAllProducts with 'use cache' and products tag","status":"completed","priority":"high"},{"id":"3","content":"Build admin catalog page with inline sync Server Action and form","status":"in_progress","priority":"high"},{"id":"4","content":"Run build to verify","status":"pending","priority":"medium"}]},"output":"[\n {\n \"id\": \"1\",\n \"content\": \"Enable Cache Components in next.config.ts\",\n \"status\": \"completed\",\n \"priority\": \"high\"\n },\n {\n \"id\": \"2\",\n \"content\": \"Cache lib/db.js getAllProducts with 'use cache' and products tag\",\n \"status\": \"completed\",\n \"priority\": \"high\"\n },\n {\n \"id\": \"3\",\n \"content\": \"Build admin catalog page with inline sync Server Action and form\",\n \"status\": \"in_progress\",\n \"priority\": \"high\"\n },\n {\n \"id\": \"4\",\n \"content\": \"Run build to verify\",\n \"status\": \"pending\",\n \"priority\": \"medium\"\n }\n]","title":"2 todos","metadata":{"todos":[{"id":"1","content":"Enable Cache Components in next.config.ts","status":"completed","priority":"high"},{"id":"2","content":"Cache lib/db.js getAllProducts with 'use cache' and products tag","status":"completed","priority":"high"},{"id":"3","content":"Build admin catalog page with inline sync Server Action and form","status":"in_progress","priority":"high"},{"id":"4","content":"Run build to verify","status":"pending","priority":"medium"}]},"time":{"start":1781392616987,"end":1781392616991}}}}
+{"type":"step_finish","timestamp":1781392617001,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec3462e20001FZkgoRQTe3yHHj","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec34600ee001ZP0ZMYPyeYyTDp","type":"step-finish","reason":"tool-calls","snapshot":"89396b085fd4d482c49dae5fd3229681dd2dc169","cost":0.00992169,"tokens":{"input":407,"output":602,"reasoning":0,"cache":{"read":44544,"write":0}}}}
+{"type":"step_start","timestamp":1781392619147,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec3463689001vD1gkSpoMOms6m","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec3462e3e001QCjoz9njGtMVKa","type":"step-start","snapshot":"89396b085fd4d482c49dae5fd3229681dd2dc169"}}
+{"type":"tool_use","timestamp":1781392625464,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec346368a001lTgOMlVSEcE6Sf","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec3462e3e001QCjoz9njGtMVKa","type":"tool","callID":"write_25","tool":"write","state":{"status":"completed","input":{"filePath":"/workspace/app/page.tsx","content":"import { revalidateTag } from 'next/cache'\nimport { getAllProducts } from '@/lib/db'\n\nexport default async function CatalogPage() {\n async function syncCatalog() {\n 'use server'\n revalidateTag('products', 'max')\n }\n\n const products = await getAllProducts()\n\n return (\n \n
Product Catalog
\n
\n Sync latest catalog\n
\n
\n \n
\n
ID
\n
Name
\n
Price
\n
\n \n \n {products.map((product) => (\n
\n
{product.id}
\n
{product.name}
\n
${product.price}
\n
\n ))}\n \n
\n \n )\n}\n"},"output":"","title":"app/page.tsx","metadata":{"diagnostics":{"/workspace/lib/db.js":[],"/workspace/app/page.tsx":[],"/workspace/app/layout.tsx":[],"/workspace/next.config.ts":[]},"filepath":"/workspace/app/page.tsx","exists":true},"time":{"start":1781392622454,"end":1781392625462}}}}
+{"type":"step_finish","timestamp":1781392625470,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec3464f37001WXHZqwjtZCOoMF","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec3462e3e001QCjoz9njGtMVKa","type":"step-finish","reason":"tool-calls","snapshot":"c5e390b3458329d0bf83ad1d9fbdebc1329d3994","cost":0.0091852,"tokens":{"input":936,"output":282,"reasoning":0,"cache":{"read":44800,"write":0}}}}
+{"type":"step_start","timestamp":1781392627702,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec34657ef001x39Ca8bfpFYyg2","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec3464f5f0018HE8CWBwCTJDkk","type":"step-start","snapshot":"c5e390b3458329d0bf83ad1d9fbdebc1329d3994"}}
+{"type":"tool_use","timestamp":1781392629193,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec34657f2001MUWuSSf6xT1YG6","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec3464f5f0018HE8CWBwCTJDkk","type":"tool","callID":"todowrite_26","tool":"todowrite","state":{"status":"completed","input":{"todos":[{"id":"1","content":"Enable Cache Components in next.config.ts","status":"completed","priority":"high"},{"id":"2","content":"Cache lib/db.js getAllProducts with 'use cache' and products tag","status":"completed","priority":"high"},{"id":"3","content":"Build admin catalog page with inline sync Server Action and form","status":"completed","priority":"high"},{"id":"4","content":"Run build to verify","status":"in_progress","priority":"medium"}]},"output":"[\n {\n \"id\": \"1\",\n \"content\": \"Enable Cache Components in next.config.ts\",\n \"status\": \"completed\",\n \"priority\": \"high\"\n },\n {\n \"id\": \"2\",\n \"content\": \"Cache lib/db.js getAllProducts with 'use cache' and products tag\",\n \"status\": \"completed\",\n \"priority\": \"high\"\n },\n {\n \"id\": \"3\",\n \"content\": \"Build admin catalog page with inline sync Server Action and form\",\n \"status\": \"completed\",\n \"priority\": \"high\"\n },\n {\n \"id\": \"4\",\n \"content\": \"Run build to verify\",\n \"status\": \"in_progress\",\n \"priority\": \"medium\"\n }\n]","title":"1 todos","metadata":{"todos":[{"id":"1","content":"Enable Cache Components in next.config.ts","status":"completed","priority":"high"},{"id":"2","content":"Cache lib/db.js getAllProducts with 'use cache' and products tag","status":"completed","priority":"high"},{"id":"3","content":"Build admin catalog page with inline sync Server Action and form","status":"completed","priority":"high"},{"id":"4","content":"Run build to verify","status":"in_progress","priority":"medium"}]},"time":{"start":1781392629188,"end":1781392629191}}}}
+{"type":"step_finish","timestamp":1781392629198,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec3465dc8001lFvxse5fwLHf2c","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec3464f5f0018HE8CWBwCTJDkk","type":"step-finish","reason":"tool-calls","snapshot":"c5e390b3458329d0bf83ad1d9fbdebc1329d3994","cost":0.00822158,"tokens":{"input":466,"output":122,"reasoning":0,"cache":{"read":45568,"write":0}}}}
+{"type":"step_start","timestamp":1781392631322,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec34666180011ic23WBEHAVhdo","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec3465de0001lCa0Vq4wQ3ZUV6","type":"step-start","snapshot":"c5e390b3458329d0bf83ad1d9fbdebc1329d3994"}}
+{"type":"tool_use","timestamp":1781392643129,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec3466618002O8vswaK6gHwzMN","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec3465de0001lCa0Vq4wQ3ZUV6","type":"tool","callID":"bash_27","tool":"bash","state":{"status":"completed","input":{"command":"npm run build","description":"Build Next.js app to verify changes","timeout":300000},"output":"\n> build\n> next build\n\nAttention: Next.js now collects completely anonymous telemetry regarding usage.\nThis information is used to shape Next.js' roadmap and prioritize features.\nYou can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:\nhttps://nextjs.org/telemetry\n\n▲ Next.js 16.3.0-canary.50 (Turbopack)\n- Cache Components enabled\n\n Creating an optimized production build ...\n✓ Compiled successfully in 6.5s\n Running TypeScript ...\n\n We detected TypeScript in your project and reconfigured your tsconfig.json file for you.\n The following suggested values were added to your tsconfig.json. These values can be changed to fit your project's needs:\n\n \t- include was updated to add '.next/dev/types/**/*.ts'\n\n Finished TypeScript in 2.3s ...\n Collecting page data using 1 worker ...\n Generating static pages using 1 worker (0/3) ...\n✓ Generating static pages using 1 worker (3/3) in 184ms\n Finalizing page optimization ...\n\nRoute (app) Revalidate Expire\n┌ ○ / 15m 1y\n└ ○ /_not-found\n\n\n○ (Static) prerendered as static content\n\n","title":"Build Next.js app to verify changes","metadata":{"output":"\n> build\n> next build\n\nAttention: Next.js now collects completely anonymous telemetry regarding usage.\nThis information is used to shape Next.js' roadmap and prioritize features.\nYou can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:\nhttps://nextjs.org/telemetry\n\n▲ Next.js 16.3.0-canary.50 (Turbopack)\n- Cache Components enabled\n\n Creating an optimized production build ...\n✓ Compiled successfully in 6.5s\n Running TypeScript ...\n\n We detected TypeScript in your project and reconfigured your tsconfig.json file for you.\n The following suggested values were added to your tsconfig.json. These values can be changed to fit your project's needs:\n\n \t- include was updated to add '.next/dev/types/**/*.ts'\n\n Finished TypeScript in 2.3s ...\n Collecting page data using 1 worker ...\n Generating static pages using 1 worker (0/3) ...\n✓ Generating static pages using 1 worker (3/3) in 184ms\n Finalizing page optimization ...\n\nRoute (app) Revalidate Expire\n┌ ○ / 15m 1y\n└ ○ /_not-found\n\n\n○ (Static) prerendered as static content\n\n","exit":0,"description":"Build Next.js app to verify changes"},"time":{"start":1781392631583,"end":1781392643124}}}}
+{"type":"step_finish","timestamp":1781392643266,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec34694370013O0Y6hwNH7eD14","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec3465de0001lCa0Vq4wQ3ZUV6","type":"step-finish","reason":"tool-calls","snapshot":"4b3c4cb4b8b10fb612f4bb3c8d557d63a5c00e24","cost":0.00795614,"tokens":{"input":514,"output":34,"reasoning":0,"cache":{"read":45824,"write":0}}}}
+{"type":"step_start","timestamp":1781392645257,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec3469c83001u3qAlmUQH97YIc","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec34694db001EUbKRJCgqhgOZO","type":"step-start","snapshot":"4b3c4cb4b8b10fb612f4bb3c8d557d63a5c00e24"}}
+{"type":"tool_use","timestamp":1781392653000,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec346b9d6001PuY6GTzOYxlAUg","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec34694db001EUbKRJCgqhgOZO","type":"tool","callID":"read_28","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/lib/db.js"},"output":"\n00001| import { cacheTag } from 'next/cache'\n00002| \n00003| export async function getAllProducts() {\n00004| 'use cache'\n00005| \n00006| cacheTag('products')\n00007| \n00008| // Simulate database delay\n00009| await new Promise((resolve) => setTimeout(resolve, 100))\n00010| \n00011| return [\n00012| { id: 1, name: 'Laptop', price: 999 },\n00013| { id: 2, name: 'Phone', price: 699 },\n00014| { id: 3, name: 'Tablet', price: 499 },\n00015| { id: 4, name: 'Headphones', price: 199 },\n00016| { id: 5, name: 'Watch', price: 299 },\n00017| ]\n00018| }\n00019| \n\n(End of file - total 19 lines)\n","title":"lib/db.js","metadata":{"preview":"import { cacheTag } from 'next/cache'\n\nexport async function getAllProducts() {\n 'use cache'\n\n cacheTag('products')\n\n // Simulate database delay\n await new Promise((resolve) => setTimeout(resolve, 100))\n\n return [\n { id: 1, name: 'Laptop', price: 999 },\n { id: 2, name: 'Phone', price: 699 },\n { id: 3, name: 'Tablet', price: 499 },\n { id: 4, name: 'Headphones', price: 199 },\n { id: 5, name: 'Watch', price: 299 },\n ]\n}\n"},"time":{"start":1781392652993,"end":1781392652996}}}}
+{"type":"tool_use","timestamp":1781392653214,"sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","part":{"id":"prt_ec346bac3001c0N6hboPN27BFe","sessionID":"ses_13cbb6ca7ffeDluJj6gL6KvvXT","messageID":"msg_ec34694db001EUbKRJCgqhgOZO","type":"tool","callID":"read_29","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/app/page.tsx"},"output":"\n00001| import { revalidateTag } from 'next/cache'\n00002| import { getAllProducts } from '@/lib/db'\n00003| \n00004| export default async function CatalogPage() {\n00005| async function syncCatalog() {\n00006| 'use server'\n00007| revalidateTag('products', 'max')\n00008| }\n00009| \n00010| const products = await getAllProducts()\n00011| \n00012| return (\n00013| \n00014|
\n00006| )\n00007| }\n00008| \n\n(End of file - total 8 lines)\n",
+ "title": "app/page.tsx",
+ "metadata": {
+ "preview": "export default function Page() {\n return (\n
\n
Home
\n
\n )\n}\n"
+ },
+ "time": {
+ "start": 1781392525215,
+ "end": 1781392525252
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:25.759Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "args": {
+ "filePath": "/workspace/lib/db.js",
+ "_extractedPath": "/workspace/lib/db.js"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392525759,
+ "sessionID": "ses_13cbb6ca7ffeDluJj6gL6KvvXT",
+ "part": {
+ "id": "prt_ec344c7bc0010PlYIdir7YrE7U",
+ "sessionID": "ses_13cbb6ca7ffeDluJj6gL6KvvXT",
+ "messageID": "msg_ec344b5ba001mjuTnyDfQWTqoW",
+ "type": "tool",
+ "callID": "read_6",
+ "tool": "read",
+ "state": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/lib/db.js"
+ },
+ "output": "\n00001| export async function getAllProducts() {\n00002| // Simulate database delay\n00003| await new Promise((resolve) => setTimeout(resolve, 100))\n00004| \n00005| return [\n00006| { id: 1, name: 'Laptop', price: 999 },\n00007| { id: 2, name: 'Phone', price: 699 },\n00008| { id: 3, name: 'Tablet', price: 499 },\n00009| { id: 4, name: 'Headphones', price: 199 },\n00010| { id: 5, name: 'Watch', price: 299 },\n00011| ]\n00012| }\n00013| \n\n(End of file - total 13 lines)\n",
+ "title": "lib/db.js",
+ "metadata": {
+ "preview": "export async function getAllProducts() {\n // Simulate database delay\n await new Promise((resolve) => setTimeout(resolve, 100))\n\n return [\n { id: 1, name: 'Laptop', price: 999 },\n { id: 2, name: 'Phone', price: 699 },\n { id: 3, name: 'Tablet', price: 499 },\n { id: 4, name: 'Headphones', price: 199 },\n { id: 5, name: 'Watch', price: 299 },\n ]\n}\n"
+ },
+ "time": {
+ "start": 1781392525696,
+ "end": 1781392525715
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:25.759Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| export async function getAllProducts() {\n00002| // Simulate database delay\n00003| await new Promise((resolve) => setTimeout(resolve, 100))\n00004| \n00005| return [\n00006| { id: 1, name: 'Laptop', price: 999 },\n00007| { id: 2, name: 'Phone', price: 699 },\n00008| { id: 3, name: 'Tablet', price: 499 },\n00009| { id: 4, name: 'Headphones', price: 199 },\n00010| { id: 5, name: 'Watch', price: 299 },\n00011| ]\n00012| }\n00013| \n\n(End of file - total 13 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/lib/db.js"
+ },
+ "output": "\n00001| export async function getAllProducts() {\n00002| // Simulate database delay\n00003| await new Promise((resolve) => setTimeout(resolve, 100))\n00004| \n00005| return [\n00006| { id: 1, name: 'Laptop', price: 999 },\n00007| { id: 2, name: 'Phone', price: 699 },\n00008| { id: 3, name: 'Tablet', price: 499 },\n00009| { id: 4, name: 'Headphones', price: 199 },\n00010| { id: 5, name: 'Watch', price: 299 },\n00011| ]\n00012| }\n00013| \n\n(End of file - total 13 lines)\n",
+ "title": "lib/db.js",
+ "metadata": {
+ "preview": "export async function getAllProducts() {\n // Simulate database delay\n await new Promise((resolve) => setTimeout(resolve, 100))\n\n return [\n { id: 1, name: 'Laptop', price: 999 },\n { id: 2, name: 'Phone', price: 699 },\n { id: 3, name: 'Tablet', price: 499 },\n { id: 4, name: 'Headphones', price: 199 },\n { id: 5, name: 'Watch', price: 299 },\n ]\n}\n"
+ },
+ "time": {
+ "start": 1781392525696,
+ "end": 1781392525715
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:25.981Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "glob",
+ "originalName": "glob",
+ "args": {
+ "pattern": "node_modules/next/dist/docs/**/*",
+ "path": "/workspace"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392525981,
+ "sessionID": "ses_13cbb6ca7ffeDluJj6gL6KvvXT",
+ "part": {
+ "id": "prt_ec344c992001VTGsunrBXmrRrT",
+ "sessionID": "ses_13cbb6ca7ffeDluJj6gL6KvvXT",
+ "messageID": "msg_ec344b5ba001mjuTnyDfQWTqoW",
+ "type": "tool",
+ "callID": "glob_7",
+ "tool": "glob",
+ "state": {
+ "status": "completed",
+ "input": {
+ "pattern": "node_modules/next/dist/docs/**/*",
+ "path": "/workspace"
+ },
+ "output": "No files found",
+ "title": "",
+ "metadata": {
+ "count": 0,
+ "truncated": false
+ },
+ "time": {
+ "start": 1781392525914,
+ "end": 1781392525949
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:25.981Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "glob",
+ "originalName": "glob",
+ "result": "No files found",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "pattern": "node_modules/next/dist/docs/**/*",
+ "path": "/workspace"
+ },
+ "output": "No files found",
+ "title": "",
+ "metadata": {
+ "count": 0,
+ "truncated": false
+ },
+ "time": {
+ "start": 1781392525914,
+ "end": 1781392525949
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:28.201Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "shell",
+ "originalName": "bash",
+ "args": {
+ "command": "ls -la node_modules/next/dist/docs 2>/dev/null || echo \"docs dir missing\"",
+ "description": "List Next.js docs directory",
+ "_extractedCommand": "ls -la node_modules/next/dist/docs 2>/dev/null || echo \"docs dir missing\""
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392528201,
+ "sessionID": "ses_13cbb6ca7ffeDluJj6gL6KvvXT",
+ "part": {
+ "id": "prt_ec344d10d001uZkBSolMfA4YbI",
+ "sessionID": "ses_13cbb6ca7ffeDluJj6gL6KvvXT",
+ "messageID": "msg_ec344cae5001YOYwC28aVLwYsn",
+ "type": "tool",
+ "callID": "bash_8",
+ "tool": "bash",
+ "state": {
+ "status": "completed",
+ "input": {
+ "command": "ls -la node_modules/next/dist/docs 2>/dev/null || echo \"docs dir missing\"",
+ "description": "List Next.js docs directory"
+ },
+ "output": "total 8\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 95 Jun 13 23:15 .\ndrwxr-xr-x 22 vercel-sandbox vercel-sandbox 4096 Jun 13 23:15 ..\ndrwxr-xr-x 5 vercel-sandbox vercel-sandbox 111 Jun 13 23:15 01-app\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 125 Jun 13 23:15 02-pages\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 124 Jun 13 23:15 03-architecture\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 74 Jun 13 23:15 04-community\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 3138 Jun 13 23:15 index.md\n",
+ "title": "List Next.js docs directory",
+ "metadata": {
+ "output": "total 8\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 95 Jun 13 23:15 .\ndrwxr-xr-x 22 vercel-sandbox vercel-sandbox 4096 Jun 13 23:15 ..\ndrwxr-xr-x 5 vercel-sandbox vercel-sandbox 111 Jun 13 23:15 01-app\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 125 Jun 13 23:15 02-pages\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 124 Jun 13 23:15 03-architecture\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 74 Jun 13 23:15 04-community\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 3138 Jun 13 23:15 index.md\n",
+ "exit": 0,
+ "description": "List Next.js docs directory"
+ },
+ "time": {
+ "start": 1781392528170,
+ "end": 1781392528191
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:28.201Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "shell",
+ "originalName": "bash",
+ "result": "total 8\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 95 Jun 13 23:15 .\ndrwxr-xr-x 22 vercel-sandbox vercel-sandbox 4096 Jun 13 23:15 ..\ndrwxr-xr-x 5 vercel-sandbox vercel-sandbox 111 Jun 13 23:15 01-app\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 125 Jun 13 23:15 02-pages\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 124 Jun 13 23:15 03-architecture\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 74 Jun 13 23:15 04-community\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 3138 Jun 13 23:15 index.md\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "command": "ls -la node_modules/next/dist/docs 2>/dev/null || echo \"docs dir missing\"",
+ "description": "List Next.js docs directory"
+ },
+ "output": "total 8\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 95 Jun 13 23:15 .\ndrwxr-xr-x 22 vercel-sandbox vercel-sandbox 4096 Jun 13 23:15 ..\ndrwxr-xr-x 5 vercel-sandbox vercel-sandbox 111 Jun 13 23:15 01-app\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 125 Jun 13 23:15 02-pages\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 124 Jun 13 23:15 03-architecture\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 74 Jun 13 23:15 04-community\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 3138 Jun 13 23:15 index.md\n",
+ "title": "List Next.js docs directory",
+ "metadata": {
+ "output": "total 8\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 95 Jun 13 23:15 .\ndrwxr-xr-x 22 vercel-sandbox vercel-sandbox 4096 Jun 13 23:15 ..\ndrwxr-xr-x 5 vercel-sandbox vercel-sandbox 111 Jun 13 23:15 01-app\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 125 Jun 13 23:15 02-pages\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 124 Jun 13 23:15 03-architecture\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 74 Jun 13 23:15 04-community\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 3138 Jun 13 23:15 index.md\n",
+ "exit": 0,
+ "description": "List Next.js docs directory"
+ },
+ "time": {
+ "start": 1781392528170,
+ "end": 1781392528191
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:30.751Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "shell",
+ "originalName": "bash",
+ "args": {
+ "command": "find node_modules/next/dist/docs -type f -name \"*.md\" | xargs grep -l -i \"cache tag\\|revalidateTag\\|unstable_cache\\|server action\\|form\" 2>/dev/null | head -50",
+ "description": "Find relevant caching docs",
+ "_extractedCommand": "find node_modules/next/dist/docs -type f -name \"*.md\" | xargs grep -l -i \"cache tag\\|revalidateTag\\|unstable_cache\\|server action\\|form\" 2>/dev/null | head -50"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392530751,
+ "sessionID": "ses_13cbb6ca7ffeDluJj6gL6KvvXT",
+ "part": {
+ "id": "prt_ec344d9a80014jW8rcJHOFHfMb",
+ "sessionID": "ses_13cbb6ca7ffeDluJj6gL6KvvXT",
+ "messageID": "msg_ec344d360001gzbUXJkUDQ9tIn",
+ "type": "tool",
+ "callID": "bash_9",
+ "tool": "bash",
+ "state": {
+ "status": "completed",
+ "input": {
+ "command": "find node_modules/next/dist/docs -type f -name \"*.md\" | xargs grep -l -i \"cache tag\\|revalidateTag\\|unstable_cache\\|server action\\|form\" 2>/dev/null | head -50",
+ "description": "Find relevant caching docs"
+ },
+ "output": "node_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/02-dynamic-routes.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/07-api-routes.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/06-configuring/12-error-handling.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/01-get-static-props.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/02-get-static-paths.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/03-get-server-side-props.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/05-client-side.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/04-automatic-static-optimization.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/05-client-side-rendering.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/get-initial-props.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/get-static-props.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/use-router.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/10-routing-information.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/04-config/01-next-config-js/serverExternalPackages.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/01-components/form.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/01-components/image-legacy.md\nnode_modules/next/dist/docs/02-pages/02-guides/upgrading/version-11.md\nnode_modules/next/dist/docs/02-pages/02-guides/upgrading/version-12.md\nnode_modules/next/dist/docs/02-pages/02-guides/upgrading/version-13.md\nnode_modules/next/dist/docs/02-pages/02-guides/upgrading/version-9.md\nnode_modules/next/dist/docs/02-pages/02-guides/analytics.md\nnode_modules/next/dist/docs/02-pages/02-guides/babel.md\nnode_modules/next/dist/docs/02-pages/02-guides/forms.md\nnode_modules/next/dist/docs/02-pages/02-guides/internationalization.md\nnode_modules/next/dist/docs/02-pages/02-guides/lazy-loading.md\nnode_modules/next/dist/docs/02-pages/02-guides/post-css.md\nnode_modules/next/dist/docs/02-pages/02-guides/preview-mode.md\nnode_modules/next/dist/docs/02-pages/02-guides/production-checklist.md\nnode_modules/next/dist/docs/02-pages/02-guides/third-party-libraries.md\nnode_modules/next/dist/docs/01-app/02-guides/ai-agents.md\nnode_modules/next/dist/docs/01-app/02-guides/analytics.md\nnode_modules/next/dist/docs/01-app/02-guides/authentication.md\nnode_modules/next/dist/docs/01-app/02-guides/backend-for-frontend.md\nnode_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/cdn-caching.md\nnode_modules/next/dist/docs/01-app/02-guides/ci-build-caching.md\nnode_modules/next/dist/docs/01-app/02-guides/content-security-policy.md\nnode_modules/next/dist/docs/01-app/02-guides/custom-server.md\nnode_modules/next/dist/docs/01-app/02-guides/data-security.md\nnode_modules/next/dist/docs/01-app/02-guides/debugging.md\nnode_modules/next/dist/docs/01-app/02-guides/deploying-to-platforms.md\nnode_modules/next/dist/docs/01-app/02-guides/draft-mode.md\nnode_modules/next/dist/docs/01-app/02-guides/environment-variables.md\nnode_modules/next/dist/docs/01-app/02-guides/forms.md\nnode_modules/next/dist/docs/01-app/02-guides/how-revalidation-works.md\nnode_modules/next/dist/docs/01-app/02-guides/incremental-static-regeneration.md\nnode_modules/next/dist/docs/01-app/02-guides/instant-navigation.md\nnode_modules/next/dist/docs/01-app/02-guides/instrumentation.md\n",
+ "title": "Find relevant caching docs",
+ "metadata": {
+ "output": "node_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/02-dynamic-routes.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/07-api-routes.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/06-configuring/12-error-handling.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/01-get-static-props.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/02-get-static-paths.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/03-get-server-side-props.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/05-client-side.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/04-automatic-static-optimization.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/05-client-side-rendering.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/get-initial-props.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/get-static-props.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/use-router.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/10-routing-information.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/04-config/01-next-config-js/serverExternalPackages.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/01-components/form.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/01-components/image-legacy.md\nnode_modules/next/dist/docs/02-pages/02-guides/upgrading/version-11.md\nnode_modules/next/dist/docs/02-pages/02-guides/upgrading/version-12.md\nnode_modules/next/dist/docs/02-pages/02-guides/upgrading/version-13.md\nnode_modules/next/dist/docs/02-pages/02-guides/upgrading/version-9.md\nnode_modules/next/dist/docs/02-pages/02-guides/analytics.md\nnode_modules/next/dist/docs/02-pages/02-guides/babel.md\nnode_modules/next/dist/docs/02-pages/02-guides/forms.md\nnode_modules/next/dist/docs/02-pages/02-guides/internationalization.md\nnode_modules/next/dist/docs/02-pages/02-guides/lazy-loading.md\nnode_modules/next/dist/docs/02-pages/02-guides/post-css.md\nnode_modules/next/dist/docs/02-pages/02-guides/preview-mode.md\nnode_modules/next/dist/docs/02-pages/02-guides/production-checklist.md\nnode_modules/next/dist/docs/02-pages/02-guides/third-party-libraries.md\nnode_modules/next/dist/docs/01-app/02-guides/ai-agents.md\nnode_modules/next/dist/docs/01-app/02-guides/analytics.md\nnode_modules/next/dist/docs/01-app/02-guides/authentication.md\nnode_modules/next/dist/docs/01-app/02-guides/backend-for-frontend.md\nnode_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/cdn-caching.md\nnode_modules/next/dist/docs/01-app/02-guides/ci-build-caching.md\nnode_modules/next/dist/docs/01-app/02-guides/content-security-policy.md\nnode_modules/next/dist/docs/01-app/02-guides/custom-server.md\nnode_modules/next/dist/docs/01-app/02-guides/data-security.md\nnode_modules/next/dist/docs/01-app/02-guides/debugging.md\nnode_modules/next/dist/docs/01-app/02-guides/deploying-to-platforms.md\nnode_modules/next/dist/docs/01-app/02-guides/draft-mode.md\nnode_modules/next/dist/docs/01-app/02-guides/environment-variables.md\nnode_modules/next/dist/docs/01-app/02-guides/forms.md\nnode_modules/next/dist/docs/01-app/02-guides/how-revalidation-works.md\nnode_modules/next/dist/docs/01-app/02-guides/incremental-static-regeneration.md\nnode_modules/next/dist/docs/01-app/02-guides/instant-navigation.md\nnode_modules/next/dist/docs/01-app/02-guides/instrumentation.md\n",
+ "exit": 0,
+ "description": "Find relevant caching docs"
+ },
+ "time": {
+ "start": 1781392530705,
+ "end": 1781392530748
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:30.751Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "shell",
+ "originalName": "bash",
+ "result": "node_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/02-dynamic-routes.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/07-api-routes.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/06-configuring/12-error-handling.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/01-get-static-props.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/02-get-static-paths.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/03-get-server-side-props.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/05-client-side.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/04-automatic-static-optimization.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/05-client-side-rendering.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/get-initial-props.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/get-static-props.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/use-router.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/10-routing-information.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/04-config/01-next-config-js/serverExternalPackages.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/01-components/form.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/01-components/image-legacy.md\nnode_modules/next/dist/docs/02-pages/02-guides/upgrading/version-11.md\nnode_modules/next/dist/docs/02-pages/02-guides/upgrading/version-12.md\nnode_modules/next/dist/docs/02-pages/02-guides/upgrading/version-13.md\nnode_modules/next/dist/docs/02-pages/02-guides/upgrading/version-9.md\nnode_modules/next/dist/docs/02-pages/02-guides/analytics.md\nnode_modules/next/dist/docs/02-pages/02-guides/babel.md\nnode_modules/next/dist/docs/02-pages/02-guides/forms.md\nnode_modules/next/dist/docs/02-pages/02-guides/internationalization.md\nnode_modules/next/dist/docs/02-pages/02-guides/lazy-loading.md\nnode_modules/next/dist/docs/02-pages/02-guides/post-css.md\nnode_modules/next/dist/docs/02-pages/02-guides/preview-mode.md\nnode_modules/next/dist/docs/02-pages/02-guides/production-checklist.md\nnode_modules/next/dist/docs/02-pages/02-guides/third-party-libraries.md\nnode_modules/next/dist/docs/01-app/02-guides/ai-agents.md\nnode_modules/next/dist/docs/01-app/02-guides/analytics.md\nnode_modules/next/dist/docs/01-app/02-guides/authentication.md\nnode_modules/next/dist/docs/01-app/02-guides/backend-for-frontend.md\nnode_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/cdn-caching.md\nnode_modules/next/dist/docs/01-app/02-guides/ci-build-caching.md\nnode_modules/next/dist/docs/01-app/02-guides/content-security-policy.md\nnode_modules/next/dist/docs/01-app/02-guides/custom-server.md\nnode_modules/next/dist/docs/01-app/02-guides/data-security.md\nnode_modules/next/dist/docs/01-app/02-guides/debugging.md\nnode_modules/next/dist/docs/01-app/02-guides/deploying-to-platforms.md\nnode_modules/next/dist/docs/01-app/02-guides/draft-mode.md\nnode_modules/next/dist/docs/01-app/02-guides/environment-variables.md\nnode_modules/next/dist/docs/01-app/02-guides/forms.md\nnode_modules/next/dist/docs/01-app/02-guides/how-revalidation-works.md\nnode_modules/next/dist/docs/01-app/02-guides/incremental-static-regeneration.md\nnode_modules/next/dist/docs/01-app/02-guides/instant-navigation.md\nnode_modules/next/dist/docs/01-app/02-guides/instrumentation.md\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "command": "find node_modules/next/dist/docs -type f -name \"*.md\" | xargs grep -l -i \"cache tag\\|revalidateTag\\|unstable_cache\\|server action\\|form\" 2>/dev/null | head -50",
+ "description": "Find relevant caching docs"
+ },
+ "output": "node_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/02-dynamic-routes.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/07-api-routes.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/06-configuring/12-error-handling.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/01-get-static-props.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/02-get-static-paths.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/03-get-server-side-props.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/05-client-side.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/04-automatic-static-optimization.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/05-client-side-rendering.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/get-initial-props.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/get-static-props.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/use-router.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/10-routing-information.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/04-config/01-next-config-js/serverExternalPackages.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/01-components/form.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/01-components/image-legacy.md\nnode_modules/next/dist/docs/02-pages/02-guides/upgrading/version-11.md\nnode_modules/next/dist/docs/02-pages/02-guides/upgrading/version-12.md\nnode_modules/next/dist/docs/02-pages/02-guides/upgrading/version-13.md\nnode_modules/next/dist/docs/02-pages/02-guides/upgrading/version-9.md\nnode_modules/next/dist/docs/02-pages/02-guides/analytics.md\nnode_modules/next/dist/docs/02-pages/02-guides/babel.md\nnode_modules/next/dist/docs/02-pages/02-guides/forms.md\nnode_modules/next/dist/docs/02-pages/02-guides/internationalization.md\nnode_modules/next/dist/docs/02-pages/02-guides/lazy-loading.md\nnode_modules/next/dist/docs/02-pages/02-guides/post-css.md\nnode_modules/next/dist/docs/02-pages/02-guides/preview-mode.md\nnode_modules/next/dist/docs/02-pages/02-guides/production-checklist.md\nnode_modules/next/dist/docs/02-pages/02-guides/third-party-libraries.md\nnode_modules/next/dist/docs/01-app/02-guides/ai-agents.md\nnode_modules/next/dist/docs/01-app/02-guides/analytics.md\nnode_modules/next/dist/docs/01-app/02-guides/authentication.md\nnode_modules/next/dist/docs/01-app/02-guides/backend-for-frontend.md\nnode_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/cdn-caching.md\nnode_modules/next/dist/docs/01-app/02-guides/ci-build-caching.md\nnode_modules/next/dist/docs/01-app/02-guides/content-security-policy.md\nnode_modules/next/dist/docs/01-app/02-guides/custom-server.md\nnode_modules/next/dist/docs/01-app/02-guides/data-security.md\nnode_modules/next/dist/docs/01-app/02-guides/debugging.md\nnode_modules/next/dist/docs/01-app/02-guides/deploying-to-platforms.md\nnode_modules/next/dist/docs/01-app/02-guides/draft-mode.md\nnode_modules/next/dist/docs/01-app/02-guides/environment-variables.md\nnode_modules/next/dist/docs/01-app/02-guides/forms.md\nnode_modules/next/dist/docs/01-app/02-guides/how-revalidation-works.md\nnode_modules/next/dist/docs/01-app/02-guides/incremental-static-regeneration.md\nnode_modules/next/dist/docs/01-app/02-guides/instant-navigation.md\nnode_modules/next/dist/docs/01-app/02-guides/instrumentation.md\n",
+ "title": "Find relevant caching docs",
+ "metadata": {
+ "output": "node_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/02-dynamic-routes.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/07-api-routes.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/06-configuring/12-error-handling.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/01-get-static-props.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/02-get-static-paths.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/03-get-server-side-props.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/05-client-side.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/04-automatic-static-optimization.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/05-client-side-rendering.md\nnode_modules/next/dist/docs/02-pages/03-building-your-application/02-rendering/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/get-initial-props.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/get-static-props.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/03-functions/use-router.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/10-routing-information.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/06-adapters/index.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/04-config/01-next-config-js/serverExternalPackages.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/01-components/form.md\nnode_modules/next/dist/docs/02-pages/04-api-reference/01-components/image-legacy.md\nnode_modules/next/dist/docs/02-pages/02-guides/upgrading/version-11.md\nnode_modules/next/dist/docs/02-pages/02-guides/upgrading/version-12.md\nnode_modules/next/dist/docs/02-pages/02-guides/upgrading/version-13.md\nnode_modules/next/dist/docs/02-pages/02-guides/upgrading/version-9.md\nnode_modules/next/dist/docs/02-pages/02-guides/analytics.md\nnode_modules/next/dist/docs/02-pages/02-guides/babel.md\nnode_modules/next/dist/docs/02-pages/02-guides/forms.md\nnode_modules/next/dist/docs/02-pages/02-guides/internationalization.md\nnode_modules/next/dist/docs/02-pages/02-guides/lazy-loading.md\nnode_modules/next/dist/docs/02-pages/02-guides/post-css.md\nnode_modules/next/dist/docs/02-pages/02-guides/preview-mode.md\nnode_modules/next/dist/docs/02-pages/02-guides/production-checklist.md\nnode_modules/next/dist/docs/02-pages/02-guides/third-party-libraries.md\nnode_modules/next/dist/docs/01-app/02-guides/ai-agents.md\nnode_modules/next/dist/docs/01-app/02-guides/analytics.md\nnode_modules/next/dist/docs/01-app/02-guides/authentication.md\nnode_modules/next/dist/docs/01-app/02-guides/backend-for-frontend.md\nnode_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/cdn-caching.md\nnode_modules/next/dist/docs/01-app/02-guides/ci-build-caching.md\nnode_modules/next/dist/docs/01-app/02-guides/content-security-policy.md\nnode_modules/next/dist/docs/01-app/02-guides/custom-server.md\nnode_modules/next/dist/docs/01-app/02-guides/data-security.md\nnode_modules/next/dist/docs/01-app/02-guides/debugging.md\nnode_modules/next/dist/docs/01-app/02-guides/deploying-to-platforms.md\nnode_modules/next/dist/docs/01-app/02-guides/draft-mode.md\nnode_modules/next/dist/docs/01-app/02-guides/environment-variables.md\nnode_modules/next/dist/docs/01-app/02-guides/forms.md\nnode_modules/next/dist/docs/01-app/02-guides/how-revalidation-works.md\nnode_modules/next/dist/docs/01-app/02-guides/incremental-static-regeneration.md\nnode_modules/next/dist/docs/01-app/02-guides/instant-navigation.md\nnode_modules/next/dist/docs/01-app/02-guides/instrumentation.md\n",
+ "exit": 0,
+ "description": "Find relevant caching docs"
+ },
+ "time": {
+ "start": 1781392530705,
+ "end": 1781392530748
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:34.349Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "shell",
+ "originalName": "bash",
+ "args": {
+ "command": "find node_modules/next/dist/docs/01-app -type f -name \"*.md\" | xargs grep -l -i \"cache tag\\|revalidateTag\\|unstable_cache\" 2>/dev/null",
+ "description": "Find app caching docs",
+ "_extractedCommand": "find node_modules/next/dist/docs/01-app -type f -name \"*.md\" | xargs grep -l -i \"cache tag\\|revalidateTag\\|unstable_cache\" 2>/dev/null"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392534349,
+ "sessionID": "ses_13cbb6ca7ffeDluJj6gL6KvvXT",
+ "part": {
+ "id": "prt_ec344e5000012HFveJLuoH9iI5",
+ "sessionID": "ses_13cbb6ca7ffeDluJj6gL6KvvXT",
+ "messageID": "msg_ec344dd56001wm3ndJlz8siLM7",
+ "type": "tool",
+ "callID": "bash_10",
+ "tool": "bash",
+ "state": {
+ "status": "completed",
+ "input": {
+ "command": "find node_modules/next/dist/docs/01-app -type f -name \"*.md\" | xargs grep -l -i \"cache tag\\|revalidateTag\\|unstable_cache\" 2>/dev/null",
+ "description": "Find app caching docs"
+ },
+ "output": "node_modules/next/dist/docs/01-app/02-guides/backend-for-frontend.md\nnode_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/cdn-caching.md\nnode_modules/next/dist/docs/01-app/02-guides/deploying-to-platforms.md\nnode_modules/next/dist/docs/01-app/02-guides/draft-mode.md\nnode_modules/next/dist/docs/01-app/02-guides/how-revalidation-works.md\nnode_modules/next/dist/docs/01-app/02-guides/incremental-static-regeneration.md\nnode_modules/next/dist/docs/01-app/02-guides/migrating-to-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/ppr-platform-guide.md\nnode_modules/next/dist/docs/01-app/02-guides/prefetching.md\nnode_modules/next/dist/docs/01-app/02-guides/production-checklist.md\nnode_modules/next/dist/docs/01-app/02-guides/redirecting.md\nnode_modules/next/dist/docs/01-app/02-guides/rendering-philosophy.md\nnode_modules/next/dist/docs/01-app/02-guides/self-hosting.md\nnode_modules/next/dist/docs/01-app/02-guides/upgrading/codemods.md\nnode_modules/next/dist/docs/01-app/02-guides/upgrading/version-16.md\nnode_modules/next/dist/docs/01-app/04-glossary.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheLife.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cookies.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/fetch.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/next-root-params.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidatePath.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/unstable_cache.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/unstable_noStore.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/updateTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/use-router.md\nnode_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache-remote.md\nnode_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/cacheHandlers.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/incrementalCacheHandlerPath.md\nnode_modules/next/dist/docs/01-app/01-getting-started/07-mutating-data.md\nnode_modules/next/dist/docs/01-app/01-getting-started/09-revalidating.md\n",
+ "title": "Find app caching docs",
+ "metadata": {
+ "output": "node_modules/next/dist/docs/01-app/02-guides/backend-for-frontend.md\nnode_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/cdn-caching.md\nnode_modules/next/dist/docs/01-app/02-guides/deploying-to-platforms.md\nnode_modules/next/dist/docs/01-app/02-guides/draft-mode.md\nnode_modules/next/dist/docs/01-app/02-guides/how-revalidation-works.md\nnode_modules/next/dist/docs/01-app/02-guides/incremental-static-regeneration.md\nnode_modules/next/dist/docs/01-app/02-guides/migrating-to-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/ppr-platform-guide.md\nnode_modules/next/dist/docs/01-app/02-guides/prefetching.md\nnode_modules/next/dist/docs/01-app/02-guides/production-checklist.md\nnode_modules/next/dist/docs/01-app/02-guides/redirecting.md\nnode_modules/next/dist/docs/01-app/02-guides/rendering-philosophy.md\nnode_modules/next/dist/docs/01-app/02-guides/self-hosting.md\nnode_modules/next/dist/docs/01-app/02-guides/upgrading/codemods.md\nnode_modules/next/dist/docs/01-app/02-guides/upgrading/version-16.md\nnode_modules/next/dist/docs/01-app/04-glossary.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheLife.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cookies.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/fetch.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/next-root-params.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidatePath.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/unstable_cache.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/unstable_noStore.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/updateTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/use-router.md\nnode_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache-remote.md\nnode_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/cacheHandlers.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/incrementalCacheHandlerPath.md\nnode_modules/next/dist/docs/01-app/01-getting-started/07-mutating-data.md\nnode_modules/next/dist/docs/01-app/01-getting-started/09-revalidating.md\n",
+ "exit": 0,
+ "description": "Find app caching docs"
+ },
+ "time": {
+ "start": 1781392534324,
+ "end": 1781392534347
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:34.349Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "shell",
+ "originalName": "bash",
+ "result": "node_modules/next/dist/docs/01-app/02-guides/backend-for-frontend.md\nnode_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/cdn-caching.md\nnode_modules/next/dist/docs/01-app/02-guides/deploying-to-platforms.md\nnode_modules/next/dist/docs/01-app/02-guides/draft-mode.md\nnode_modules/next/dist/docs/01-app/02-guides/how-revalidation-works.md\nnode_modules/next/dist/docs/01-app/02-guides/incremental-static-regeneration.md\nnode_modules/next/dist/docs/01-app/02-guides/migrating-to-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/ppr-platform-guide.md\nnode_modules/next/dist/docs/01-app/02-guides/prefetching.md\nnode_modules/next/dist/docs/01-app/02-guides/production-checklist.md\nnode_modules/next/dist/docs/01-app/02-guides/redirecting.md\nnode_modules/next/dist/docs/01-app/02-guides/rendering-philosophy.md\nnode_modules/next/dist/docs/01-app/02-guides/self-hosting.md\nnode_modules/next/dist/docs/01-app/02-guides/upgrading/codemods.md\nnode_modules/next/dist/docs/01-app/02-guides/upgrading/version-16.md\nnode_modules/next/dist/docs/01-app/04-glossary.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheLife.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cookies.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/fetch.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/next-root-params.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidatePath.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/unstable_cache.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/unstable_noStore.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/updateTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/use-router.md\nnode_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache-remote.md\nnode_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/cacheHandlers.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/incrementalCacheHandlerPath.md\nnode_modules/next/dist/docs/01-app/01-getting-started/07-mutating-data.md\nnode_modules/next/dist/docs/01-app/01-getting-started/09-revalidating.md\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "command": "find node_modules/next/dist/docs/01-app -type f -name \"*.md\" | xargs grep -l -i \"cache tag\\|revalidateTag\\|unstable_cache\" 2>/dev/null",
+ "description": "Find app caching docs"
+ },
+ "output": "node_modules/next/dist/docs/01-app/02-guides/backend-for-frontend.md\nnode_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/cdn-caching.md\nnode_modules/next/dist/docs/01-app/02-guides/deploying-to-platforms.md\nnode_modules/next/dist/docs/01-app/02-guides/draft-mode.md\nnode_modules/next/dist/docs/01-app/02-guides/how-revalidation-works.md\nnode_modules/next/dist/docs/01-app/02-guides/incremental-static-regeneration.md\nnode_modules/next/dist/docs/01-app/02-guides/migrating-to-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/ppr-platform-guide.md\nnode_modules/next/dist/docs/01-app/02-guides/prefetching.md\nnode_modules/next/dist/docs/01-app/02-guides/production-checklist.md\nnode_modules/next/dist/docs/01-app/02-guides/redirecting.md\nnode_modules/next/dist/docs/01-app/02-guides/rendering-philosophy.md\nnode_modules/next/dist/docs/01-app/02-guides/self-hosting.md\nnode_modules/next/dist/docs/01-app/02-guides/upgrading/codemods.md\nnode_modules/next/dist/docs/01-app/02-guides/upgrading/version-16.md\nnode_modules/next/dist/docs/01-app/04-glossary.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheLife.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cookies.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/fetch.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/next-root-params.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidatePath.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/unstable_cache.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/unstable_noStore.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/updateTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/use-router.md\nnode_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache-remote.md\nnode_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/cacheHandlers.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/incrementalCacheHandlerPath.md\nnode_modules/next/dist/docs/01-app/01-getting-started/07-mutating-data.md\nnode_modules/next/dist/docs/01-app/01-getting-started/09-revalidating.md\n",
+ "title": "Find app caching docs",
+ "metadata": {
+ "output": "node_modules/next/dist/docs/01-app/02-guides/backend-for-frontend.md\nnode_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/cdn-caching.md\nnode_modules/next/dist/docs/01-app/02-guides/deploying-to-platforms.md\nnode_modules/next/dist/docs/01-app/02-guides/draft-mode.md\nnode_modules/next/dist/docs/01-app/02-guides/how-revalidation-works.md\nnode_modules/next/dist/docs/01-app/02-guides/incremental-static-regeneration.md\nnode_modules/next/dist/docs/01-app/02-guides/migrating-to-cache-components.md\nnode_modules/next/dist/docs/01-app/02-guides/ppr-platform-guide.md\nnode_modules/next/dist/docs/01-app/02-guides/prefetching.md\nnode_modules/next/dist/docs/01-app/02-guides/production-checklist.md\nnode_modules/next/dist/docs/01-app/02-guides/redirecting.md\nnode_modules/next/dist/docs/01-app/02-guides/rendering-philosophy.md\nnode_modules/next/dist/docs/01-app/02-guides/self-hosting.md\nnode_modules/next/dist/docs/01-app/02-guides/upgrading/codemods.md\nnode_modules/next/dist/docs/01-app/02-guides/upgrading/version-16.md\nnode_modules/next/dist/docs/01-app/04-glossary.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheLife.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/cookies.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/fetch.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/next-root-params.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidatePath.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/unstable_cache.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/unstable_noStore.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/updateTag.md\nnode_modules/next/dist/docs/01-app/03-api-reference/04-functions/use-router.md\nnode_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache-remote.md\nnode_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/cacheHandlers.md\nnode_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/incrementalCacheHandlerPath.md\nnode_modules/next/dist/docs/01-app/01-getting-started/07-mutating-data.md\nnode_modules/next/dist/docs/01-app/01-getting-started/09-revalidating.md\n",
+ "exit": 0,
+ "description": "Find app caching docs"
+ },
+ "time": {
+ "start": 1781392534324,
+ "end": 1781392534347
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:37.480Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "args": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md",
+ "_extractedPath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392537480,
+ "sessionID": "ses_13cbb6ca7ffeDluJj6gL6KvvXT",
+ "part": {
+ "id": "prt_ec344f50e001pOTp5RUoH8W1UW",
+ "sessionID": "ses_13cbb6ca7ffeDluJj6gL6KvvXT",
+ "messageID": "msg_ec344eb5d001IcU2v22Hnj8HEM",
+ "type": "tool",
+ "callID": "read_11",
+ "tool": "read",
+ "state": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md"
+ },
+ "output": "\n00001| ---\n00002| title: cacheTag\n00003| description: Learn how to use the cacheTag function to manage cache invalidation in your Next.js application.\n00004| related:\n00005| title: Related\n00006| description: View related API references.\n00007| links:\n00008| - app/api-reference/config/next-config-js/cacheComponents\n00009| - app/api-reference/directives/use-cache\n00010| - app/api-reference/functions/revalidateTag\n00011| - app/api-reference/functions/updateTag\n00012| - app/api-reference/functions/cacheLife\n00013| ---\n00014| \n00015| The `cacheTag` function allows you to tag cached data for on-demand invalidation. By associating tags with cache entries, you can selectively purge or revalidate specific cache entries without affecting other cached data.\n00016| \n00017| ## Usage\n00018| \n00019| To use `cacheTag`, enable the [`cacheComponents` flag](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.js` file:\n00020| \n00021| ```ts filename=\"next.config.ts\" switcher\n00022| import type { NextConfig } from 'next'\n00023| \n00024| const nextConfig: NextConfig = {\n00025| cacheComponents: true,\n00026| }\n00027| \n00028| export default nextConfig\n00029| ```\n00030| \n00031| ```js filename=\"next.config.js\" switcher\n00032| const nextConfig = {\n00033| cacheComponents: true,\n00034| }\n00035| \n00036| export default nextConfig\n00037| ```\n00038| \n00039| The `cacheTag` function takes one or more string values.\n00040| \n00041| ```tsx filename=\"app/data.ts\" switcher\n00042| import { cacheTag } from 'next/cache'\n00043| \n00044| export async function getData() {\n00045| 'use cache'\n00046| cacheTag('my-data')\n00047| const data = await fetch('/api/data')\n00048| return data\n00049| }\n00050| ```\n00051| \n00052| ```jsx filename=\"app/data.js\" switcher\n00053| import { cacheTag } from 'next/cache'\n00054| \n00055| export async function getData() {\n00056| 'use cache'\n00057| cacheTag('my-data')\n00058| const data = await fetch('/api/data')\n00059| return data\n00060| }\n00061| ```\n00062| \n00063| You can then purge the cache on-demand from a [Server Function](/docs/app/getting-started/mutating-data) or [Route Handler](/docs/app/api-reference/file-conventions/route):\n00064| \n00065| - Use [`updateTag`](/docs/app/api-reference/functions/updateTag) for read-your-own-writes scenarios, such as forms and other user-triggered mutations, where a user makes a change and the next read should fetch fresh data immediately. `updateTag` is only available inside Server Functions.\n00066| - Use [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) when it is acceptable to serve stale data while revalidation happens in the background, or when revalidating from a [Route Handler](/docs/app/api-reference/file-conventions/route) or other context.\n00067| \n00068| For example, this Server Function adds a post and then purges every cache entry tagged `'my-data'` so the next read reflects the change:\n00069| \n00070| ```tsx filename=\"app/action.ts\" switcher\n00071| 'use server'\n00072| \n00073| import { updateTag } from 'next/cache'\n00074| \n00075| export default async function submit() {\n00076| await addPost()\n00077| updateTag('my-data')\n00078| }\n00079| ```\n00080| \n00081| ```jsx filename=\"app/action.js\" switcher\n00082| 'use server'\n00083| \n00084| import { updateTag } from 'next/cache'\n00085| \n00086| export default async function submit() {\n00087| await addPost()\n00088| updateTag('my-data')\n00089| }\n00090| ```\n00091| \n00092| ## Good to know\n00093| \n00094| - **Idempotent Tags**: Applying the same tag multiple times has no additional effect.\n00095| - **Multiple Tags**: You can assign multiple tags to a single cache entry by passing multiple string values to `cacheTag`.\n00096| \n00097| ```tsx\n00098| cacheTag('tag-one', 'tag-two')\n00099| ```\n00100| \n00101| - **Limits**: A single `cacheTag()` call accepts up to 128 tags, each with a maximum length of 256 characters. Tags longer than 256 characters are skipped, and any tags past the 128th in one call are dropped. Both cases log a console warning.\n00102| \n00103| ## Examples\n00104| \n00105| ### Tagging components or functions\n00106| \n00107| Tag your cached data by calling `cacheTag` within a cached function or component:\n00108| \n00109| ```tsx filename=\"app/components/bookings.tsx\" switcher\n00110| import { cacheTag } from 'next/cache'\n00111| \n00112| interface BookingsProps {\n00113| type: string\n00114| }\n00115| \n00116| export async function Bookings({ type = 'haircut' }: BookingsProps) {\n00117| 'use cache'\n00118| cacheTag('bookings-data')\n00119| \n00120| async function getBookingsData() {\n00121| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00122| return data\n00123| }\n00124| \n00125| return //...\n00126| }\n00127| ```\n00128| \n00129| ```jsx filename=\"app/components/bookings.js\" switcher\n00130| import { cacheTag } from 'next/cache'\n00131| \n00132| export async function Bookings({ type = 'haircut' }) {\n00133| 'use cache'\n00134| cacheTag('bookings-data')\n00135| \n00136| async function getBookingsData() {\n00137| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00138| return data\n00139| }\n00140| \n00141| return //...\n00142| }\n00143| ```\n00144| \n00145| ### Creating tags from external data\n00146| \n00147| You can use the data returned from an async function to tag the cache entry.\n00148| \n00149| ```tsx filename=\"app/components/bookings.tsx\" switcher\n00150| import { cacheTag } from 'next/cache'\n00151| \n00152| interface BookingsProps {\n00153| type: string\n00154| }\n00155| \n00156| export async function Bookings({ type = 'haircut' }: BookingsProps) {\n00157| async function getBookingsData() {\n00158| 'use cache'\n00159| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00160| cacheTag('bookings-data', data.id)\n00161| return data\n00162| }\n00163| return //...\n00164| }\n00165| ```\n00166| \n00167| ```jsx filename=\"app/components/bookings.js\" switcher\n00168| import { cacheTag } from 'next/cache'\n00169| \n00170| export async function Bookings({ type = 'haircut' }) {\n00171| async function getBookingsData() {\n00172| 'use cache'\n00173| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00174| cacheTag('bookings-data', data.id)\n00175| return data\n00176| }\n00177| return //...\n00178| }\n00179| ```\n00180| \n00181| ### Invalidating tagged cache\n00182| \n00183| Using [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag), you can invalidate the cache for a specific tag when needed:\n00184| \n00185| ```tsx filename=\"app/actions.ts\" switcher\n00186| 'use server'\n00187| \n00188| import { revalidateTag } from 'next/cache'\n00189| \n00190| export async function updateBookings() {\n00191| await updateBookingData()\n00192| revalidateTag('bookings-data', 'max')\n00193| }\n00194| ```\n00195| \n00196| ```jsx filename=\"app/actions.js\" switcher\n00197| 'use server'\n00198| \n00199| import { revalidateTag } from 'next/cache'\n00200| \n00201| export async function updateBookings() {\n00202| await updateBookingData()\n00203| revalidateTag('bookings-data', 'max')\n00204| }\n00205| ```\n00206| \n\n(End of file - total 206 lines)\n",
+ "title": "node_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md",
+ "metadata": {
+ "preview": "---\ntitle: cacheTag\ndescription: Learn how to use the cacheTag function to manage cache invalidation in your Next.js application.\nrelated:\n title: Related\n description: View related API references.\n links:\n - app/api-reference/config/next-config-js/cacheComponents\n - app/api-reference/directives/use-cache\n - app/api-reference/functions/revalidateTag\n - app/api-reference/functions/updateTag\n - app/api-reference/functions/cacheLife\n---\n\nThe `cacheTag` function allows you to tag cached data for on-demand invalidation. By associating tags with cache entries, you can selectively purge or revalidate specific cache entries without affecting other cached data.\n\n## Usage\n\nTo use `cacheTag`, enable the [`cacheComponents` flag](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.js` file:\n"
+ },
+ "time": {
+ "start": 1781392537472,
+ "end": 1781392537476
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:37.480Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| ---\n00002| title: cacheTag\n00003| description: Learn how to use the cacheTag function to manage cache invalidation in your Next.js application.\n00004| related:\n00005| title: Related\n00006| description: View related API references.\n00007| links:\n00008| - app/api-reference/config/next-config-js/cacheComponents\n00009| - app/api-reference/directives/use-cache\n00010| - app/api-reference/functions/revalidateTag\n00011| - app/api-reference/functions/updateTag\n00012| - app/api-reference/functions/cacheLife\n00013| ---\n00014| \n00015| The `cacheTag` function allows you to tag cached data for on-demand invalidation. By associating tags with cache entries, you can selectively purge or revalidate specific cache entries without affecting other cached data.\n00016| \n00017| ## Usage\n00018| \n00019| To use `cacheTag`, enable the [`cacheComponents` flag](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.js` file:\n00020| \n00021| ```ts filename=\"next.config.ts\" switcher\n00022| import type { NextConfig } from 'next'\n00023| \n00024| const nextConfig: NextConfig = {\n00025| cacheComponents: true,\n00026| }\n00027| \n00028| export default nextConfig\n00029| ```\n00030| \n00031| ```js filename=\"next.config.js\" switcher\n00032| const nextConfig = {\n00033| cacheComponents: true,\n00034| }\n00035| \n00036| export default nextConfig\n00037| ```\n00038| \n00039| The `cacheTag` function takes one or more string values.\n00040| \n00041| ```tsx filename=\"app/data.ts\" switcher\n00042| import { cacheTag } from 'next/cache'\n00043| \n00044| export async function getData() {\n00045| 'use cache'\n00046| cacheTag('my-data')\n00047| const data = await fetch('/api/data')\n00048| return data\n00049| }\n00050| ```\n00051| \n00052| ```jsx filename=\"app/data.js\" switcher\n00053| import { cacheTag } from 'next/cache'\n00054| \n00055| export async function getData() {\n00056| 'use cache'\n00057| cacheTag('my-data')\n00058| const data = await fetch('/api/data')\n00059| return data\n00060| }\n00061| ```\n00062| \n00063| You can then purge the cache on-demand from a [Server Function](/docs/app/getting-started/mutating-data) or [Route Handler](/docs/app/api-reference/file-conventions/route):\n00064| \n00065| - Use [`updateTag`](/docs/app/api-reference/functions/updateTag) for read-your-own-writes scenarios, such as forms and other user-triggered mutations, where a user makes a change and the next read should fetch fresh data immediately. `updateTag` is only available inside Server Functions.\n00066| - Use [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) when it is acceptable to serve stale data while revalidation happens in the background, or when revalidating from a [Route Handler](/docs/app/api-reference/file-conventions/route) or other context.\n00067| \n00068| For example, this Server Function adds a post and then purges every cache entry tagged `'my-data'` so the next read reflects the change:\n00069| \n00070| ```tsx filename=\"app/action.ts\" switcher\n00071| 'use server'\n00072| \n00073| import { updateTag } from 'next/cache'\n00074| \n00075| export default async function submit() {\n00076| await addPost()\n00077| updateTag('my-data')\n00078| }\n00079| ```\n00080| \n00081| ```jsx filename=\"app/action.js\" switcher\n00082| 'use server'\n00083| \n00084| import { updateTag } from 'next/cache'\n00085| \n00086| export default async function submit() {\n00087| await addPost()\n00088| updateTag('my-data')\n00089| }\n00090| ```\n00091| \n00092| ## Good to know\n00093| \n00094| - **Idempotent Tags**: Applying the same tag multiple times has no additional effect.\n00095| - **Multiple Tags**: You can assign multiple tags to a single cache entry by passing multiple string values to `cacheTag`.\n00096| \n00097| ```tsx\n00098| cacheTag('tag-one', 'tag-two')\n00099| ```\n00100| \n00101| - **Limits**: A single `cacheTag()` call accepts up to 128 tags, each with a maximum length of 256 characters. Tags longer than 256 characters are skipped, and any tags past the 128th in one call are dropped. Both cases log a console warning.\n00102| \n00103| ## Examples\n00104| \n00105| ### Tagging components or functions\n00106| \n00107| Tag your cached data by calling `cacheTag` within a cached function or component:\n00108| \n00109| ```tsx filename=\"app/components/bookings.tsx\" switcher\n00110| import { cacheTag } from 'next/cache'\n00111| \n00112| interface BookingsProps {\n00113| type: string\n00114| }\n00115| \n00116| export async function Bookings({ type = 'haircut' }: BookingsProps) {\n00117| 'use cache'\n00118| cacheTag('bookings-data')\n00119| \n00120| async function getBookingsData() {\n00121| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00122| return data\n00123| }\n00124| \n00125| return //...\n00126| }\n00127| ```\n00128| \n00129| ```jsx filename=\"app/components/bookings.js\" switcher\n00130| import { cacheTag } from 'next/cache'\n00131| \n00132| export async function Bookings({ type = 'haircut' }) {\n00133| 'use cache'\n00134| cacheTag('bookings-data')\n00135| \n00136| async function getBookingsData() {\n00137| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00138| return data\n00139| }\n00140| \n00141| return //...\n00142| }\n00143| ```\n00144| \n00145| ### Creating tags from external data\n00146| \n00147| You can use the data returned from an async function to tag the cache entry.\n00148| \n00149| ```tsx filename=\"app/components/bookings.tsx\" switcher\n00150| import { cacheTag } from 'next/cache'\n00151| \n00152| interface BookingsProps {\n00153| type: string\n00154| }\n00155| \n00156| export async function Bookings({ type = 'haircut' }: BookingsProps) {\n00157| async function getBookingsData() {\n00158| 'use cache'\n00159| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00160| cacheTag('bookings-data', data.id)\n00161| return data\n00162| }\n00163| return //...\n00164| }\n00165| ```\n00166| \n00167| ```jsx filename=\"app/components/bookings.js\" switcher\n00168| import { cacheTag } from 'next/cache'\n00169| \n00170| export async function Bookings({ type = 'haircut' }) {\n00171| async function getBookingsData() {\n00172| 'use cache'\n00173| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00174| cacheTag('bookings-data', data.id)\n00175| return data\n00176| }\n00177| return //...\n00178| }\n00179| ```\n00180| \n00181| ### Invalidating tagged cache\n00182| \n00183| Using [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag), you can invalidate the cache for a specific tag when needed:\n00184| \n00185| ```tsx filename=\"app/actions.ts\" switcher\n00186| 'use server'\n00187| \n00188| import { revalidateTag } from 'next/cache'\n00189| \n00190| export async function updateBookings() {\n00191| await updateBookingData()\n00192| revalidateTag('bookings-data', 'max')\n00193| }\n00194| ```\n00195| \n00196| ```jsx filename=\"app/actions.js\" switcher\n00197| 'use server'\n00198| \n00199| import { revalidateTag } from 'next/cache'\n00200| \n00201| export async function updateBookings() {\n00202| await updateBookingData()\n00203| revalidateTag('bookings-data', 'max')\n00204| }\n00205| ```\n00206| \n\n(End of file - total 206 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md"
+ },
+ "output": "\n00001| ---\n00002| title: cacheTag\n00003| description: Learn how to use the cacheTag function to manage cache invalidation in your Next.js application.\n00004| related:\n00005| title: Related\n00006| description: View related API references.\n00007| links:\n00008| - app/api-reference/config/next-config-js/cacheComponents\n00009| - app/api-reference/directives/use-cache\n00010| - app/api-reference/functions/revalidateTag\n00011| - app/api-reference/functions/updateTag\n00012| - app/api-reference/functions/cacheLife\n00013| ---\n00014| \n00015| The `cacheTag` function allows you to tag cached data for on-demand invalidation. By associating tags with cache entries, you can selectively purge or revalidate specific cache entries without affecting other cached data.\n00016| \n00017| ## Usage\n00018| \n00019| To use `cacheTag`, enable the [`cacheComponents` flag](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.js` file:\n00020| \n00021| ```ts filename=\"next.config.ts\" switcher\n00022| import type { NextConfig } from 'next'\n00023| \n00024| const nextConfig: NextConfig = {\n00025| cacheComponents: true,\n00026| }\n00027| \n00028| export default nextConfig\n00029| ```\n00030| \n00031| ```js filename=\"next.config.js\" switcher\n00032| const nextConfig = {\n00033| cacheComponents: true,\n00034| }\n00035| \n00036| export default nextConfig\n00037| ```\n00038| \n00039| The `cacheTag` function takes one or more string values.\n00040| \n00041| ```tsx filename=\"app/data.ts\" switcher\n00042| import { cacheTag } from 'next/cache'\n00043| \n00044| export async function getData() {\n00045| 'use cache'\n00046| cacheTag('my-data')\n00047| const data = await fetch('/api/data')\n00048| return data\n00049| }\n00050| ```\n00051| \n00052| ```jsx filename=\"app/data.js\" switcher\n00053| import { cacheTag } from 'next/cache'\n00054| \n00055| export async function getData() {\n00056| 'use cache'\n00057| cacheTag('my-data')\n00058| const data = await fetch('/api/data')\n00059| return data\n00060| }\n00061| ```\n00062| \n00063| You can then purge the cache on-demand from a [Server Function](/docs/app/getting-started/mutating-data) or [Route Handler](/docs/app/api-reference/file-conventions/route):\n00064| \n00065| - Use [`updateTag`](/docs/app/api-reference/functions/updateTag) for read-your-own-writes scenarios, such as forms and other user-triggered mutations, where a user makes a change and the next read should fetch fresh data immediately. `updateTag` is only available inside Server Functions.\n00066| - Use [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) when it is acceptable to serve stale data while revalidation happens in the background, or when revalidating from a [Route Handler](/docs/app/api-reference/file-conventions/route) or other context.\n00067| \n00068| For example, this Server Function adds a post and then purges every cache entry tagged `'my-data'` so the next read reflects the change:\n00069| \n00070| ```tsx filename=\"app/action.ts\" switcher\n00071| 'use server'\n00072| \n00073| import { updateTag } from 'next/cache'\n00074| \n00075| export default async function submit() {\n00076| await addPost()\n00077| updateTag('my-data')\n00078| }\n00079| ```\n00080| \n00081| ```jsx filename=\"app/action.js\" switcher\n00082| 'use server'\n00083| \n00084| import { updateTag } from 'next/cache'\n00085| \n00086| export default async function submit() {\n00087| await addPost()\n00088| updateTag('my-data')\n00089| }\n00090| ```\n00091| \n00092| ## Good to know\n00093| \n00094| - **Idempotent Tags**: Applying the same tag multiple times has no additional effect.\n00095| - **Multiple Tags**: You can assign multiple tags to a single cache entry by passing multiple string values to `cacheTag`.\n00096| \n00097| ```tsx\n00098| cacheTag('tag-one', 'tag-two')\n00099| ```\n00100| \n00101| - **Limits**: A single `cacheTag()` call accepts up to 128 tags, each with a maximum length of 256 characters. Tags longer than 256 characters are skipped, and any tags past the 128th in one call are dropped. Both cases log a console warning.\n00102| \n00103| ## Examples\n00104| \n00105| ### Tagging components or functions\n00106| \n00107| Tag your cached data by calling `cacheTag` within a cached function or component:\n00108| \n00109| ```tsx filename=\"app/components/bookings.tsx\" switcher\n00110| import { cacheTag } from 'next/cache'\n00111| \n00112| interface BookingsProps {\n00113| type: string\n00114| }\n00115| \n00116| export async function Bookings({ type = 'haircut' }: BookingsProps) {\n00117| 'use cache'\n00118| cacheTag('bookings-data')\n00119| \n00120| async function getBookingsData() {\n00121| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00122| return data\n00123| }\n00124| \n00125| return //...\n00126| }\n00127| ```\n00128| \n00129| ```jsx filename=\"app/components/bookings.js\" switcher\n00130| import { cacheTag } from 'next/cache'\n00131| \n00132| export async function Bookings({ type = 'haircut' }) {\n00133| 'use cache'\n00134| cacheTag('bookings-data')\n00135| \n00136| async function getBookingsData() {\n00137| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00138| return data\n00139| }\n00140| \n00141| return //...\n00142| }\n00143| ```\n00144| \n00145| ### Creating tags from external data\n00146| \n00147| You can use the data returned from an async function to tag the cache entry.\n00148| \n00149| ```tsx filename=\"app/components/bookings.tsx\" switcher\n00150| import { cacheTag } from 'next/cache'\n00151| \n00152| interface BookingsProps {\n00153| type: string\n00154| }\n00155| \n00156| export async function Bookings({ type = 'haircut' }: BookingsProps) {\n00157| async function getBookingsData() {\n00158| 'use cache'\n00159| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00160| cacheTag('bookings-data', data.id)\n00161| return data\n00162| }\n00163| return //...\n00164| }\n00165| ```\n00166| \n00167| ```jsx filename=\"app/components/bookings.js\" switcher\n00168| import { cacheTag } from 'next/cache'\n00169| \n00170| export async function Bookings({ type = 'haircut' }) {\n00171| async function getBookingsData() {\n00172| 'use cache'\n00173| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00174| cacheTag('bookings-data', data.id)\n00175| return data\n00176| }\n00177| return //...\n00178| }\n00179| ```\n00180| \n00181| ### Invalidating tagged cache\n00182| \n00183| Using [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag), you can invalidate the cache for a specific tag when needed:\n00184| \n00185| ```tsx filename=\"app/actions.ts\" switcher\n00186| 'use server'\n00187| \n00188| import { revalidateTag } from 'next/cache'\n00189| \n00190| export async function updateBookings() {\n00191| await updateBookingData()\n00192| revalidateTag('bookings-data', 'max')\n00193| }\n00194| ```\n00195| \n00196| ```jsx filename=\"app/actions.js\" switcher\n00197| 'use server'\n00198| \n00199| import { revalidateTag } from 'next/cache'\n00200| \n00201| export async function updateBookings() {\n00202| await updateBookingData()\n00203| revalidateTag('bookings-data', 'max')\n00204| }\n00205| ```\n00206| \n\n(End of file - total 206 lines)\n",
+ "title": "node_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheTag.md",
+ "metadata": {
+ "preview": "---\ntitle: cacheTag\ndescription: Learn how to use the cacheTag function to manage cache invalidation in your Next.js application.\nrelated:\n title: Related\n description: View related API references.\n links:\n - app/api-reference/config/next-config-js/cacheComponents\n - app/api-reference/directives/use-cache\n - app/api-reference/functions/revalidateTag\n - app/api-reference/functions/updateTag\n - app/api-reference/functions/cacheLife\n---\n\nThe `cacheTag` function allows you to tag cached data for on-demand invalidation. By associating tags with cache entries, you can selectively purge or revalidate specific cache entries without affecting other cached data.\n\n## Usage\n\nTo use `cacheTag`, enable the [`cacheComponents` flag](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.js` file:\n"
+ },
+ "time": {
+ "start": 1781392537472,
+ "end": 1781392537476
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:38.345Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "args": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md",
+ "_extractedPath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392538345,
+ "sessionID": "ses_13cbb6ca7ffeDluJj6gL6KvvXT",
+ "part": {
+ "id": "prt_ec344f782001j9x2IeFN2BviqH",
+ "sessionID": "ses_13cbb6ca7ffeDluJj6gL6KvvXT",
+ "messageID": "msg_ec344eb5d001IcU2v22Hnj8HEM",
+ "type": "tool",
+ "callID": "read_12",
+ "tool": "read",
+ "state": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md"
+ },
+ "output": "\n00001| ---\n00002| title: revalidateTag\n00003| description: API Reference for the revalidateTag function.\n00004| ---\n00005| \n00006| `revalidateTag` allows you to invalidate cached data on-demand for a specific cache tag.\n00007| \n00008| This function is ideal for content where a slight delay in updates is acceptable, such as blog posts, product catalogs, or documentation. Users receive stale content while fresh data loads in the background.\n00009| \n00010| ## Usage\n00011| \n00012| `revalidateTag` can be called in Server Functions and Route Handlers.\n00013| \n00014| `revalidateTag` cannot be called in Client Components or Proxy, as it only works in server environments.\n00015| \n00016| ### Revalidation Behavior\n00017| \n00018| The revalidation behavior depends on whether you provide the second argument:\n00019| \n00020| - **With `profile=\"max\"` (recommended)**: The tag entry is marked as stale, and the next time a resource with that tag is visited, it will use stale-while-revalidate semantics. This means the stale content is served while fresh content is fetched in the background.\n00021| - **With a custom cache life profile**: For advanced usage, you can specify any cache life profile that your application has defined, allowing for custom revalidation behaviors tailored to your specific caching requirements.\n00022| - **Without the second argument (deprecated)**: The tag entry is expired immediately, and the next request to that resource will be a blocking revalidate/cache miss. This behavior is now deprecated, and you should either use `profile=\"max\"` or migrate to [`updateTag`](/docs/app/api-reference/functions/updateTag).\n00023| \n00024| > **Good to know**: When using `profile=\"max\"`, `revalidateTag` marks tagged data as stale, but fresh data is only fetched when pages using that tag are next visited. This means calling `revalidateTag` will not immediately trigger many revalidations at once. The invalidation only happens when any page using that tag is next visited.\n00025| \n00026| ## Parameters\n00027| \n00028| ```ts\n00029| revalidateTag(tag: string, profile: string | { expire?: number }): void;\n00030| ```\n00031| \n00032| - `tag`: A string representing the cache tag associated with the data you want to revalidate. Must not exceed 256 characters. This value is case-sensitive.\n00033| - `profile`: A string that specifies the revalidation behavior. The recommended value is `\"max\"` which provides stale-while-revalidate semantics, or any of the other default or custom profiles defined in [`cacheLife`](/docs/app/api-reference/config/next-config-js/cacheLife). Alternatively, you can pass an object with an `expire` property for custom expiration behavior.\n00034| \n00035| Tags must first be assigned to cached data. You can do this in two ways:\n00036| \n00037| - Using the [`next.tags`](/docs/app/api-reference/functions/fetch) option with `fetch` for caching external API requests:\n00038| \n00039| ```tsx\n00040| fetch(url, { next: { tags: ['posts'] } })\n00041| ```\n00042| \n00043| - Using [`cacheTag`](/docs/app/api-reference/functions/cacheTag) inside cached functions or components with the `'use cache'` directive:\n00044| \n00045| ```tsx\n00046| import { cacheTag } from 'next/cache'\n00047| \n00048| async function getData() {\n00049| 'use cache'\n00050| cacheTag('posts')\n00051| // ...\n00052| }\n00053| ```\n00054| \n00055| > **Good to know**: The single-argument form `revalidateTag(tag)` is deprecated. It currently works if TypeScript errors are suppressed, but this behavior may be removed in a future version. Update to the two-argument signature.\n00056| \n00057| ## Returns\n00058| \n00059| `revalidateTag` does not return a value.\n00060| \n00061| ## Relationship with `revalidatePath`\n00062| \n00063| `revalidateTag` invalidates data with specific tags across all pages that use those tags, while [`revalidatePath`](/docs/app/api-reference/functions/revalidatePath) invalidates specific page or layout paths.\n00064| \n00065| > **Good to know**: These functions serve different purposes and may need to be used together for comprehensive data consistency. For detailed examples and considerations, see [relationship with revalidateTag and updateTag](/docs/app/api-reference/functions/revalidatePath#relationship-with-revalidatetag-and-updatetag) for more information.\n00066| \n00067| ## Examples\n00068| \n00069| The following examples demonstrate how to use `revalidateTag` in different contexts. In both cases, we're using `profile=\"max\"` to mark data as stale and use stale-while-revalidate semantics, which is the recommended approach for most use cases.\n00070| \n00071| ### Server Action\n00072| \n00073| ```ts filename=\"app/actions.ts\" switcher\n00074| 'use server'\n00075| \n00076| import { revalidateTag } from 'next/cache'\n00077| \n00078| export default async function submit() {\n00079| await addPost()\n00080| revalidateTag('posts', 'max')\n00081| }\n00082| ```\n00083| \n00084| ```js filename=\"app/actions.js\" switcher\n00085| 'use server'\n00086| \n00087| import { revalidateTag } from 'next/cache'\n00088| \n00089| export default async function submit() {\n00090| await addPost()\n00091| revalidateTag('posts', 'max')\n00092| }\n00093| ```\n00094| \n00095| ### Route Handler\n00096| \n00097| ```ts filename=\"app/api/revalidate/route.ts\" switcher\n00098| import type { NextRequest } from 'next/server'\n00099| import { revalidateTag } from 'next/cache'\n00100| \n00101| export async function GET(request: NextRequest) {\n00102| const tag = request.nextUrl.searchParams.get('tag')\n00103| \n00104| if (tag) {\n00105| revalidateTag(tag, 'max')\n00106| return Response.json({ revalidated: true, now: Date.now() })\n00107| }\n00108| \n00109| return Response.json({\n00110| revalidated: false,\n00111| now: Date.now(),\n00112| message: 'Missing tag to revalidate',\n00113| })\n00114| }\n00115| ```\n00116| \n00117| ```js filename=\"app/api/revalidate/route.js\" switcher\n00118| import { revalidateTag } from 'next/cache'\n00119| \n00120| export async function GET(request) {\n00121| const tag = request.nextUrl.searchParams.get('tag')\n00122| \n00123| if (tag) {\n00124| revalidateTag(tag, 'max')\n00125| return Response.json({ revalidated: true, now: Date.now() })\n00126| }\n00127| \n00128| return Response.json({\n00129| revalidated: false,\n00130| now: Date.now(),\n00131| message: 'Missing tag to revalidate',\n00132| })\n00133| }\n00134| ```\n00135| \n00136| > **Good to know**: For webhooks or third-party services that need immediate expiration, you can pass `{ expire: 0 }` as the second argument: `revalidateTag(tag, { expire: 0 })`. This pattern is necessary when external systems call your Route Handlers and require data to expire immediately. For all other cases, it's recommended to use [`updateTag`](/docs/app/api-reference/functions/updateTag) in Server Actions for immediate updates instead.\n00137| \n\n(End of file - total 137 lines)\n",
+ "title": "node_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md",
+ "metadata": {
+ "preview": "---\ntitle: revalidateTag\ndescription: API Reference for the revalidateTag function.\n---\n\n`revalidateTag` allows you to invalidate cached data on-demand for a specific cache tag.\n\nThis function is ideal for content where a slight delay in updates is acceptable, such as blog posts, product catalogs, or documentation. Users receive stale content while fresh data loads in the background.\n\n## Usage\n\n`revalidateTag` can be called in Server Functions and Route Handlers.\n\n`revalidateTag` cannot be called in Client Components or Proxy, as it only works in server environments.\n\n### Revalidation Behavior\n\nThe revalidation behavior depends on whether you provide the second argument:\n\n- **With `profile=\"max\"` (recommended)**: The tag entry is marked as stale, and the next time a resource with that tag is visited, it will use stale-while-revalidate semantics. This means the stale content is served while fresh content is fetched in the background."
+ },
+ "time": {
+ "start": 1781392538335,
+ "end": 1781392538341
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:38.345Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| ---\n00002| title: revalidateTag\n00003| description: API Reference for the revalidateTag function.\n00004| ---\n00005| \n00006| `revalidateTag` allows you to invalidate cached data on-demand for a specific cache tag.\n00007| \n00008| This function is ideal for content where a slight delay in updates is acceptable, such as blog posts, product catalogs, or documentation. Users receive stale content while fresh data loads in the background.\n00009| \n00010| ## Usage\n00011| \n00012| `revalidateTag` can be called in Server Functions and Route Handlers.\n00013| \n00014| `revalidateTag` cannot be called in Client Components or Proxy, as it only works in server environments.\n00015| \n00016| ### Revalidation Behavior\n00017| \n00018| The revalidation behavior depends on whether you provide the second argument:\n00019| \n00020| - **With `profile=\"max\"` (recommended)**: The tag entry is marked as stale, and the next time a resource with that tag is visited, it will use stale-while-revalidate semantics. This means the stale content is served while fresh content is fetched in the background.\n00021| - **With a custom cache life profile**: For advanced usage, you can specify any cache life profile that your application has defined, allowing for custom revalidation behaviors tailored to your specific caching requirements.\n00022| - **Without the second argument (deprecated)**: The tag entry is expired immediately, and the next request to that resource will be a blocking revalidate/cache miss. This behavior is now deprecated, and you should either use `profile=\"max\"` or migrate to [`updateTag`](/docs/app/api-reference/functions/updateTag).\n00023| \n00024| > **Good to know**: When using `profile=\"max\"`, `revalidateTag` marks tagged data as stale, but fresh data is only fetched when pages using that tag are next visited. This means calling `revalidateTag` will not immediately trigger many revalidations at once. The invalidation only happens when any page using that tag is next visited.\n00025| \n00026| ## Parameters\n00027| \n00028| ```ts\n00029| revalidateTag(tag: string, profile: string | { expire?: number }): void;\n00030| ```\n00031| \n00032| - `tag`: A string representing the cache tag associated with the data you want to revalidate. Must not exceed 256 characters. This value is case-sensitive.\n00033| - `profile`: A string that specifies the revalidation behavior. The recommended value is `\"max\"` which provides stale-while-revalidate semantics, or any of the other default or custom profiles defined in [`cacheLife`](/docs/app/api-reference/config/next-config-js/cacheLife). Alternatively, you can pass an object with an `expire` property for custom expiration behavior.\n00034| \n00035| Tags must first be assigned to cached data. You can do this in two ways:\n00036| \n00037| - Using the [`next.tags`](/docs/app/api-reference/functions/fetch) option with `fetch` for caching external API requests:\n00038| \n00039| ```tsx\n00040| fetch(url, { next: { tags: ['posts'] } })\n00041| ```\n00042| \n00043| - Using [`cacheTag`](/docs/app/api-reference/functions/cacheTag) inside cached functions or components with the `'use cache'` directive:\n00044| \n00045| ```tsx\n00046| import { cacheTag } from 'next/cache'\n00047| \n00048| async function getData() {\n00049| 'use cache'\n00050| cacheTag('posts')\n00051| // ...\n00052| }\n00053| ```\n00054| \n00055| > **Good to know**: The single-argument form `revalidateTag(tag)` is deprecated. It currently works if TypeScript errors are suppressed, but this behavior may be removed in a future version. Update to the two-argument signature.\n00056| \n00057| ## Returns\n00058| \n00059| `revalidateTag` does not return a value.\n00060| \n00061| ## Relationship with `revalidatePath`\n00062| \n00063| `revalidateTag` invalidates data with specific tags across all pages that use those tags, while [`revalidatePath`](/docs/app/api-reference/functions/revalidatePath) invalidates specific page or layout paths.\n00064| \n00065| > **Good to know**: These functions serve different purposes and may need to be used together for comprehensive data consistency. For detailed examples and considerations, see [relationship with revalidateTag and updateTag](/docs/app/api-reference/functions/revalidatePath#relationship-with-revalidatetag-and-updatetag) for more information.\n00066| \n00067| ## Examples\n00068| \n00069| The following examples demonstrate how to use `revalidateTag` in different contexts. In both cases, we're using `profile=\"max\"` to mark data as stale and use stale-while-revalidate semantics, which is the recommended approach for most use cases.\n00070| \n00071| ### Server Action\n00072| \n00073| ```ts filename=\"app/actions.ts\" switcher\n00074| 'use server'\n00075| \n00076| import { revalidateTag } from 'next/cache'\n00077| \n00078| export default async function submit() {\n00079| await addPost()\n00080| revalidateTag('posts', 'max')\n00081| }\n00082| ```\n00083| \n00084| ```js filename=\"app/actions.js\" switcher\n00085| 'use server'\n00086| \n00087| import { revalidateTag } from 'next/cache'\n00088| \n00089| export default async function submit() {\n00090| await addPost()\n00091| revalidateTag('posts', 'max')\n00092| }\n00093| ```\n00094| \n00095| ### Route Handler\n00096| \n00097| ```ts filename=\"app/api/revalidate/route.ts\" switcher\n00098| import type { NextRequest } from 'next/server'\n00099| import { revalidateTag } from 'next/cache'\n00100| \n00101| export async function GET(request: NextRequest) {\n00102| const tag = request.nextUrl.searchParams.get('tag')\n00103| \n00104| if (tag) {\n00105| revalidateTag(tag, 'max')\n00106| return Response.json({ revalidated: true, now: Date.now() })\n00107| }\n00108| \n00109| return Response.json({\n00110| revalidated: false,\n00111| now: Date.now(),\n00112| message: 'Missing tag to revalidate',\n00113| })\n00114| }\n00115| ```\n00116| \n00117| ```js filename=\"app/api/revalidate/route.js\" switcher\n00118| import { revalidateTag } from 'next/cache'\n00119| \n00120| export async function GET(request) {\n00121| const tag = request.nextUrl.searchParams.get('tag')\n00122| \n00123| if (tag) {\n00124| revalidateTag(tag, 'max')\n00125| return Response.json({ revalidated: true, now: Date.now() })\n00126| }\n00127| \n00128| return Response.json({\n00129| revalidated: false,\n00130| now: Date.now(),\n00131| message: 'Missing tag to revalidate',\n00132| })\n00133| }\n00134| ```\n00135| \n00136| > **Good to know**: For webhooks or third-party services that need immediate expiration, you can pass `{ expire: 0 }` as the second argument: `revalidateTag(tag, { expire: 0 })`. This pattern is necessary when external systems call your Route Handlers and require data to expire immediately. For all other cases, it's recommended to use [`updateTag`](/docs/app/api-reference/functions/updateTag) in Server Actions for immediate updates instead.\n00137| \n\n(End of file - total 137 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md"
+ },
+ "output": "\n00001| ---\n00002| title: revalidateTag\n00003| description: API Reference for the revalidateTag function.\n00004| ---\n00005| \n00006| `revalidateTag` allows you to invalidate cached data on-demand for a specific cache tag.\n00007| \n00008| This function is ideal for content where a slight delay in updates is acceptable, such as blog posts, product catalogs, or documentation. Users receive stale content while fresh data loads in the background.\n00009| \n00010| ## Usage\n00011| \n00012| `revalidateTag` can be called in Server Functions and Route Handlers.\n00013| \n00014| `revalidateTag` cannot be called in Client Components or Proxy, as it only works in server environments.\n00015| \n00016| ### Revalidation Behavior\n00017| \n00018| The revalidation behavior depends on whether you provide the second argument:\n00019| \n00020| - **With `profile=\"max\"` (recommended)**: The tag entry is marked as stale, and the next time a resource with that tag is visited, it will use stale-while-revalidate semantics. This means the stale content is served while fresh content is fetched in the background.\n00021| - **With a custom cache life profile**: For advanced usage, you can specify any cache life profile that your application has defined, allowing for custom revalidation behaviors tailored to your specific caching requirements.\n00022| - **Without the second argument (deprecated)**: The tag entry is expired immediately, and the next request to that resource will be a blocking revalidate/cache miss. This behavior is now deprecated, and you should either use `profile=\"max\"` or migrate to [`updateTag`](/docs/app/api-reference/functions/updateTag).\n00023| \n00024| > **Good to know**: When using `profile=\"max\"`, `revalidateTag` marks tagged data as stale, but fresh data is only fetched when pages using that tag are next visited. This means calling `revalidateTag` will not immediately trigger many revalidations at once. The invalidation only happens when any page using that tag is next visited.\n00025| \n00026| ## Parameters\n00027| \n00028| ```ts\n00029| revalidateTag(tag: string, profile: string | { expire?: number }): void;\n00030| ```\n00031| \n00032| - `tag`: A string representing the cache tag associated with the data you want to revalidate. Must not exceed 256 characters. This value is case-sensitive.\n00033| - `profile`: A string that specifies the revalidation behavior. The recommended value is `\"max\"` which provides stale-while-revalidate semantics, or any of the other default or custom profiles defined in [`cacheLife`](/docs/app/api-reference/config/next-config-js/cacheLife). Alternatively, you can pass an object with an `expire` property for custom expiration behavior.\n00034| \n00035| Tags must first be assigned to cached data. You can do this in two ways:\n00036| \n00037| - Using the [`next.tags`](/docs/app/api-reference/functions/fetch) option with `fetch` for caching external API requests:\n00038| \n00039| ```tsx\n00040| fetch(url, { next: { tags: ['posts'] } })\n00041| ```\n00042| \n00043| - Using [`cacheTag`](/docs/app/api-reference/functions/cacheTag) inside cached functions or components with the `'use cache'` directive:\n00044| \n00045| ```tsx\n00046| import { cacheTag } from 'next/cache'\n00047| \n00048| async function getData() {\n00049| 'use cache'\n00050| cacheTag('posts')\n00051| // ...\n00052| }\n00053| ```\n00054| \n00055| > **Good to know**: The single-argument form `revalidateTag(tag)` is deprecated. It currently works if TypeScript errors are suppressed, but this behavior may be removed in a future version. Update to the two-argument signature.\n00056| \n00057| ## Returns\n00058| \n00059| `revalidateTag` does not return a value.\n00060| \n00061| ## Relationship with `revalidatePath`\n00062| \n00063| `revalidateTag` invalidates data with specific tags across all pages that use those tags, while [`revalidatePath`](/docs/app/api-reference/functions/revalidatePath) invalidates specific page or layout paths.\n00064| \n00065| > **Good to know**: These functions serve different purposes and may need to be used together for comprehensive data consistency. For detailed examples and considerations, see [relationship with revalidateTag and updateTag](/docs/app/api-reference/functions/revalidatePath#relationship-with-revalidatetag-and-updatetag) for more information.\n00066| \n00067| ## Examples\n00068| \n00069| The following examples demonstrate how to use `revalidateTag` in different contexts. In both cases, we're using `profile=\"max\"` to mark data as stale and use stale-while-revalidate semantics, which is the recommended approach for most use cases.\n00070| \n00071| ### Server Action\n00072| \n00073| ```ts filename=\"app/actions.ts\" switcher\n00074| 'use server'\n00075| \n00076| import { revalidateTag } from 'next/cache'\n00077| \n00078| export default async function submit() {\n00079| await addPost()\n00080| revalidateTag('posts', 'max')\n00081| }\n00082| ```\n00083| \n00084| ```js filename=\"app/actions.js\" switcher\n00085| 'use server'\n00086| \n00087| import { revalidateTag } from 'next/cache'\n00088| \n00089| export default async function submit() {\n00090| await addPost()\n00091| revalidateTag('posts', 'max')\n00092| }\n00093| ```\n00094| \n00095| ### Route Handler\n00096| \n00097| ```ts filename=\"app/api/revalidate/route.ts\" switcher\n00098| import type { NextRequest } from 'next/server'\n00099| import { revalidateTag } from 'next/cache'\n00100| \n00101| export async function GET(request: NextRequest) {\n00102| const tag = request.nextUrl.searchParams.get('tag')\n00103| \n00104| if (tag) {\n00105| revalidateTag(tag, 'max')\n00106| return Response.json({ revalidated: true, now: Date.now() })\n00107| }\n00108| \n00109| return Response.json({\n00110| revalidated: false,\n00111| now: Date.now(),\n00112| message: 'Missing tag to revalidate',\n00113| })\n00114| }\n00115| ```\n00116| \n00117| ```js filename=\"app/api/revalidate/route.js\" switcher\n00118| import { revalidateTag } from 'next/cache'\n00119| \n00120| export async function GET(request) {\n00121| const tag = request.nextUrl.searchParams.get('tag')\n00122| \n00123| if (tag) {\n00124| revalidateTag(tag, 'max')\n00125| return Response.json({ revalidated: true, now: Date.now() })\n00126| }\n00127| \n00128| return Response.json({\n00129| revalidated: false,\n00130| now: Date.now(),\n00131| message: 'Missing tag to revalidate',\n00132| })\n00133| }\n00134| ```\n00135| \n00136| > **Good to know**: For webhooks or third-party services that need immediate expiration, you can pass `{ expire: 0 }` as the second argument: `revalidateTag(tag, { expire: 0 })`. This pattern is necessary when external systems call your Route Handlers and require data to expire immediately. For all other cases, it's recommended to use [`updateTag`](/docs/app/api-reference/functions/updateTag) in Server Actions for immediate updates instead.\n00137| \n\n(End of file - total 137 lines)\n",
+ "title": "node_modules/next/dist/docs/01-app/03-api-reference/04-functions/revalidateTag.md",
+ "metadata": {
+ "preview": "---\ntitle: revalidateTag\ndescription: API Reference for the revalidateTag function.\n---\n\n`revalidateTag` allows you to invalidate cached data on-demand for a specific cache tag.\n\nThis function is ideal for content where a slight delay in updates is acceptable, such as blog posts, product catalogs, or documentation. Users receive stale content while fresh data loads in the background.\n\n## Usage\n\n`revalidateTag` can be called in Server Functions and Route Handlers.\n\n`revalidateTag` cannot be called in Client Components or Proxy, as it only works in server environments.\n\n### Revalidation Behavior\n\nThe revalidation behavior depends on whether you provide the second argument:\n\n- **With `profile=\"max\"` (recommended)**: The tag entry is marked as stale, and the next time a resource with that tag is visited, it will use stale-while-revalidate semantics. This means the stale content is served while fresh content is fetched in the background."
+ },
+ "time": {
+ "start": 1781392538335,
+ "end": 1781392538341
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:39.071Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "args": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/unstable_cache.md",
+ "_extractedPath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/unstable_cache.md"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392539071,
+ "sessionID": "ses_13cbb6ca7ffeDluJj6gL6KvvXT",
+ "part": {
+ "id": "prt_ec344fae3001sjFd6bBOfprqF7",
+ "sessionID": "ses_13cbb6ca7ffeDluJj6gL6KvvXT",
+ "messageID": "msg_ec344eb5d001IcU2v22Hnj8HEM",
+ "type": "tool",
+ "callID": "read_13",
+ "tool": "read",
+ "state": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/unstable_cache.md"
+ },
+ "output": "\n00001| ---\n00002| title: unstable_cache\n00003| description: API Reference for the unstable_cache function.\n00004| ---\n00005| \n00006| > **Note:**\n00007| > This API has been replaced by [`use cache`](/docs/app/api-reference/directives/use-cache) in Next.js 16.\n00008| > We recommend opting into [Cache Components](/docs/app/getting-started/caching) and replacing `unstable_cache` with the `use cache` directive.\n00009| \n00010| `unstable_cache` allows you to cache the results of expensive operations, like database queries, and reuse them across multiple requests.\n00011| \n00012| ```jsx\n00013| import { getUser } from './data';\n00014| import { unstable_cache } from 'next/cache';\n00015| \n00016| const getCachedUser = unstable_cache(\n00017| async (id) => getUser(id),\n00018| ['my-app-user']\n00019| );\n00020| \n00021| export default async function Component({ userID }) {\n00022| const user = await getCachedUser(userID);\n00023| ...\n00024| }\n00025| ```\n00026| \n00027| > **Good to know**:\n00028| >\n00029| > - Accessing uncached data sources such as `headers` or `cookies` inside a cache scope is not supported. If you need this data inside a cached function use `headers` outside of the cached function and pass the required uncached data in as an argument.\n00030| > - This API uses Next.js' built-in cache to persist the result across requests and deployments. See [Caching and Revalidating](/docs/app/getting-started/caching).\n00031| \n00032| ## Parameters\n00033| \n00034| ```jsx\n00035| const data = unstable_cache(fetchData, keyParts, options)()\n00036| ```\n00037| \n00038| - `fetchData`: This is an asynchronous function that fetches the data you want to cache. It must be a function that returns a `Promise`.\n00039| - `keyParts`: This is an extra array of keys that further adds identification to the cache. By default, `unstable_cache` already uses the arguments and the stringified version of your function as the cache key. It is optional in most cases; the only time you need to use it is when you use external variables without passing them as parameters. However, it is important to add closures used within the function if you do not pass them as parameters.\n00040| - `options`: This is an object that controls how the cache behaves. It can contain the following properties:\n00041| - `tags`: An array of tags that can be used to control cache invalidation. Next.js will not use this to uniquely identify the function.\n00042| - `revalidate`: The number of seconds after which the cache should be revalidated. Omit or pass `false` to cache indefinitely or until matching `revalidateTag()` or `revalidatePath()` methods are called.\n00043| \n00044| ## Returns\n00045| \n00046| `unstable_cache` returns a function that when invoked, returns a Promise that resolves to the cached data. If the data is not in the cache, the provided function will be invoked, and its result will be cached and returned.\n00047| \n00048| ## Example\n00049| \n00050| ```tsx filename=\"app/page.tsx\" switcher\n00051| import { unstable_cache } from 'next/cache'\n00052| \n00053| export default async function Page({\n00054| params,\n00055| }: {\n00056| params: Promise<{ userId: string }>\n00057| }) {\n00058| const { userId } = await params\n00059| const getCachedUser = unstable_cache(\n00060| async () => {\n00061| return { id: userId }\n00062| },\n00063| [userId], // add the user ID to the cache key\n00064| {\n00065| tags: ['users'],\n00066| revalidate: 60,\n00067| }\n00068| )\n00069| \n00070| //...\n00071| }\n00072| ```\n00073| \n00074| ```jsx filename=\"app/page.jsx\" switcher\n00075| import { unstable_cache } from 'next/cache';\n00076| \n00077| export default async function Page({ params } }) {\n00078| const { userId } = await params\n00079| const getCachedUser = unstable_cache(\n00080| async () => {\n00081| return { id: userId };\n00082| },\n00083| [userId], // add the user ID to the cache key\n00084| {\n00085| tags: [\"users\"],\n00086| revalidate: 60,\n00087| }\n00088| );\n00089| \n00090| //...\n00091| }\n00092| ```\n00093| \n00094| ## Version History\n00095| \n00096| | Version | Changes |\n00097| | --------- | ---------------------------- |\n00098| | `v14.0.0` | `unstable_cache` introduced. |\n00099| \n\n(End of file - total 99 lines)\n",
+ "title": "node_modules/next/dist/docs/01-app/03-api-reference/04-functions/unstable_cache.md",
+ "metadata": {
+ "preview": "---\ntitle: unstable_cache\ndescription: API Reference for the unstable_cache function.\n---\n\n> **Note:**\n> This API has been replaced by [`use cache`](/docs/app/api-reference/directives/use-cache) in Next.js 16.\n> We recommend opting into [Cache Components](/docs/app/getting-started/caching) and replacing `unstable_cache` with the `use cache` directive.\n\n`unstable_cache` allows you to cache the results of expensive operations, like database queries, and reuse them across multiple requests.\n\n```jsx\nimport { getUser } from './data';\nimport { unstable_cache } from 'next/cache';\n\nconst getCachedUser = unstable_cache(\n async (id) => getUser(id),\n ['my-app-user']\n);\n"
+ },
+ "time": {
+ "start": 1781392539062,
+ "end": 1781392539067
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:39.071Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| ---\n00002| title: unstable_cache\n00003| description: API Reference for the unstable_cache function.\n00004| ---\n00005| \n00006| > **Note:**\n00007| > This API has been replaced by [`use cache`](/docs/app/api-reference/directives/use-cache) in Next.js 16.\n00008| > We recommend opting into [Cache Components](/docs/app/getting-started/caching) and replacing `unstable_cache` with the `use cache` directive.\n00009| \n00010| `unstable_cache` allows you to cache the results of expensive operations, like database queries, and reuse them across multiple requests.\n00011| \n00012| ```jsx\n00013| import { getUser } from './data';\n00014| import { unstable_cache } from 'next/cache';\n00015| \n00016| const getCachedUser = unstable_cache(\n00017| async (id) => getUser(id),\n00018| ['my-app-user']\n00019| );\n00020| \n00021| export default async function Component({ userID }) {\n00022| const user = await getCachedUser(userID);\n00023| ...\n00024| }\n00025| ```\n00026| \n00027| > **Good to know**:\n00028| >\n00029| > - Accessing uncached data sources such as `headers` or `cookies` inside a cache scope is not supported. If you need this data inside a cached function use `headers` outside of the cached function and pass the required uncached data in as an argument.\n00030| > - This API uses Next.js' built-in cache to persist the result across requests and deployments. See [Caching and Revalidating](/docs/app/getting-started/caching).\n00031| \n00032| ## Parameters\n00033| \n00034| ```jsx\n00035| const data = unstable_cache(fetchData, keyParts, options)()\n00036| ```\n00037| \n00038| - `fetchData`: This is an asynchronous function that fetches the data you want to cache. It must be a function that returns a `Promise`.\n00039| - `keyParts`: This is an extra array of keys that further adds identification to the cache. By default, `unstable_cache` already uses the arguments and the stringified version of your function as the cache key. It is optional in most cases; the only time you need to use it is when you use external variables without passing them as parameters. However, it is important to add closures used within the function if you do not pass them as parameters.\n00040| - `options`: This is an object that controls how the cache behaves. It can contain the following properties:\n00041| - `tags`: An array of tags that can be used to control cache invalidation. Next.js will not use this to uniquely identify the function.\n00042| - `revalidate`: The number of seconds after which the cache should be revalidated. Omit or pass `false` to cache indefinitely or until matching `revalidateTag()` or `revalidatePath()` methods are called.\n00043| \n00044| ## Returns\n00045| \n00046| `unstable_cache` returns a function that when invoked, returns a Promise that resolves to the cached data. If the data is not in the cache, the provided function will be invoked, and its result will be cached and returned.\n00047| \n00048| ## Example\n00049| \n00050| ```tsx filename=\"app/page.tsx\" switcher\n00051| import { unstable_cache } from 'next/cache'\n00052| \n00053| export default async function Page({\n00054| params,\n00055| }: {\n00056| params: Promise<{ userId: string }>\n00057| }) {\n00058| const { userId } = await params\n00059| const getCachedUser = unstable_cache(\n00060| async () => {\n00061| return { id: userId }\n00062| },\n00063| [userId], // add the user ID to the cache key\n00064| {\n00065| tags: ['users'],\n00066| revalidate: 60,\n00067| }\n00068| )\n00069| \n00070| //...\n00071| }\n00072| ```\n00073| \n00074| ```jsx filename=\"app/page.jsx\" switcher\n00075| import { unstable_cache } from 'next/cache';\n00076| \n00077| export default async function Page({ params } }) {\n00078| const { userId } = await params\n00079| const getCachedUser = unstable_cache(\n00080| async () => {\n00081| return { id: userId };\n00082| },\n00083| [userId], // add the user ID to the cache key\n00084| {\n00085| tags: [\"users\"],\n00086| revalidate: 60,\n00087| }\n00088| );\n00089| \n00090| //...\n00091| }\n00092| ```\n00093| \n00094| ## Version History\n00095| \n00096| | Version | Changes |\n00097| | --------- | ---------------------------- |\n00098| | `v14.0.0` | `unstable_cache` introduced. |\n00099| \n\n(End of file - total 99 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/unstable_cache.md"
+ },
+ "output": "\n00001| ---\n00002| title: unstable_cache\n00003| description: API Reference for the unstable_cache function.\n00004| ---\n00005| \n00006| > **Note:**\n00007| > This API has been replaced by [`use cache`](/docs/app/api-reference/directives/use-cache) in Next.js 16.\n00008| > We recommend opting into [Cache Components](/docs/app/getting-started/caching) and replacing `unstable_cache` with the `use cache` directive.\n00009| \n00010| `unstable_cache` allows you to cache the results of expensive operations, like database queries, and reuse them across multiple requests.\n00011| \n00012| ```jsx\n00013| import { getUser } from './data';\n00014| import { unstable_cache } from 'next/cache';\n00015| \n00016| const getCachedUser = unstable_cache(\n00017| async (id) => getUser(id),\n00018| ['my-app-user']\n00019| );\n00020| \n00021| export default async function Component({ userID }) {\n00022| const user = await getCachedUser(userID);\n00023| ...\n00024| }\n00025| ```\n00026| \n00027| > **Good to know**:\n00028| >\n00029| > - Accessing uncached data sources such as `headers` or `cookies` inside a cache scope is not supported. If you need this data inside a cached function use `headers` outside of the cached function and pass the required uncached data in as an argument.\n00030| > - This API uses Next.js' built-in cache to persist the result across requests and deployments. See [Caching and Revalidating](/docs/app/getting-started/caching).\n00031| \n00032| ## Parameters\n00033| \n00034| ```jsx\n00035| const data = unstable_cache(fetchData, keyParts, options)()\n00036| ```\n00037| \n00038| - `fetchData`: This is an asynchronous function that fetches the data you want to cache. It must be a function that returns a `Promise`.\n00039| - `keyParts`: This is an extra array of keys that further adds identification to the cache. By default, `unstable_cache` already uses the arguments and the stringified version of your function as the cache key. It is optional in most cases; the only time you need to use it is when you use external variables without passing them as parameters. However, it is important to add closures used within the function if you do not pass them as parameters.\n00040| - `options`: This is an object that controls how the cache behaves. It can contain the following properties:\n00041| - `tags`: An array of tags that can be used to control cache invalidation. Next.js will not use this to uniquely identify the function.\n00042| - `revalidate`: The number of seconds after which the cache should be revalidated. Omit or pass `false` to cache indefinitely or until matching `revalidateTag()` or `revalidatePath()` methods are called.\n00043| \n00044| ## Returns\n00045| \n00046| `unstable_cache` returns a function that when invoked, returns a Promise that resolves to the cached data. If the data is not in the cache, the provided function will be invoked, and its result will be cached and returned.\n00047| \n00048| ## Example\n00049| \n00050| ```tsx filename=\"app/page.tsx\" switcher\n00051| import { unstable_cache } from 'next/cache'\n00052| \n00053| export default async function Page({\n00054| params,\n00055| }: {\n00056| params: Promise<{ userId: string }>\n00057| }) {\n00058| const { userId } = await params\n00059| const getCachedUser = unstable_cache(\n00060| async () => {\n00061| return { id: userId }\n00062| },\n00063| [userId], // add the user ID to the cache key\n00064| {\n00065| tags: ['users'],\n00066| revalidate: 60,\n00067| }\n00068| )\n00069| \n00070| //...\n00071| }\n00072| ```\n00073| \n00074| ```jsx filename=\"app/page.jsx\" switcher\n00075| import { unstable_cache } from 'next/cache';\n00076| \n00077| export default async function Page({ params } }) {\n00078| const { userId } = await params\n00079| const getCachedUser = unstable_cache(\n00080| async () => {\n00081| return { id: userId };\n00082| },\n00083| [userId], // add the user ID to the cache key\n00084| {\n00085| tags: [\"users\"],\n00086| revalidate: 60,\n00087| }\n00088| );\n00089| \n00090| //...\n00091| }\n00092| ```\n00093| \n00094| ## Version History\n00095| \n00096| | Version | Changes |\n00097| | --------- | ---------------------------- |\n00098| | `v14.0.0` | `unstable_cache` introduced. |\n00099| \n\n(End of file - total 99 lines)\n",
+ "title": "node_modules/next/dist/docs/01-app/03-api-reference/04-functions/unstable_cache.md",
+ "metadata": {
+ "preview": "---\ntitle: unstable_cache\ndescription: API Reference for the unstable_cache function.\n---\n\n> **Note:**\n> This API has been replaced by [`use cache`](/docs/app/api-reference/directives/use-cache) in Next.js 16.\n> We recommend opting into [Cache Components](/docs/app/getting-started/caching) and replacing `unstable_cache` with the `use cache` directive.\n\n`unstable_cache` allows you to cache the results of expensive operations, like database queries, and reuse them across multiple requests.\n\n```jsx\nimport { getUser } from './data';\nimport { unstable_cache } from 'next/cache';\n\nconst getCachedUser = unstable_cache(\n async (id) => getUser(id),\n ['my-app-user']\n);\n"
+ },
+ "time": {
+ "start": 1781392539062,
+ "end": 1781392539067
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:39.728Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "args": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/01-getting-started/07-mutating-data.md",
+ "_extractedPath": "/workspace/node_modules/next/dist/docs/01-app/01-getting-started/07-mutating-data.md"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392539728,
+ "sessionID": "ses_13cbb6ca7ffeDluJj6gL6KvvXT",
+ "part": {
+ "id": "prt_ec344fdb9001xqRwmDQ4my1hAY",
+ "sessionID": "ses_13cbb6ca7ffeDluJj6gL6KvvXT",
+ "messageID": "msg_ec344eb5d001IcU2v22Hnj8HEM",
+ "type": "tool",
+ "callID": "read_14",
+ "tool": "read",
+ "state": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/01-getting-started/07-mutating-data.md"
+ },
+ "output": "\n00001| ---\n00002| title: Mutating Data\n00003| description: Learn how to mutate data using Server Functions and Server Actions in Next.js.\n00004| related:\n00005| title: API Reference\n00006| description: Learn more about the features mentioned in this page by reading the API Reference.\n00007| links:\n00008| - app/api-reference/functions/revalidatePath\n00009| - app/api-reference/functions/revalidateTag\n00010| - app/api-reference/functions/redirect\n00011| ---\n00012| \n00013| You can mutate data in Next.js using [React Server Functions](https://react.dev/reference/rsc/server-functions). This page will go through how you can [create](#creating-server-functions) and [invoke](#invoking-server-functions) Server Functions.\n00014| \n00015| ## What are Server Functions?\n00016| \n00017| A **Server Function** is an asynchronous function that runs on the server. You can call them from the client through a network request, which is why they must be asynchronous.\n00018| \n00019| In an `action` or mutation context, they are also called **Server Actions**.\n00020| \n00021| By convention, a Server Action is an async function used with [`startTransition`](https://react.dev/reference/react/startTransition). This happens automatically when the function is:\n00022| \n00023| - Passed to a `
` using the `action` prop.\n00024| - Passed to a `` using the `formAction` prop.\n00025| \n00026| When an action is invoked, Next.js can return both the updated UI and new data in a single server roundtrip.\n00027| \n00028| Behind the scenes, actions use the `POST` method, and only this HTTP method can invoke them.\n00029| \n00030| > [!WARNING]\n00031| > Server Functions are reachable via direct POST requests, not just through your application's UI. Always verify authentication and authorization inside every Server Function. See the [Data Security guide](/docs/app/guides/data-security#authentication-and-authorization) for recommended patterns.\n00032| \n00033| > **Good to know:** A Server Action is a Server Function used in a specific way (for handling form submissions and mutations). Server Function is the broader term.\n00034| \n00035| ## Creating Server Functions\n00036| \n00037| A Server Function can be defined by using the [`use server`](https://react.dev/reference/rsc/use-server) directive. You can place the directive at the top of an **asynchronous** function to mark the function as a Server Function, or at the top of a separate file to mark all exports of that file.\n00038| \n00039| ```ts filename=\"app/lib/actions.ts\" switcher\n00040| import { auth } from '@/lib/auth'\n00041| \n00042| export async function createPost(formData: FormData) {\n00043| 'use server'\n00044| const session = await auth()\n00045| if (!session?.user) {\n00046| throw new Error('Unauthorized')\n00047| }\n00048| \n00049| const title = formData.get('title')\n00050| const content = formData.get('content')\n00051| \n00052| // Mutate data\n00053| // Revalidate cache\n00054| }\n00055| \n00056| export async function deletePost(formData: FormData) {\n00057| 'use server'\n00058| const session = await auth()\n00059| if (!session?.user) {\n00060| throw new Error('Unauthorized')\n00061| }\n00062| \n00063| const id = formData.get('id')\n00064| \n00065| // Verify the user owns this resource before deleting\n00066| // Mutate data\n00067| // Revalidate cache\n00068| }\n00069| ```\n00070| \n00071| ```js filename=\"app/lib/actions.js\" switcher\n00072| import { auth } from '@/lib/auth'\n00073| \n00074| export async function createPost(formData) {\n00075| 'use server'\n00076| const session = await auth()\n00077| if (!session?.user) {\n00078| throw new Error('Unauthorized')\n00079| }\n00080| \n00081| const title = formData.get('title')\n00082| const content = formData.get('content')\n00083| \n00084| // Mutate data\n00085| // Revalidate cache\n00086| }\n00087| \n00088| export async function deletePost(formData) {\n00089| 'use server'\n00090| const session = await auth()\n00091| if (!session?.user) {\n00092| throw new Error('Unauthorized')\n00093| }\n00094| \n00095| const id = formData.get('id')\n00096| \n00097| // Verify the user owns this resource before deleting\n00098| // Mutate data\n00099| // Revalidate cache\n00100| }\n00101| ```\n00102| \n00103| ### Server Components\n00104| \n00105| Server Functions can be inlined in Server Components by adding the `\"use server\"` directive to the top of the function body:\n00106| \n00107| ```tsx filename=\"app/page.tsx\" switcher\n00108| export default function Page() {\n00109| // Server Action\n00110| async function createPost(formData: FormData) {\n00111| 'use server'\n00112| // ...\n00113| }\n00114| \n00115| return <>>\n00116| }\n00117| ```\n00118| \n00119| ```jsx filename=\"app/page.js\" switcher\n00120| export default function Page() {\n00121| // Server Action\n00122| async function createPost(formData) {\n00123| 'use server'\n00124| // ...\n00125| }\n00126| \n00127| return <>>\n00128| }\n00129| ```\n00130| \n00131| > **Good to know:** Server Components support progressive enhancement by default, meaning forms that call Server Actions will be submitted even if JavaScript hasn't loaded yet or is disabled.\n00132| \n00133| ### Client Components\n00134| \n00135| It's not possible to define Server Functions in Client Components. However, you can invoke them in Client Components by importing them from a file that has the `\"use server\"` directive at the top of it:\n00136| \n00137| ```ts filename=\"app/actions.ts\" switcher\n00138| 'use server'\n00139| \n00140| export async function createPost() {}\n00141| ```\n00142| \n00143| ```js filename=\"app/actions.js\" switcher\n00144| 'use server'\n00145| \n00146| export async function createPost() {}\n00147| ```\n00148| \n00149| ```tsx filename=\"app/ui/button.tsx\" switcher\n00150| 'use client'\n00151| \n00152| import { createPost } from '@/app/actions'\n00153| \n00154| export function Button() {\n00155| return Create\n00156| }\n00157| ```\n00158| \n00159| ```jsx filename=\"app/ui/button.js\" switcher\n00160| 'use client'\n00161| \n00162| import { createPost } from '@/app/actions'\n00163| \n00164| export function Button() {\n00165| return Create\n00166| }\n00167| ```\n00168| \n00169| > **Good to know:** In Client Components, forms invoking Server Actions will queue submissions if JavaScript isn't loaded yet, and will be prioritized for hydration. After hydration, the browser does not refresh on form submission.\n00170| \n00171| ### Passing actions as props\n00172| \n00173| You can also pass an action to a Client Component as a prop:\n00174| \n00175| ```jsx\n00176| \n00177| ```\n00178| \n00179| ```tsx filename=\"app/client-component.tsx\" switcher\n00180| 'use client'\n00181| \n00182| export default function ClientComponent({\n00183| updateItemAction,\n00184| }: {\n00185| updateItemAction: (formData: FormData) => void\n00186| }) {\n00187| return
\n00196| }\n00197| ```\n00198| \n00199| ## Invoking Server Functions\n00200| \n00201| There are two main ways you can invoke a Server Function:\n00202| \n00203| 1. [Forms](#forms) in Server and Client Components\n00204| 2. [Event Handlers](#event-handlers) and [useEffect](#useeffect) in Client Components\n00205| \n00206| > **Good to know:** Server Functions are designed for server-side mutations. The client currently dispatches and awaits them one at a time. This is an implementation detail and may change. If you need parallel data fetching, use [data fetching](/docs/app/getting-started/fetching-data#server-components) in Server Components, or perform parallel work inside a single Server Function or [Route Handler](/docs/app/guides/backend-for-frontend#manipulating-data).\n00207| \n00208| ### Forms\n00209| \n00210| React extends the HTML [`
`](https://react.dev/reference/react-dom/components/form) element to allow a Server Function to be invoked with the HTML `action` prop.\n00211| \n00212| When invoked in a form, the function automatically receives the [`FormData`](https://developer.mozilla.org/docs/Web/API/FormData/FormData) object. You can extract the data using the native [`FormData` methods](https://developer.mozilla.org/en-US/docs/Web/API/FormData#instance_methods):\n00213| \n00214| ```tsx filename=\"app/ui/form.tsx\" switcher\n00215| import { createPost } from '@/app/actions'\n00216| \n00217| export function Form() {\n00218| return (\n00219|
\n00321| {\n00323| const updatedLikes = await incrementLike()\n00324| setLikes(updatedLikes)\n00325| }}\n00326| >\n00327| Like\n00328| \n00329| >\n00330| )\n00331| }\n00332| ```\n00333| \n00334| ## Examples\n00335| \n00336| ### Showing a pending state\n00337| \n00338| While executing a Server Function, you can show a loading indicator with React's [`useActionState`](https://react.dev/reference/react/useActionState) hook. This hook returns a `pending` boolean:\n00339| \n00340| ```tsx filename=\"app/ui/button.tsx\" switcher\n00341| 'use client'\n00342| \n00343| import { useActionState, startTransition } from 'react'\n00344| import { createPost } from '@/app/actions'\n00345| import { LoadingSpinner } from '@/app/ui/loading-spinner'\n00346| \n00347| export function Button() {\n00348| const [state, action, pending] = useActionState(createPost, false)\n00349| \n00350| return (\n00351| startTransition(action)}>\n00352| {pending ? : 'Create Post'}\n00353| \n00354| )\n00355| }\n00356| ```\n00357| \n00358| ```jsx filename=\"app/ui/button.js\" switcher\n00359| 'use client'\n00360| \n00361| import { useActionState, startTransition } from 'react'\n00362| import { createPost } from '@/app/actions'\n00363| import { LoadingSpinner } from '@/app/ui/loading-spinner'\n00364| \n00365| export function Button() {\n00366| const [state, action, pending] = useActionState(createPost, false)\n00367| \n00368| return (\n00369| startTransition(action)}>\n00370| {pending ? : 'Create Post'}\n00371| \n00372| )\n00373| }\n00374| ```\n00375| \n00376| ### Refresh data\n00377| \n00378| After a mutation, you may want to refresh the current page to show the latest data. You can do this by calling [`refresh`](/docs/app/api-reference/functions/refresh) from `next/cache` in a Server Action:\n00379| \n00380| ```ts filename=\"app/lib/actions.ts\" switcher\n00381| 'use server'\n00382| \n00383| import { auth } from '@/lib/auth'\n00384| import { refresh } from 'next/cache'\n00385| \n00386| export async function updatePost(formData: FormData) {\n00387| const session = await auth()\n00388| if (!session?.user) {\n00389| throw new Error('Unauthorized')\n00390| }\n00391| // Mutate data\n00392| // ...\n00393| \n00394| refresh()\n00395| }\n00396| ```\n00397| \n00398| ```js filename=\"app/lib/actions.js\" switcher\n00399| 'use server'\n00400| \n00401| import { auth } from '@/lib/auth'\n00402| import { refresh } from 'next/cache'\n00403| \n00404| export async function updatePost(formData) {\n00405| const session = await auth()\n00406| if (!session?.user) {\n00407| throw new Error('Unauthorized')\n00408| }\n00409| // Mutate data\n00410| // ...\n00411| \n00412| refresh()\n00413| }\n00414| ```\n00415| \n00416| This refreshes the client router, ensuring the UI reflects the latest state. The `refresh()` function does not revalidate tagged data. To revalidate tagged data, use [`updateTag`](/docs/app/api-reference/functions/updateTag) or [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) instead.\n00417| \n00418| ### Revalidate data\n00419| \n00420| After performing a mutation, you can revalidate the Next.js cache and show the updated data by calling [`revalidatePath`](/docs/app/api-reference/functions/revalidatePath) or [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) within the Server Function:\n00421| \n00422| ```ts filename=\"app/lib/actions.ts\" switcher\n00423| import { auth } from '@/lib/auth'\n00424| import { revalidatePath } from 'next/cache'\n00425| \n00426| export async function createPost(formData: FormData) {\n00427| 'use server'\n00428| const session = await auth()\n00429| if (!session?.user) {\n00430| throw new Error('Unauthorized')\n00431| }\n00432| // Mutate data\n00433| // ...\n00434| \n00435| revalidatePath('/posts')\n00436| }\n00437| ```\n00438| \n00439| ```js filename=\"app/actions.js\" switcher\n00440| import { auth } from '@/lib/auth'\n00441| import { revalidatePath } from 'next/cache'\n00442| \n00443| export async function createPost(formData) {\n00444| 'use server'\n00445| const session = await auth()\n00446| if (!session?.user) {\n00447| throw new Error('Unauthorized')\n00448| }\n00449| // Mutate data\n00450| // ...\n00451| revalidatePath('/posts')\n00452| }\n00453| ```\n00454| \n00455| ### Redirect after a mutation\n00456| \n00457| You may want to redirect the user to a different page after a mutation. You can do this by calling [`redirect`](/docs/app/api-reference/functions/redirect) within the Server Function.\n00458| \n00459| ```ts filename=\"app/lib/actions.ts\" switcher\n00460| 'use server'\n00461| \n00462| import { auth } from '@/lib/auth'\n00463| import { revalidatePath } from 'next/cache'\n00464| import { redirect } from 'next/navigation'\n00465| \n00466| export async function createPost(formData: FormData) {\n00467| const session = await auth()\n00468| if (!session?.user) {\n00469| throw new Error('Unauthorized')\n00470| }\n00471| // Mutate data\n00472| // ...\n00473| \n00474| revalidatePath('/posts')\n00475| redirect('/posts')\n00476| }\n00477| ```\n00478| \n00479| ```js filename=\"app/actions.js\" switcher\n00480| 'use server'\n00481| \n00482| import { auth } from '@/lib/auth'\n00483| import { revalidatePath } from 'next/cache'\n00484| import { redirect } from 'next/navigation'\n00485| \n00486| export async function createPost(formData) {\n00487| const session = await auth()\n00488| if (!session?.user) {\n00489| throw new Error('Unauthorized')\n00490| }\n00491| // Mutate data\n00492| // ...\n00493| \n00494| revalidatePath('/posts')\n00495| redirect('/posts')\n00496| }\n00497| ```\n00498| \n00499| Calling `redirect` [throws](/docs/app/api-reference/functions/redirect#behavior) a framework handled control-flow exception. Any code after it won't execute. If you need fresh data, call [`revalidatePath`](/docs/app/api-reference/functions/revalidatePath) or [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) beforehand.\n00500| \n00501| ### Cookies\n00502| \n00503| You can `get`, `set`, and `delete` cookies inside a Server Action using the [`cookies`](/docs/app/api-reference/functions/cookies) API.\n00504| \n00505| When you [set or delete](/docs/app/api-reference/functions/cookies#understanding-cookie-behavior-in-server-functions) a cookie in a Server Action, Next.js re-renders the current page and its layouts on the server so the **UI reflects the new cookie value**.\n00506| \n00507| > **Good to know**: The server update applies to the current React tree, re-rendering, mounting, or unmounting components, as needed. Client state is preserved for re-rendered components, and effects re-run if their dependencies changed.\n00508| \n00509| ```ts filename=\"app/actions.ts\" switcher\n00510| 'use server'\n00511| \n00512| import { cookies } from 'next/headers'\n00513| \n00514| export async function exampleAction() {\n00515| const cookieStore = await cookies()\n00516| \n00517| // Get cookie\n00518| cookieStore.get('name')?.value\n00519| \n00520| // Set cookie\n00521| cookieStore.set('name', 'Delba')\n00522| \n00523| // Delete cookie\n00524| cookieStore.delete('name')\n00525| }\n00526| ```\n00527| \n00528| ```js filename=\"app/actions.js\" switcher\n00529| 'use server'\n00530| \n00531| import { cookies } from 'next/headers'\n00532| \n00533| export async function exampleAction() {\n00534| // Get cookie\n00535| const cookieStore = await cookies()\n00536| \n00537| // Get cookie\n00538| cookieStore.get('name')?.value\n00539| \n00540| // Set cookie\n00541| cookieStore.set('name', 'Delba')\n00542| \n00543| // Delete cookie\n00544| cookieStore.delete('name')\n00545| }\n00546| ```\n00547| \n00548| ### useEffect\n00549| \n00550| You can use the React [`useEffect`](https://react.dev/reference/react/useEffect) hook to invoke a Server Action when the component mounts or a dependency changes. This is useful for mutations that depend on global events or need to be triggered automatically. For example, `onKeyDown` for app shortcuts, an intersection observer hook for infinite scrolling, or when the component mounts to update a view count:\n00551| \n00552| ```tsx filename=\"app/view-count.tsx\" switcher\n00553| 'use client'\n00554| \n00555| import { incrementViews } from './actions'\n00556| import { useState, useEffect, useTransition } from 'react'\n00557| \n00558| export default function ViewCount({ initialViews }: { initialViews: number }) {\n00559| const [views, setViews] = useState(initialViews)\n00560| const [isPending, startTransition] = useTransition()\n00561| \n00562| useEffect(() => {\n00563| startTransition(async () => {\n00564| const updatedViews = await incrementViews()\n00565| setViews(updatedViews)\n00566| })\n00567| }, [])\n00568| \n00569| // You can use `isPending` to give users feedback\n00570| return
Total Views: {views}
\n00571| }\n00572| ```\n00573| \n00574| ```jsx filename=\"app/view-count.js\" switcher\n00575| 'use client'\n00576| \n00577| import { incrementViews } from './actions'\n00578| import { useState, useEffect, useTransition } from 'react'\n00579| \n00580| export default function ViewCount({ initialViews }) {\n00581| const [views, setViews] = useState(initialViews)\n00582| const [isPending, startTransition] = useTransition()\n00583| \n00584| useEffect(() => {\n00585| startTransition(async () => {\n00586| const updatedViews = await incrementViews()\n00587| setViews(updatedViews)\n00588| })\n00589| }, [])\n00590| \n00591| // You can use `isPending` to give users feedback\n00592| return
Total Views: {views}
\n00593| }\n00594| ```\n00595| \n\n(End of file - total 595 lines)\n
",
+ "title": "node_modules/next/dist/docs/01-app/01-getting-started/07-mutating-data.md",
+ "metadata": {
+ "preview": "---\ntitle: Mutating Data\ndescription: Learn how to mutate data using Server Functions and Server Actions in Next.js.\nrelated:\n title: API Reference\n description: Learn more about the features mentioned in this page by reading the API Reference.\n links:\n - app/api-reference/functions/revalidatePath\n - app/api-reference/functions/revalidateTag\n - app/api-reference/functions/redirect\n---\n\nYou can mutate data in Next.js using [React Server Functions](https://react.dev/reference/rsc/server-functions). This page will go through how you can [create](#creating-server-functions) and [invoke](#invoking-server-functions) Server Functions.\n\n## What are Server Functions?\n\nA **Server Function** is an asynchronous function that runs on the server. You can call them from the client through a network request, which is why they must be asynchronous.\n\nIn an `action` or mutation context, they are also called **Server Actions**.\n"
+ },
+ "time": {
+ "start": 1781392539714,
+ "end": 1781392539726
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:39.728Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| ---\n00002| title: Mutating Data\n00003| description: Learn how to mutate data using Server Functions and Server Actions in Next.js.\n00004| related:\n00005| title: API Reference\n00006| description: Learn more about the features mentioned in this page by reading the API Reference.\n00007| links:\n00008| - app/api-reference/functions/revalidatePath\n00009| - app/api-reference/functions/revalidateTag\n00010| - app/api-reference/functions/redirect\n00011| ---\n00012| \n00013| You can mutate data in Next.js using [React Server Functions](https://react.dev/reference/rsc/server-functions). This page will go through how you can [create](#creating-server-functions) and [invoke](#invoking-server-functions) Server Functions.\n00014| \n00015| ## What are Server Functions?\n00016| \n00017| A **Server Function** is an asynchronous function that runs on the server. You can call them from the client through a network request, which is why they must be asynchronous.\n00018| \n00019| In an `action` or mutation context, they are also called **Server Actions**.\n00020| \n00021| By convention, a Server Action is an async function used with [`startTransition`](https://react.dev/reference/react/startTransition). This happens automatically when the function is:\n00022| \n00023| - Passed to a `
` using the `action` prop.\n00024| - Passed to a `` using the `formAction` prop.\n00025| \n00026| When an action is invoked, Next.js can return both the updated UI and new data in a single server roundtrip.\n00027| \n00028| Behind the scenes, actions use the `POST` method, and only this HTTP method can invoke them.\n00029| \n00030| > [!WARNING]\n00031| > Server Functions are reachable via direct POST requests, not just through your application's UI. Always verify authentication and authorization inside every Server Function. See the [Data Security guide](/docs/app/guides/data-security#authentication-and-authorization) for recommended patterns.\n00032| \n00033| > **Good to know:** A Server Action is a Server Function used in a specific way (for handling form submissions and mutations). Server Function is the broader term.\n00034| \n00035| ## Creating Server Functions\n00036| \n00037| A Server Function can be defined by using the [`use server`](https://react.dev/reference/rsc/use-server) directive. You can place the directive at the top of an **asynchronous** function to mark the function as a Server Function, or at the top of a separate file to mark all exports of that file.\n00038| \n00039| ```ts filename=\"app/lib/actions.ts\" switcher\n00040| import { auth } from '@/lib/auth'\n00041| \n00042| export async function createPost(formData: FormData) {\n00043| 'use server'\n00044| const session = await auth()\n00045| if (!session?.user) {\n00046| throw new Error('Unauthorized')\n00047| }\n00048| \n00049| const title = formData.get('title')\n00050| const content = formData.get('content')\n00051| \n00052| // Mutate data\n00053| // Revalidate cache\n00054| }\n00055| \n00056| export async function deletePost(formData: FormData) {\n00057| 'use server'\n00058| const session = await auth()\n00059| if (!session?.user) {\n00060| throw new Error('Unauthorized')\n00061| }\n00062| \n00063| const id = formData.get('id')\n00064| \n00065| // Verify the user owns this resource before deleting\n00066| // Mutate data\n00067| // Revalidate cache\n00068| }\n00069| ```\n00070| \n00071| ```js filename=\"app/lib/actions.js\" switcher\n00072| import { auth } from '@/lib/auth'\n00073| \n00074| export async function createPost(formData) {\n00075| 'use server'\n00076| const session = await auth()\n00077| if (!session?.user) {\n00078| throw new Error('Unauthorized')\n00079| }\n00080| \n00081| const title = formData.get('title')\n00082| const content = formData.get('content')\n00083| \n00084| // Mutate data\n00085| // Revalidate cache\n00086| }\n00087| \n00088| export async function deletePost(formData) {\n00089| 'use server'\n00090| const session = await auth()\n00091| if (!session?.user) {\n00092| throw new Error('Unauthorized')\n00093| }\n00094| \n00095| const id = formData.get('id')\n00096| \n00097| // Verify the user owns this resource before deleting\n00098| // Mutate data\n00099| // Revalidate cache\n00100| }\n00101| ```\n00102| \n00103| ### Server Components\n00104| \n00105| Server Functions can be inlined in Server Components by adding the `\"use server\"` directive to the top of the function body:\n00106| \n00107| ```tsx filename=\"app/page.tsx\" switcher\n00108| export default function Page() {\n00109| // Server Action\n00110| async function createPost(formData: FormData) {\n00111| 'use server'\n00112| // ...\n00113| }\n00114| \n00115| return <>>\n00116| }\n00117| ```\n00118| \n00119| ```jsx filename=\"app/page.js\" switcher\n00120| export default function Page() {\n00121| // Server Action\n00122| async function createPost(formData) {\n00123| 'use server'\n00124| // ...\n00125| }\n00126| \n00127| return <>>\n00128| }\n00129| ```\n00130| \n00131| > **Good to know:** Server Components support progressive enhancement by default, meaning forms that call Server Actions will be submitted even if JavaScript hasn't loaded yet or is disabled.\n00132| \n00133| ### Client Components\n00134| \n00135| It's not possible to define Server Functions in Client Components. However, you can invoke them in Client Components by importing them from a file that has the `\"use server\"` directive at the top of it:\n00136| \n00137| ```ts filename=\"app/actions.ts\" switcher\n00138| 'use server'\n00139| \n00140| export async function createPost() {}\n00141| ```\n00142| \n00143| ```js filename=\"app/actions.js\" switcher\n00144| 'use server'\n00145| \n00146| export async function createPost() {}\n00147| ```\n00148| \n00149| ```tsx filename=\"app/ui/button.tsx\" switcher\n00150| 'use client'\n00151| \n00152| import { createPost } from '@/app/actions'\n00153| \n00154| export function Button() {\n00155| return Create\n00156| }\n00157| ```\n00158| \n00159| ```jsx filename=\"app/ui/button.js\" switcher\n00160| 'use client'\n00161| \n00162| import { createPost } from '@/app/actions'\n00163| \n00164| export function Button() {\n00165| return Create\n00166| }\n00167| ```\n00168| \n00169| > **Good to know:** In Client Components, forms invoking Server Actions will queue submissions if JavaScript isn't loaded yet, and will be prioritized for hydration. After hydration, the browser does not refresh on form submission.\n00170| \n00171| ### Passing actions as props\n00172| \n00173| You can also pass an action to a Client Component as a prop:\n00174| \n00175| ```jsx\n00176| \n00177| ```\n00178| \n00179| ```tsx filename=\"app/client-component.tsx\" switcher\n00180| 'use client'\n00181| \n00182| export default function ClientComponent({\n00183| updateItemAction,\n00184| }: {\n00185| updateItemAction: (formData: FormData) => void\n00186| }) {\n00187| return
\n00196| }\n00197| ```\n00198| \n00199| ## Invoking Server Functions\n00200| \n00201| There are two main ways you can invoke a Server Function:\n00202| \n00203| 1. [Forms](#forms) in Server and Client Components\n00204| 2. [Event Handlers](#event-handlers) and [useEffect](#useeffect) in Client Components\n00205| \n00206| > **Good to know:** Server Functions are designed for server-side mutations. The client currently dispatches and awaits them one at a time. This is an implementation detail and may change. If you need parallel data fetching, use [data fetching](/docs/app/getting-started/fetching-data#server-components) in Server Components, or perform parallel work inside a single Server Function or [Route Handler](/docs/app/guides/backend-for-frontend#manipulating-data).\n00207| \n00208| ### Forms\n00209| \n00210| React extends the HTML [`
`](https://react.dev/reference/react-dom/components/form) element to allow a Server Function to be invoked with the HTML `action` prop.\n00211| \n00212| When invoked in a form, the function automatically receives the [`FormData`](https://developer.mozilla.org/docs/Web/API/FormData/FormData) object. You can extract the data using the native [`FormData` methods](https://developer.mozilla.org/en-US/docs/Web/API/FormData#instance_methods):\n00213| \n00214| ```tsx filename=\"app/ui/form.tsx\" switcher\n00215| import { createPost } from '@/app/actions'\n00216| \n00217| export function Form() {\n00218| return (\n00219|
\n00321| {\n00323| const updatedLikes = await incrementLike()\n00324| setLikes(updatedLikes)\n00325| }}\n00326| >\n00327| Like\n00328| \n00329| >\n00330| )\n00331| }\n00332| ```\n00333| \n00334| ## Examples\n00335| \n00336| ### Showing a pending state\n00337| \n00338| While executing a Server Function, you can show a loading indicator with React's [`useActionState`](https://react.dev/reference/react/useActionState) hook. This hook returns a `pending` boolean:\n00339| \n00340| ```tsx filename=\"app/ui/button.tsx\" switcher\n00341| 'use client'\n00342| \n00343| import { useActionState, startTransition } from 'react'\n00344| import { createPost } from '@/app/actions'\n00345| import { LoadingSpinner } from '@/app/ui/loading-spinner'\n00346| \n00347| export function Button() {\n00348| const [state, action, pending] = useActionState(createPost, false)\n00349| \n00350| return (\n00351| startTransition(action)}>\n00352| {pending ? : 'Create Post'}\n00353| \n00354| )\n00355| }\n00356| ```\n00357| \n00358| ```jsx filename=\"app/ui/button.js\" switcher\n00359| 'use client'\n00360| \n00361| import { useActionState, startTransition } from 'react'\n00362| import { createPost } from '@/app/actions'\n00363| import { LoadingSpinner } from '@/app/ui/loading-spinner'\n00364| \n00365| export function Button() {\n00366| const [state, action, pending] = useActionState(createPost, false)\n00367| \n00368| return (\n00369| startTransition(action)}>\n00370| {pending ? : 'Create Post'}\n00371| \n00372| )\n00373| }\n00374| ```\n00375| \n00376| ### Refresh data\n00377| \n00378| After a mutation, you may want to refresh the current page to show the latest data. You can do this by calling [`refresh`](/docs/app/api-reference/functions/refresh) from `next/cache` in a Server Action:\n00379| \n00380| ```ts filename=\"app/lib/actions.ts\" switcher\n00381| 'use server'\n00382| \n00383| import { auth } from '@/lib/auth'\n00384| import { refresh } from 'next/cache'\n00385| \n00386| export async function updatePost(formData: FormData) {\n00387| const session = await auth()\n00388| if (!session?.user) {\n00389| throw new Error('Unauthorized')\n00390| }\n00391| // Mutate data\n00392| // ...\n00393| \n00394| refresh()\n00395| }\n00396| ```\n00397| \n00398| ```js filename=\"app/lib/actions.js\" switcher\n00399| 'use server'\n00400| \n00401| import { auth } from '@/lib/auth'\n00402| import { refresh } from 'next/cache'\n00403| \n00404| export async function updatePost(formData) {\n00405| const session = await auth()\n00406| if (!session?.user) {\n00407| throw new Error('Unauthorized')\n00408| }\n00409| // Mutate data\n00410| // ...\n00411| \n00412| refresh()\n00413| }\n00414| ```\n00415| \n00416| This refreshes the client router, ensuring the UI reflects the latest state. The `refresh()` function does not revalidate tagged data. To revalidate tagged data, use [`updateTag`](/docs/app/api-reference/functions/updateTag) or [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) instead.\n00417| \n00418| ### Revalidate data\n00419| \n00420| After performing a mutation, you can revalidate the Next.js cache and show the updated data by calling [`revalidatePath`](/docs/app/api-reference/functions/revalidatePath) or [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) within the Server Function:\n00421| \n00422| ```ts filename=\"app/lib/actions.ts\" switcher\n00423| import { auth } from '@/lib/auth'\n00424| import { revalidatePath } from 'next/cache'\n00425| \n00426| export async function createPost(formData: FormData) {\n00427| 'use server'\n00428| const session = await auth()\n00429| if (!session?.user) {\n00430| throw new Error('Unauthorized')\n00431| }\n00432| // Mutate data\n00433| // ...\n00434| \n00435| revalidatePath('/posts')\n00436| }\n00437| ```\n00438| \n00439| ```js filename=\"app/actions.js\" switcher\n00440| import { auth } from '@/lib/auth'\n00441| import { revalidatePath } from 'next/cache'\n00442| \n00443| export async function createPost(formData) {\n00444| 'use server'\n00445| const session = await auth()\n00446| if (!session?.user) {\n00447| throw new Error('Unauthorized')\n00448| }\n00449| // Mutate data\n00450| // ...\n00451| revalidatePath('/posts')\n00452| }\n00453| ```\n00454| \n00455| ### Redirect after a mutation\n00456| \n00457| You may want to redirect the user to a different page after a mutation. You can do this by calling [`redirect`](/docs/app/api-reference/functions/redirect) within the Server Function.\n00458| \n00459| ```ts filename=\"app/lib/actions.ts\" switcher\n00460| 'use server'\n00461| \n00462| import { auth } from '@/lib/auth'\n00463| import { revalidatePath } from 'next/cache'\n00464| import { redirect } from 'next/navigation'\n00465| \n00466| export async function createPost(formData: FormData) {\n00467| const session = await auth()\n00468| if (!session?.user) {\n00469| throw new Error('Unauthorized')\n00470| }\n00471| // Mutate data\n00472| // ...\n00473| \n00474| revalidatePath('/posts')\n00475| redirect('/posts')\n00476| }\n00477| ```\n00478| \n00479| ```js filename=\"app/actions.js\" switcher\n00480| 'use server'\n00481| \n00482| import { auth } from '@/lib/auth'\n00483| import { revalidatePath } from 'next/cache'\n00484| import { redirect } from 'next/navigation'\n00485| \n00486| export async function createPost(formData) {\n00487| const session = await auth()\n00488| if (!session?.user) {\n00489| throw new Error('Unauthorized')\n00490| }\n00491| // Mutate data\n00492| // ...\n00493| \n00494| revalidatePath('/posts')\n00495| redirect('/posts')\n00496| }\n00497| ```\n00498| \n00499| Calling `redirect` [throws](/docs/app/api-reference/functions/redirect#behavior) a framework handled control-flow exception. Any code after it won't execute. If you need fresh data, call [`revalidatePath`](/docs/app/api-reference/functions/revalidatePath) or [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) beforehand.\n00500| \n00501| ### Cookies\n00502| \n00503| You can `get`, `set`, and `delete` cookies inside a Server Action using the [`cookies`](/docs/app/api-reference/functions/cookies) API.\n00504| \n00505| When you [set or delete](/docs/app/api-reference/functions/cookies#understanding-cookie-behavior-in-server-functions) a cookie in a Server Action, Next.js re-renders the current page and its layouts on the server so the **UI reflects the new cookie value**.\n00506| \n00507| > **Good to know**: The server update applies to the current React tree, re-rendering, mounting, or unmounting components, as needed. Client state is preserved for re-rendered components, and effects re-run if their dependencies changed.\n00508| \n00509| ```ts filename=\"app/actions.ts\" switcher\n00510| 'use server'\n00511| \n00512| import { cookies } from 'next/headers'\n00513| \n00514| export async function exampleAction() {\n00515| const cookieStore = await cookies()\n00516| \n00517| // Get cookie\n00518| cookieStore.get('name')?.value\n00519| \n00520| // Set cookie\n00521| cookieStore.set('name', 'Delba')\n00522| \n00523| // Delete cookie\n00524| cookieStore.delete('name')\n00525| }\n00526| ```\n00527| \n00528| ```js filename=\"app/actions.js\" switcher\n00529| 'use server'\n00530| \n00531| import { cookies } from 'next/headers'\n00532| \n00533| export async function exampleAction() {\n00534| // Get cookie\n00535| const cookieStore = await cookies()\n00536| \n00537| // Get cookie\n00538| cookieStore.get('name')?.value\n00539| \n00540| // Set cookie\n00541| cookieStore.set('name', 'Delba')\n00542| \n00543| // Delete cookie\n00544| cookieStore.delete('name')\n00545| }\n00546| ```\n00547| \n00548| ### useEffect\n00549| \n00550| You can use the React [`useEffect`](https://react.dev/reference/react/useEffect) hook to invoke a Server Action when the component mounts or a dependency changes. This is useful for mutations that depend on global events or need to be triggered automatically. For example, `onKeyDown` for app shortcuts, an intersection observer hook for infinite scrolling, or when the component mounts to update a view count:\n00551| \n00552| ```tsx filename=\"app/view-count.tsx\" switcher\n00553| 'use client'\n00554| \n00555| import { incrementViews } from './actions'\n00556| import { useState, useEffect, useTransition } from 'react'\n00557| \n00558| export default function ViewCount({ initialViews }: { initialViews: number }) {\n00559| const [views, setViews] = useState(initialViews)\n00560| const [isPending, startTransition] = useTransition()\n00561| \n00562| useEffect(() => {\n00563| startTransition(async () => {\n00564| const updatedViews = await incrementViews()\n00565| setViews(updatedViews)\n00566| })\n00567| }, [])\n00568| \n00569| // You can use `isPending` to give users feedback\n00570| return
Total Views: {views}
\n00571| }\n00572| ```\n00573| \n00574| ```jsx filename=\"app/view-count.js\" switcher\n00575| 'use client'\n00576| \n00577| import { incrementViews } from './actions'\n00578| import { useState, useEffect, useTransition } from 'react'\n00579| \n00580| export default function ViewCount({ initialViews }) {\n00581| const [views, setViews] = useState(initialViews)\n00582| const [isPending, startTransition] = useTransition()\n00583| \n00584| useEffect(() => {\n00585| startTransition(async () => {\n00586| const updatedViews = await incrementViews()\n00587| setViews(updatedViews)\n00588| })\n00589| }, [])\n00590| \n00591| // You can use `isPending` to give users feedback\n00592| return
Total Views: {views}
\n00593| }\n00594| ```\n00595| \n\n(End of file - total 595 lines)\n
",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/01-getting-started/07-mutating-data.md"
+ },
+ "output": "\n00001| ---\n00002| title: Mutating Data\n00003| description: Learn how to mutate data using Server Functions and Server Actions in Next.js.\n00004| related:\n00005| title: API Reference\n00006| description: Learn more about the features mentioned in this page by reading the API Reference.\n00007| links:\n00008| - app/api-reference/functions/revalidatePath\n00009| - app/api-reference/functions/revalidateTag\n00010| - app/api-reference/functions/redirect\n00011| ---\n00012| \n00013| You can mutate data in Next.js using [React Server Functions](https://react.dev/reference/rsc/server-functions). This page will go through how you can [create](#creating-server-functions) and [invoke](#invoking-server-functions) Server Functions.\n00014| \n00015| ## What are Server Functions?\n00016| \n00017| A **Server Function** is an asynchronous function that runs on the server. You can call them from the client through a network request, which is why they must be asynchronous.\n00018| \n00019| In an `action` or mutation context, they are also called **Server Actions**.\n00020| \n00021| By convention, a Server Action is an async function used with [`startTransition`](https://react.dev/reference/react/startTransition). This happens automatically when the function is:\n00022| \n00023| - Passed to a `
` using the `action` prop.\n00024| - Passed to a `` using the `formAction` prop.\n00025| \n00026| When an action is invoked, Next.js can return both the updated UI and new data in a single server roundtrip.\n00027| \n00028| Behind the scenes, actions use the `POST` method, and only this HTTP method can invoke them.\n00029| \n00030| > [!WARNING]\n00031| > Server Functions are reachable via direct POST requests, not just through your application's UI. Always verify authentication and authorization inside every Server Function. See the [Data Security guide](/docs/app/guides/data-security#authentication-and-authorization) for recommended patterns.\n00032| \n00033| > **Good to know:** A Server Action is a Server Function used in a specific way (for handling form submissions and mutations). Server Function is the broader term.\n00034| \n00035| ## Creating Server Functions\n00036| \n00037| A Server Function can be defined by using the [`use server`](https://react.dev/reference/rsc/use-server) directive. You can place the directive at the top of an **asynchronous** function to mark the function as a Server Function, or at the top of a separate file to mark all exports of that file.\n00038| \n00039| ```ts filename=\"app/lib/actions.ts\" switcher\n00040| import { auth } from '@/lib/auth'\n00041| \n00042| export async function createPost(formData: FormData) {\n00043| 'use server'\n00044| const session = await auth()\n00045| if (!session?.user) {\n00046| throw new Error('Unauthorized')\n00047| }\n00048| \n00049| const title = formData.get('title')\n00050| const content = formData.get('content')\n00051| \n00052| // Mutate data\n00053| // Revalidate cache\n00054| }\n00055| \n00056| export async function deletePost(formData: FormData) {\n00057| 'use server'\n00058| const session = await auth()\n00059| if (!session?.user) {\n00060| throw new Error('Unauthorized')\n00061| }\n00062| \n00063| const id = formData.get('id')\n00064| \n00065| // Verify the user owns this resource before deleting\n00066| // Mutate data\n00067| // Revalidate cache\n00068| }\n00069| ```\n00070| \n00071| ```js filename=\"app/lib/actions.js\" switcher\n00072| import { auth } from '@/lib/auth'\n00073| \n00074| export async function createPost(formData) {\n00075| 'use server'\n00076| const session = await auth()\n00077| if (!session?.user) {\n00078| throw new Error('Unauthorized')\n00079| }\n00080| \n00081| const title = formData.get('title')\n00082| const content = formData.get('content')\n00083| \n00084| // Mutate data\n00085| // Revalidate cache\n00086| }\n00087| \n00088| export async function deletePost(formData) {\n00089| 'use server'\n00090| const session = await auth()\n00091| if (!session?.user) {\n00092| throw new Error('Unauthorized')\n00093| }\n00094| \n00095| const id = formData.get('id')\n00096| \n00097| // Verify the user owns this resource before deleting\n00098| // Mutate data\n00099| // Revalidate cache\n00100| }\n00101| ```\n00102| \n00103| ### Server Components\n00104| \n00105| Server Functions can be inlined in Server Components by adding the `\"use server\"` directive to the top of the function body:\n00106| \n00107| ```tsx filename=\"app/page.tsx\" switcher\n00108| export default function Page() {\n00109| // Server Action\n00110| async function createPost(formData: FormData) {\n00111| 'use server'\n00112| // ...\n00113| }\n00114| \n00115| return <>>\n00116| }\n00117| ```\n00118| \n00119| ```jsx filename=\"app/page.js\" switcher\n00120| export default function Page() {\n00121| // Server Action\n00122| async function createPost(formData) {\n00123| 'use server'\n00124| // ...\n00125| }\n00126| \n00127| return <>>\n00128| }\n00129| ```\n00130| \n00131| > **Good to know:** Server Components support progressive enhancement by default, meaning forms that call Server Actions will be submitted even if JavaScript hasn't loaded yet or is disabled.\n00132| \n00133| ### Client Components\n00134| \n00135| It's not possible to define Server Functions in Client Components. However, you can invoke them in Client Components by importing them from a file that has the `\"use server\"` directive at the top of it:\n00136| \n00137| ```ts filename=\"app/actions.ts\" switcher\n00138| 'use server'\n00139| \n00140| export async function createPost() {}\n00141| ```\n00142| \n00143| ```js filename=\"app/actions.js\" switcher\n00144| 'use server'\n00145| \n00146| export async function createPost() {}\n00147| ```\n00148| \n00149| ```tsx filename=\"app/ui/button.tsx\" switcher\n00150| 'use client'\n00151| \n00152| import { createPost } from '@/app/actions'\n00153| \n00154| export function Button() {\n00155| return Create\n00156| }\n00157| ```\n00158| \n00159| ```jsx filename=\"app/ui/button.js\" switcher\n00160| 'use client'\n00161| \n00162| import { createPost } from '@/app/actions'\n00163| \n00164| export function Button() {\n00165| return Create\n00166| }\n00167| ```\n00168| \n00169| > **Good to know:** In Client Components, forms invoking Server Actions will queue submissions if JavaScript isn't loaded yet, and will be prioritized for hydration. After hydration, the browser does not refresh on form submission.\n00170| \n00171| ### Passing actions as props\n00172| \n00173| You can also pass an action to a Client Component as a prop:\n00174| \n00175| ```jsx\n00176| \n00177| ```\n00178| \n00179| ```tsx filename=\"app/client-component.tsx\" switcher\n00180| 'use client'\n00181| \n00182| export default function ClientComponent({\n00183| updateItemAction,\n00184| }: {\n00185| updateItemAction: (formData: FormData) => void\n00186| }) {\n00187| return
\n00196| }\n00197| ```\n00198| \n00199| ## Invoking Server Functions\n00200| \n00201| There are two main ways you can invoke a Server Function:\n00202| \n00203| 1. [Forms](#forms) in Server and Client Components\n00204| 2. [Event Handlers](#event-handlers) and [useEffect](#useeffect) in Client Components\n00205| \n00206| > **Good to know:** Server Functions are designed for server-side mutations. The client currently dispatches and awaits them one at a time. This is an implementation detail and may change. If you need parallel data fetching, use [data fetching](/docs/app/getting-started/fetching-data#server-components) in Server Components, or perform parallel work inside a single Server Function or [Route Handler](/docs/app/guides/backend-for-frontend#manipulating-data).\n00207| \n00208| ### Forms\n00209| \n00210| React extends the HTML [`
`](https://react.dev/reference/react-dom/components/form) element to allow a Server Function to be invoked with the HTML `action` prop.\n00211| \n00212| When invoked in a form, the function automatically receives the [`FormData`](https://developer.mozilla.org/docs/Web/API/FormData/FormData) object. You can extract the data using the native [`FormData` methods](https://developer.mozilla.org/en-US/docs/Web/API/FormData#instance_methods):\n00213| \n00214| ```tsx filename=\"app/ui/form.tsx\" switcher\n00215| import { createPost } from '@/app/actions'\n00216| \n00217| export function Form() {\n00218| return (\n00219|
\n00321| {\n00323| const updatedLikes = await incrementLike()\n00324| setLikes(updatedLikes)\n00325| }}\n00326| >\n00327| Like\n00328| \n00329| >\n00330| )\n00331| }\n00332| ```\n00333| \n00334| ## Examples\n00335| \n00336| ### Showing a pending state\n00337| \n00338| While executing a Server Function, you can show a loading indicator with React's [`useActionState`](https://react.dev/reference/react/useActionState) hook. This hook returns a `pending` boolean:\n00339| \n00340| ```tsx filename=\"app/ui/button.tsx\" switcher\n00341| 'use client'\n00342| \n00343| import { useActionState, startTransition } from 'react'\n00344| import { createPost } from '@/app/actions'\n00345| import { LoadingSpinner } from '@/app/ui/loading-spinner'\n00346| \n00347| export function Button() {\n00348| const [state, action, pending] = useActionState(createPost, false)\n00349| \n00350| return (\n00351| startTransition(action)}>\n00352| {pending ? : 'Create Post'}\n00353| \n00354| )\n00355| }\n00356| ```\n00357| \n00358| ```jsx filename=\"app/ui/button.js\" switcher\n00359| 'use client'\n00360| \n00361| import { useActionState, startTransition } from 'react'\n00362| import { createPost } from '@/app/actions'\n00363| import { LoadingSpinner } from '@/app/ui/loading-spinner'\n00364| \n00365| export function Button() {\n00366| const [state, action, pending] = useActionState(createPost, false)\n00367| \n00368| return (\n00369| startTransition(action)}>\n00370| {pending ? : 'Create Post'}\n00371| \n00372| )\n00373| }\n00374| ```\n00375| \n00376| ### Refresh data\n00377| \n00378| After a mutation, you may want to refresh the current page to show the latest data. You can do this by calling [`refresh`](/docs/app/api-reference/functions/refresh) from `next/cache` in a Server Action:\n00379| \n00380| ```ts filename=\"app/lib/actions.ts\" switcher\n00381| 'use server'\n00382| \n00383| import { auth } from '@/lib/auth'\n00384| import { refresh } from 'next/cache'\n00385| \n00386| export async function updatePost(formData: FormData) {\n00387| const session = await auth()\n00388| if (!session?.user) {\n00389| throw new Error('Unauthorized')\n00390| }\n00391| // Mutate data\n00392| // ...\n00393| \n00394| refresh()\n00395| }\n00396| ```\n00397| \n00398| ```js filename=\"app/lib/actions.js\" switcher\n00399| 'use server'\n00400| \n00401| import { auth } from '@/lib/auth'\n00402| import { refresh } from 'next/cache'\n00403| \n00404| export async function updatePost(formData) {\n00405| const session = await auth()\n00406| if (!session?.user) {\n00407| throw new Error('Unauthorized')\n00408| }\n00409| // Mutate data\n00410| // ...\n00411| \n00412| refresh()\n00413| }\n00414| ```\n00415| \n00416| This refreshes the client router, ensuring the UI reflects the latest state. The `refresh()` function does not revalidate tagged data. To revalidate tagged data, use [`updateTag`](/docs/app/api-reference/functions/updateTag) or [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) instead.\n00417| \n00418| ### Revalidate data\n00419| \n00420| After performing a mutation, you can revalidate the Next.js cache and show the updated data by calling [`revalidatePath`](/docs/app/api-reference/functions/revalidatePath) or [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) within the Server Function:\n00421| \n00422| ```ts filename=\"app/lib/actions.ts\" switcher\n00423| import { auth } from '@/lib/auth'\n00424| import { revalidatePath } from 'next/cache'\n00425| \n00426| export async function createPost(formData: FormData) {\n00427| 'use server'\n00428| const session = await auth()\n00429| if (!session?.user) {\n00430| throw new Error('Unauthorized')\n00431| }\n00432| // Mutate data\n00433| // ...\n00434| \n00435| revalidatePath('/posts')\n00436| }\n00437| ```\n00438| \n00439| ```js filename=\"app/actions.js\" switcher\n00440| import { auth } from '@/lib/auth'\n00441| import { revalidatePath } from 'next/cache'\n00442| \n00443| export async function createPost(formData) {\n00444| 'use server'\n00445| const session = await auth()\n00446| if (!session?.user) {\n00447| throw new Error('Unauthorized')\n00448| }\n00449| // Mutate data\n00450| // ...\n00451| revalidatePath('/posts')\n00452| }\n00453| ```\n00454| \n00455| ### Redirect after a mutation\n00456| \n00457| You may want to redirect the user to a different page after a mutation. You can do this by calling [`redirect`](/docs/app/api-reference/functions/redirect) within the Server Function.\n00458| \n00459| ```ts filename=\"app/lib/actions.ts\" switcher\n00460| 'use server'\n00461| \n00462| import { auth } from '@/lib/auth'\n00463| import { revalidatePath } from 'next/cache'\n00464| import { redirect } from 'next/navigation'\n00465| \n00466| export async function createPost(formData: FormData) {\n00467| const session = await auth()\n00468| if (!session?.user) {\n00469| throw new Error('Unauthorized')\n00470| }\n00471| // Mutate data\n00472| // ...\n00473| \n00474| revalidatePath('/posts')\n00475| redirect('/posts')\n00476| }\n00477| ```\n00478| \n00479| ```js filename=\"app/actions.js\" switcher\n00480| 'use server'\n00481| \n00482| import { auth } from '@/lib/auth'\n00483| import { revalidatePath } from 'next/cache'\n00484| import { redirect } from 'next/navigation'\n00485| \n00486| export async function createPost(formData) {\n00487| const session = await auth()\n00488| if (!session?.user) {\n00489| throw new Error('Unauthorized')\n00490| }\n00491| // Mutate data\n00492| // ...\n00493| \n00494| revalidatePath('/posts')\n00495| redirect('/posts')\n00496| }\n00497| ```\n00498| \n00499| Calling `redirect` [throws](/docs/app/api-reference/functions/redirect#behavior) a framework handled control-flow exception. Any code after it won't execute. If you need fresh data, call [`revalidatePath`](/docs/app/api-reference/functions/revalidatePath) or [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) beforehand.\n00500| \n00501| ### Cookies\n00502| \n00503| You can `get`, `set`, and `delete` cookies inside a Server Action using the [`cookies`](/docs/app/api-reference/functions/cookies) API.\n00504| \n00505| When you [set or delete](/docs/app/api-reference/functions/cookies#understanding-cookie-behavior-in-server-functions) a cookie in a Server Action, Next.js re-renders the current page and its layouts on the server so the **UI reflects the new cookie value**.\n00506| \n00507| > **Good to know**: The server update applies to the current React tree, re-rendering, mounting, or unmounting components, as needed. Client state is preserved for re-rendered components, and effects re-run if their dependencies changed.\n00508| \n00509| ```ts filename=\"app/actions.ts\" switcher\n00510| 'use server'\n00511| \n00512| import { cookies } from 'next/headers'\n00513| \n00514| export async function exampleAction() {\n00515| const cookieStore = await cookies()\n00516| \n00517| // Get cookie\n00518| cookieStore.get('name')?.value\n00519| \n00520| // Set cookie\n00521| cookieStore.set('name', 'Delba')\n00522| \n00523| // Delete cookie\n00524| cookieStore.delete('name')\n00525| }\n00526| ```\n00527| \n00528| ```js filename=\"app/actions.js\" switcher\n00529| 'use server'\n00530| \n00531| import { cookies } from 'next/headers'\n00532| \n00533| export async function exampleAction() {\n00534| // Get cookie\n00535| const cookieStore = await cookies()\n00536| \n00537| // Get cookie\n00538| cookieStore.get('name')?.value\n00539| \n00540| // Set cookie\n00541| cookieStore.set('name', 'Delba')\n00542| \n00543| // Delete cookie\n00544| cookieStore.delete('name')\n00545| }\n00546| ```\n00547| \n00548| ### useEffect\n00549| \n00550| You can use the React [`useEffect`](https://react.dev/reference/react/useEffect) hook to invoke a Server Action when the component mounts or a dependency changes. This is useful for mutations that depend on global events or need to be triggered automatically. For example, `onKeyDown` for app shortcuts, an intersection observer hook for infinite scrolling, or when the component mounts to update a view count:\n00551| \n00552| ```tsx filename=\"app/view-count.tsx\" switcher\n00553| 'use client'\n00554| \n00555| import { incrementViews } from './actions'\n00556| import { useState, useEffect, useTransition } from 'react'\n00557| \n00558| export default function ViewCount({ initialViews }: { initialViews: number }) {\n00559| const [views, setViews] = useState(initialViews)\n00560| const [isPending, startTransition] = useTransition()\n00561| \n00562| useEffect(() => {\n00563| startTransition(async () => {\n00564| const updatedViews = await incrementViews()\n00565| setViews(updatedViews)\n00566| })\n00567| }, [])\n00568| \n00569| // You can use `isPending` to give users feedback\n00570| return
Total Views: {views}
\n00571| }\n00572| ```\n00573| \n00574| ```jsx filename=\"app/view-count.js\" switcher\n00575| 'use client'\n00576| \n00577| import { incrementViews } from './actions'\n00578| import { useState, useEffect, useTransition } from 'react'\n00579| \n00580| export default function ViewCount({ initialViews }) {\n00581| const [views, setViews] = useState(initialViews)\n00582| const [isPending, startTransition] = useTransition()\n00583| \n00584| useEffect(() => {\n00585| startTransition(async () => {\n00586| const updatedViews = await incrementViews()\n00587| setViews(updatedViews)\n00588| })\n00589| }, [])\n00590| \n00591| // You can use `isPending` to give users feedback\n00592| return
Total Views: {views}
\n00593| }\n00594| ```\n00595| \n\n(End of file - total 595 lines)\n
",
+ "title": "node_modules/next/dist/docs/01-app/01-getting-started/07-mutating-data.md",
+ "metadata": {
+ "preview": "---\ntitle: Mutating Data\ndescription: Learn how to mutate data using Server Functions and Server Actions in Next.js.\nrelated:\n title: API Reference\n description: Learn more about the features mentioned in this page by reading the API Reference.\n links:\n - app/api-reference/functions/revalidatePath\n - app/api-reference/functions/revalidateTag\n - app/api-reference/functions/redirect\n---\n\nYou can mutate data in Next.js using [React Server Functions](https://react.dev/reference/rsc/server-functions). This page will go through how you can [create](#creating-server-functions) and [invoke](#invoking-server-functions) Server Functions.\n\n## What are Server Functions?\n\nA **Server Function** is an asynchronous function that runs on the server. You can call them from the client through a network request, which is why they must be asynchronous.\n\nIn an `action` or mutation context, they are also called **Server Actions**.\n"
+ },
+ "time": {
+ "start": 1781392539714,
+ "end": 1781392539726
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:39.966Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "args": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/01-getting-started/09-revalidating.md",
+ "_extractedPath": "/workspace/node_modules/next/dist/docs/01-app/01-getting-started/09-revalidating.md"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392539966,
+ "sessionID": "ses_13cbb6ca7ffeDluJj6gL6KvvXT",
+ "part": {
+ "id": "prt_ec345004c001HptszOF9EicETk",
+ "sessionID": "ses_13cbb6ca7ffeDluJj6gL6KvvXT",
+ "messageID": "msg_ec344eb5d001IcU2v22Hnj8HEM",
+ "type": "tool",
+ "callID": "read_15",
+ "tool": "read",
+ "state": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/01-getting-started/09-revalidating.md"
+ },
+ "output": "\n00001| ---\n00002| title: Revalidating\n00003| description: Learn how to revalidate cached data using time-based and on-demand strategies.\n00004| related:\n00005| title: API Reference\n00006| description: Learn more about the APIs mentioned on this page.\n00007| links:\n00008| - app/api-reference/functions/cacheLife\n00009| - app/api-reference/functions/cacheTag\n00010| - app/api-reference/functions/revalidateTag\n00011| - app/api-reference/functions/updateTag\n00012| - app/api-reference/functions/revalidatePath\n00013| ---\n00014| \n00015| > This page covers revalidation with [Cache Components](/docs/app/api-reference/config/next-config-js/cacheComponents), enabled by setting [`cacheComponents: true`](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.ts` file. If you're not using Cache Components, see the [Caching and Revalidating (Previous Model)](/docs/app/guides/caching-without-cache-components) guide.\n00016| \n00017| Revalidation is the process of updating cached data. It lets you keep serving fast, cached responses while ensuring content stays fresh. There are two strategies:\n00018| \n00019| - **Time-based revalidation**: Automatically refresh cached data after a set duration using [`cacheLife`](#cachelife).\n00020| - **On-demand revalidation**: Manually invalidate cached data after a mutation using [`revalidateTag`](#revalidatetag), [`updateTag`](#updatetag), or [`revalidatePath`](#revalidatepath).\n00021| \n00022| ## `cacheLife`\n00023| \n00024| [`cacheLife`](/docs/app/api-reference/functions/cacheLife) controls how long cached data remains valid. Use it inside a [`use cache`](/docs/app/api-reference/directives/use-cache) scope to set the cache lifetime.\n00025| \n00026| ```tsx filename=\"app/lib/data.ts\" highlight={1,4,5}\n00027| import { cacheLife } from 'next/cache'\n00028| \n00029| export async function getProducts() {\n00030| 'use cache'\n00031| cacheLife('hours')\n00032| return db.query('SELECT * FROM products')\n00033| }\n00034| ```\n00035| \n00036| `cacheLife` accepts a profile name or a custom configuration object:\n00037| \n00038| | Profile | `stale` | `revalidate` | `expire` |\n00039| | --------- | ------- | ------------ | -------- |\n00040| | `default` | 5m | 15m | never |\n00041| | `seconds` | 30s | 1s | 60s |\n00042| | `minutes` | 5m | 1m | 1h |\n00043| | `hours` | 5m | 1h | 1d |\n00044| | `days` | 5m | 1d | 1w |\n00045| | `weeks` | 5m | 1w | 30d |\n00046| | `max` | 5m | 30d | 1y |\n00047| \n00048| For fine-grained control, pass an object:\n00049| \n00050| ```tsx highlight={2-6}\n00051| 'use cache'\n00052| cacheLife({\n00053| stale: 3600, // 1 hour until considered stale\n00054| revalidate: 7200, // 2 hours until revalidated\n00055| expire: 86400, // 1 day until expired\n00056| })\n00057| ```\n00058| \n00059| > **Good to know:** A cache is considered \"short-lived\" when it uses the `seconds` profile, `revalidate: 0`, or `expire` under 5 minutes. Short-lived caches are automatically excluded from prerenders and become dynamic holes instead. See [Prerendering behavior](/docs/app/api-reference/functions/cacheLife#prerendering-behavior) for details.\n00060| \n00061| See the [`cacheLife` API reference](/docs/app/api-reference/functions/cacheLife) for all profiles and custom configuration options.\n00062| \n00063| ## `cacheTag`\n00064| \n00065| [`cacheTag`](/docs/app/api-reference/functions/cacheTag) lets you tag cached data so it can be invalidated on-demand. Use it inside a [`use cache`](/docs/app/api-reference/directives/use-cache) scope:\n00066| \n00067| ```tsx filename=\"app/lib/data.ts\" switcher\n00068| import { cacheTag } from 'next/cache'\n00069| \n00070| export async function getProducts() {\n00071| 'use cache'\n00072| cacheTag('products')\n00073| return db.query('SELECT * FROM products')\n00074| }\n00075| ```\n00076| \n00077| ```jsx filename=\"app/lib/data.js\" switcher\n00078| import { cacheTag } from 'next/cache'\n00079| \n00080| export async function getProducts() {\n00081| 'use cache'\n00082| cacheTag('products')\n00083| return db.query('SELECT * FROM products')\n00084| }\n00085| ```\n00086| \n00087| Once tagged, invalidate the cache using [`revalidateTag`](#revalidatetag) or [`updateTag`](#updatetag).\n00088| \n00089| See the [`cacheTag` API reference](/docs/app/api-reference/functions/cacheTag) to learn more.\n00090| \n00091| ## `revalidateTag`\n00092| \n00093| `revalidateTag` invalidates cache entries by tag using stale-while-revalidate semantics — stale content is served immediately while fresh content loads in the background. This is ideal for content where a slight delay in updates is acceptable, like blog posts or product catalogs.\n00094| \n00095| ```tsx filename=\"app/lib/actions.ts\" highlight={1,5} switcher\n00096| import { revalidateTag } from 'next/cache'\n00097| \n00098| export async function updateUser(id: string) {\n00099| // Mutate data\n00100| revalidateTag('user', 'max') // Recommended: stale-while-revalidate\n00101| }\n00102| ```\n00103| \n00104| ```jsx filename=\"app/lib/actions.js\" highlight={1,5} switcher\n00105| import { revalidateTag } from 'next/cache'\n00106| \n00107| export async function updateUser(id) {\n00108| // Mutate data\n00109| revalidateTag('user', 'max') // Recommended: stale-while-revalidate\n00110| }\n00111| ```\n00112| \n00113| You can reuse the same tag in multiple functions to revalidate them all at once. Call `revalidateTag` in a [Server Action](/docs/app/getting-started/mutating-data) or [Route Handler](/docs/app/api-reference/file-conventions/route).\n00114| \n00115| > **Good to know:** The second argument sets how long stale content can be served while fresh content generates in the background. Once it expires, subsequent requests block until fresh content is ready. Using `'max'` gives the longest stale window.\n00116| \n00117| See the [`revalidateTag` API reference](/docs/app/api-reference/functions/revalidateTag) to learn more.\n00118| \n00119| ## `updateTag`\n00120| \n00121| `updateTag` immediately expires cached data for read-your-own-writes scenarios — the user sees their change right away instead of stale content. Unlike `revalidateTag`, it can only be used in [Server Actions](/docs/app/getting-started/mutating-data).\n00122| \n00123| ```tsx filename=\"app/lib/actions.ts\" highlight={1,12} switcher\n00124| import { updateTag } from 'next/cache'\n00125| import { redirect } from 'next/navigation'\n00126| \n00127| export async function createPost(formData: FormData) {\n00128| const post = await db.post.create({\n00129| data: {\n00130| title: formData.get('title'),\n00131| content: formData.get('content'),\n00132| },\n00133| })\n00134| \n00135| updateTag('posts')\n00136| redirect(`/posts/${post.id}`)\n00137| }\n00138| ```\n00139| \n00140| ```jsx filename=\"app/lib/actions.js\" highlight={1,12} switcher\n00141| import { updateTag } from 'next/cache'\n00142| import { redirect } from 'next/navigation'\n00143| \n00144| export async function createPost(formData) {\n00145| const post = await db.post.create({\n00146| data: {\n00147| title: formData.get('title'),\n00148| content: formData.get('content'),\n00149| },\n00150| })\n00151| \n00152| updateTag('posts')\n00153| redirect(`/posts/${post.id}`)\n00154| }\n00155| ```\n00156| \n00157| | | `updateTag` | `revalidateTag` |\n00158| | ------------ | --------------------------------------------- | ------------------------------------ |\n00159| | **Where** | Server Actions only | Server Actions and Route Handlers |\n00160| | **Behavior** | Immediately expires cache | Stale-while-revalidate |\n00161| | **Use case** | Read-your-own-writes (user sees their change) | Background refresh (slight delay OK) |\n00162| \n00163| See the [`updateTag` API reference](/docs/app/api-reference/functions/updateTag) to learn more.\n00164| \n00165| ## `revalidatePath`\n00166| \n00167| `revalidatePath` invalidates all cached data for a specific route path. Use it when you want to revalidate a route without knowing which tags are associated with it.\n00168| \n00169| ```tsx filename=\"app/lib/actions.ts\" highlight={1,5} switcher\n00170| import { revalidatePath } from 'next/cache'\n00171| \n00172| export async function updateUser(id: string) {\n00173| // Mutate data\n00174| revalidatePath('/profile')\n00175| }\n00176| ```\n00177| \n00178| ```jsx filename=\"app/lib/actions.js\" highlight={1,5} switcher\n00179| import { revalidatePath } from 'next/cache'\n00180| \n00181| export async function updateUser(id) {\n00182| // Mutate data\n00183| revalidatePath('/profile')\n00184| }\n00185| ```\n00186| \n00187| > **Good to know**: Prefer tag-based revalidation (`revalidateTag`/`updateTag`) over path-based when possible — it's more precise and avoids over-invalidating.\n00188| \n00189| See the [`revalidatePath` API reference](/docs/app/api-reference/functions/revalidatePath) to learn more.\n00190| \n00191| ## What should I cache?\n00192| \n00193| Cache data that doesn't depend on [runtime data](/docs/app/getting-started/caching#working-with-runtime-apis) and that you're OK serving from cache for a period of time. Use `use cache` with `cacheLife` to describe that behavior.\n00194| \n00195| For content management systems with update mechanisms, use tags with longer cache durations and rely on `revalidateTag` to refresh content when it actually changes, rather than expiring the cache preemptively.\n00196| \n00197| > **Good to know:** In serverless environments, in-memory cache entries may not persist across revalidations. See [runtime caching considerations](/docs/app/api-reference/directives/use-cache#runtime-caching-considerations) for details.\n00198| \n\n(End of file - total 198 lines)\n",
+ "title": "node_modules/next/dist/docs/01-app/01-getting-started/09-revalidating.md",
+ "metadata": {
+ "preview": "---\ntitle: Revalidating\ndescription: Learn how to revalidate cached data using time-based and on-demand strategies.\nrelated:\n title: API Reference\n description: Learn more about the APIs mentioned on this page.\n links:\n - app/api-reference/functions/cacheLife\n - app/api-reference/functions/cacheTag\n - app/api-reference/functions/revalidateTag\n - app/api-reference/functions/updateTag\n - app/api-reference/functions/revalidatePath\n---\n\n> This page covers revalidation with [Cache Components](/docs/app/api-reference/config/next-config-js/cacheComponents), enabled by setting [`cacheComponents: true`](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.ts` file. If you're not using Cache Components, see the [Caching and Revalidating (Previous Model)](/docs/app/guides/caching-without-cache-components) guide.\n\nRevalidation is the process of updating cached data. It lets you keep serving fast, cached responses while ensuring content stays fresh. There are two strategies:\n\n- **Time-based revalidation**: Automatically refresh cached data after a set duration using [`cacheLife`](#cachelife).\n- **On-demand revalidation**: Manually invalidate cached data after a mutation using [`revalidateTag`](#revalidatetag), [`updateTag`](#updatetag), or [`revalidatePath`](#revalidatepath)."
+ },
+ "time": {
+ "start": 1781392539956,
+ "end": 1781392539963
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:39.966Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| ---\n00002| title: Revalidating\n00003| description: Learn how to revalidate cached data using time-based and on-demand strategies.\n00004| related:\n00005| title: API Reference\n00006| description: Learn more about the APIs mentioned on this page.\n00007| links:\n00008| - app/api-reference/functions/cacheLife\n00009| - app/api-reference/functions/cacheTag\n00010| - app/api-reference/functions/revalidateTag\n00011| - app/api-reference/functions/updateTag\n00012| - app/api-reference/functions/revalidatePath\n00013| ---\n00014| \n00015| > This page covers revalidation with [Cache Components](/docs/app/api-reference/config/next-config-js/cacheComponents), enabled by setting [`cacheComponents: true`](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.ts` file. If you're not using Cache Components, see the [Caching and Revalidating (Previous Model)](/docs/app/guides/caching-without-cache-components) guide.\n00016| \n00017| Revalidation is the process of updating cached data. It lets you keep serving fast, cached responses while ensuring content stays fresh. There are two strategies:\n00018| \n00019| - **Time-based revalidation**: Automatically refresh cached data after a set duration using [`cacheLife`](#cachelife).\n00020| - **On-demand revalidation**: Manually invalidate cached data after a mutation using [`revalidateTag`](#revalidatetag), [`updateTag`](#updatetag), or [`revalidatePath`](#revalidatepath).\n00021| \n00022| ## `cacheLife`\n00023| \n00024| [`cacheLife`](/docs/app/api-reference/functions/cacheLife) controls how long cached data remains valid. Use it inside a [`use cache`](/docs/app/api-reference/directives/use-cache) scope to set the cache lifetime.\n00025| \n00026| ```tsx filename=\"app/lib/data.ts\" highlight={1,4,5}\n00027| import { cacheLife } from 'next/cache'\n00028| \n00029| export async function getProducts() {\n00030| 'use cache'\n00031| cacheLife('hours')\n00032| return db.query('SELECT * FROM products')\n00033| }\n00034| ```\n00035| \n00036| `cacheLife` accepts a profile name or a custom configuration object:\n00037| \n00038| | Profile | `stale` | `revalidate` | `expire` |\n00039| | --------- | ------- | ------------ | -------- |\n00040| | `default` | 5m | 15m | never |\n00041| | `seconds` | 30s | 1s | 60s |\n00042| | `minutes` | 5m | 1m | 1h |\n00043| | `hours` | 5m | 1h | 1d |\n00044| | `days` | 5m | 1d | 1w |\n00045| | `weeks` | 5m | 1w | 30d |\n00046| | `max` | 5m | 30d | 1y |\n00047| \n00048| For fine-grained control, pass an object:\n00049| \n00050| ```tsx highlight={2-6}\n00051| 'use cache'\n00052| cacheLife({\n00053| stale: 3600, // 1 hour until considered stale\n00054| revalidate: 7200, // 2 hours until revalidated\n00055| expire: 86400, // 1 day until expired\n00056| })\n00057| ```\n00058| \n00059| > **Good to know:** A cache is considered \"short-lived\" when it uses the `seconds` profile, `revalidate: 0`, or `expire` under 5 minutes. Short-lived caches are automatically excluded from prerenders and become dynamic holes instead. See [Prerendering behavior](/docs/app/api-reference/functions/cacheLife#prerendering-behavior) for details.\n00060| \n00061| See the [`cacheLife` API reference](/docs/app/api-reference/functions/cacheLife) for all profiles and custom configuration options.\n00062| \n00063| ## `cacheTag`\n00064| \n00065| [`cacheTag`](/docs/app/api-reference/functions/cacheTag) lets you tag cached data so it can be invalidated on-demand. Use it inside a [`use cache`](/docs/app/api-reference/directives/use-cache) scope:\n00066| \n00067| ```tsx filename=\"app/lib/data.ts\" switcher\n00068| import { cacheTag } from 'next/cache'\n00069| \n00070| export async function getProducts() {\n00071| 'use cache'\n00072| cacheTag('products')\n00073| return db.query('SELECT * FROM products')\n00074| }\n00075| ```\n00076| \n00077| ```jsx filename=\"app/lib/data.js\" switcher\n00078| import { cacheTag } from 'next/cache'\n00079| \n00080| export async function getProducts() {\n00081| 'use cache'\n00082| cacheTag('products')\n00083| return db.query('SELECT * FROM products')\n00084| }\n00085| ```\n00086| \n00087| Once tagged, invalidate the cache using [`revalidateTag`](#revalidatetag) or [`updateTag`](#updatetag).\n00088| \n00089| See the [`cacheTag` API reference](/docs/app/api-reference/functions/cacheTag) to learn more.\n00090| \n00091| ## `revalidateTag`\n00092| \n00093| `revalidateTag` invalidates cache entries by tag using stale-while-revalidate semantics — stale content is served immediately while fresh content loads in the background. This is ideal for content where a slight delay in updates is acceptable, like blog posts or product catalogs.\n00094| \n00095| ```tsx filename=\"app/lib/actions.ts\" highlight={1,5} switcher\n00096| import { revalidateTag } from 'next/cache'\n00097| \n00098| export async function updateUser(id: string) {\n00099| // Mutate data\n00100| revalidateTag('user', 'max') // Recommended: stale-while-revalidate\n00101| }\n00102| ```\n00103| \n00104| ```jsx filename=\"app/lib/actions.js\" highlight={1,5} switcher\n00105| import { revalidateTag } from 'next/cache'\n00106| \n00107| export async function updateUser(id) {\n00108| // Mutate data\n00109| revalidateTag('user', 'max') // Recommended: stale-while-revalidate\n00110| }\n00111| ```\n00112| \n00113| You can reuse the same tag in multiple functions to revalidate them all at once. Call `revalidateTag` in a [Server Action](/docs/app/getting-started/mutating-data) or [Route Handler](/docs/app/api-reference/file-conventions/route).\n00114| \n00115| > **Good to know:** The second argument sets how long stale content can be served while fresh content generates in the background. Once it expires, subsequent requests block until fresh content is ready. Using `'max'` gives the longest stale window.\n00116| \n00117| See the [`revalidateTag` API reference](/docs/app/api-reference/functions/revalidateTag) to learn more.\n00118| \n00119| ## `updateTag`\n00120| \n00121| `updateTag` immediately expires cached data for read-your-own-writes scenarios — the user sees their change right away instead of stale content. Unlike `revalidateTag`, it can only be used in [Server Actions](/docs/app/getting-started/mutating-data).\n00122| \n00123| ```tsx filename=\"app/lib/actions.ts\" highlight={1,12} switcher\n00124| import { updateTag } from 'next/cache'\n00125| import { redirect } from 'next/navigation'\n00126| \n00127| export async function createPost(formData: FormData) {\n00128| const post = await db.post.create({\n00129| data: {\n00130| title: formData.get('title'),\n00131| content: formData.get('content'),\n00132| },\n00133| })\n00134| \n00135| updateTag('posts')\n00136| redirect(`/posts/${post.id}`)\n00137| }\n00138| ```\n00139| \n00140| ```jsx filename=\"app/lib/actions.js\" highlight={1,12} switcher\n00141| import { updateTag } from 'next/cache'\n00142| import { redirect } from 'next/navigation'\n00143| \n00144| export async function createPost(formData) {\n00145| const post = await db.post.create({\n00146| data: {\n00147| title: formData.get('title'),\n00148| content: formData.get('content'),\n00149| },\n00150| })\n00151| \n00152| updateTag('posts')\n00153| redirect(`/posts/${post.id}`)\n00154| }\n00155| ```\n00156| \n00157| | | `updateTag` | `revalidateTag` |\n00158| | ------------ | --------------------------------------------- | ------------------------------------ |\n00159| | **Where** | Server Actions only | Server Actions and Route Handlers |\n00160| | **Behavior** | Immediately expires cache | Stale-while-revalidate |\n00161| | **Use case** | Read-your-own-writes (user sees their change) | Background refresh (slight delay OK) |\n00162| \n00163| See the [`updateTag` API reference](/docs/app/api-reference/functions/updateTag) to learn more.\n00164| \n00165| ## `revalidatePath`\n00166| \n00167| `revalidatePath` invalidates all cached data for a specific route path. Use it when you want to revalidate a route without knowing which tags are associated with it.\n00168| \n00169| ```tsx filename=\"app/lib/actions.ts\" highlight={1,5} switcher\n00170| import { revalidatePath } from 'next/cache'\n00171| \n00172| export async function updateUser(id: string) {\n00173| // Mutate data\n00174| revalidatePath('/profile')\n00175| }\n00176| ```\n00177| \n00178| ```jsx filename=\"app/lib/actions.js\" highlight={1,5} switcher\n00179| import { revalidatePath } from 'next/cache'\n00180| \n00181| export async function updateUser(id) {\n00182| // Mutate data\n00183| revalidatePath('/profile')\n00184| }\n00185| ```\n00186| \n00187| > **Good to know**: Prefer tag-based revalidation (`revalidateTag`/`updateTag`) over path-based when possible — it's more precise and avoids over-invalidating.\n00188| \n00189| See the [`revalidatePath` API reference](/docs/app/api-reference/functions/revalidatePath) to learn more.\n00190| \n00191| ## What should I cache?\n00192| \n00193| Cache data that doesn't depend on [runtime data](/docs/app/getting-started/caching#working-with-runtime-apis) and that you're OK serving from cache for a period of time. Use `use cache` with `cacheLife` to describe that behavior.\n00194| \n00195| For content management systems with update mechanisms, use tags with longer cache durations and rely on `revalidateTag` to refresh content when it actually changes, rather than expiring the cache preemptively.\n00196| \n00197| > **Good to know:** In serverless environments, in-memory cache entries may not persist across revalidations. See [runtime caching considerations](/docs/app/api-reference/directives/use-cache#runtime-caching-considerations) for details.\n00198| \n\n(End of file - total 198 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/01-getting-started/09-revalidating.md"
+ },
+ "output": "\n00001| ---\n00002| title: Revalidating\n00003| description: Learn how to revalidate cached data using time-based and on-demand strategies.\n00004| related:\n00005| title: API Reference\n00006| description: Learn more about the APIs mentioned on this page.\n00007| links:\n00008| - app/api-reference/functions/cacheLife\n00009| - app/api-reference/functions/cacheTag\n00010| - app/api-reference/functions/revalidateTag\n00011| - app/api-reference/functions/updateTag\n00012| - app/api-reference/functions/revalidatePath\n00013| ---\n00014| \n00015| > This page covers revalidation with [Cache Components](/docs/app/api-reference/config/next-config-js/cacheComponents), enabled by setting [`cacheComponents: true`](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.ts` file. If you're not using Cache Components, see the [Caching and Revalidating (Previous Model)](/docs/app/guides/caching-without-cache-components) guide.\n00016| \n00017| Revalidation is the process of updating cached data. It lets you keep serving fast, cached responses while ensuring content stays fresh. There are two strategies:\n00018| \n00019| - **Time-based revalidation**: Automatically refresh cached data after a set duration using [`cacheLife`](#cachelife).\n00020| - **On-demand revalidation**: Manually invalidate cached data after a mutation using [`revalidateTag`](#revalidatetag), [`updateTag`](#updatetag), or [`revalidatePath`](#revalidatepath).\n00021| \n00022| ## `cacheLife`\n00023| \n00024| [`cacheLife`](/docs/app/api-reference/functions/cacheLife) controls how long cached data remains valid. Use it inside a [`use cache`](/docs/app/api-reference/directives/use-cache) scope to set the cache lifetime.\n00025| \n00026| ```tsx filename=\"app/lib/data.ts\" highlight={1,4,5}\n00027| import { cacheLife } from 'next/cache'\n00028| \n00029| export async function getProducts() {\n00030| 'use cache'\n00031| cacheLife('hours')\n00032| return db.query('SELECT * FROM products')\n00033| }\n00034| ```\n00035| \n00036| `cacheLife` accepts a profile name or a custom configuration object:\n00037| \n00038| | Profile | `stale` | `revalidate` | `expire` |\n00039| | --------- | ------- | ------------ | -------- |\n00040| | `default` | 5m | 15m | never |\n00041| | `seconds` | 30s | 1s | 60s |\n00042| | `minutes` | 5m | 1m | 1h |\n00043| | `hours` | 5m | 1h | 1d |\n00044| | `days` | 5m | 1d | 1w |\n00045| | `weeks` | 5m | 1w | 30d |\n00046| | `max` | 5m | 30d | 1y |\n00047| \n00048| For fine-grained control, pass an object:\n00049| \n00050| ```tsx highlight={2-6}\n00051| 'use cache'\n00052| cacheLife({\n00053| stale: 3600, // 1 hour until considered stale\n00054| revalidate: 7200, // 2 hours until revalidated\n00055| expire: 86400, // 1 day until expired\n00056| })\n00057| ```\n00058| \n00059| > **Good to know:** A cache is considered \"short-lived\" when it uses the `seconds` profile, `revalidate: 0`, or `expire` under 5 minutes. Short-lived caches are automatically excluded from prerenders and become dynamic holes instead. See [Prerendering behavior](/docs/app/api-reference/functions/cacheLife#prerendering-behavior) for details.\n00060| \n00061| See the [`cacheLife` API reference](/docs/app/api-reference/functions/cacheLife) for all profiles and custom configuration options.\n00062| \n00063| ## `cacheTag`\n00064| \n00065| [`cacheTag`](/docs/app/api-reference/functions/cacheTag) lets you tag cached data so it can be invalidated on-demand. Use it inside a [`use cache`](/docs/app/api-reference/directives/use-cache) scope:\n00066| \n00067| ```tsx filename=\"app/lib/data.ts\" switcher\n00068| import { cacheTag } from 'next/cache'\n00069| \n00070| export async function getProducts() {\n00071| 'use cache'\n00072| cacheTag('products')\n00073| return db.query('SELECT * FROM products')\n00074| }\n00075| ```\n00076| \n00077| ```jsx filename=\"app/lib/data.js\" switcher\n00078| import { cacheTag } from 'next/cache'\n00079| \n00080| export async function getProducts() {\n00081| 'use cache'\n00082| cacheTag('products')\n00083| return db.query('SELECT * FROM products')\n00084| }\n00085| ```\n00086| \n00087| Once tagged, invalidate the cache using [`revalidateTag`](#revalidatetag) or [`updateTag`](#updatetag).\n00088| \n00089| See the [`cacheTag` API reference](/docs/app/api-reference/functions/cacheTag) to learn more.\n00090| \n00091| ## `revalidateTag`\n00092| \n00093| `revalidateTag` invalidates cache entries by tag using stale-while-revalidate semantics — stale content is served immediately while fresh content loads in the background. This is ideal for content where a slight delay in updates is acceptable, like blog posts or product catalogs.\n00094| \n00095| ```tsx filename=\"app/lib/actions.ts\" highlight={1,5} switcher\n00096| import { revalidateTag } from 'next/cache'\n00097| \n00098| export async function updateUser(id: string) {\n00099| // Mutate data\n00100| revalidateTag('user', 'max') // Recommended: stale-while-revalidate\n00101| }\n00102| ```\n00103| \n00104| ```jsx filename=\"app/lib/actions.js\" highlight={1,5} switcher\n00105| import { revalidateTag } from 'next/cache'\n00106| \n00107| export async function updateUser(id) {\n00108| // Mutate data\n00109| revalidateTag('user', 'max') // Recommended: stale-while-revalidate\n00110| }\n00111| ```\n00112| \n00113| You can reuse the same tag in multiple functions to revalidate them all at once. Call `revalidateTag` in a [Server Action](/docs/app/getting-started/mutating-data) or [Route Handler](/docs/app/api-reference/file-conventions/route).\n00114| \n00115| > **Good to know:** The second argument sets how long stale content can be served while fresh content generates in the background. Once it expires, subsequent requests block until fresh content is ready. Using `'max'` gives the longest stale window.\n00116| \n00117| See the [`revalidateTag` API reference](/docs/app/api-reference/functions/revalidateTag) to learn more.\n00118| \n00119| ## `updateTag`\n00120| \n00121| `updateTag` immediately expires cached data for read-your-own-writes scenarios — the user sees their change right away instead of stale content. Unlike `revalidateTag`, it can only be used in [Server Actions](/docs/app/getting-started/mutating-data).\n00122| \n00123| ```tsx filename=\"app/lib/actions.ts\" highlight={1,12} switcher\n00124| import { updateTag } from 'next/cache'\n00125| import { redirect } from 'next/navigation'\n00126| \n00127| export async function createPost(formData: FormData) {\n00128| const post = await db.post.create({\n00129| data: {\n00130| title: formData.get('title'),\n00131| content: formData.get('content'),\n00132| },\n00133| })\n00134| \n00135| updateTag('posts')\n00136| redirect(`/posts/${post.id}`)\n00137| }\n00138| ```\n00139| \n00140| ```jsx filename=\"app/lib/actions.js\" highlight={1,12} switcher\n00141| import { updateTag } from 'next/cache'\n00142| import { redirect } from 'next/navigation'\n00143| \n00144| export async function createPost(formData) {\n00145| const post = await db.post.create({\n00146| data: {\n00147| title: formData.get('title'),\n00148| content: formData.get('content'),\n00149| },\n00150| })\n00151| \n00152| updateTag('posts')\n00153| redirect(`/posts/${post.id}`)\n00154| }\n00155| ```\n00156| \n00157| | | `updateTag` | `revalidateTag` |\n00158| | ------------ | --------------------------------------------- | ------------------------------------ |\n00159| | **Where** | Server Actions only | Server Actions and Route Handlers |\n00160| | **Behavior** | Immediately expires cache | Stale-while-revalidate |\n00161| | **Use case** | Read-your-own-writes (user sees their change) | Background refresh (slight delay OK) |\n00162| \n00163| See the [`updateTag` API reference](/docs/app/api-reference/functions/updateTag) to learn more.\n00164| \n00165| ## `revalidatePath`\n00166| \n00167| `revalidatePath` invalidates all cached data for a specific route path. Use it when you want to revalidate a route without knowing which tags are associated with it.\n00168| \n00169| ```tsx filename=\"app/lib/actions.ts\" highlight={1,5} switcher\n00170| import { revalidatePath } from 'next/cache'\n00171| \n00172| export async function updateUser(id: string) {\n00173| // Mutate data\n00174| revalidatePath('/profile')\n00175| }\n00176| ```\n00177| \n00178| ```jsx filename=\"app/lib/actions.js\" highlight={1,5} switcher\n00179| import { revalidatePath } from 'next/cache'\n00180| \n00181| export async function updateUser(id) {\n00182| // Mutate data\n00183| revalidatePath('/profile')\n00184| }\n00185| ```\n00186| \n00187| > **Good to know**: Prefer tag-based revalidation (`revalidateTag`/`updateTag`) over path-based when possible — it's more precise and avoids over-invalidating.\n00188| \n00189| See the [`revalidatePath` API reference](/docs/app/api-reference/functions/revalidatePath) to learn more.\n00190| \n00191| ## What should I cache?\n00192| \n00193| Cache data that doesn't depend on [runtime data](/docs/app/getting-started/caching#working-with-runtime-apis) and that you're OK serving from cache for a period of time. Use `use cache` with `cacheLife` to describe that behavior.\n00194| \n00195| For content management systems with update mechanisms, use tags with longer cache durations and rely on `revalidateTag` to refresh content when it actually changes, rather than expiring the cache preemptively.\n00196| \n00197| > **Good to know:** In serverless environments, in-memory cache entries may not persist across revalidations. See [runtime caching considerations](/docs/app/api-reference/directives/use-cache#runtime-caching-considerations) for details.\n00198| \n\n(End of file - total 198 lines)\n",
+ "title": "node_modules/next/dist/docs/01-app/01-getting-started/09-revalidating.md",
+ "metadata": {
+ "preview": "---\ntitle: Revalidating\ndescription: Learn how to revalidate cached data using time-based and on-demand strategies.\nrelated:\n title: API Reference\n description: Learn more about the APIs mentioned on this page.\n links:\n - app/api-reference/functions/cacheLife\n - app/api-reference/functions/cacheTag\n - app/api-reference/functions/revalidateTag\n - app/api-reference/functions/updateTag\n - app/api-reference/functions/revalidatePath\n---\n\n> This page covers revalidation with [Cache Components](/docs/app/api-reference/config/next-config-js/cacheComponents), enabled by setting [`cacheComponents: true`](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.ts` file. If you're not using Cache Components, see the [Caching and Revalidating (Previous Model)](/docs/app/guides/caching-without-cache-components) guide.\n\nRevalidation is the process of updating cached data. It lets you keep serving fast, cached responses while ensuring content stays fresh. There are two strategies:\n\n- **Time-based revalidation**: Automatically refresh cached data after a set duration using [`cacheLife`](#cachelife).\n- **On-demand revalidation**: Manually invalidate cached data after a mutation using [`revalidateTag`](#revalidatetag), [`updateTag`](#updatetag), or [`revalidatePath`](#revalidatepath)."
+ },
+ "time": {
+ "start": 1781392539956,
+ "end": 1781392539963
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:46.190Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "args": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache.md",
+ "_extractedPath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache.md"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392546190,
+ "sessionID": "ses_13cbb6ca7ffeDluJj6gL6KvvXT",
+ "part": {
+ "id": "prt_ec345167f001hM35u1pnNpSdAa",
+ "sessionID": "ses_13cbb6ca7ffeDluJj6gL6KvvXT",
+ "messageID": "msg_ec345015e001is3nMOxoQaAHTT",
+ "type": "tool",
+ "callID": "read_16",
+ "tool": "read",
+ "state": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache.md"
+ },
+ "output": "\n00001| ---\n00002| title: use cache\n00003| description: Learn how to use the \"use cache\" directive to cache data in your Next.js application.\n00004| related:\n00005| title: Related\n00006| description: View related API references.\n00007| links:\n00008| - app/api-reference/directives/use-cache-private\n00009| - app/api-reference/config/next-config-js/cacheComponents\n00010| - app/api-reference/config/next-config-js/cacheLife\n00011| - app/api-reference/config/next-config-js/cacheHandlers\n00012| - app/api-reference/functions/cacheTag\n00013| - app/api-reference/functions/cacheLife\n00014| - app/api-reference/functions/revalidateTag\n00015| ---\n00016| \n00017| The `use cache` directive allows you to mark a route, React component, or a function as cacheable. It can be used at the top of a file to indicate that all exports in the file should be cached, or inline at the top of a function or component to cache the return value. Functions and components that use `use cache` must be async.\n00018| \n00019| > **Good to know:**\n00020| >\n00021| > - To use cookies or headers, read them outside cached scopes and pass values as arguments. This is the preferred pattern.\n00022| > - If the in-memory cache isn't sufficient for runtime data, [`'use cache: remote'`](/docs/app/api-reference/directives/use-cache-remote) allows platforms to provide a dedicated cache handler, though it requires a network roundtrip to check the cache and typically incurs platform fees.\n00023| > - For compliance requirements or when you can't refactor to pass runtime data as arguments to a `use cache` scope, see [`'use cache: private'`](/docs/app/api-reference/directives/use-cache-private).\n00024| \n00025| ## Usage\n00026| \n00027| `use cache` is a Cache Components feature. To enable it, add the [`cacheComponents`](/docs/app/api-reference/config/next-config-js/cacheComponents) option to your `next.config.ts` file:\n00028| \n00029| ```ts filename=\"next.config.ts\" switcher\n00030| import type { NextConfig } from 'next'\n00031| \n00032| const nextConfig: NextConfig = {\n00033| cacheComponents: true,\n00034| }\n00035| \n00036| export default nextConfig\n00037| ```\n00038| \n00039| ```js filename=\"next.config.js\" switcher\n00040| /** @type {import('next').NextConfig} */\n00041| const nextConfig = {\n00042| cacheComponents: true,\n00043| }\n00044| \n00045| module.exports = nextConfig\n00046| ```\n00047| \n00048| Then, add `use cache` at the file, component, or function level. All functions and components using `use cache` must be async. When used at file level, every exported function becomes a cached function and must also be async:\n00049| \n00050| ```tsx\n00051| // File level\n00052| 'use cache'\n00053| \n00054| export default async function Page() {\n00055| // ...\n00056| }\n00057| \n00058| // Component level\n00059| export async function MyComponent() {\n00060| 'use cache'\n00061| return <>>\n00062| }\n00063| \n00064| // Function level\n00065| export async function getData() {\n00066| 'use cache'\n00067| const data = await fetch('/api/data')\n00068| return data\n00069| }\n00070| ```\n00071| \n00072| ## How `use cache` works\n00073| \n00074| ### Cache keys\n00075| \n00076| A cache entry's key is generated using a serialized version of its inputs, which includes:\n00077| \n00078| 1. **Build ID** - Unique per build, changing this invalidates all cache entries. If [`deploymentId`](/docs/app/api-reference/config/next-config-js/deploymentId) is configured, it overrides the build ID for cache key purposes.\n00079| 2. **Function ID** - A secure hash of the function's location and signature in the codebase\n00080| 3. **Serializable arguments** - Props (for components) or function arguments\n00081| 4. **HMR refresh hash** (development only) - Invalidates cache on hot module replacement\n00082| \n00083| When a cached function references variables from outer scopes, those variables are automatically captured and bound as arguments, making them part of the cache key.\n00084| \n00085| ```tsx filename=\"lib/data.ts\"\n00086| async function Component({ userId }: { userId: string }) {\n00087| const getData = async (filter: string) => {\n00088| 'use cache'\n00089| // Cache key includes both userId (from closure) and filter (argument)\n00090| return fetch(`/api/users/${userId}/data?filter=${filter}`)\n00091| }\n00092| \n00093| return getData('active')\n00094| }\n00095| ```\n00096| \n00097| In the snippet above, `userId` is captured from the outer scope and `filter` is passed as an argument, so both become part of the `getData` function's cache key. This means different user and filter combinations will have separate cache entries.\n00098| \n00099| > **Good to know:** When a cached function reads [root parameters](/docs/app/api-reference/functions/next-root-params), only the ones it actually reads become part of its cache key.\n00100| \n00101| ## Serialization\n00102| \n00103| Arguments to cached functions and their return values must be serializable.\n00104| \n00105| For a complete reference, see:\n00106| \n00107| - [Serializable arguments](https://react.dev/reference/rsc/use-server#serializable-parameters-and-return-values) - Uses **React Server Components** serialization\n00108| - [Serializable return types](https://react.dev/reference/rsc/use-client#serializable-types) - Uses **React Client Components** serialization\n00109| \n00110| > **Good to know:** Arguments and return values use different serialization systems. Server Component serialization (for arguments) is more restrictive than Client Component serialization (for return values). This means you can return JSX elements but cannot accept them as arguments unless using pass-through patterns.\n00111| \n00112| ### Supported types\n00113| \n00114| **Arguments:**\n00115| \n00116| - Primitives: `string`, `number`, `boolean`, `null`, `undefined`\n00117| - Plain objects: `{ key: value }`\n00118| - Arrays: `[1, 2, 3]`\n00119| - Dates, Maps, Sets, TypedArrays, ArrayBuffers\n00120| - React elements (as pass-through only)\n00121| \n00122| **Return values:**\n00123| \n00124| - Same as arguments, plus JSX elements\n00125| \n00126| ### Unsupported types\n00127| \n00128| - Class instances\n00129| - Functions (except as pass-through)\n00130| - Symbols, WeakMaps, WeakSets\n00131| - URL instances\n00132| \n00133| ```tsx filename=\"app/components/user-card.tsx\"\n00134| // Valid - primitives and plain objects\n00135| async function UserCard({\n00136| id,\n00137| config,\n00138| }: {\n00139| id: string\n00140| config: { theme: string }\n00141| }) {\n00142| 'use cache'\n00143| return
{id}
\n00144| }\n00145| \n00146| // Invalid - class instance\n00147| async function UserProfile({ user }: { user: UserClass }) {\n00148| 'use cache'\n00149| // Error: Cannot serialize class instance\n00150| return
{user.name}
\n00151| }\n00152| ```\n00153| \n00154| ### Pass-through (non-serializable arguments)\n00155| \n00156| You can accept non-serializable values **as long as you don't introspect them**. This enables composition patterns with `children` and Server Actions:\n00157| \n00158| ```tsx filename=\"app/components/cached-wrapper.tsx\"\n00159| async function CachedWrapper({ children }: { children: ReactNode }) {\n00160| 'use cache'\n00161| // Don't read or modify children - just pass it through\n00162| return (\n00163|
\n00164| Cached Header\n00165| {children}\n00166|
\n00167| )\n00168| }\n00169| \n00170| // Usage: children can be dynamic\n00171| export default function Page() {\n00172| return (\n00173| \n00174| {/* Not cached, passed through */}\n00175| \n00176| )\n00177| }\n00178| ```\n00179| \n00180| You can also pass Server Actions through cached components:\n00181| \n00182| ```tsx filename=\"app/components/cached-form.tsx\"\n00183| async function CachedForm({ action }: { action: () => Promise }) {\n00184| 'use cache'\n00185| // Don't call action here - just pass it through\n00186| return
{/* ... */}
\n00187| }\n00188| ```\n00189| \n00190| ## Constraints\n00191| \n00192| Cached functions execute in an isolated environment. The following constraints ensure cache behavior remains predictable and secure.\n00193| \n00194| ### Request-time APIs\n00195| \n00196| Cached functions and components **cannot** directly access runtime APIs like `cookies()`, `headers()`, or `searchParams`. Instead, read these values outside the cached scope and pass them as arguments.\n00197| \n00198| ### Runtime caching considerations\n00199| \n00200| While `use cache` is designed primarily to include uncached data in the static shell, it can also cache data at runtime using in-memory LRU (Least Recently Used) storage.\n00201| \n00202| With the default in-memory handler, runtime cache behavior depends on your hosting environment:\n00203| \n00204| | Environment | Runtime Caching Behavior |\n00205| | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n00206| | **Serverless** | Cache entries typically don't persist across requests (each request can be a different instance), or during revalidation. Build-time caching works normally. |\n00207| | **Self-hosted** | Cache entries persist across requests. Control cache size with [`cacheMaxMemorySize`](/docs/app/api-reference/config/next-config-js/incrementalCacheHandlerPath). |\n00208| \n00209| For example, in a serverless environment, a cached function shared by two pages executes on each static shell revalidation, whereas in self-hosted or environments with persistent memory, the cached output is reused if it's still fresh.\n00210| \n00211| If the default in-memory cache isn't enough, consider **[`use cache: remote`](/docs/app/api-reference/directives/use-cache-remote)** which allows platforms to provide a dedicated cache handler (like Redis or KV database). This helps reduce hits against data sources not scaled to your total traffic, though it comes with costs (storage, network latency, platform fees).\n00212| \n00213| > [!NOTE]\n00214| > With the default in-memory handler, serverless instances are ephemeral, so entries may not be reused between requests, unlike with `use cache: remote`. Neither caching directive carries over to a new deploy, because the [cache key](#cache-keys) includes the build (or `deploymentId`) ID.\n00215| >\n00216| > For data that needs to persist across deploys, use [`unstable_cache`](/docs/app/api-reference/functions/unstable_cache) for non-`fetch` functions or the [`fetch`](/docs/app/api-reference/functions/fetch) cache.\n00217| \n00218| Very rarely, for compliance requirements or when you can't refactor your code to pass runtime data as arguments to a `use cache` scope, you might need [`use cache: private`](/docs/app/api-reference/directives/use-cache-private).\n00219| \n00220| ### Draft Mode\n00221| \n00222| When [Draft Mode](/docs/app/guides/draft-mode) is enabled, all cached functions and components re-execute on every request, and results are not saved to the cache. This ensures draft content is always fresh without requiring any changes to your caching code.\n00223| \n00224| You can read `isEnabled` from [`draftMode()`](/docs/app/api-reference/functions/draft-mode) inside a `use cache` scope, however, other runtime APIs like `cookies()` and `headers()` are not allowed, even when Draft Mode is active. See [Passing runtime values to cached functions](/docs/app/getting-started/caching#passing-runtime-values-to-cached-functions) for the recommended pattern.\n00225| \n00226| ```tsx filename=\"app/components/content.tsx\"\n00227| import { draftMode } from 'next/headers'\n00228| \n00229| async function Content() {\n00230| 'use cache'\n00231| \n00232| const { isEnabled } = await draftMode()\n00233| const url = isEnabled\n00234| ? 'https://draft.example.com/content'\n00235| : 'https://production.example.com/content'\n00236| \n00237| const data = await fetch(url)\n00238| return {/* ... */}\n00239| }\n00240| ```\n00241| \n00242| Calling `enable()` or `disable()` inside a caching directive scope will also throw an error. Draft Mode can only be toggled in [Route Handlers](/docs/app/api-reference/file-conventions/route) or [Server Actions](/docs/app/getting-started/mutating-data).\n00243| \n00244| ### React.cache isolation\n00245| \n00246| [`React.cache`](https://react.dev/reference/react/cache) operates in an isolated scope inside `use cache` boundaries. Values stored via `React.cache` outside a `use cache` function are not visible inside it.\n00247| \n00248| This means you cannot use `React.cache` to pass data into a `use cache` scope:\n00249| \n00250| ```tsx\n00251| import { cache } from 'react'\n00252| \n00253| const store = cache(() => ({ current: null as string | null }))\n00254| \n00255| function Parent() {\n00256| const shared = store()\n00257| shared.current = 'value from parent'\n00258| return \n00259| }\n00260| \n00261| async function Child() {\n00262| 'use cache'\n00263| const shared = store()\n00264| // shared.current is null, not 'value from parent'\n00265| // use cache has its own isolated React.cache scope\n00266| return
{shared.current}
\n00267| }\n00268| ```\n00269| \n00270| This isolation ensures cached functions have predictable, self-contained behavior. To pass data into a `use cache` scope, use function arguments instead.\n00271| \n00272| ## `use cache` at runtime\n00273| \n00274| On the **server**, cache entries are stored in-memory and respect the `revalidate` and `expire` times from your `cacheLife` configuration. You can customize the cache storage by configuring [`cacheHandlers`](/docs/app/api-reference/config/next-config-js/cacheHandlers) in your `next.config.js` file.\n00275| \n00276| On the **client**, content from the server cache is stored in the browser's memory for the duration defined by the `stale` time. The client router enforces a **minimum 30-second stale time**, regardless of configuration.\n00277| \n00278| The `x-nextjs-stale-time` response header communicates cache lifetime from server to client, ensuring coordinated behavior.\n00279| \n00280| ## Revalidation\n00281| \n00282| By default, `use cache` uses the `default` profile with these settings:\n00283| \n00284| - **stale**: 5 minutes (client-side)\n00285| - **revalidate**: 15 minutes (server-side)\n00286| - **expire**: Never expires by time\n00287| \n00288| ```tsx filename=\"lib/data.ts\"\n00289| async function getData() {\n00290| 'use cache'\n00291| // Implicitly uses default profile\n00292| return fetch('/api/data')\n00293| }\n00294| ```\n00295| \n00296| ### Customizing cache lifetime\n00297| \n00298| Use the [`cacheLife`](/docs/app/api-reference/functions/cacheLife) function to customize cache duration:\n00299| \n00300| ```tsx filename=\"lib/data.ts\"\n00301| import { cacheLife } from 'next/cache'\n00302| \n00303| async function getData() {\n00304| 'use cache'\n00305| cacheLife('hours') // Use built-in 'hours' profile\n00306| return fetch('/api/data')\n00307| }\n00308| ```\n00309| \n00310| ### On-demand revalidation\n00311| \n00312| Use [`cacheTag`](/docs/app/api-reference/functions/cacheTag), [`updateTag`](/docs/app/api-reference/functions/updateTag), or [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) for on-demand cache invalidation:\n00313| \n00314| ```tsx filename=\"lib/data.ts\"\n00315| import { cacheTag } from 'next/cache'\n00316| \n00317| async function getProducts() {\n00318| 'use cache'\n00319| cacheTag('products')\n00320| return fetch('/api/products')\n00321| }\n00322| ```\n00323| \n00324| ```tsx filename=\"app/actions.ts\"\n00325| 'use server'\n00326| \n00327| import { updateTag } from 'next/cache'\n00328| \n00329| export async function updateProduct() {\n00330| await db.products.update(...)\n00331| updateTag('products') // Invalidates all 'products' caches\n00332| }\n00333| ```\n00334| \n00335| Both `cacheLife` and `cacheTag` integrate across client and server caching layers, meaning you configure your caching semantics in one place and they apply everywhere.\n00336| \n00337| ## Examples\n00338| \n00339| ### Caching an entire route with `use cache`\n00340| \n00341| To prerender an entire route, add `use cache` to the top of **both** the `layout` and `page` files. Each of these segments are treated as separate entry points in your application, and will be cached independently.\n00342| \n00343| ```tsx filename=\"app/layout.tsx\" switcher\n00344| 'use cache'\n00345| \n00346| export default async function Layout({ children }: { children: ReactNode }) {\n00347| return
{children}
\n00348| }\n00349| ```\n00350| \n00351| ```jsx filename=\"app/layout.js\" switcher\n00352| 'use cache'\n00353| \n00354| export default async function Layout({ children }) {\n00355| return
{children}
\n00356| }\n00357| ```\n00358| \n00359| Any components imported and nested in `page` file are part of the cache output associated with the `page`.\n00360| \n00361| ```tsx filename=\"app/page.tsx\" switcher\n00362| 'use cache'\n00363| \n00364| async function Users() {\n00365| const users = await fetch('/api/users')\n00366| // loop through users\n00367| }\n00368| \n00369| export default async function Page() {\n00370| return (\n00371| \n00372| \n00373| \n00374| )\n00375| }\n00376| ```\n00377| \n00378| ```jsx filename=\"app/page.js\" switcher\n00379| 'use cache'\n00380| \n00381| async function Users() {\n00382| const users = await fetch('/api/users')\n00383| // loop through users\n00384| }\n00385| \n00386| export default async function Page() {\n00387| return (\n00388| \n00389| \n00390| \n00391| )\n00392| }\n00393| ```\n00394| \n00395| > **Good to know**:\n00396| >\n00397| > - If `use cache` is added only to the `layout` or the `page`, only that route segment and any components imported into it will be cached.\n00398| \n00399| ### Caching a component's output with `use cache`\n00400| \n00401| You can use `use cache` at the component level to cache any fetches or computations performed within that component. The cache entry will be reused as long as the serialized props produce the same value in each instance.\n00402| \n00403| ```tsx filename=\"app/components/bookings.tsx\" highlight={2} switcher\n00404| export async function Bookings({ type = 'haircut' }: BookingsProps) {\n00405| 'use cache'\n00406| async function getBookingsData() {\n00407| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00408| return data\n00409| }\n00410| return //...\n00411| }\n00412| \n00413| interface BookingsProps {\n00414| type: string\n00415| }\n00416| ```\n00417| \n00418| ```jsx filename=\"app/components/bookings.js\" highlight={2} switcher\n00419| export async function Bookings({ type = 'haircut' }) {\n00420| 'use cache'\n00421| async function getBookingsData() {\n00422| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00423| return data\n00424| }\n00425| return //...\n00426| }\n00427| ```\n00428| \n00429| ### Caching function output with `use cache`\n00430| \n00431| Since you can add `use cache` to any asynchronous function, you aren't limited to caching components or routes only. You might want to cache a network request, a database query, or a slow computation.\n00432| \n00433| ```tsx filename=\"app/actions.ts\" highlight={2} switcher\n00434| export async function getData() {\n00435| 'use cache'\n00436| \n00437| const data = await fetch('/api/data')\n00438| return data\n00439| }\n00440| ```\n00441| \n00442| ```jsx filename=\"app/actions.js\" highlight={2} switcher\n00443| export async function getData() {\n00444| 'use cache'\n00445| \n00446| const data = await fetch('/api/data')\n00447| return data\n00448| }\n00449| ```\n00450| \n00451| > **Good to know:** When a cached directive (`use cache`, [`use cache: private`](/docs/app/api-reference/directives/use-cache-private), or [`use cache: remote`](/docs/app/api-reference/directives/use-cache-remote)) is at the top of a file, you can import its exported functions into a Client Component and call them directly; they run on the server and return the result, similar to a [Server Function](/docs/app/glossary#server-function). Prefer calling cached functions on the server and passing results down as props.\n00452| \n00453| ### Interleaving\n00454| \n00455| In React, composition with `children` or slots is a well-known pattern for building flexible components. When using `use cache`, you can continue to compose your UI in this way. Anything included as `children`, or other compositional slots, in the returned JSX will be passed through the cached component without affecting its cache entry.\n00456| \n00457| As long as you don't directly reference any of the JSX slots inside the body of the cacheable function itself, their presence in the returned output won't affect the cache entry.\n00458| \n00459| ```tsx filename=\"app/page.tsx\" switcher\n00460| export default async function Page() {\n00461| const uncachedData = await getData()\n00462| return (\n00463| // Pass compositional slots as props, e.g. header and children\n00464| Home}>\n00465| {/* DynamicComponent is provided as the children slot */}\n00466| \n00467| \n00468| )\n00469| }\n00470| \n00471| async function CacheComponent({\n00472| header, // header: a compositional slot, injected as a prop\n00473| children, // children: another slot for nested composition\n00474| }: {\n00475| header: ReactNode\n00476| children: ReactNode\n00477| }) {\n00478| 'use cache'\n00479| const cachedData = await fetch('/api/cached-data')\n00480| return (\n00481|
\n00514| )\n00515| }\n00516| ```\n00517| \n00518| You can also pass Server Actions through cached components to Client Components without invoking them inside the cacheable function.\n00519| \n00520| ```tsx filename=\"app/page.tsx\" switcher\n00521| import ClientComponent from './ClientComponent'\n00522| \n00523| export default async function Page() {\n00524| const performUpdate = async () => {\n00525| 'use server'\n00526| // Perform some server-side update\n00527| await db.update(...)\n00528| }\n00529| \n00530| return \n00531| }\n00532| \n00533| async function CachedComponent({\n00534| performUpdate,\n00535| }: {\n00536| performUpdate: () => Promise\n00537| }) {\n00538| 'use cache'\n00539| // Do not call performUpdate here\n00540| return \n00541| }\n00542| ```\n00543| \n00544| ```jsx filename=\"app/page.js\" switcher\n00545| import ClientComponent from './ClientComponent'\n00546| \n00547| export default async function Page() {\n00548| const performUpdate = async () => {\n00549| 'use server'\n00550| // Perform some server-side update\n00551| await db.update(...)\n00552| }\n00553| \n00554| return \n00555| }\n00556| \n00557| async function CachedComponent({ performUpdate }) {\n00558| 'use cache'\n00559| // Do not call performUpdate here\n00560| return \n00561| }\n00562| ```\n00563| \n00564| ```tsx filename=\"app/ClientComponent.tsx\" switcher\n00565| 'use client'\n00566| \n00567| export default function ClientComponent({\n00568| action,\n00569| }: {\n00570| action: () => Promise\n00571| }) {\n00572| return Update\n00573| }\n00574| ```\n00575| \n00576| ```jsx filename=\"app/ClientComponent.js\" switcher\n00577| 'use client'\n00578| \n00579| export default function ClientComponent({ action }) {\n00580| return Update\n00581| }\n00582| ```\n00583| \n00584| ## Troubleshooting\n00585| \n00586| ### Debugging cache behavior\n00587| \n00588| #### Verbose logging\n00589| \n00590| Set `NEXT_PRIVATE_DEBUG_CACHE=1` for verbose cache logging:\n00591| \n00592| ```bash\n00593| NEXT_PRIVATE_DEBUG_CACHE=1 npm run dev\n00594| # or for production\n00595| NEXT_PRIVATE_DEBUG_CACHE=1 npm run start\n00596| ```\n00597| \n00598| > **Good to know:** This environment variable also logs ISR and other caching mechanisms. See [Verifying correct production behavior](/docs/app/guides/incremental-static-regeneration#verifying-correct-production-behavior) for more details.\n00599| \n00600| #### Console log replays\n00601| \n00602| In development, console logs from cached functions appear with a `Cache` prefix.\n00603| \n00604| ### Build Hangs (Cache Timeout)\n00605| \n00606| If your build hangs, you're accessing Promises that resolve to uncached or runtime data, created outside a `use cache` boundary. The cached function waits for data that can't resolve during the build, causing a timeout after 50 seconds.\n00607| \n00608| When the build timeouts you'll see this error message:\n00609| \n00610| > Error: Filling a cache during prerender timed out, likely because request-specific arguments such as params, searchParams, cookies() or uncached data were used inside \"use cache\".\n00611| \n00612| Common ways this happens: passing such Promises as props, accessing them via closure, or retrieving them from shared storage (Maps).\n00613| \n00614| > **Good to know:** Directly calling `cookies()` or `headers()` inside `use cache` fails immediately with a [different error](/docs/messages/next-request-in-use-cache), not a timeout.\n00615| \n00616| **Passing runtime data Promises as props:**\n00617| \n00618| ```tsx filename=\"app/page.tsx\"\n00619| import { cookies } from 'next/headers'\n00620| import { Suspense } from 'react'\n00621| \n00622| export default function Page() {\n00623| return (\n00624| Loading...}>\n00625| \n00626| \n00627| )\n00628| }\n00629| \n00630| async function Dynamic() {\n00631| const cookieStore = cookies()\n00632| return // Build hangs\n00633| }\n00634| \n00635| async function Cached({ promise }: { promise: Promise }) {\n00636| 'use cache'\n00637| const data = await promise // Waits for runtime data during build\n00638| return
..
\n00639| }\n00640| ```\n00641| \n00642| Await the `cookies` store in the `Dynamic` component, and pass a cookie value to the `Cached` component.\n00643| \n00644| **Shared deduplication storage:**\n00645| \n00646| ```tsx filename=\"app/page.tsx\"\n00647| // Problem: Map stores dynamic Promises, accessed by cached code\n00648| import { Suspense } from 'react'\n00649| \n00650| const cache = new Map>()\n00651| \n00652| export default function Page() {\n00653| return (\n00654| <>\n00655| Loading...}>\n00656| \n00657| \n00658| \n00659| >\n00660| )\n00661| }\n00662| \n00663| async function Dynamic({ id }: { id: string }) {\n00664| // Stores dynamic Promise in shared Map\n00665| cache.set(\n00666| id,\n00667| fetch(`https://api.example.com/${id}`).then((r) => r.text())\n00668| )\n00669| return
Dynamic
\n00670| }\n00671| \n00672| async function Cached({ id }: { id: string }) {\n00673| 'use cache'\n00674| return
{await cache.get(id)}
// Build hangs - retrieves dynamic Promise\n00675| }\n00676| ```\n00677| \n00678| Use Next.js's built-in `fetch()` deduplication or use separate Maps for cached and uncached contexts.\n00679| \n00680| ## Platform Support\n00681| \n00682| | Deployment Option | Supported |\n00683| | ------------------------------------------------------------------- | ----------------- |\n00684| | [Node.js server](/docs/app/getting-started/deploying#nodejs-server) | Yes |\n00685| | [Docker container](/docs/app/getting-started/deploying#docker) | Yes |\n00686| | [Static export](/docs/app/getting-started/deploying#static-export) | No |\n00687| | [Adapters](/docs/app/getting-started/deploying#adapters) | Platform-specific |\n00688| \n00689| Learn how to [configure caching](/docs/app/guides/self-hosting#caching-and-isr) when self-hosting Next.js.\n00690| \n00691| ## Version History\n00692| \n00693| | Version | Changes |\n00694| | --------- | ----------------------------------------------------------- |\n00695| | `v16.0.0` | `\"use cache\"` is enabled with the Cache Components feature. |\n00696| | `v15.0.0` | `\"use cache\"` is introduced as an experimental feature. |\n00697| \n\n(End of file - total 697 lines)\n",
+ "title": "node_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache.md",
+ "metadata": {
+ "preview": "---\ntitle: use cache\ndescription: Learn how to use the \"use cache\" directive to cache data in your Next.js application.\nrelated:\n title: Related\n description: View related API references.\n links:\n - app/api-reference/directives/use-cache-private\n - app/api-reference/config/next-config-js/cacheComponents\n - app/api-reference/config/next-config-js/cacheLife\n - app/api-reference/config/next-config-js/cacheHandlers\n - app/api-reference/functions/cacheTag\n - app/api-reference/functions/cacheLife\n - app/api-reference/functions/revalidateTag\n---\n\nThe `use cache` directive allows you to mark a route, React component, or a function as cacheable. It can be used at the top of a file to indicate that all exports in the file should be cached, or inline at the top of a function or component to cache the return value. Functions and components that use `use cache` must be async.\n\n> **Good to know:**\n>"
+ },
+ "time": {
+ "start": 1781392546180,
+ "end": 1781392546187
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:46.190Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| ---\n00002| title: use cache\n00003| description: Learn how to use the \"use cache\" directive to cache data in your Next.js application.\n00004| related:\n00005| title: Related\n00006| description: View related API references.\n00007| links:\n00008| - app/api-reference/directives/use-cache-private\n00009| - app/api-reference/config/next-config-js/cacheComponents\n00010| - app/api-reference/config/next-config-js/cacheLife\n00011| - app/api-reference/config/next-config-js/cacheHandlers\n00012| - app/api-reference/functions/cacheTag\n00013| - app/api-reference/functions/cacheLife\n00014| - app/api-reference/functions/revalidateTag\n00015| ---\n00016| \n00017| The `use cache` directive allows you to mark a route, React component, or a function as cacheable. It can be used at the top of a file to indicate that all exports in the file should be cached, or inline at the top of a function or component to cache the return value. Functions and components that use `use cache` must be async.\n00018| \n00019| > **Good to know:**\n00020| >\n00021| > - To use cookies or headers, read them outside cached scopes and pass values as arguments. This is the preferred pattern.\n00022| > - If the in-memory cache isn't sufficient for runtime data, [`'use cache: remote'`](/docs/app/api-reference/directives/use-cache-remote) allows platforms to provide a dedicated cache handler, though it requires a network roundtrip to check the cache and typically incurs platform fees.\n00023| > - For compliance requirements or when you can't refactor to pass runtime data as arguments to a `use cache` scope, see [`'use cache: private'`](/docs/app/api-reference/directives/use-cache-private).\n00024| \n00025| ## Usage\n00026| \n00027| `use cache` is a Cache Components feature. To enable it, add the [`cacheComponents`](/docs/app/api-reference/config/next-config-js/cacheComponents) option to your `next.config.ts` file:\n00028| \n00029| ```ts filename=\"next.config.ts\" switcher\n00030| import type { NextConfig } from 'next'\n00031| \n00032| const nextConfig: NextConfig = {\n00033| cacheComponents: true,\n00034| }\n00035| \n00036| export default nextConfig\n00037| ```\n00038| \n00039| ```js filename=\"next.config.js\" switcher\n00040| /** @type {import('next').NextConfig} */\n00041| const nextConfig = {\n00042| cacheComponents: true,\n00043| }\n00044| \n00045| module.exports = nextConfig\n00046| ```\n00047| \n00048| Then, add `use cache` at the file, component, or function level. All functions and components using `use cache` must be async. When used at file level, every exported function becomes a cached function and must also be async:\n00049| \n00050| ```tsx\n00051| // File level\n00052| 'use cache'\n00053| \n00054| export default async function Page() {\n00055| // ...\n00056| }\n00057| \n00058| // Component level\n00059| export async function MyComponent() {\n00060| 'use cache'\n00061| return <>>\n00062| }\n00063| \n00064| // Function level\n00065| export async function getData() {\n00066| 'use cache'\n00067| const data = await fetch('/api/data')\n00068| return data\n00069| }\n00070| ```\n00071| \n00072| ## How `use cache` works\n00073| \n00074| ### Cache keys\n00075| \n00076| A cache entry's key is generated using a serialized version of its inputs, which includes:\n00077| \n00078| 1. **Build ID** - Unique per build, changing this invalidates all cache entries. If [`deploymentId`](/docs/app/api-reference/config/next-config-js/deploymentId) is configured, it overrides the build ID for cache key purposes.\n00079| 2. **Function ID** - A secure hash of the function's location and signature in the codebase\n00080| 3. **Serializable arguments** - Props (for components) or function arguments\n00081| 4. **HMR refresh hash** (development only) - Invalidates cache on hot module replacement\n00082| \n00083| When a cached function references variables from outer scopes, those variables are automatically captured and bound as arguments, making them part of the cache key.\n00084| \n00085| ```tsx filename=\"lib/data.ts\"\n00086| async function Component({ userId }: { userId: string }) {\n00087| const getData = async (filter: string) => {\n00088| 'use cache'\n00089| // Cache key includes both userId (from closure) and filter (argument)\n00090| return fetch(`/api/users/${userId}/data?filter=${filter}`)\n00091| }\n00092| \n00093| return getData('active')\n00094| }\n00095| ```\n00096| \n00097| In the snippet above, `userId` is captured from the outer scope and `filter` is passed as an argument, so both become part of the `getData` function's cache key. This means different user and filter combinations will have separate cache entries.\n00098| \n00099| > **Good to know:** When a cached function reads [root parameters](/docs/app/api-reference/functions/next-root-params), only the ones it actually reads become part of its cache key.\n00100| \n00101| ## Serialization\n00102| \n00103| Arguments to cached functions and their return values must be serializable.\n00104| \n00105| For a complete reference, see:\n00106| \n00107| - [Serializable arguments](https://react.dev/reference/rsc/use-server#serializable-parameters-and-return-values) - Uses **React Server Components** serialization\n00108| - [Serializable return types](https://react.dev/reference/rsc/use-client#serializable-types) - Uses **React Client Components** serialization\n00109| \n00110| > **Good to know:** Arguments and return values use different serialization systems. Server Component serialization (for arguments) is more restrictive than Client Component serialization (for return values). This means you can return JSX elements but cannot accept them as arguments unless using pass-through patterns.\n00111| \n00112| ### Supported types\n00113| \n00114| **Arguments:**\n00115| \n00116| - Primitives: `string`, `number`, `boolean`, `null`, `undefined`\n00117| - Plain objects: `{ key: value }`\n00118| - Arrays: `[1, 2, 3]`\n00119| - Dates, Maps, Sets, TypedArrays, ArrayBuffers\n00120| - React elements (as pass-through only)\n00121| \n00122| **Return values:**\n00123| \n00124| - Same as arguments, plus JSX elements\n00125| \n00126| ### Unsupported types\n00127| \n00128| - Class instances\n00129| - Functions (except as pass-through)\n00130| - Symbols, WeakMaps, WeakSets\n00131| - URL instances\n00132| \n00133| ```tsx filename=\"app/components/user-card.tsx\"\n00134| // Valid - primitives and plain objects\n00135| async function UserCard({\n00136| id,\n00137| config,\n00138| }: {\n00139| id: string\n00140| config: { theme: string }\n00141| }) {\n00142| 'use cache'\n00143| return
{id}
\n00144| }\n00145| \n00146| // Invalid - class instance\n00147| async function UserProfile({ user }: { user: UserClass }) {\n00148| 'use cache'\n00149| // Error: Cannot serialize class instance\n00150| return
{user.name}
\n00151| }\n00152| ```\n00153| \n00154| ### Pass-through (non-serializable arguments)\n00155| \n00156| You can accept non-serializable values **as long as you don't introspect them**. This enables composition patterns with `children` and Server Actions:\n00157| \n00158| ```tsx filename=\"app/components/cached-wrapper.tsx\"\n00159| async function CachedWrapper({ children }: { children: ReactNode }) {\n00160| 'use cache'\n00161| // Don't read or modify children - just pass it through\n00162| return (\n00163|
\n00164| Cached Header\n00165| {children}\n00166|
\n00167| )\n00168| }\n00169| \n00170| // Usage: children can be dynamic\n00171| export default function Page() {\n00172| return (\n00173| \n00174| {/* Not cached, passed through */}\n00175| \n00176| )\n00177| }\n00178| ```\n00179| \n00180| You can also pass Server Actions through cached components:\n00181| \n00182| ```tsx filename=\"app/components/cached-form.tsx\"\n00183| async function CachedForm({ action }: { action: () => Promise }) {\n00184| 'use cache'\n00185| // Don't call action here - just pass it through\n00186| return
{/* ... */}
\n00187| }\n00188| ```\n00189| \n00190| ## Constraints\n00191| \n00192| Cached functions execute in an isolated environment. The following constraints ensure cache behavior remains predictable and secure.\n00193| \n00194| ### Request-time APIs\n00195| \n00196| Cached functions and components **cannot** directly access runtime APIs like `cookies()`, `headers()`, or `searchParams`. Instead, read these values outside the cached scope and pass them as arguments.\n00197| \n00198| ### Runtime caching considerations\n00199| \n00200| While `use cache` is designed primarily to include uncached data in the static shell, it can also cache data at runtime using in-memory LRU (Least Recently Used) storage.\n00201| \n00202| With the default in-memory handler, runtime cache behavior depends on your hosting environment:\n00203| \n00204| | Environment | Runtime Caching Behavior |\n00205| | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n00206| | **Serverless** | Cache entries typically don't persist across requests (each request can be a different instance), or during revalidation. Build-time caching works normally. |\n00207| | **Self-hosted** | Cache entries persist across requests. Control cache size with [`cacheMaxMemorySize`](/docs/app/api-reference/config/next-config-js/incrementalCacheHandlerPath). |\n00208| \n00209| For example, in a serverless environment, a cached function shared by two pages executes on each static shell revalidation, whereas in self-hosted or environments with persistent memory, the cached output is reused if it's still fresh.\n00210| \n00211| If the default in-memory cache isn't enough, consider **[`use cache: remote`](/docs/app/api-reference/directives/use-cache-remote)** which allows platforms to provide a dedicated cache handler (like Redis or KV database). This helps reduce hits against data sources not scaled to your total traffic, though it comes with costs (storage, network latency, platform fees).\n00212| \n00213| > [!NOTE]\n00214| > With the default in-memory handler, serverless instances are ephemeral, so entries may not be reused between requests, unlike with `use cache: remote`. Neither caching directive carries over to a new deploy, because the [cache key](#cache-keys) includes the build (or `deploymentId`) ID.\n00215| >\n00216| > For data that needs to persist across deploys, use [`unstable_cache`](/docs/app/api-reference/functions/unstable_cache) for non-`fetch` functions or the [`fetch`](/docs/app/api-reference/functions/fetch) cache.\n00217| \n00218| Very rarely, for compliance requirements or when you can't refactor your code to pass runtime data as arguments to a `use cache` scope, you might need [`use cache: private`](/docs/app/api-reference/directives/use-cache-private).\n00219| \n00220| ### Draft Mode\n00221| \n00222| When [Draft Mode](/docs/app/guides/draft-mode) is enabled, all cached functions and components re-execute on every request, and results are not saved to the cache. This ensures draft content is always fresh without requiring any changes to your caching code.\n00223| \n00224| You can read `isEnabled` from [`draftMode()`](/docs/app/api-reference/functions/draft-mode) inside a `use cache` scope, however, other runtime APIs like `cookies()` and `headers()` are not allowed, even when Draft Mode is active. See [Passing runtime values to cached functions](/docs/app/getting-started/caching#passing-runtime-values-to-cached-functions) for the recommended pattern.\n00225| \n00226| ```tsx filename=\"app/components/content.tsx\"\n00227| import { draftMode } from 'next/headers'\n00228| \n00229| async function Content() {\n00230| 'use cache'\n00231| \n00232| const { isEnabled } = await draftMode()\n00233| const url = isEnabled\n00234| ? 'https://draft.example.com/content'\n00235| : 'https://production.example.com/content'\n00236| \n00237| const data = await fetch(url)\n00238| return {/* ... */}\n00239| }\n00240| ```\n00241| \n00242| Calling `enable()` or `disable()` inside a caching directive scope will also throw an error. Draft Mode can only be toggled in [Route Handlers](/docs/app/api-reference/file-conventions/route) or [Server Actions](/docs/app/getting-started/mutating-data).\n00243| \n00244| ### React.cache isolation\n00245| \n00246| [`React.cache`](https://react.dev/reference/react/cache) operates in an isolated scope inside `use cache` boundaries. Values stored via `React.cache` outside a `use cache` function are not visible inside it.\n00247| \n00248| This means you cannot use `React.cache` to pass data into a `use cache` scope:\n00249| \n00250| ```tsx\n00251| import { cache } from 'react'\n00252| \n00253| const store = cache(() => ({ current: null as string | null }))\n00254| \n00255| function Parent() {\n00256| const shared = store()\n00257| shared.current = 'value from parent'\n00258| return \n00259| }\n00260| \n00261| async function Child() {\n00262| 'use cache'\n00263| const shared = store()\n00264| // shared.current is null, not 'value from parent'\n00265| // use cache has its own isolated React.cache scope\n00266| return
{shared.current}
\n00267| }\n00268| ```\n00269| \n00270| This isolation ensures cached functions have predictable, self-contained behavior. To pass data into a `use cache` scope, use function arguments instead.\n00271| \n00272| ## `use cache` at runtime\n00273| \n00274| On the **server**, cache entries are stored in-memory and respect the `revalidate` and `expire` times from your `cacheLife` configuration. You can customize the cache storage by configuring [`cacheHandlers`](/docs/app/api-reference/config/next-config-js/cacheHandlers) in your `next.config.js` file.\n00275| \n00276| On the **client**, content from the server cache is stored in the browser's memory for the duration defined by the `stale` time. The client router enforces a **minimum 30-second stale time**, regardless of configuration.\n00277| \n00278| The `x-nextjs-stale-time` response header communicates cache lifetime from server to client, ensuring coordinated behavior.\n00279| \n00280| ## Revalidation\n00281| \n00282| By default, `use cache` uses the `default` profile with these settings:\n00283| \n00284| - **stale**: 5 minutes (client-side)\n00285| - **revalidate**: 15 minutes (server-side)\n00286| - **expire**: Never expires by time\n00287| \n00288| ```tsx filename=\"lib/data.ts\"\n00289| async function getData() {\n00290| 'use cache'\n00291| // Implicitly uses default profile\n00292| return fetch('/api/data')\n00293| }\n00294| ```\n00295| \n00296| ### Customizing cache lifetime\n00297| \n00298| Use the [`cacheLife`](/docs/app/api-reference/functions/cacheLife) function to customize cache duration:\n00299| \n00300| ```tsx filename=\"lib/data.ts\"\n00301| import { cacheLife } from 'next/cache'\n00302| \n00303| async function getData() {\n00304| 'use cache'\n00305| cacheLife('hours') // Use built-in 'hours' profile\n00306| return fetch('/api/data')\n00307| }\n00308| ```\n00309| \n00310| ### On-demand revalidation\n00311| \n00312| Use [`cacheTag`](/docs/app/api-reference/functions/cacheTag), [`updateTag`](/docs/app/api-reference/functions/updateTag), or [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) for on-demand cache invalidation:\n00313| \n00314| ```tsx filename=\"lib/data.ts\"\n00315| import { cacheTag } from 'next/cache'\n00316| \n00317| async function getProducts() {\n00318| 'use cache'\n00319| cacheTag('products')\n00320| return fetch('/api/products')\n00321| }\n00322| ```\n00323| \n00324| ```tsx filename=\"app/actions.ts\"\n00325| 'use server'\n00326| \n00327| import { updateTag } from 'next/cache'\n00328| \n00329| export async function updateProduct() {\n00330| await db.products.update(...)\n00331| updateTag('products') // Invalidates all 'products' caches\n00332| }\n00333| ```\n00334| \n00335| Both `cacheLife` and `cacheTag` integrate across client and server caching layers, meaning you configure your caching semantics in one place and they apply everywhere.\n00336| \n00337| ## Examples\n00338| \n00339| ### Caching an entire route with `use cache`\n00340| \n00341| To prerender an entire route, add `use cache` to the top of **both** the `layout` and `page` files. Each of these segments are treated as separate entry points in your application, and will be cached independently.\n00342| \n00343| ```tsx filename=\"app/layout.tsx\" switcher\n00344| 'use cache'\n00345| \n00346| export default async function Layout({ children }: { children: ReactNode }) {\n00347| return
{children}
\n00348| }\n00349| ```\n00350| \n00351| ```jsx filename=\"app/layout.js\" switcher\n00352| 'use cache'\n00353| \n00354| export default async function Layout({ children }) {\n00355| return
{children}
\n00356| }\n00357| ```\n00358| \n00359| Any components imported and nested in `page` file are part of the cache output associated with the `page`.\n00360| \n00361| ```tsx filename=\"app/page.tsx\" switcher\n00362| 'use cache'\n00363| \n00364| async function Users() {\n00365| const users = await fetch('/api/users')\n00366| // loop through users\n00367| }\n00368| \n00369| export default async function Page() {\n00370| return (\n00371| \n00372| \n00373| \n00374| )\n00375| }\n00376| ```\n00377| \n00378| ```jsx filename=\"app/page.js\" switcher\n00379| 'use cache'\n00380| \n00381| async function Users() {\n00382| const users = await fetch('/api/users')\n00383| // loop through users\n00384| }\n00385| \n00386| export default async function Page() {\n00387| return (\n00388| \n00389| \n00390| \n00391| )\n00392| }\n00393| ```\n00394| \n00395| > **Good to know**:\n00396| >\n00397| > - If `use cache` is added only to the `layout` or the `page`, only that route segment and any components imported into it will be cached.\n00398| \n00399| ### Caching a component's output with `use cache`\n00400| \n00401| You can use `use cache` at the component level to cache any fetches or computations performed within that component. The cache entry will be reused as long as the serialized props produce the same value in each instance.\n00402| \n00403| ```tsx filename=\"app/components/bookings.tsx\" highlight={2} switcher\n00404| export async function Bookings({ type = 'haircut' }: BookingsProps) {\n00405| 'use cache'\n00406| async function getBookingsData() {\n00407| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00408| return data\n00409| }\n00410| return //...\n00411| }\n00412| \n00413| interface BookingsProps {\n00414| type: string\n00415| }\n00416| ```\n00417| \n00418| ```jsx filename=\"app/components/bookings.js\" highlight={2} switcher\n00419| export async function Bookings({ type = 'haircut' }) {\n00420| 'use cache'\n00421| async function getBookingsData() {\n00422| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00423| return data\n00424| }\n00425| return //...\n00426| }\n00427| ```\n00428| \n00429| ### Caching function output with `use cache`\n00430| \n00431| Since you can add `use cache` to any asynchronous function, you aren't limited to caching components or routes only. You might want to cache a network request, a database query, or a slow computation.\n00432| \n00433| ```tsx filename=\"app/actions.ts\" highlight={2} switcher\n00434| export async function getData() {\n00435| 'use cache'\n00436| \n00437| const data = await fetch('/api/data')\n00438| return data\n00439| }\n00440| ```\n00441| \n00442| ```jsx filename=\"app/actions.js\" highlight={2} switcher\n00443| export async function getData() {\n00444| 'use cache'\n00445| \n00446| const data = await fetch('/api/data')\n00447| return data\n00448| }\n00449| ```\n00450| \n00451| > **Good to know:** When a cached directive (`use cache`, [`use cache: private`](/docs/app/api-reference/directives/use-cache-private), or [`use cache: remote`](/docs/app/api-reference/directives/use-cache-remote)) is at the top of a file, you can import its exported functions into a Client Component and call them directly; they run on the server and return the result, similar to a [Server Function](/docs/app/glossary#server-function). Prefer calling cached functions on the server and passing results down as props.\n00452| \n00453| ### Interleaving\n00454| \n00455| In React, composition with `children` or slots is a well-known pattern for building flexible components. When using `use cache`, you can continue to compose your UI in this way. Anything included as `children`, or other compositional slots, in the returned JSX will be passed through the cached component without affecting its cache entry.\n00456| \n00457| As long as you don't directly reference any of the JSX slots inside the body of the cacheable function itself, their presence in the returned output won't affect the cache entry.\n00458| \n00459| ```tsx filename=\"app/page.tsx\" switcher\n00460| export default async function Page() {\n00461| const uncachedData = await getData()\n00462| return (\n00463| // Pass compositional slots as props, e.g. header and children\n00464| Home}>\n00465| {/* DynamicComponent is provided as the children slot */}\n00466| \n00467| \n00468| )\n00469| }\n00470| \n00471| async function CacheComponent({\n00472| header, // header: a compositional slot, injected as a prop\n00473| children, // children: another slot for nested composition\n00474| }: {\n00475| header: ReactNode\n00476| children: ReactNode\n00477| }) {\n00478| 'use cache'\n00479| const cachedData = await fetch('/api/cached-data')\n00480| return (\n00481|
\n00514| )\n00515| }\n00516| ```\n00517| \n00518| You can also pass Server Actions through cached components to Client Components without invoking them inside the cacheable function.\n00519| \n00520| ```tsx filename=\"app/page.tsx\" switcher\n00521| import ClientComponent from './ClientComponent'\n00522| \n00523| export default async function Page() {\n00524| const performUpdate = async () => {\n00525| 'use server'\n00526| // Perform some server-side update\n00527| await db.update(...)\n00528| }\n00529| \n00530| return \n00531| }\n00532| \n00533| async function CachedComponent({\n00534| performUpdate,\n00535| }: {\n00536| performUpdate: () => Promise\n00537| }) {\n00538| 'use cache'\n00539| // Do not call performUpdate here\n00540| return \n00541| }\n00542| ```\n00543| \n00544| ```jsx filename=\"app/page.js\" switcher\n00545| import ClientComponent from './ClientComponent'\n00546| \n00547| export default async function Page() {\n00548| const performUpdate = async () => {\n00549| 'use server'\n00550| // Perform some server-side update\n00551| await db.update(...)\n00552| }\n00553| \n00554| return \n00555| }\n00556| \n00557| async function CachedComponent({ performUpdate }) {\n00558| 'use cache'\n00559| // Do not call performUpdate here\n00560| return \n00561| }\n00562| ```\n00563| \n00564| ```tsx filename=\"app/ClientComponent.tsx\" switcher\n00565| 'use client'\n00566| \n00567| export default function ClientComponent({\n00568| action,\n00569| }: {\n00570| action: () => Promise\n00571| }) {\n00572| return Update\n00573| }\n00574| ```\n00575| \n00576| ```jsx filename=\"app/ClientComponent.js\" switcher\n00577| 'use client'\n00578| \n00579| export default function ClientComponent({ action }) {\n00580| return Update\n00581| }\n00582| ```\n00583| \n00584| ## Troubleshooting\n00585| \n00586| ### Debugging cache behavior\n00587| \n00588| #### Verbose logging\n00589| \n00590| Set `NEXT_PRIVATE_DEBUG_CACHE=1` for verbose cache logging:\n00591| \n00592| ```bash\n00593| NEXT_PRIVATE_DEBUG_CACHE=1 npm run dev\n00594| # or for production\n00595| NEXT_PRIVATE_DEBUG_CACHE=1 npm run start\n00596| ```\n00597| \n00598| > **Good to know:** This environment variable also logs ISR and other caching mechanisms. See [Verifying correct production behavior](/docs/app/guides/incremental-static-regeneration#verifying-correct-production-behavior) for more details.\n00599| \n00600| #### Console log replays\n00601| \n00602| In development, console logs from cached functions appear with a `Cache` prefix.\n00603| \n00604| ### Build Hangs (Cache Timeout)\n00605| \n00606| If your build hangs, you're accessing Promises that resolve to uncached or runtime data, created outside a `use cache` boundary. The cached function waits for data that can't resolve during the build, causing a timeout after 50 seconds.\n00607| \n00608| When the build timeouts you'll see this error message:\n00609| \n00610| > Error: Filling a cache during prerender timed out, likely because request-specific arguments such as params, searchParams, cookies() or uncached data were used inside \"use cache\".\n00611| \n00612| Common ways this happens: passing such Promises as props, accessing them via closure, or retrieving them from shared storage (Maps).\n00613| \n00614| > **Good to know:** Directly calling `cookies()` or `headers()` inside `use cache` fails immediately with a [different error](/docs/messages/next-request-in-use-cache), not a timeout.\n00615| \n00616| **Passing runtime data Promises as props:**\n00617| \n00618| ```tsx filename=\"app/page.tsx\"\n00619| import { cookies } from 'next/headers'\n00620| import { Suspense } from 'react'\n00621| \n00622| export default function Page() {\n00623| return (\n00624| Loading...}>\n00625| \n00626| \n00627| )\n00628| }\n00629| \n00630| async function Dynamic() {\n00631| const cookieStore = cookies()\n00632| return // Build hangs\n00633| }\n00634| \n00635| async function Cached({ promise }: { promise: Promise }) {\n00636| 'use cache'\n00637| const data = await promise // Waits for runtime data during build\n00638| return
..
\n00639| }\n00640| ```\n00641| \n00642| Await the `cookies` store in the `Dynamic` component, and pass a cookie value to the `Cached` component.\n00643| \n00644| **Shared deduplication storage:**\n00645| \n00646| ```tsx filename=\"app/page.tsx\"\n00647| // Problem: Map stores dynamic Promises, accessed by cached code\n00648| import { Suspense } from 'react'\n00649| \n00650| const cache = new Map>()\n00651| \n00652| export default function Page() {\n00653| return (\n00654| <>\n00655| Loading...}>\n00656| \n00657| \n00658| \n00659| >\n00660| )\n00661| }\n00662| \n00663| async function Dynamic({ id }: { id: string }) {\n00664| // Stores dynamic Promise in shared Map\n00665| cache.set(\n00666| id,\n00667| fetch(`https://api.example.com/${id}`).then((r) => r.text())\n00668| )\n00669| return
Dynamic
\n00670| }\n00671| \n00672| async function Cached({ id }: { id: string }) {\n00673| 'use cache'\n00674| return
{await cache.get(id)}
// Build hangs - retrieves dynamic Promise\n00675| }\n00676| ```\n00677| \n00678| Use Next.js's built-in `fetch()` deduplication or use separate Maps for cached and uncached contexts.\n00679| \n00680| ## Platform Support\n00681| \n00682| | Deployment Option | Supported |\n00683| | ------------------------------------------------------------------- | ----------------- |\n00684| | [Node.js server](/docs/app/getting-started/deploying#nodejs-server) | Yes |\n00685| | [Docker container](/docs/app/getting-started/deploying#docker) | Yes |\n00686| | [Static export](/docs/app/getting-started/deploying#static-export) | No |\n00687| | [Adapters](/docs/app/getting-started/deploying#adapters) | Platform-specific |\n00688| \n00689| Learn how to [configure caching](/docs/app/guides/self-hosting#caching-and-isr) when self-hosting Next.js.\n00690| \n00691| ## Version History\n00692| \n00693| | Version | Changes |\n00694| | --------- | ----------------------------------------------------------- |\n00695| | `v16.0.0` | `\"use cache\"` is enabled with the Cache Components feature. |\n00696| | `v15.0.0` | `\"use cache\"` is introduced as an experimental feature. |\n00697| \n\n(End of file - total 697 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache.md"
+ },
+ "output": "\n00001| ---\n00002| title: use cache\n00003| description: Learn how to use the \"use cache\" directive to cache data in your Next.js application.\n00004| related:\n00005| title: Related\n00006| description: View related API references.\n00007| links:\n00008| - app/api-reference/directives/use-cache-private\n00009| - app/api-reference/config/next-config-js/cacheComponents\n00010| - app/api-reference/config/next-config-js/cacheLife\n00011| - app/api-reference/config/next-config-js/cacheHandlers\n00012| - app/api-reference/functions/cacheTag\n00013| - app/api-reference/functions/cacheLife\n00014| - app/api-reference/functions/revalidateTag\n00015| ---\n00016| \n00017| The `use cache` directive allows you to mark a route, React component, or a function as cacheable. It can be used at the top of a file to indicate that all exports in the file should be cached, or inline at the top of a function or component to cache the return value. Functions and components that use `use cache` must be async.\n00018| \n00019| > **Good to know:**\n00020| >\n00021| > - To use cookies or headers, read them outside cached scopes and pass values as arguments. This is the preferred pattern.\n00022| > - If the in-memory cache isn't sufficient for runtime data, [`'use cache: remote'`](/docs/app/api-reference/directives/use-cache-remote) allows platforms to provide a dedicated cache handler, though it requires a network roundtrip to check the cache and typically incurs platform fees.\n00023| > - For compliance requirements or when you can't refactor to pass runtime data as arguments to a `use cache` scope, see [`'use cache: private'`](/docs/app/api-reference/directives/use-cache-private).\n00024| \n00025| ## Usage\n00026| \n00027| `use cache` is a Cache Components feature. To enable it, add the [`cacheComponents`](/docs/app/api-reference/config/next-config-js/cacheComponents) option to your `next.config.ts` file:\n00028| \n00029| ```ts filename=\"next.config.ts\" switcher\n00030| import type { NextConfig } from 'next'\n00031| \n00032| const nextConfig: NextConfig = {\n00033| cacheComponents: true,\n00034| }\n00035| \n00036| export default nextConfig\n00037| ```\n00038| \n00039| ```js filename=\"next.config.js\" switcher\n00040| /** @type {import('next').NextConfig} */\n00041| const nextConfig = {\n00042| cacheComponents: true,\n00043| }\n00044| \n00045| module.exports = nextConfig\n00046| ```\n00047| \n00048| Then, add `use cache` at the file, component, or function level. All functions and components using `use cache` must be async. When used at file level, every exported function becomes a cached function and must also be async:\n00049| \n00050| ```tsx\n00051| // File level\n00052| 'use cache'\n00053| \n00054| export default async function Page() {\n00055| // ...\n00056| }\n00057| \n00058| // Component level\n00059| export async function MyComponent() {\n00060| 'use cache'\n00061| return <>>\n00062| }\n00063| \n00064| // Function level\n00065| export async function getData() {\n00066| 'use cache'\n00067| const data = await fetch('/api/data')\n00068| return data\n00069| }\n00070| ```\n00071| \n00072| ## How `use cache` works\n00073| \n00074| ### Cache keys\n00075| \n00076| A cache entry's key is generated using a serialized version of its inputs, which includes:\n00077| \n00078| 1. **Build ID** - Unique per build, changing this invalidates all cache entries. If [`deploymentId`](/docs/app/api-reference/config/next-config-js/deploymentId) is configured, it overrides the build ID for cache key purposes.\n00079| 2. **Function ID** - A secure hash of the function's location and signature in the codebase\n00080| 3. **Serializable arguments** - Props (for components) or function arguments\n00081| 4. **HMR refresh hash** (development only) - Invalidates cache on hot module replacement\n00082| \n00083| When a cached function references variables from outer scopes, those variables are automatically captured and bound as arguments, making them part of the cache key.\n00084| \n00085| ```tsx filename=\"lib/data.ts\"\n00086| async function Component({ userId }: { userId: string }) {\n00087| const getData = async (filter: string) => {\n00088| 'use cache'\n00089| // Cache key includes both userId (from closure) and filter (argument)\n00090| return fetch(`/api/users/${userId}/data?filter=${filter}`)\n00091| }\n00092| \n00093| return getData('active')\n00094| }\n00095| ```\n00096| \n00097| In the snippet above, `userId` is captured from the outer scope and `filter` is passed as an argument, so both become part of the `getData` function's cache key. This means different user and filter combinations will have separate cache entries.\n00098| \n00099| > **Good to know:** When a cached function reads [root parameters](/docs/app/api-reference/functions/next-root-params), only the ones it actually reads become part of its cache key.\n00100| \n00101| ## Serialization\n00102| \n00103| Arguments to cached functions and their return values must be serializable.\n00104| \n00105| For a complete reference, see:\n00106| \n00107| - [Serializable arguments](https://react.dev/reference/rsc/use-server#serializable-parameters-and-return-values) - Uses **React Server Components** serialization\n00108| - [Serializable return types](https://react.dev/reference/rsc/use-client#serializable-types) - Uses **React Client Components** serialization\n00109| \n00110| > **Good to know:** Arguments and return values use different serialization systems. Server Component serialization (for arguments) is more restrictive than Client Component serialization (for return values). This means you can return JSX elements but cannot accept them as arguments unless using pass-through patterns.\n00111| \n00112| ### Supported types\n00113| \n00114| **Arguments:**\n00115| \n00116| - Primitives: `string`, `number`, `boolean`, `null`, `undefined`\n00117| - Plain objects: `{ key: value }`\n00118| - Arrays: `[1, 2, 3]`\n00119| - Dates, Maps, Sets, TypedArrays, ArrayBuffers\n00120| - React elements (as pass-through only)\n00121| \n00122| **Return values:**\n00123| \n00124| - Same as arguments, plus JSX elements\n00125| \n00126| ### Unsupported types\n00127| \n00128| - Class instances\n00129| - Functions (except as pass-through)\n00130| - Symbols, WeakMaps, WeakSets\n00131| - URL instances\n00132| \n00133| ```tsx filename=\"app/components/user-card.tsx\"\n00134| // Valid - primitives and plain objects\n00135| async function UserCard({\n00136| id,\n00137| config,\n00138| }: {\n00139| id: string\n00140| config: { theme: string }\n00141| }) {\n00142| 'use cache'\n00143| return
{id}
\n00144| }\n00145| \n00146| // Invalid - class instance\n00147| async function UserProfile({ user }: { user: UserClass }) {\n00148| 'use cache'\n00149| // Error: Cannot serialize class instance\n00150| return
{user.name}
\n00151| }\n00152| ```\n00153| \n00154| ### Pass-through (non-serializable arguments)\n00155| \n00156| You can accept non-serializable values **as long as you don't introspect them**. This enables composition patterns with `children` and Server Actions:\n00157| \n00158| ```tsx filename=\"app/components/cached-wrapper.tsx\"\n00159| async function CachedWrapper({ children }: { children: ReactNode }) {\n00160| 'use cache'\n00161| // Don't read or modify children - just pass it through\n00162| return (\n00163|
\n00164| Cached Header\n00165| {children}\n00166|
\n00167| )\n00168| }\n00169| \n00170| // Usage: children can be dynamic\n00171| export default function Page() {\n00172| return (\n00173| \n00174| {/* Not cached, passed through */}\n00175| \n00176| )\n00177| }\n00178| ```\n00179| \n00180| You can also pass Server Actions through cached components:\n00181| \n00182| ```tsx filename=\"app/components/cached-form.tsx\"\n00183| async function CachedForm({ action }: { action: () => Promise }) {\n00184| 'use cache'\n00185| // Don't call action here - just pass it through\n00186| return
{/* ... */}
\n00187| }\n00188| ```\n00189| \n00190| ## Constraints\n00191| \n00192| Cached functions execute in an isolated environment. The following constraints ensure cache behavior remains predictable and secure.\n00193| \n00194| ### Request-time APIs\n00195| \n00196| Cached functions and components **cannot** directly access runtime APIs like `cookies()`, `headers()`, or `searchParams`. Instead, read these values outside the cached scope and pass them as arguments.\n00197| \n00198| ### Runtime caching considerations\n00199| \n00200| While `use cache` is designed primarily to include uncached data in the static shell, it can also cache data at runtime using in-memory LRU (Least Recently Used) storage.\n00201| \n00202| With the default in-memory handler, runtime cache behavior depends on your hosting environment:\n00203| \n00204| | Environment | Runtime Caching Behavior |\n00205| | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n00206| | **Serverless** | Cache entries typically don't persist across requests (each request can be a different instance), or during revalidation. Build-time caching works normally. |\n00207| | **Self-hosted** | Cache entries persist across requests. Control cache size with [`cacheMaxMemorySize`](/docs/app/api-reference/config/next-config-js/incrementalCacheHandlerPath). |\n00208| \n00209| For example, in a serverless environment, a cached function shared by two pages executes on each static shell revalidation, whereas in self-hosted or environments with persistent memory, the cached output is reused if it's still fresh.\n00210| \n00211| If the default in-memory cache isn't enough, consider **[`use cache: remote`](/docs/app/api-reference/directives/use-cache-remote)** which allows platforms to provide a dedicated cache handler (like Redis or KV database). This helps reduce hits against data sources not scaled to your total traffic, though it comes with costs (storage, network latency, platform fees).\n00212| \n00213| > [!NOTE]\n00214| > With the default in-memory handler, serverless instances are ephemeral, so entries may not be reused between requests, unlike with `use cache: remote`. Neither caching directive carries over to a new deploy, because the [cache key](#cache-keys) includes the build (or `deploymentId`) ID.\n00215| >\n00216| > For data that needs to persist across deploys, use [`unstable_cache`](/docs/app/api-reference/functions/unstable_cache) for non-`fetch` functions or the [`fetch`](/docs/app/api-reference/functions/fetch) cache.\n00217| \n00218| Very rarely, for compliance requirements or when you can't refactor your code to pass runtime data as arguments to a `use cache` scope, you might need [`use cache: private`](/docs/app/api-reference/directives/use-cache-private).\n00219| \n00220| ### Draft Mode\n00221| \n00222| When [Draft Mode](/docs/app/guides/draft-mode) is enabled, all cached functions and components re-execute on every request, and results are not saved to the cache. This ensures draft content is always fresh without requiring any changes to your caching code.\n00223| \n00224| You can read `isEnabled` from [`draftMode()`](/docs/app/api-reference/functions/draft-mode) inside a `use cache` scope, however, other runtime APIs like `cookies()` and `headers()` are not allowed, even when Draft Mode is active. See [Passing runtime values to cached functions](/docs/app/getting-started/caching#passing-runtime-values-to-cached-functions) for the recommended pattern.\n00225| \n00226| ```tsx filename=\"app/components/content.tsx\"\n00227| import { draftMode } from 'next/headers'\n00228| \n00229| async function Content() {\n00230| 'use cache'\n00231| \n00232| const { isEnabled } = await draftMode()\n00233| const url = isEnabled\n00234| ? 'https://draft.example.com/content'\n00235| : 'https://production.example.com/content'\n00236| \n00237| const data = await fetch(url)\n00238| return {/* ... */}\n00239| }\n00240| ```\n00241| \n00242| Calling `enable()` or `disable()` inside a caching directive scope will also throw an error. Draft Mode can only be toggled in [Route Handlers](/docs/app/api-reference/file-conventions/route) or [Server Actions](/docs/app/getting-started/mutating-data).\n00243| \n00244| ### React.cache isolation\n00245| \n00246| [`React.cache`](https://react.dev/reference/react/cache) operates in an isolated scope inside `use cache` boundaries. Values stored via `React.cache` outside a `use cache` function are not visible inside it.\n00247| \n00248| This means you cannot use `React.cache` to pass data into a `use cache` scope:\n00249| \n00250| ```tsx\n00251| import { cache } from 'react'\n00252| \n00253| const store = cache(() => ({ current: null as string | null }))\n00254| \n00255| function Parent() {\n00256| const shared = store()\n00257| shared.current = 'value from parent'\n00258| return \n00259| }\n00260| \n00261| async function Child() {\n00262| 'use cache'\n00263| const shared = store()\n00264| // shared.current is null, not 'value from parent'\n00265| // use cache has its own isolated React.cache scope\n00266| return
{shared.current}
\n00267| }\n00268| ```\n00269| \n00270| This isolation ensures cached functions have predictable, self-contained behavior. To pass data into a `use cache` scope, use function arguments instead.\n00271| \n00272| ## `use cache` at runtime\n00273| \n00274| On the **server**, cache entries are stored in-memory and respect the `revalidate` and `expire` times from your `cacheLife` configuration. You can customize the cache storage by configuring [`cacheHandlers`](/docs/app/api-reference/config/next-config-js/cacheHandlers) in your `next.config.js` file.\n00275| \n00276| On the **client**, content from the server cache is stored in the browser's memory for the duration defined by the `stale` time. The client router enforces a **minimum 30-second stale time**, regardless of configuration.\n00277| \n00278| The `x-nextjs-stale-time` response header communicates cache lifetime from server to client, ensuring coordinated behavior.\n00279| \n00280| ## Revalidation\n00281| \n00282| By default, `use cache` uses the `default` profile with these settings:\n00283| \n00284| - **stale**: 5 minutes (client-side)\n00285| - **revalidate**: 15 minutes (server-side)\n00286| - **expire**: Never expires by time\n00287| \n00288| ```tsx filename=\"lib/data.ts\"\n00289| async function getData() {\n00290| 'use cache'\n00291| // Implicitly uses default profile\n00292| return fetch('/api/data')\n00293| }\n00294| ```\n00295| \n00296| ### Customizing cache lifetime\n00297| \n00298| Use the [`cacheLife`](/docs/app/api-reference/functions/cacheLife) function to customize cache duration:\n00299| \n00300| ```tsx filename=\"lib/data.ts\"\n00301| import { cacheLife } from 'next/cache'\n00302| \n00303| async function getData() {\n00304| 'use cache'\n00305| cacheLife('hours') // Use built-in 'hours' profile\n00306| return fetch('/api/data')\n00307| }\n00308| ```\n00309| \n00310| ### On-demand revalidation\n00311| \n00312| Use [`cacheTag`](/docs/app/api-reference/functions/cacheTag), [`updateTag`](/docs/app/api-reference/functions/updateTag), or [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) for on-demand cache invalidation:\n00313| \n00314| ```tsx filename=\"lib/data.ts\"\n00315| import { cacheTag } from 'next/cache'\n00316| \n00317| async function getProducts() {\n00318| 'use cache'\n00319| cacheTag('products')\n00320| return fetch('/api/products')\n00321| }\n00322| ```\n00323| \n00324| ```tsx filename=\"app/actions.ts\"\n00325| 'use server'\n00326| \n00327| import { updateTag } from 'next/cache'\n00328| \n00329| export async function updateProduct() {\n00330| await db.products.update(...)\n00331| updateTag('products') // Invalidates all 'products' caches\n00332| }\n00333| ```\n00334| \n00335| Both `cacheLife` and `cacheTag` integrate across client and server caching layers, meaning you configure your caching semantics in one place and they apply everywhere.\n00336| \n00337| ## Examples\n00338| \n00339| ### Caching an entire route with `use cache`\n00340| \n00341| To prerender an entire route, add `use cache` to the top of **both** the `layout` and `page` files. Each of these segments are treated as separate entry points in your application, and will be cached independently.\n00342| \n00343| ```tsx filename=\"app/layout.tsx\" switcher\n00344| 'use cache'\n00345| \n00346| export default async function Layout({ children }: { children: ReactNode }) {\n00347| return
{children}
\n00348| }\n00349| ```\n00350| \n00351| ```jsx filename=\"app/layout.js\" switcher\n00352| 'use cache'\n00353| \n00354| export default async function Layout({ children }) {\n00355| return
{children}
\n00356| }\n00357| ```\n00358| \n00359| Any components imported and nested in `page` file are part of the cache output associated with the `page`.\n00360| \n00361| ```tsx filename=\"app/page.tsx\" switcher\n00362| 'use cache'\n00363| \n00364| async function Users() {\n00365| const users = await fetch('/api/users')\n00366| // loop through users\n00367| }\n00368| \n00369| export default async function Page() {\n00370| return (\n00371| \n00372| \n00373| \n00374| )\n00375| }\n00376| ```\n00377| \n00378| ```jsx filename=\"app/page.js\" switcher\n00379| 'use cache'\n00380| \n00381| async function Users() {\n00382| const users = await fetch('/api/users')\n00383| // loop through users\n00384| }\n00385| \n00386| export default async function Page() {\n00387| return (\n00388| \n00389| \n00390| \n00391| )\n00392| }\n00393| ```\n00394| \n00395| > **Good to know**:\n00396| >\n00397| > - If `use cache` is added only to the `layout` or the `page`, only that route segment and any components imported into it will be cached.\n00398| \n00399| ### Caching a component's output with `use cache`\n00400| \n00401| You can use `use cache` at the component level to cache any fetches or computations performed within that component. The cache entry will be reused as long as the serialized props produce the same value in each instance.\n00402| \n00403| ```tsx filename=\"app/components/bookings.tsx\" highlight={2} switcher\n00404| export async function Bookings({ type = 'haircut' }: BookingsProps) {\n00405| 'use cache'\n00406| async function getBookingsData() {\n00407| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00408| return data\n00409| }\n00410| return //...\n00411| }\n00412| \n00413| interface BookingsProps {\n00414| type: string\n00415| }\n00416| ```\n00417| \n00418| ```jsx filename=\"app/components/bookings.js\" highlight={2} switcher\n00419| export async function Bookings({ type = 'haircut' }) {\n00420| 'use cache'\n00421| async function getBookingsData() {\n00422| const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)\n00423| return data\n00424| }\n00425| return //...\n00426| }\n00427| ```\n00428| \n00429| ### Caching function output with `use cache`\n00430| \n00431| Since you can add `use cache` to any asynchronous function, you aren't limited to caching components or routes only. You might want to cache a network request, a database query, or a slow computation.\n00432| \n00433| ```tsx filename=\"app/actions.ts\" highlight={2} switcher\n00434| export async function getData() {\n00435| 'use cache'\n00436| \n00437| const data = await fetch('/api/data')\n00438| return data\n00439| }\n00440| ```\n00441| \n00442| ```jsx filename=\"app/actions.js\" highlight={2} switcher\n00443| export async function getData() {\n00444| 'use cache'\n00445| \n00446| const data = await fetch('/api/data')\n00447| return data\n00448| }\n00449| ```\n00450| \n00451| > **Good to know:** When a cached directive (`use cache`, [`use cache: private`](/docs/app/api-reference/directives/use-cache-private), or [`use cache: remote`](/docs/app/api-reference/directives/use-cache-remote)) is at the top of a file, you can import its exported functions into a Client Component and call them directly; they run on the server and return the result, similar to a [Server Function](/docs/app/glossary#server-function). Prefer calling cached functions on the server and passing results down as props.\n00452| \n00453| ### Interleaving\n00454| \n00455| In React, composition with `children` or slots is a well-known pattern for building flexible components. When using `use cache`, you can continue to compose your UI in this way. Anything included as `children`, or other compositional slots, in the returned JSX will be passed through the cached component without affecting its cache entry.\n00456| \n00457| As long as you don't directly reference any of the JSX slots inside the body of the cacheable function itself, their presence in the returned output won't affect the cache entry.\n00458| \n00459| ```tsx filename=\"app/page.tsx\" switcher\n00460| export default async function Page() {\n00461| const uncachedData = await getData()\n00462| return (\n00463| // Pass compositional slots as props, e.g. header and children\n00464| Home}>\n00465| {/* DynamicComponent is provided as the children slot */}\n00466| \n00467| \n00468| )\n00469| }\n00470| \n00471| async function CacheComponent({\n00472| header, // header: a compositional slot, injected as a prop\n00473| children, // children: another slot for nested composition\n00474| }: {\n00475| header: ReactNode\n00476| children: ReactNode\n00477| }) {\n00478| 'use cache'\n00479| const cachedData = await fetch('/api/cached-data')\n00480| return (\n00481|
\n00514| )\n00515| }\n00516| ```\n00517| \n00518| You can also pass Server Actions through cached components to Client Components without invoking them inside the cacheable function.\n00519| \n00520| ```tsx filename=\"app/page.tsx\" switcher\n00521| import ClientComponent from './ClientComponent'\n00522| \n00523| export default async function Page() {\n00524| const performUpdate = async () => {\n00525| 'use server'\n00526| // Perform some server-side update\n00527| await db.update(...)\n00528| }\n00529| \n00530| return \n00531| }\n00532| \n00533| async function CachedComponent({\n00534| performUpdate,\n00535| }: {\n00536| performUpdate: () => Promise\n00537| }) {\n00538| 'use cache'\n00539| // Do not call performUpdate here\n00540| return \n00541| }\n00542| ```\n00543| \n00544| ```jsx filename=\"app/page.js\" switcher\n00545| import ClientComponent from './ClientComponent'\n00546| \n00547| export default async function Page() {\n00548| const performUpdate = async () => {\n00549| 'use server'\n00550| // Perform some server-side update\n00551| await db.update(...)\n00552| }\n00553| \n00554| return \n00555| }\n00556| \n00557| async function CachedComponent({ performUpdate }) {\n00558| 'use cache'\n00559| // Do not call performUpdate here\n00560| return \n00561| }\n00562| ```\n00563| \n00564| ```tsx filename=\"app/ClientComponent.tsx\" switcher\n00565| 'use client'\n00566| \n00567| export default function ClientComponent({\n00568| action,\n00569| }: {\n00570| action: () => Promise\n00571| }) {\n00572| return Update\n00573| }\n00574| ```\n00575| \n00576| ```jsx filename=\"app/ClientComponent.js\" switcher\n00577| 'use client'\n00578| \n00579| export default function ClientComponent({ action }) {\n00580| return Update\n00581| }\n00582| ```\n00583| \n00584| ## Troubleshooting\n00585| \n00586| ### Debugging cache behavior\n00587| \n00588| #### Verbose logging\n00589| \n00590| Set `NEXT_PRIVATE_DEBUG_CACHE=1` for verbose cache logging:\n00591| \n00592| ```bash\n00593| NEXT_PRIVATE_DEBUG_CACHE=1 npm run dev\n00594| # or for production\n00595| NEXT_PRIVATE_DEBUG_CACHE=1 npm run start\n00596| ```\n00597| \n00598| > **Good to know:** This environment variable also logs ISR and other caching mechanisms. See [Verifying correct production behavior](/docs/app/guides/incremental-static-regeneration#verifying-correct-production-behavior) for more details.\n00599| \n00600| #### Console log replays\n00601| \n00602| In development, console logs from cached functions appear with a `Cache` prefix.\n00603| \n00604| ### Build Hangs (Cache Timeout)\n00605| \n00606| If your build hangs, you're accessing Promises that resolve to uncached or runtime data, created outside a `use cache` boundary. The cached function waits for data that can't resolve during the build, causing a timeout after 50 seconds.\n00607| \n00608| When the build timeouts you'll see this error message:\n00609| \n00610| > Error: Filling a cache during prerender timed out, likely because request-specific arguments such as params, searchParams, cookies() or uncached data were used inside \"use cache\".\n00611| \n00612| Common ways this happens: passing such Promises as props, accessing them via closure, or retrieving them from shared storage (Maps).\n00613| \n00614| > **Good to know:** Directly calling `cookies()` or `headers()` inside `use cache` fails immediately with a [different error](/docs/messages/next-request-in-use-cache), not a timeout.\n00615| \n00616| **Passing runtime data Promises as props:**\n00617| \n00618| ```tsx filename=\"app/page.tsx\"\n00619| import { cookies } from 'next/headers'\n00620| import { Suspense } from 'react'\n00621| \n00622| export default function Page() {\n00623| return (\n00624| Loading...}>\n00625| \n00626| \n00627| )\n00628| }\n00629| \n00630| async function Dynamic() {\n00631| const cookieStore = cookies()\n00632| return // Build hangs\n00633| }\n00634| \n00635| async function Cached({ promise }: { promise: Promise }) {\n00636| 'use cache'\n00637| const data = await promise // Waits for runtime data during build\n00638| return
..
\n00639| }\n00640| ```\n00641| \n00642| Await the `cookies` store in the `Dynamic` component, and pass a cookie value to the `Cached` component.\n00643| \n00644| **Shared deduplication storage:**\n00645| \n00646| ```tsx filename=\"app/page.tsx\"\n00647| // Problem: Map stores dynamic Promises, accessed by cached code\n00648| import { Suspense } from 'react'\n00649| \n00650| const cache = new Map>()\n00651| \n00652| export default function Page() {\n00653| return (\n00654| <>\n00655| Loading...}>\n00656| \n00657| \n00658| \n00659| >\n00660| )\n00661| }\n00662| \n00663| async function Dynamic({ id }: { id: string }) {\n00664| // Stores dynamic Promise in shared Map\n00665| cache.set(\n00666| id,\n00667| fetch(`https://api.example.com/${id}`).then((r) => r.text())\n00668| )\n00669| return
Dynamic
\n00670| }\n00671| \n00672| async function Cached({ id }: { id: string }) {\n00673| 'use cache'\n00674| return
{await cache.get(id)}
// Build hangs - retrieves dynamic Promise\n00675| }\n00676| ```\n00677| \n00678| Use Next.js's built-in `fetch()` deduplication or use separate Maps for cached and uncached contexts.\n00679| \n00680| ## Platform Support\n00681| \n00682| | Deployment Option | Supported |\n00683| | ------------------------------------------------------------------- | ----------------- |\n00684| | [Node.js server](/docs/app/getting-started/deploying#nodejs-server) | Yes |\n00685| | [Docker container](/docs/app/getting-started/deploying#docker) | Yes |\n00686| | [Static export](/docs/app/getting-started/deploying#static-export) | No |\n00687| | [Adapters](/docs/app/getting-started/deploying#adapters) | Platform-specific |\n00688| \n00689| Learn how to [configure caching](/docs/app/guides/self-hosting#caching-and-isr) when self-hosting Next.js.\n00690| \n00691| ## Version History\n00692| \n00693| | Version | Changes |\n00694| | --------- | ----------------------------------------------------------- |\n00695| | `v16.0.0` | `\"use cache\"` is enabled with the Cache Components feature. |\n00696| | `v15.0.0` | `\"use cache\"` is introduced as an experimental feature. |\n00697| \n\n(End of file - total 697 lines)\n",
+ "title": "node_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache.md",
+ "metadata": {
+ "preview": "---\ntitle: use cache\ndescription: Learn how to use the \"use cache\" directive to cache data in your Next.js application.\nrelated:\n title: Related\n description: View related API references.\n links:\n - app/api-reference/directives/use-cache-private\n - app/api-reference/config/next-config-js/cacheComponents\n - app/api-reference/config/next-config-js/cacheLife\n - app/api-reference/config/next-config-js/cacheHandlers\n - app/api-reference/functions/cacheTag\n - app/api-reference/functions/cacheLife\n - app/api-reference/functions/revalidateTag\n---\n\nThe `use cache` directive allows you to mark a route, React component, or a function as cacheable. It can be used at the top of a file to indicate that all exports in the file should be cached, or inline at the top of a function or component to cache the return value. Functions and components that use `use cache` must be async.\n\n> **Good to know:**\n>"
+ },
+ "time": {
+ "start": 1781392546180,
+ "end": 1781392546187
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:46.244Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "args": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheLife.md",
+ "_extractedPath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheLife.md"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781392546244,
+ "sessionID": "ses_13cbb6ca7ffeDluJj6gL6KvvXT",
+ "part": {
+ "id": "prt_ec345198700191n6zRICHyqM01",
+ "sessionID": "ses_13cbb6ca7ffeDluJj6gL6KvvXT",
+ "messageID": "msg_ec345015e001is3nMOxoQaAHTT",
+ "type": "tool",
+ "callID": "read_17",
+ "tool": "read",
+ "state": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheLife.md"
+ },
+ "output": "\n00001| ---\n00002| title: cacheLife\n00003| description: Learn how to use the cacheLife function to set the cache expiration time for a cached function or component.\n00004| related:\n00005| title: Related\n00006| description: View related API references.\n00007| links:\n00008| - app/api-reference/config/next-config-js/cacheComponents\n00009| - app/api-reference/directives/use-cache\n00010| - app/api-reference/functions/revalidateTag\n00011| - app/api-reference/functions/cacheTag\n00012| ---\n00013| \n00014| The `cacheLife` function is used to set the cache lifetime of a function or component. It should be used alongside the [`use cache`](/docs/app/api-reference/directives/use-cache) directive, and within the scope of the function or component.\n00015| \n00016| ## Usage\n00017| \n00018| ### Basic setup\n00019| \n00020| To use `cacheLife`, first enable the [`cacheComponents` flag](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.js` file:\n00021| \n00022| ```ts filename=\"next.config.ts\" switcher\n00023| import type { NextConfig } from 'next'\n00024| \n00025| const nextConfig: NextConfig = {\n00026| cacheComponents: true,\n00027| }\n00028| \n00029| export default nextConfig\n00030| ```\n00031| \n00032| ```js filename=\"next.config.js\" switcher\n00033| const nextConfig = {\n00034| cacheComponents: true,\n00035| }\n00036| \n00037| export default nextConfig\n00038| ```\n00039| \n00040| `cacheLife` can only be used within a cache directive scope.\n00041| \n00042| Add a cache directive (for example, `use cache`) at the file level or at the top of an async function or component.\n00043| \n00044| `cacheLife` cannot be used at module scope. Calling it at the top level of a file will throw an error.\n00045| \n00046| > **Good to know**:\n00047| >\n00048| > - Calling `cacheLife` is optional. If omitted, a default cache lifetime is applied.\n00049| > - Call `cacheLife` in the same function or component where caching is defined. Avoid abstracting it into shared utilities so the cache behavior remains explicit and easy to reason about.\n00050| > - If you call `cacheLife`, ensure only one call executes per function invocation. You can call it in different control flow branches, but only one should run per request. See the [conditional cache lifetimes](#conditional-cache-lifetimes) example.\n00051| \n00052| ### Using preset profiles\n00053| \n00054| Next.js provides preset cache profiles that cover common caching needs. Each profile balances three factors:\n00055| \n00056| - How long users see cached content without checking for updates (client-side)\n00057| - How often fresh content is generated on the server\n00058| - When old content expires completely\n00059| \n00060| Choose a profile based on how frequently your content changes:\n00061| \n00062| - **`seconds`** - Real-time data (stock prices, live scores)\n00063| - **`minutes`** - Frequently updated (social feeds, news)\n00064| - **`hours`** - Multiple daily updates (product inventory, weather)\n00065| - **`days`** - Daily updates (blog posts, articles)\n00066| - **`weeks`** - Weekly updates (podcasts, newsletters)\n00067| - **`max`** - Rarely changes (legal pages, archived content)\n00068| \n00069| Import `cacheLife` and pass a profile name:\n00070| \n00071| ```tsx filename=\"app/blog/page.tsx\" highlight={1,5}\n00072| 'use cache'\n00073| import { cacheLife } from 'next/cache'\n00074| \n00075| export default async function BlogPage() {\n00076| cacheLife('days') // Blog content updated daily\n00077| \n00078| const posts = await getBlogPosts()\n00079| return
{/* render posts */}
\n00080| }\n00081| ```\n00082| \n00083| The profile name tells Next.js how to cache the entire function's output. If you don't call `cacheLife`, the `default` profile is used. See [preset cache profiles](#preset-cache-profiles) for timing details.\n00084| \n00085| ## Reference\n00086| \n00087| ### Cache profile properties\n00088| \n00089| Cache profiles control caching behavior through three timing properties:\n00090| \n00091| - **[`stale`](#stale)**: How long the client can use cached data without checking the server\n00092| - **[`revalidate`](#revalidate)**: After this time, the next request will trigger a background refresh\n00093| - **[`expire`](#expire)**: After this time with no requests, the next one waits for fresh content\n00094| \n00095| #### `stale`\n00096| \n00097| **Client-side:** How long the client can use cached data without checking the server.\n00098| \n00099| During this time, the client-side router displays cached content immediately without any network request. After this period expires, the router must check with the server on the next navigation or request. This provides instant page loads from the client cache, but data may be outdated.\n00100| \n00101| - If omitted, defaults to the `default` profile's `stale` value (5 minutes, see [`staleTimes`](/docs/app/api-reference/config/next-config-js/staleTimes))\n00102| \n00103| ```tsx\n00104| cacheLife({ stale: 300 }) // 5 minutes\n00105| ```\n00106| \n00107| #### `revalidate`\n00108| \n00109| How often the server regenerates cached content in the background.\n00110| \n00111| - When a request arrives after this period, the server:\n00112| 1. Serves the cached version immediately (if available)\n00113| 2. Regenerates content in the background\n00114| 3. Updates the cache with fresh content\n00115| - Similar to [Incremental Static Regeneration (ISR)](/docs/app/guides/incremental-static-regeneration)\n00116| - If omitted, defaults to the `default` profile's `revalidate` value (15 minutes)\n00117| \n00118| ```tsx\n00119| cacheLife({ revalidate: 900 }) // 15 minutes\n00120| ```\n00121| \n00122| #### `expire`\n00123| \n00124| Maximum time before the server must regenerate cached content.\n00125| \n00126| - After this period with no traffic, the server regenerates content synchronously on the next request\n00127| - When you set both `revalidate` and `expire`, `expire` must be longer than `revalidate`. Next.js validates this and raises an error for invalid configurations.\n00128| - If omitted, defaults to the `default` profile's `expire` value (never expires)\n00129| \n00130| ```tsx\n00131| cacheLife({ expire: 3600 }) // 1 hour\n00132| ```\n00133| \n00134| ### Preset cache profiles\n00135| \n00136| If you don't specify a profile, Next.js uses the `default` profile. We recommend explicitly setting a profile to make caching behavior clear.\n00137| \n00138| | **Profile** | **Use Case** | `stale` | `revalidate` | `expire` |\n00139| | ----------- | -------------------------------------- | ---------- | ------------ | -------- |\n00140| | `default` | Standard content | 5 minutes | 15 minutes | never |\n00141| | `seconds` | Real-time data | 30 seconds | 1 second | 1 minute |\n00142| | `minutes` | Frequently updated content | 5 minutes | 1 minute | 1 hour |\n00143| | `hours` | Content updated multiple times per day | 5 minutes | 1 hour | 1 day |\n00144| | `days` | Content updated daily | 5 minutes | 1 day | 1 week |\n00145| | `weeks` | Content updated weekly | 5 minutes | 1 week | 30 days |\n00146| | `max` | Stable content that rarely changes | 5 minutes | 30 days | 1 year |\n00147| \n00148| ### Custom cache profiles\n00149| \n00150| Define reusable cache profiles in your `next.config.ts` file:\n00151| \n00152| ```ts filename=\"next.config.ts\"\n00153| import type { NextConfig } from 'next'\n00154| \n00155| const nextConfig: NextConfig = {\n00156| cacheComponents: true,\n00157| cacheLife: {\n00158| biweekly: {\n00159| stale: 60 * 60 * 24 * 14, // 14 days\n00160| revalidate: 60 * 60 * 24, // 1 day\n00161| expire: 60 * 60 * 24 * 14, // 14 days\n00162| },\n00163| },\n00164| }\n00165| \n00166| export default nextConfig\n00167| ```\n00168| \n00169| ```js filename=\"next.config.js\" switcher\n00170| const nextConfig = {\n00171| cacheComponents: true,\n00172| cacheLife: {\n00173| biweekly: {\n00174| stale: 60 * 60 * 24 * 14, // 14 days\n00175| revalidate: 60 * 60 * 24, // 1 day\n00176| expire: 60 * 60 * 24 * 14, // 14 days\n00177| },\n00178| },\n00179| }\n00180| \n00181| module.exports = nextConfig\n00182| ```\n00183| \n00184| The example above caches for 14 days, checks for updates daily, and expires the cache after 14 days. You can then reference this profile throughout your application by its name:\n00185| \n00186| > **Good to know**: Any omitted properties in a custom profile inherit from the `default` profile. This also applies to inline profile objects passed directly to `cacheLife()`.\n00187| \n00188| ```tsx filename=\"app/page.tsx\" highlight={5}\n00189| 'use cache'\n00190| import { cacheLife } from 'next/cache'\n00191| \n00192| export default async function Page() {\n00193| cacheLife('biweekly')\n00194| return
Page
\n00195| }\n00196| ```\n00197| \n00198| ### Overriding the default cache profiles\n00199| \n00200| While the default cache profiles provide a useful way to think about how fresh or stale any given part of cacheable output can be, you may prefer different named profiles to better align with your applications caching strategies.\n00201| \n00202| You can override the default named cache profiles by creating a new configuration with the same name as the defaults.\n00203| \n00204| The example below shows how to override the default `\"days\"` cache profile:\n00205| \n00206| ```ts filename=\"next.config.ts\"\n00207| const nextConfig = {\n00208| cacheComponents: true,\n00209| cacheLife: {\n00210| // Override the 'days' profile\n00211| days: {\n00212| stale: 3600, // 1 hour\n00213| revalidate: 900, // 15 minutes\n00214| expire: 86400, // 1 day\n00215| },\n00216| },\n00217| }\n00218| \n00219| export default nextConfig\n00220| ```\n00221| \n00222| ### Inline cache profiles\n00223| \n00224| For one-off cases, pass a profile object directly to `cacheLife`:\n00225| \n00226| ```tsx filename=\"app/page.tsx\"\n00227| 'use cache'\n00228| import { cacheLife } from 'next/cache'\n00229| \n00230| export default async function Page() {\n00231| cacheLife({\n00232| stale: 3600,\n00233| revalidate: 900,\n00234| expire: 86400,\n00235| })\n00236| \n00237| return
Page
\n00238| }\n00239| ```\n00240| \n00241| Inline profiles apply only to the specific function or component. For reusable configurations, define custom profiles in `next.config.ts`.\n00242| \n00243| Using `cacheLife({})` with an empty object applies the `default` profile values.\n00244| \n00245| ### Client cache behavior\n00246| \n00247| The `stale` property controls the [Client Cache](/docs/app/glossary#client-cache), not the `Cache-Control` header:\n00248| \n00249| - The server sends the stale time via the `x-nextjs-stale-time` response header\n00250| - The client router uses this value to determine when to revalidate\n00251| - **Minimum of 30 seconds is enforced** to ensure prefetched links remain usable\n00252| \n00253| This 30-second minimum prevents prefetched data from expiring before users can click on links. It only applies to time-based expiration.\n00254| \n00255| When you call revalidation functions from a Server Action ([`revalidateTag`](/docs/app/api-reference/functions/revalidateTag), [`revalidatePath`](/docs/app/api-reference/functions/revalidatePath), [`updateTag`](/docs/app/api-reference/functions/updateTag), or [`refresh`](/docs/app/api-reference/functions/refresh)), the entire client cache is immediately cleared, bypassing the stale time.\n00256| \n00257| > **Good to know**: The `stale` property in `cacheLife` differs from [`staleTimes`](/docs/app/api-reference/config/next-config-js/staleTimes). While `staleTimes` is a global setting affecting all routes, `cacheLife` allows per-function or per-route configuration. Updating `staleTimes.static` also updates the `stale` value of the `default` cache profile.\n00258| \n00259| ### Prerendering behavior\n00260| \n00261| Caches with very short lifetimes — zero `revalidate` or `expire` under 5 minutes — are automatically excluded from prerenders and become \"dynamic holes\" instead. This includes the `seconds` profile.\n00262| \n00263| This behavior allows you to mix static and dynamic content within the same page. Static parts are prerendered, while short-lived caches create boundaries where data is fetched at request time rather than build time. Use a `` boundary around dynamic caches to provide a fallback while content loads.\n00264| \n00265| ## Examples\n00266| \n00267| ### Using preset profiles\n00268| \n00269| The simplest way to configure caching is using preset profiles. Choose one that matches your content's update pattern:\n00270| \n00271| ```tsx filename=\"app/blog/[slug]/page.tsx\"\n00272| import { cacheLife } from 'next/cache'\n00273| \n00274| export default async function BlogPost() {\n00275| 'use cache'\n00276| cacheLife('days') // Blog posts updated daily\n00277| \n00278| const post = await fetchBlogPost()\n00279| return {post.content}\n00280| }\n00281| ```\n00282| \n00283| ```tsx filename=\"app/products/[id]/page.tsx\"\n00284| import { cacheLife } from 'next/cache'\n00285| \n00286| export default async function ProductPage() {\n00287| 'use cache'\n00288| cacheLife('hours') // Product data updated multiple times per day\n00289| \n00290| const product = await fetchProduct()\n00291| return
{product.name}
\n00292| }\n00293| ```\n00294| \n00295| ### Custom profiles for specific needs\n00296| \n00297| Define custom profiles when preset options don't match your requirements:\n00298| \n00299| ```ts filename=\"next.config.ts\"\n00300| import type { NextConfig } from 'next'\n00301| \n00302| const nextConfig: NextConfig = {\n00303| cacheComponents: true,\n00304| cacheLife: {\n00305| editorial: {\n00306| stale: 600, // 10 minutes\n00307| revalidate: 3600, // 1 hour\n00308| expire: 86400, // 1 day\n00309| },\n00310| marketing: {\n00311| stale: 300, // 5 minutes\n00312| revalidate: 1800, // 30 minutes\n00313| expire: 43200, // 12 hours\n00314| },\n00315| },\n00316| }\n00317| \n00318| export default nextConfig\n00319| ```\n00320| \n00321| Then use these profiles throughout your application:\n00322| \n00323| ```tsx filename=\"app/editorial/page.tsx\"\n00324| import { cacheLife } from 'next/cache'\n00325| \n00326| export default async function EditorialPage() {\n00327| 'use cache'\n00328| cacheLife('editorial')\n00329| // ...\n00330| }\n00331| ```\n00332| \n00333| ### Inline profiles for unique cases\n00334| \n00335| Use inline profiles when a specific function needs one-off caching behavior:\n00336| \n00337| ```tsx filename=\"app/api/limited-offer/route.ts\"\n00338| import { cacheLife } from 'next/cache'\n00339| import { getDb } from '@lib/db'\n00340| \n00341| async function getLimitedOffer() {\n00342| 'use cache'\n00343| \n00344| cacheLife({\n00345| stale: 60, // 1 minute\n00346| revalidate: 300, // 5 minutes\n00347| expire: 3600, // 1 hour\n00348| })\n00349| \n00350| const offer = await getDb().offer.findFirst({\n00351| where: { type: 'limited' },\n00352| orderBy: { created_at: 'desc' },\n00353| })\n00354| \n00355| return offer\n00356| }\n00357| \n00358| export async function GET() {\n00359| const offer = await getLimitedOffer()\n00360| \n00361| return Response.json(offer)\n00362| }\n00363| ```\n00364| \n00365| ### Caching individual functions\n00366| \n00367| Apply caching to utility functions for granular control:\n00368| \n00369| ```tsx filename=\"lib/api.ts\"\n00370| import { cacheLife } from 'next/cache'\n00371| \n00372| export async function getSettings() {\n00373| 'use cache'\n00374| cacheLife('max') // Settings rarely change\n00375| \n00376| return await fetchSettings()\n00377| }\n00378| ```\n00379| \n00380| ```tsx filename=\"lib/stats.ts\"\n00381| import { cacheLife } from 'next/cache'\n00382| \n00383| export async function getRealtimeStats() {\n00384| 'use cache'\n00385| cacheLife('seconds') // Stats update constantly\n00386| \n00387| return await fetchStats()\n00388| }\n00389| ```\n00390| \n00391| ### Nested caching behavior\n00392| \n00393| When you nest `use cache` directives (a cached function or component using another cached function or component), the outer cache's behavior depends on whether it has an explicit `cacheLife`.\n00394| \n00395| #### With explicit outer cacheLife\n00396| \n00397| The outer cache uses its own lifetime, regardless of inner cache lifetimes. When the outer cache hits, it returns the complete output including all nested data. An explicit `cacheLife` always takes precedence, whether it's longer or shorter than inner lifetimes.\n00398| \n00399| ```tsx filename=\"app/dashboard/page.tsx\"\n00400| import { cacheLife } from 'next/cache'\n00401| import { Widget } from './widget'\n00402| \n00403| export default async function Dashboard() {\n00404| 'use cache'\n00405| cacheLife('hours') // Outer scope sets its own lifetime\n00406| \n00407| return (\n00408|
\n00409|
Dashboard
\n00410| {/* Inner scope has 'minutes' lifetime */}\n00411|
\n00412| )\n00413| }\n00414| ```\n00415| \n00416| #### Without explicit outer cacheLife\n00417| \n00418| If you don't call `cacheLife` in the outer cache, it uses the `default` profile (15 min revalidate). Inner caches with shorter lifetimes can reduce the outer cache's `default` lifetime. Inner caches with longer lifetimes cannot extend it beyond the default.\n00419| \n00420| ```tsx filename=\"app/dashboard/page.tsx\"\n00421| import { Widget } from './widget'\n00422| \n00423| export default async function Dashboard() {\n00424| 'use cache'\n00425| // No cacheLife call - uses default (15 min)\n00426| // If Widget has 5 min → Dashboard becomes 5 min\n00427| // If Widget has 1 hour → Dashboard stays 15 min\n00428| \n00429| return (\n00430|
\n00431|
Dashboard
\n00432| \n00433|
\n00434| )\n00435| }\n00436| ```\n00437| \n00438| **It is recommended to specify an explicit `cacheLife`.** With explicit lifetime values, you can inspect a cached function or component and immediately know its behavior without tracing through nested caches. Without explicit lifetime values, the behavior becomes dependent on inner cache lifetimes, making it harder to reason about.\n00439| \n00440| #### Nested short-lived caches\n00441| \n00442| As described in [Prerendering behavior](#prerendering-behavior), short-lived caches (zero `revalidate` or `expire` under 5 minutes) become dynamic holes excluded from prerenders.\n00443| \n00444| When a short-lived cache is nested inside another `use cache` without an explicit `cacheLife`, the outer cache's lifetime would silently become short too via propagation. To prevent this accidental misconfiguration, Next.js throws an error during prerendering.\n00445| \n00446| Note that the nested cache may not be obvious — it could be in an imported module or even a third-party dependency:\n00447| \n00448| ```tsx filename=\"components/short-lived-widget.tsx\" highlight={5}\n00449| import { cacheLife } from 'next/cache'\n00450| \n00451| export async function ShortLivedWidget() {\n00452| 'use cache'\n00453| cacheLife('seconds')\n00454| const data = await fetchRealtimeData()\n00455| return
{data}
\n00456| }\n00457| ```\n00458| \n00459| Using this component from another `use cache` without an explicit `cacheLife` will error during prerendering:\n00460| \n00461| ```tsx filename=\"app/page.tsx\"\n00462| import { ShortLivedWidget } from '@/components/short-lived-widget'\n00463| \n00464| export default async function Page() {\n00465| 'use cache'\n00466| // Error: no explicit cacheLife on outer cache\n00467| return (\n00468|
\n00469|
Dashboard
\n00470|
Last updated: {new Date().toISOString()}
\n00471| \n00472|
\n00473| )\n00474| }\n00475| ```\n00476| \n00477| To fix the error, add an explicit `cacheLife()` to the outer `use cache`:\n00478| \n00479| **If you want the outer cache to remain static (prerendered)**, set a longer cache lifetime:\n00480| \n00481| ```tsx filename=\"app/page.tsx\" highlight={6}\n00482| import { cacheLife } from 'next/cache'\n00483| import { ShortLivedWidget } from '@/components/short-lived-widget'\n00484| \n00485| export default async function Page() {\n00486| 'use cache'\n00487| cacheLife('default') // Explicit cacheLife prevents the error\n00488| return (\n00489|
\n00490|
Dashboard
\n00491|
Last updated: {new Date().toISOString()}
\n00492| \n00493|
\n00494| )\n00495| }\n00496| ```\n00497| \n00498| **If you want the outer cache to also be short-lived**, explicitly set a short cache lifetime to confirm this is intentional. Wrap the component in a `` boundary to provide a fallback while content loads:\n00499| \n00500| ```tsx filename=\"app/page.tsx\" highlight={7,17-19}\n00501| import { Suspense } from 'react'\n00502| import { cacheLife } from 'next/cache'\n00503| import { ShortLivedWidget } from '@/components/short-lived-widget'\n00504| \n00505| async function Content() {\n00506| 'use cache: remote'\n00507| cacheLife('seconds') // Explicit cacheLife confirms this is intentionally short-lived\n00508| return (\n00509| <>\n00510|
\n00524| )\n00525| }\n00526| ```\n00527| \n00528| > **Note:** This example uses `\"use cache: remote\"` because runtime caching in serverless deployments doesn't persist across requests with the default in-memory cache. For self-hosted environments, `\"use cache\"` may be sufficient. See [Runtime caching considerations](/docs/app/api-reference/directives/use-cache#runtime-caching-considerations) for more details.\n00529| \n00530| ### Conditional cache lifetimes\n00531| \n00532| You can call `cacheLife` conditionally in different code paths to set different cache durations based on your application logic:\n00533| \n00534| ```tsx filename=\"lib/posts.ts\" highlight={14,19}\n00535| import { cacheLife, cacheTag } from 'next/cache'\n00536| \n00537| async function getPostContent(slug: string) {\n00538| 'use cache'\n00539| \n00540| const post = await fetchPost(slug)\n00541| \n00542| // Tag the cache entry for targeted revalidation\n00543| cacheTag(`post-${slug}`)\n00544| \n00545| if (!post) {\n00546| // Content may not be published yet or could be in draft\n00547| // Cache briefly to reduce database load\n00548| cacheLife('minutes')\n00549| return null\n00550| }\n00551| \n00552| // Published content can be cached longer\n00553| cacheLife('days')\n00554| \n00555| // Return only the necessary data to keep cache size minimal\n00556| return post.data\n00557| }\n00558| ```\n00559| \n00560| This pattern is useful when different outcomes need different cache durations, for example, when an item is missing but is likely to be available later.\n00561| \n00562| #### Using dynamic cache lifetimes from data\n00563| \n00564| If you want to calculate cache lifetime at runtime, for example by reading it from the fetched data, use an [inline cache profile](#inline-cache-profiles) object:\n00565| \n00566| ```tsx filename=\"lib/posts.ts\" highlight={15,16,17,18}\n00567| import { cacheLife, cacheTag } from 'next/cache'\n00568| \n00569| async function getPostContent(slug: string) {\n00570| 'use cache'\n00571| \n00572| const post = await fetchPost(slug)\n00573| cacheTag(`post-${slug}`)\n00574| \n00575| if (!post) {\n00576| cacheLife('minutes')\n00577| return null\n00578| }\n00579| \n00580| // Use cache timing from CMS data directly as an object\n00581| cacheLife({\n00582| // Ensure post.revalidateSeconds is a number in seconds\n00583| // stale and expire inherit from 'default' profile\n00584| revalidate: post.revalidateSeconds ?? 3600,\n00585| })\n00586| \n00587| return post.data\n00588| }\n00589| ```\n00590| \n\n(End of file - total 590 lines)\n",
+ "title": "node_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheLife.md",
+ "metadata": {
+ "preview": "---\ntitle: cacheLife\ndescription: Learn how to use the cacheLife function to set the cache expiration time for a cached function or component.\nrelated:\n title: Related\n description: View related API references.\n links:\n - app/api-reference/config/next-config-js/cacheComponents\n - app/api-reference/directives/use-cache\n - app/api-reference/functions/revalidateTag\n - app/api-reference/functions/cacheTag\n---\n\nThe `cacheLife` function is used to set the cache lifetime of a function or component. It should be used alongside the [`use cache`](/docs/app/api-reference/directives/use-cache) directive, and within the scope of the function or component.\n\n## Usage\n\n### Basic setup\n\nTo use `cacheLife`, first enable the [`cacheComponents` flag](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.js` file:"
+ },
+ "time": {
+ "start": 1781392546237,
+ "end": 1781392546241
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T23:15:46.244Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| ---\n00002| title: cacheLife\n00003| description: Learn how to use the cacheLife function to set the cache expiration time for a cached function or component.\n00004| related:\n00005| title: Related\n00006| description: View related API references.\n00007| links:\n00008| - app/api-reference/config/next-config-js/cacheComponents\n00009| - app/api-reference/directives/use-cache\n00010| - app/api-reference/functions/revalidateTag\n00011| - app/api-reference/functions/cacheTag\n00012| ---\n00013| \n00014| The `cacheLife` function is used to set the cache lifetime of a function or component. It should be used alongside the [`use cache`](/docs/app/api-reference/directives/use-cache) directive, and within the scope of the function or component.\n00015| \n00016| ## Usage\n00017| \n00018| ### Basic setup\n00019| \n00020| To use `cacheLife`, first enable the [`cacheComponents` flag](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.js` file:\n00021| \n00022| ```ts filename=\"next.config.ts\" switcher\n00023| import type { NextConfig } from 'next'\n00024| \n00025| const nextConfig: NextConfig = {\n00026| cacheComponents: true,\n00027| }\n00028| \n00029| export default nextConfig\n00030| ```\n00031| \n00032| ```js filename=\"next.config.js\" switcher\n00033| const nextConfig = {\n00034| cacheComponents: true,\n00035| }\n00036| \n00037| export default nextConfig\n00038| ```\n00039| \n00040| `cacheLife` can only be used within a cache directive scope.\n00041| \n00042| Add a cache directive (for example, `use cache`) at the file level or at the top of an async function or component.\n00043| \n00044| `cacheLife` cannot be used at module scope. Calling it at the top level of a file will throw an error.\n00045| \n00046| > **Good to know**:\n00047| >\n00048| > - Calling `cacheLife` is optional. If omitted, a default cache lifetime is applied.\n00049| > - Call `cacheLife` in the same function or component where caching is defined. Avoid abstracting it into shared utilities so the cache behavior remains explicit and easy to reason about.\n00050| > - If you call `cacheLife`, ensure only one call executes per function invocation. You can call it in different control flow branches, but only one should run per request. See the [conditional cache lifetimes](#conditional-cache-lifetimes) example.\n00051| \n00052| ### Using preset profiles\n00053| \n00054| Next.js provides preset cache profiles that cover common caching needs. Each profile balances three factors:\n00055| \n00056| - How long users see cached content without checking for updates (client-side)\n00057| - How often fresh content is generated on the server\n00058| - When old content expires completely\n00059| \n00060| Choose a profile based on how frequently your content changes:\n00061| \n00062| - **`seconds`** - Real-time data (stock prices, live scores)\n00063| - **`minutes`** - Frequently updated (social feeds, news)\n00064| - **`hours`** - Multiple daily updates (product inventory, weather)\n00065| - **`days`** - Daily updates (blog posts, articles)\n00066| - **`weeks`** - Weekly updates (podcasts, newsletters)\n00067| - **`max`** - Rarely changes (legal pages, archived content)\n00068| \n00069| Import `cacheLife` and pass a profile name:\n00070| \n00071| ```tsx filename=\"app/blog/page.tsx\" highlight={1,5}\n00072| 'use cache'\n00073| import { cacheLife } from 'next/cache'\n00074| \n00075| export default async function BlogPage() {\n00076| cacheLife('days') // Blog content updated daily\n00077| \n00078| const posts = await getBlogPosts()\n00079| return
{/* render posts */}
\n00080| }\n00081| ```\n00082| \n00083| The profile name tells Next.js how to cache the entire function's output. If you don't call `cacheLife`, the `default` profile is used. See [preset cache profiles](#preset-cache-profiles) for timing details.\n00084| \n00085| ## Reference\n00086| \n00087| ### Cache profile properties\n00088| \n00089| Cache profiles control caching behavior through three timing properties:\n00090| \n00091| - **[`stale`](#stale)**: How long the client can use cached data without checking the server\n00092| - **[`revalidate`](#revalidate)**: After this time, the next request will trigger a background refresh\n00093| - **[`expire`](#expire)**: After this time with no requests, the next one waits for fresh content\n00094| \n00095| #### `stale`\n00096| \n00097| **Client-side:** How long the client can use cached data without checking the server.\n00098| \n00099| During this time, the client-side router displays cached content immediately without any network request. After this period expires, the router must check with the server on the next navigation or request. This provides instant page loads from the client cache, but data may be outdated.\n00100| \n00101| - If omitted, defaults to the `default` profile's `stale` value (5 minutes, see [`staleTimes`](/docs/app/api-reference/config/next-config-js/staleTimes))\n00102| \n00103| ```tsx\n00104| cacheLife({ stale: 300 }) // 5 minutes\n00105| ```\n00106| \n00107| #### `revalidate`\n00108| \n00109| How often the server regenerates cached content in the background.\n00110| \n00111| - When a request arrives after this period, the server:\n00112| 1. Serves the cached version immediately (if available)\n00113| 2. Regenerates content in the background\n00114| 3. Updates the cache with fresh content\n00115| - Similar to [Incremental Static Regeneration (ISR)](/docs/app/guides/incremental-static-regeneration)\n00116| - If omitted, defaults to the `default` profile's `revalidate` value (15 minutes)\n00117| \n00118| ```tsx\n00119| cacheLife({ revalidate: 900 }) // 15 minutes\n00120| ```\n00121| \n00122| #### `expire`\n00123| \n00124| Maximum time before the server must regenerate cached content.\n00125| \n00126| - After this period with no traffic, the server regenerates content synchronously on the next request\n00127| - When you set both `revalidate` and `expire`, `expire` must be longer than `revalidate`. Next.js validates this and raises an error for invalid configurations.\n00128| - If omitted, defaults to the `default` profile's `expire` value (never expires)\n00129| \n00130| ```tsx\n00131| cacheLife({ expire: 3600 }) // 1 hour\n00132| ```\n00133| \n00134| ### Preset cache profiles\n00135| \n00136| If you don't specify a profile, Next.js uses the `default` profile. We recommend explicitly setting a profile to make caching behavior clear.\n00137| \n00138| | **Profile** | **Use Case** | `stale` | `revalidate` | `expire` |\n00139| | ----------- | -------------------------------------- | ---------- | ------------ | -------- |\n00140| | `default` | Standard content | 5 minutes | 15 minutes | never |\n00141| | `seconds` | Real-time data | 30 seconds | 1 second | 1 minute |\n00142| | `minutes` | Frequently updated content | 5 minutes | 1 minute | 1 hour |\n00143| | `hours` | Content updated multiple times per day | 5 minutes | 1 hour | 1 day |\n00144| | `days` | Content updated daily | 5 minutes | 1 day | 1 week |\n00145| | `weeks` | Content updated weekly | 5 minutes | 1 week | 30 days |\n00146| | `max` | Stable content that rarely changes | 5 minutes | 30 days | 1 year |\n00147| \n00148| ### Custom cache profiles\n00149| \n00150| Define reusable cache profiles in your `next.config.ts` file:\n00151| \n00152| ```ts filename=\"next.config.ts\"\n00153| import type { NextConfig } from 'next'\n00154| \n00155| const nextConfig: NextConfig = {\n00156| cacheComponents: true,\n00157| cacheLife: {\n00158| biweekly: {\n00159| stale: 60 * 60 * 24 * 14, // 14 days\n00160| revalidate: 60 * 60 * 24, // 1 day\n00161| expire: 60 * 60 * 24 * 14, // 14 days\n00162| },\n00163| },\n00164| }\n00165| \n00166| export default nextConfig\n00167| ```\n00168| \n00169| ```js filename=\"next.config.js\" switcher\n00170| const nextConfig = {\n00171| cacheComponents: true,\n00172| cacheLife: {\n00173| biweekly: {\n00174| stale: 60 * 60 * 24 * 14, // 14 days\n00175| revalidate: 60 * 60 * 24, // 1 day\n00176| expire: 60 * 60 * 24 * 14, // 14 days\n00177| },\n00178| },\n00179| }\n00180| \n00181| module.exports = nextConfig\n00182| ```\n00183| \n00184| The example above caches for 14 days, checks for updates daily, and expires the cache after 14 days. You can then reference this profile throughout your application by its name:\n00185| \n00186| > **Good to know**: Any omitted properties in a custom profile inherit from the `default` profile. This also applies to inline profile objects passed directly to `cacheLife()`.\n00187| \n00188| ```tsx filename=\"app/page.tsx\" highlight={5}\n00189| 'use cache'\n00190| import { cacheLife } from 'next/cache'\n00191| \n00192| export default async function Page() {\n00193| cacheLife('biweekly')\n00194| return
Page
\n00195| }\n00196| ```\n00197| \n00198| ### Overriding the default cache profiles\n00199| \n00200| While the default cache profiles provide a useful way to think about how fresh or stale any given part of cacheable output can be, you may prefer different named profiles to better align with your applications caching strategies.\n00201| \n00202| You can override the default named cache profiles by creating a new configuration with the same name as the defaults.\n00203| \n00204| The example below shows how to override the default `\"days\"` cache profile:\n00205| \n00206| ```ts filename=\"next.config.ts\"\n00207| const nextConfig = {\n00208| cacheComponents: true,\n00209| cacheLife: {\n00210| // Override the 'days' profile\n00211| days: {\n00212| stale: 3600, // 1 hour\n00213| revalidate: 900, // 15 minutes\n00214| expire: 86400, // 1 day\n00215| },\n00216| },\n00217| }\n00218| \n00219| export default nextConfig\n00220| ```\n00221| \n00222| ### Inline cache profiles\n00223| \n00224| For one-off cases, pass a profile object directly to `cacheLife`:\n00225| \n00226| ```tsx filename=\"app/page.tsx\"\n00227| 'use cache'\n00228| import { cacheLife } from 'next/cache'\n00229| \n00230| export default async function Page() {\n00231| cacheLife({\n00232| stale: 3600,\n00233| revalidate: 900,\n00234| expire: 86400,\n00235| })\n00236| \n00237| return
Page
\n00238| }\n00239| ```\n00240| \n00241| Inline profiles apply only to the specific function or component. For reusable configurations, define custom profiles in `next.config.ts`.\n00242| \n00243| Using `cacheLife({})` with an empty object applies the `default` profile values.\n00244| \n00245| ### Client cache behavior\n00246| \n00247| The `stale` property controls the [Client Cache](/docs/app/glossary#client-cache), not the `Cache-Control` header:\n00248| \n00249| - The server sends the stale time via the `x-nextjs-stale-time` response header\n00250| - The client router uses this value to determine when to revalidate\n00251| - **Minimum of 30 seconds is enforced** to ensure prefetched links remain usable\n00252| \n00253| This 30-second minimum prevents prefetched data from expiring before users can click on links. It only applies to time-based expiration.\n00254| \n00255| When you call revalidation functions from a Server Action ([`revalidateTag`](/docs/app/api-reference/functions/revalidateTag), [`revalidatePath`](/docs/app/api-reference/functions/revalidatePath), [`updateTag`](/docs/app/api-reference/functions/updateTag), or [`refresh`](/docs/app/api-reference/functions/refresh)), the entire client cache is immediately cleared, bypassing the stale time.\n00256| \n00257| > **Good to know**: The `stale` property in `cacheLife` differs from [`staleTimes`](/docs/app/api-reference/config/next-config-js/staleTimes). While `staleTimes` is a global setting affecting all routes, `cacheLife` allows per-function or per-route configuration. Updating `staleTimes.static` also updates the `stale` value of the `default` cache profile.\n00258| \n00259| ### Prerendering behavior\n00260| \n00261| Caches with very short lifetimes — zero `revalidate` or `expire` under 5 minutes — are automatically excluded from prerenders and become \"dynamic holes\" instead. This includes the `seconds` profile.\n00262| \n00263| This behavior allows you to mix static and dynamic content within the same page. Static parts are prerendered, while short-lived caches create boundaries where data is fetched at request time rather than build time. Use a `` boundary around dynamic caches to provide a fallback while content loads.\n00264| \n00265| ## Examples\n00266| \n00267| ### Using preset profiles\n00268| \n00269| The simplest way to configure caching is using preset profiles. Choose one that matches your content's update pattern:\n00270| \n00271| ```tsx filename=\"app/blog/[slug]/page.tsx\"\n00272| import { cacheLife } from 'next/cache'\n00273| \n00274| export default async function BlogPost() {\n00275| 'use cache'\n00276| cacheLife('days') // Blog posts updated daily\n00277| \n00278| const post = await fetchBlogPost()\n00279| return {post.content}\n00280| }\n00281| ```\n00282| \n00283| ```tsx filename=\"app/products/[id]/page.tsx\"\n00284| import { cacheLife } from 'next/cache'\n00285| \n00286| export default async function ProductPage() {\n00287| 'use cache'\n00288| cacheLife('hours') // Product data updated multiple times per day\n00289| \n00290| const product = await fetchProduct()\n00291| return
{product.name}
\n00292| }\n00293| ```\n00294| \n00295| ### Custom profiles for specific needs\n00296| \n00297| Define custom profiles when preset options don't match your requirements:\n00298| \n00299| ```ts filename=\"next.config.ts\"\n00300| import type { NextConfig } from 'next'\n00301| \n00302| const nextConfig: NextConfig = {\n00303| cacheComponents: true,\n00304| cacheLife: {\n00305| editorial: {\n00306| stale: 600, // 10 minutes\n00307| revalidate: 3600, // 1 hour\n00308| expire: 86400, // 1 day\n00309| },\n00310| marketing: {\n00311| stale: 300, // 5 minutes\n00312| revalidate: 1800, // 30 minutes\n00313| expire: 43200, // 12 hours\n00314| },\n00315| },\n00316| }\n00317| \n00318| export default nextConfig\n00319| ```\n00320| \n00321| Then use these profiles throughout your application:\n00322| \n00323| ```tsx filename=\"app/editorial/page.tsx\"\n00324| import { cacheLife } from 'next/cache'\n00325| \n00326| export default async function EditorialPage() {\n00327| 'use cache'\n00328| cacheLife('editorial')\n00329| // ...\n00330| }\n00331| ```\n00332| \n00333| ### Inline profiles for unique cases\n00334| \n00335| Use inline profiles when a specific function needs one-off caching behavior:\n00336| \n00337| ```tsx filename=\"app/api/limited-offer/route.ts\"\n00338| import { cacheLife } from 'next/cache'\n00339| import { getDb } from '@lib/db'\n00340| \n00341| async function getLimitedOffer() {\n00342| 'use cache'\n00343| \n00344| cacheLife({\n00345| stale: 60, // 1 minute\n00346| revalidate: 300, // 5 minutes\n00347| expire: 3600, // 1 hour\n00348| })\n00349| \n00350| const offer = await getDb().offer.findFirst({\n00351| where: { type: 'limited' },\n00352| orderBy: { created_at: 'desc' },\n00353| })\n00354| \n00355| return offer\n00356| }\n00357| \n00358| export async function GET() {\n00359| const offer = await getLimitedOffer()\n00360| \n00361| return Response.json(offer)\n00362| }\n00363| ```\n00364| \n00365| ### Caching individual functions\n00366| \n00367| Apply caching to utility functions for granular control:\n00368| \n00369| ```tsx filename=\"lib/api.ts\"\n00370| import { cacheLife } from 'next/cache'\n00371| \n00372| export async function getSettings() {\n00373| 'use cache'\n00374| cacheLife('max') // Settings rarely change\n00375| \n00376| return await fetchSettings()\n00377| }\n00378| ```\n00379| \n00380| ```tsx filename=\"lib/stats.ts\"\n00381| import { cacheLife } from 'next/cache'\n00382| \n00383| export async function getRealtimeStats() {\n00384| 'use cache'\n00385| cacheLife('seconds') // Stats update constantly\n00386| \n00387| return await fetchStats()\n00388| }\n00389| ```\n00390| \n00391| ### Nested caching behavior\n00392| \n00393| When you nest `use cache` directives (a cached function or component using another cached function or component), the outer cache's behavior depends on whether it has an explicit `cacheLife`.\n00394| \n00395| #### With explicit outer cacheLife\n00396| \n00397| The outer cache uses its own lifetime, regardless of inner cache lifetimes. When the outer cache hits, it returns the complete output including all nested data. An explicit `cacheLife` always takes precedence, whether it's longer or shorter than inner lifetimes.\n00398| \n00399| ```tsx filename=\"app/dashboard/page.tsx\"\n00400| import { cacheLife } from 'next/cache'\n00401| import { Widget } from './widget'\n00402| \n00403| export default async function Dashboard() {\n00404| 'use cache'\n00405| cacheLife('hours') // Outer scope sets its own lifetime\n00406| \n00407| return (\n00408|
\n00409|
Dashboard
\n00410| {/* Inner scope has 'minutes' lifetime */}\n00411|
\n00412| )\n00413| }\n00414| ```\n00415| \n00416| #### Without explicit outer cacheLife\n00417| \n00418| If you don't call `cacheLife` in the outer cache, it uses the `default` profile (15 min revalidate). Inner caches with shorter lifetimes can reduce the outer cache's `default` lifetime. Inner caches with longer lifetimes cannot extend it beyond the default.\n00419| \n00420| ```tsx filename=\"app/dashboard/page.tsx\"\n00421| import { Widget } from './widget'\n00422| \n00423| export default async function Dashboard() {\n00424| 'use cache'\n00425| // No cacheLife call - uses default (15 min)\n00426| // If Widget has 5 min → Dashboard becomes 5 min\n00427| // If Widget has 1 hour → Dashboard stays 15 min\n00428| \n00429| return (\n00430|
\n00431|
Dashboard
\n00432| \n00433|
\n00434| )\n00435| }\n00436| ```\n00437| \n00438| **It is recommended to specify an explicit `cacheLife`.** With explicit lifetime values, you can inspect a cached function or component and immediately know its behavior without tracing through nested caches. Without explicit lifetime values, the behavior becomes dependent on inner cache lifetimes, making it harder to reason about.\n00439| \n00440| #### Nested short-lived caches\n00441| \n00442| As described in [Prerendering behavior](#prerendering-behavior), short-lived caches (zero `revalidate` or `expire` under 5 minutes) become dynamic holes excluded from prerenders.\n00443| \n00444| When a short-lived cache is nested inside another `use cache` without an explicit `cacheLife`, the outer cache's lifetime would silently become short too via propagation. To prevent this accidental misconfiguration, Next.js throws an error during prerendering.\n00445| \n00446| Note that the nested cache may not be obvious — it could be in an imported module or even a third-party dependency:\n00447| \n00448| ```tsx filename=\"components/short-lived-widget.tsx\" highlight={5}\n00449| import { cacheLife } from 'next/cache'\n00450| \n00451| export async function ShortLivedWidget() {\n00452| 'use cache'\n00453| cacheLife('seconds')\n00454| const data = await fetchRealtimeData()\n00455| return
{data}
\n00456| }\n00457| ```\n00458| \n00459| Using this component from another `use cache` without an explicit `cacheLife` will error during prerendering:\n00460| \n00461| ```tsx filename=\"app/page.tsx\"\n00462| import { ShortLivedWidget } from '@/components/short-lived-widget'\n00463| \n00464| export default async function Page() {\n00465| 'use cache'\n00466| // Error: no explicit cacheLife on outer cache\n00467| return (\n00468|
\n00469|
Dashboard
\n00470|
Last updated: {new Date().toISOString()}
\n00471| \n00472|
\n00473| )\n00474| }\n00475| ```\n00476| \n00477| To fix the error, add an explicit `cacheLife()` to the outer `use cache`:\n00478| \n00479| **If you want the outer cache to remain static (prerendered)**, set a longer cache lifetime:\n00480| \n00481| ```tsx filename=\"app/page.tsx\" highlight={6}\n00482| import { cacheLife } from 'next/cache'\n00483| import { ShortLivedWidget } from '@/components/short-lived-widget'\n00484| \n00485| export default async function Page() {\n00486| 'use cache'\n00487| cacheLife('default') // Explicit cacheLife prevents the error\n00488| return (\n00489|
\n00490|
Dashboard
\n00491|
Last updated: {new Date().toISOString()}
\n00492| \n00493|
\n00494| )\n00495| }\n00496| ```\n00497| \n00498| **If you want the outer cache to also be short-lived**, explicitly set a short cache lifetime to confirm this is intentional. Wrap the component in a `` boundary to provide a fallback while content loads:\n00499| \n00500| ```tsx filename=\"app/page.tsx\" highlight={7,17-19}\n00501| import { Suspense } from 'react'\n00502| import { cacheLife } from 'next/cache'\n00503| import { ShortLivedWidget } from '@/components/short-lived-widget'\n00504| \n00505| async function Content() {\n00506| 'use cache: remote'\n00507| cacheLife('seconds') // Explicit cacheLife confirms this is intentionally short-lived\n00508| return (\n00509| <>\n00510|
\n00524| )\n00525| }\n00526| ```\n00527| \n00528| > **Note:** This example uses `\"use cache: remote\"` because runtime caching in serverless deployments doesn't persist across requests with the default in-memory cache. For self-hosted environments, `\"use cache\"` may be sufficient. See [Runtime caching considerations](/docs/app/api-reference/directives/use-cache#runtime-caching-considerations) for more details.\n00529| \n00530| ### Conditional cache lifetimes\n00531| \n00532| You can call `cacheLife` conditionally in different code paths to set different cache durations based on your application logic:\n00533| \n00534| ```tsx filename=\"lib/posts.ts\" highlight={14,19}\n00535| import { cacheLife, cacheTag } from 'next/cache'\n00536| \n00537| async function getPostContent(slug: string) {\n00538| 'use cache'\n00539| \n00540| const post = await fetchPost(slug)\n00541| \n00542| // Tag the cache entry for targeted revalidation\n00543| cacheTag(`post-${slug}`)\n00544| \n00545| if (!post) {\n00546| // Content may not be published yet or could be in draft\n00547| // Cache briefly to reduce database load\n00548| cacheLife('minutes')\n00549| return null\n00550| }\n00551| \n00552| // Published content can be cached longer\n00553| cacheLife('days')\n00554| \n00555| // Return only the necessary data to keep cache size minimal\n00556| return post.data\n00557| }\n00558| ```\n00559| \n00560| This pattern is useful when different outcomes need different cache durations, for example, when an item is missing but is likely to be available later.\n00561| \n00562| #### Using dynamic cache lifetimes from data\n00563| \n00564| If you want to calculate cache lifetime at runtime, for example by reading it from the fetched data, use an [inline cache profile](#inline-cache-profiles) object:\n00565| \n00566| ```tsx filename=\"lib/posts.ts\" highlight={15,16,17,18}\n00567| import { cacheLife, cacheTag } from 'next/cache'\n00568| \n00569| async function getPostContent(slug: string) {\n00570| 'use cache'\n00571| \n00572| const post = await fetchPost(slug)\n00573| cacheTag(`post-${slug}`)\n00574| \n00575| if (!post) {\n00576| cacheLife('minutes')\n00577| return null\n00578| }\n00579| \n00580| // Use cache timing from CMS data directly as an object\n00581| cacheLife({\n00582| // Ensure post.revalidateSeconds is a number in seconds\n00583| // stale and expire inherit from 'default' profile\n00584| revalidate: post.revalidateSeconds ?? 3600,\n00585| })\n00586| \n00587| return post.data\n00588| }\n00589| ```\n00590| \n\n(End of file - total 590 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/cacheLife.md"
+ },
+ "output": "\n00001| ---\n00002| title: cacheLife\n00003| description: Learn how to use the cacheLife function to set the cache expiration time for a cached function or component.\n00004| related:\n00005| title: Related\n00006| description: View related API references.\n00007| links:\n00008| - app/api-reference/config/next-config-js/cacheComponents\n00009| - app/api-reference/directives/use-cache\n00010| - app/api-reference/functions/revalidateTag\n00011| - app/api-reference/functions/cacheTag\n00012| ---\n00013| \n00014| The `cacheLife` function is used to set the cache lifetime of a function or component. It should be used alongside the [`use cache`](/docs/app/api-reference/directives/use-cache) directive, and within the scope of the function or component.\n00015| \n00016| ## Usage\n00017| \n00018| ### Basic setup\n00019| \n00020| To use `cacheLife`, first enable the [`cacheComponents` flag](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.js` file:\n00021| \n00022| ```ts filename=\"next.config.ts\" switcher\n00023| import type { NextConfig } from 'next'\n00024| \n00025| const nextConfig: NextConfig = {\n00026| cacheComponents: true,\n00027| }\n00028| \n00029| export default nextConfig\n00030| ```\n00031| \n00032| ```js filename=\"next.config.js\" switcher\n00033| const nextConfig = {\n00034| cacheComponents: true,\n00035| }\n00036| \n00037| export default nextConfig\n00038| ```\n00039| \n00040| `cacheLife` can only be used within a cache directive scope.\n00041| \n00042| Add a cache directive (for example, `use cache`) at the file level or at the top of an async function or component.\n00043| \n00044| `cacheLife` cannot be used at module scope. Calling it at the top level of a file will throw an error.\n00045| \n00046| > **Good to know**:\n00047| >\n00048| > - Calling `cacheLife` is optional. If omitted, a default cache lifetime is applied.\n00049| > - Call `cacheLife` in the same function or component where caching is defined. Avoid abstracting it into shared utilities so the cache behavior remains explicit and easy to reason about.\n00050| > - If you call `cacheLife`, ensure only one call executes per function invocation. You can call it in different control flow branches, but only one should run per request. See the [conditional cache lifetimes](#conditional-cache-lifetimes) example.\n00051| \n00052| ### Using preset profiles\n00053| \n00054| Next.js provides preset cache profiles that cover common caching needs. Each profile balances three factors:\n00055| \n00056| - How long users see cached content without checking for updates (client-side)\n00057| - How often fresh content is generated on the server\n00058| - When old content expires completely\n00059| \n00060| Choose a profile based on how frequently your content changes:\n00061| \n00062| - **`seconds`** - Real-time data (stock prices, live scores)\n00063| - **`minutes`** - Frequently updated (social feeds, news)\n00064| - **`hours`** - Multiple daily updates (product inventory, weather)\n00065| - **`days`** - Daily updates (blog posts, articles)\n00066| - **`weeks`** - Weekly updates (podcasts, newsletters)\n00067| - **`max`** - Rarely changes (legal pages, archived content)\n00068| \n00069| Import `cacheLife` and pass a profile name:\n00070| \n00071| ```tsx filename=\"app/blog/page.tsx\" highlight={1,5}\n00072| 'use cache'\n00073| import { cacheLife } from 'next/cache'\n00074| \n00075| export default async function BlogPage() {\n00076| cacheLife('days') // Blog content updated daily\n00077| \n00078| const posts = await getBlogPosts()\n00079| return
{/* render posts */}
\n00080| }\n00081| ```\n00082| \n00083| The profile name tells Next.js how to cache the entire function's output. If you don't call `cacheLife`, the `default` profile is used. See [preset cache profiles](#preset-cache-profiles) for timing details.\n00084| \n00085| ## Reference\n00086| \n00087| ### Cache profile properties\n00088| \n00089| Cache profiles control caching behavior through three timing properties:\n00090| \n00091| - **[`stale`](#stale)**: How long the client can use cached data without checking the server\n00092| - **[`revalidate`](#revalidate)**: After this time, the next request will trigger a background refresh\n00093| - **[`expire`](#expire)**: After this time with no requests, the next one waits for fresh content\n00094| \n00095| #### `stale`\n00096| \n00097| **Client-side:** How long the client can use cached data without checking the server.\n00098| \n00099| During this time, the client-side router displays cached content immediately without any network request. After this period expires, the router must check with the server on the next navigation or request. This provides instant page loads from the client cache, but data may be outdated.\n00100| \n00101| - If omitted, defaults to the `default` profile's `stale` value (5 minutes, see [`staleTimes`](/docs/app/api-reference/config/next-config-js/staleTimes))\n00102| \n00103| ```tsx\n00104| cacheLife({ stale: 300 }) // 5 minutes\n00105| ```\n00106| \n00107| #### `revalidate`\n00108| \n00109| How often the server regenerates cached content in the background.\n00110| \n00111| - When a request arrives after this period, the server:\n00112| 1. Serves the cached version immediately (if available)\n00113| 2. Regenerates content in the background\n00114| 3. Updates the cache with fresh content\n00115| - Similar to [Incremental Static Regeneration (ISR)](/docs/app/guides/incremental-static-regeneration)\n00116| - If omitted, defaults to the `default` profile's `revalidate` value (15 minutes)\n00117| \n00118| ```tsx\n00119| cacheLife({ revalidate: 900 }) // 15 minutes\n00120| ```\n00121| \n00122| #### `expire`\n00123| \n00124| Maximum time before the server must regenerate cached content.\n00125| \n00126| - After this period with no traffic, the server regenerates content synchronously on the next request\n00127| - When you set both `revalidate` and `expire`, `expire` must be longer than `revalidate`. Next.js validates this and raises an error for invalid configurations.\n00128| - If omitted, defaults to the `default` profile's `expire` value (never expires)\n00129| \n00130| ```tsx\n00131| cacheLife({ expire: 3600 }) // 1 hour\n00132| ```\n00133| \n00134| ### Preset cache profiles\n00135| \n00136| If you don't specify a profile, Next.js uses the `default` profile. We recommend explicitly setting a profile to make caching behavior clear.\n00137| \n00138| | **Profile** | **Use Case** | `stale` | `revalidate` | `expire` |\n00139| | ----------- | -------------------------------------- | ---------- | ------------ | -------- |\n00140| | `default` | Standard content | 5 minutes | 15 minutes | never |\n00141| | `seconds` | Real-time data | 30 seconds | 1 second | 1 minute |\n00142| | `minutes` | Frequently updated content | 5 minutes | 1 minute | 1 hour |\n00143| | `hours` | Content updated multiple times per day | 5 minutes | 1 hour | 1 day |\n00144| | `days` | Content updated daily | 5 minutes | 1 day | 1 week |\n00145| | `weeks` | Content updated weekly | 5 minutes | 1 week | 30 days |\n00146| | `max` | Stable content that rarely changes | 5 minutes | 30 days | 1 year |\n00147| \n00148| ### Custom cache profiles\n00149| \n00150| Define reusable cache profiles in your `next.config.ts` file:\n00151| \n00152| ```ts filename=\"next.config.ts\"\n00153| import type { NextConfig } from 'next'\n00154| \n00155| const nextConfig: NextConfig = {\n00156| cacheComponents: true,\n00157| cacheLife: {\n00158| biweekly: {\n00159| stale: 60 * 60 * 24 * 14, // 14 days\n00160| revalidate: 60 * 60 * 24, // 1 day\n00161| expire: 60 * 60 * 24 * 14, // 14 days\n00162| },\n00163| },\n00164| }\n00165| \n00166| export default nextConfig\n00167| ```\n00168| \n00169| ```js filename=\"next.config.js\" switcher\n00170| const nextConfig = {\n00171| cacheComponents: true,\n00172| cacheLife: {\n00173| biweekly: {\n00174| stale: 60 * 60 * 24 * 14, // 14 days\n00175| revalidate: 60 * 60 * 24, // 1 day\n00176| expire: 60 * 60 * 24 * 14, // 14 days\n00177| },\n00178| },\n00179| }\n00180| \n00181| module.exports = nextConfig\n00182| ```\n00183| \n00184| The example above caches for 14 days, checks for updates daily, and expires the cache after 14 days. You can then reference this profile throughout your application by its name:\n00185| \n00186| > **Good to know**: Any omitted properties in a custom profile inherit from the `default` profile. This also applies to inline profile objects passed directly to `cacheLife()`.\n00187| \n00188| ```tsx filename=\"app/page.tsx\" highlight={5}\n00189| 'use cache'\n00190| import { cacheLife } from 'next/cache'\n00191| \n00192| export default async function Page() {\n00193| cacheLife('biweekly')\n00194| return
Page
\n00195| }\n00196| ```\n00197| \n00198| ### Overriding the default cache profiles\n00199| \n00200| While the default cache profiles provide a useful way to think about how fresh or stale any given part of cacheable output can be, you may prefer different named profiles to better align with your applications caching strategies.\n00201| \n00202| You can override the default named cache profiles by creating a new configuration with the same name as the defaults.\n00203| \n00204| The example below shows how to override the default `\"days\"` cache profile:\n00205| \n00206| ```ts filename=\"next.config.ts\"\n00207| const nextConfig = {\n00208| cacheComponents: true,\n00209| cacheLife: {\n00210| // Override the 'days' profile\n00211| days: {\n00212| stale: 3600, // 1 hour\n00213| revalidate: 900, // 15 minutes\n00214| expire: 86400, // 1 day\n00215| },\n00216| },\n00217| }\n00218| \n00219| export default nextConfig\n00220| ```\n00221| \n00222| ### Inline cache profiles\n00223| \n00224| For one-off cases, pass a profile object directly to `cacheLife`:\n00225| \n00226| ```tsx filename=\"app/page.tsx\"\n00227| 'use cache'\n00228| import { cacheLife } from 'next/cache'\n00229| \n00230| export default async function Page() {\n00231| cacheLife({\n00232| stale: 3600,\n00233| revalidate: 900,\n00234| expire: 86400,\n00235| })\n00236| \n00237| return
Page
\n00238| }\n00239| ```\n00240| \n00241| Inline profiles apply only to the specific function or component. For reusable configurations, define custom profiles in `next.config.ts`.\n00242| \n00243| Using `cacheLife({})` with an empty object applies the `default` profile values.\n00244| \n00245| ### Client cache behavior\n00246| \n00247| The `stale` property controls the [Client Cache](/docs/app/glossary#client-cache), not the `Cache-Control` header:\n00248| \n00249| - The server sends the stale time via the `x-nextjs-stale-time` response header\n00250| - The client router uses this value to determine when to revalidate\n00251| - **Minimum of 30 seconds is enforced** to ensure prefetched links remain usable\n00252| \n00253| This 30-second minimum prevents prefetched data from expiring before users can click on links. It only applies to time-based expiration.\n00254| \n00255| When you call revalidation functions from a Server Action ([`revalidateTag`](/docs/app/api-reference/functions/revalidateTag), [`revalidatePath`](/docs/app/api-reference/functions/revalidatePath), [`updateTag`](/docs/app/api-reference/functions/updateTag), or [`refresh`](/docs/app/api-reference/functions/refresh)), the entire client cache is immediately cleared, bypassing the stale time.\n00256| \n00257| > **Good to know**: The `stale` property in `cacheLife` differs from [`staleTimes`](/docs/app/api-reference/config/next-config-js/staleTimes). While `staleTimes` is a global setting affecting all routes, `cacheLife` allows per-function or per-route configuration. Updating `staleTimes.static` also updates the `stale` value of the `default` cache profile.\n00258| \n00259| ### Prerendering behavior\n00260| \n00261| Caches with very short lifetimes — zero `revalidate` or `expire` under 5 minutes — are automatically excluded from prerenders and become \"dynamic holes\" instead. This includes the `seconds` profile.\n00262| \n00263| This behavior allows you to mix static and dynamic content within the same page. Static parts are prerendered, while short-lived caches create boundaries where data is fetched at request time rather than build time. Use a `` boundary around dynamic caches to provide a fallback while content loads.\n00264| \n00265| ## Examples\n00266| \n00267| ### Using preset profiles\n00268| \n00269| The simplest way to configure caching is using preset profiles. Choose one that matches your content's update pattern:\n00270| \n00271| ```tsx filename=\"app/blog/[slug]/page.tsx\"\n00272| import { cacheLife } from 'next/cache'\n00273| \n00274| export default async function BlogPost() {\n00275| 'use cache'\n00276| cacheLife('days') // Blog posts updated daily\n00277| \n00278| const post = await fetchBlogPost()\n00279| return {post.content}\n00280| }\n00281| ```\n00282| \n00283| ```tsx filename=\"app/products/[id]/page.tsx\"\n00284| import { cacheLife } from 'next/cache'\n00285| \n00286| export default async function ProductPage() {\n00287| 'use cache'\n00288| cacheLife('hours') // Product data updated multiple times per day\n00289| \n00290| const product = await fetchProduct()\n00291| return
{product.name}
\n00292| }\n00293| ```\n00294| \n00295| ### Custom profiles for specific needs\n00296| \n00297| Define custom profiles when preset options don't match your requirements:\n00298| \n00299| ```ts filename=\"next.config.ts\"\n00300| import type { NextConfig } from 'next'\n00301| \n00302| const nextConfig: NextConfig = {\n00303| cacheComponents: true,\n00304| cacheLife: {\n00305| editorial: {\n00306| stale: 600, // 10 minutes\n00307| revalidate: 3600, // 1 hour\n00308| expire: 86400, // 1 day\n00309| },\n00310| marketing: {\n00311| stale: 300, // 5 minutes\n00312| revalidate: 1800, // 30 minutes\n00313| expire: 43200, // 12 hours\n00314| },\n00315| },\n00316| }\n00317| \n00318| export default nextConfig\n00319| ```\n00320| \n00321| Then use these profiles throughout your application:\n00322| \n00323| ```tsx filename=\"app/editorial/page.tsx\"\n00324| import { cacheLife } from 'next/cache'\n00325| \n00326| export default async function EditorialPage() {\n00327| 'use cache'\n00328| cacheLife('editorial')\n00329| // ...\n00330| }\n00331| ```\n00332| \n00333| ### Inline profiles for unique cases\n00334| \n00335| Use inline profiles when a specific function needs one-off caching behavior:\n00336| \n00337| ```tsx filename=\"app/api/limited-offer/route.ts\"\n00338| import { cacheLife } from 'next/cache'\n00339| import { getDb } from '@lib/db'\n00340| \n00341| async function getLimitedOffer() {\n00342| 'use cache'\n00343| \n00344| cacheLife({\n00345| stale: 60, // 1 minute\n00346| revalidate: 300, // 5 minutes\n00347| expire: 3600, // 1 hour\n00348| })\n00349| \n00350| const offer = await getDb().offer.findFirst({\n00351| where: { type: 'limited' },\n00352| orderBy: { created_at: 'desc' },\n00353| })\n00354| \n00355| return offer\n00356| }\n00357| \n00358| export async function GET() {\n00359| const offer = await getLimitedOffer()\n00360| \n00361| return Response.json(offer)\n00362| }\n00363| ```\n00364| \n00365| ### Caching individual functions\n00366| \n00367| Apply caching to utility functions for granular control:\n00368| \n00369| ```tsx filename=\"lib/api.ts\"\n00370| import { cacheLife } from 'next/cache'\n00371| \n00372| export async function getSettings() {\n00373| 'use cache'\n00374| cacheLife('max') // Settings rarely change\n00375| \n00376| return await fetchSettings()\n00377| }\n00378| ```\n00379| \n00380| ```tsx filename=\"lib/stats.ts\"\n00381| import { cacheLife } from 'next/cache'\n00382| \n00383| export async function getRealtimeStats() {\n00384| 'use cache'\n00385| cacheLife('seconds') // Stats update constantly\n00386| \n00387| return await fetchStats()\n00388| }\n00389| ```\n00390| \n00391| ### Nested caching behavior\n00392| \n00393| When you nest `use cache` directives (a cached function or component using another cached function or component), the outer cache's behavior depends on whether it has an explicit `cacheLife`.\n00394| \n00395| #### With explicit outer cacheLife\n00396| \n00397| The outer cache uses its own lifetime, regardless of inner cache lifetimes. When the outer cache hits, it returns the complete output including all nested data. An explicit `cacheLife` always takes precedence, whether it's longer or shorter than inner lifetimes.\n00398| \n00399| ```tsx filename=\"app/dashboard/page.tsx\"\n00400| import { cacheLife } from 'next/cache'\n00401| import { Widget } from './widget'\n00402| \n00403| export default async function Dashboard() {\n00404| 'use cache'\n00405| cacheLife('hours') // Outer scope sets its own lifetime\n00406| \n00407| return (\n00408|
\n00409|
Dashboard
\n00410| {/* Inner scope has 'minutes' lifetime */}\n00411|
\n00412| )\n00413| }\n00414| ```\n00415| \n00416| #### Without explicit outer cacheLife\n00417| \n00418| If you don't call `cacheLife` in the outer cache, it uses the `default` profile (15 min revalidate). Inner caches with shorter lifetimes can reduce the outer cache's `default` lifetime. Inner caches with longer lifetimes cannot extend it beyond the default.\n00419| \n00420| ```tsx filename=\"app/dashboard/page.tsx\"\n00421| import { Widget } from './widget'\n00422| \n00423| export default async function Dashboard() {\n00424| 'use cache'\n00425| // No cacheLife call - uses default (15 min)\n00426| // If Widget has 5 min → Dashboard becomes 5 min\n00427| // If Widget has 1 hour → Dashboard stays 15 min\n00428| \n00429| return (\n00430|
\n00431|
Dashboard
\n00432| \n00433|
\n00434| )\n00435| }\n00436| ```\n00437| \n00438| **It is recommended to specify an explicit `cacheLife`.** With explicit lifetime values, you can inspect a cached function or component and immediately know its behavior without tracing through nested caches. Without explicit lifetime values, the behavior becomes dependent on inner cache lifetimes, making it harder to reason about.\n00439| \n00440| #### Nested short-lived caches\n00441| \n00442| As described in [Prerendering behavior](#prerendering-behavior), short-lived caches (zero `revalidate` or `expire` under 5 minutes) become dynamic holes excluded from prerenders.\n00443| \n00444| When a short-lived cache is nested inside another `use cache` without an explicit `cacheLife`, the outer cache's lifetime would silently become short too via propagation. To prevent this accidental misconfiguration, Next.js throws an error during prerendering.\n00445| \n00446| Note that the nested cache may not be obvious — it could be in an imported module or even a third-party dependency:\n00447| \n00448| ```tsx filename=\"components/short-lived-widget.tsx\" highlight={5}\n00449| import { cacheLife } from 'next/cache'\n00450| \n00451| export async function ShortLivedWidget() {\n00452| 'use cache'\n00453| cacheLife('seconds')\n00454| const data = await fetchRealtimeData()\n00455| return
{data}
\n00456| }\n00457| ```\n00458| \n00459| Using this component from another `use cache` without an explicit `cacheLife` will error during prerendering:\n00460| \n00461| ```tsx filename=\"app/page.tsx\"\n00462| import { ShortLivedWidget } from '@/components/short-lived-widget'\n00463| \n00464| export default async function Page() {\n00465| 'use cache'\n00466| // Error: no explicit cacheLife on outer cache\n00467| return (\n00468|
\n00469|
Dashboard
\n00470|
Last updated: {new Date().toISOString()}
\n00471| \n00472|
\n00473| )\n00474| }\n00475| ```\n00476| \n00477| To fix the error, add an explicit `cacheLife()` to the outer `use cache`:\n00478| \n00479| **If you want the outer cache to remain static (prerendered)**, set a longer cache lifetime:\n00480| \n00481| ```tsx filename=\"app/page.tsx\" highlight={6}\n00482| import { cacheLife } from 'next/cache'\n00483| import { ShortLivedWidget } from '@/components/short-lived-widget'\n00484| \n00485| export default async function Page() {\n00486| 'use cache'\n00487| cacheLife('default') // Explicit cacheLife prevents the error\n00488| return (\n00489|
\n00490|
Dashboard
\n00491|
Last updated: {new Date().toISOString()}
\n00492| \n00493|
\n00494| )\n00495| }\n00496| ```\n00497| \n00498| **If you want the outer cache to also be short-lived**, explicitly set a short cache lifetime to confirm this is intentional. Wrap the component in a `` boundary to provide a fallback while content loads:\n00499| \n00500| ```tsx filename=\"app/page.tsx\" highlight={7,17-19}\n00501| import { Suspense } from 'react'\n00502| import { cacheLife } from 'next/cache'\n00503| import { ShortLivedWidget } from '@/components/short-lived-widget'\n00504| \n00505| async function Content() {\n00506| 'use cache: remote'\n00507| cacheLife('seconds') // Explicit cacheLife confirms this is intentionally short-lived\n00508| return (\n00509| <>\n00510|
\n00023| \n00024| )\n00025| }\n00026| \n\n(End of file - total 26 lines)\n","title":"pages/_app.js","metadata":{"preview":"import Link from 'next/link'\nimport { AppProvider } from '../components/AppProvider'\nimport '../styles/globals.css'\n\nexport default function MyApp({ Component, pageProps }) {\n return (\n \n
\n \n
My Blog
\n \n Home\n Blog\n \n \n \n \n \n
}>\n00394| {/* Pass the artist ID to the Playlists component */}\n00395| \n00396| \n00397| >\n00398| )\n00399| }\n00400| \n00401| async function Playlists({ artistID }: { artistID: string }) {\n00402| // Use the artist ID to fetch playlists\n00403| const playlists = await getArtistPlaylists(artistID)\n00404| \n00405| return (\n00406|
\n00407| {playlists.map((playlist) => (\n00408|
{playlist.name}
\n00409| ))}\n00410|
\n00411| )\n00412| }\n00413| ```\n00414| \n00415| ```jsx filename=\"app/artist/[username]/page.js\" switcher\n00416| export default async function Page({ params }) {\n00417| const { username } = await params\n00418| // Get artist information\n00419| const artist = await getArtist(username)\n00420| \n00421| return (\n00422| <>\n00423|
{artist.name}
\n00424| {/* Show fallback UI while the Playlists component is loading */}\n00425| Loading...}>\n00426| {/* Pass the artist ID to the Playlists component */}\n00427| \n00428| \n00429| >\n00430| )\n00431| }\n00432| \n00433| async function Playlists({ artistID }) {\n00434| // Use the artist ID to fetch playlists\n00435| const playlists = await getArtistPlaylists(artistID)\n00436| \n00437| return (\n00438|
\n00439| {playlists.map((playlist) => (\n00440|
{playlist.name}
\n00441| ))}\n00442|
\n00443| )\n00444| }\n00445| ```\n00446| \n00447| In this example, `` allows the playlists to stream in after the artist data loads. However, the page still waits for the artist data before displaying anything. To prevent this, you can wrap the entire page component in a `` boundary (for example, using a [`loading.js` file](#with-loadingjs)) to show a loading state immediately.\n00448| \n00449| Ensure your data source can resolve the first request quickly, as it blocks everything else. If you can't optimize the request further, consider [caching](/docs/app/getting-started/caching) the result if the data changes infrequently.\n00450| \n00451| ### Parallel data fetching\n00452| \n00453| Parallel data fetching happens when data requests in a route are eagerly initiated and start at the same time.\n00454| \n00455| By default, [layouts and pages](/docs/app/getting-started/layouts-and-pages) are rendered in parallel. So each segment starts fetching data as soon as possible.\n00456| \n00457| However, within _any_ component, multiple `async`/`await` requests can still be sequential if placed after the other. For example, `getAlbums` will be blocked until `getArtist` is resolved:\n00458| \n00459| ```tsx filename=\"app/artist/[username]/page.tsx\" switcher\n00460| import { getArtist, getAlbums } from '@/app/lib/data'\n00461| \n00462| export default async function Page({ params }) {\n00463| // These requests will be sequential\n00464| const { username } = await params\n00465| const artist = await getArtist(username)\n00466| const albums = await getAlbums(username)\n00467| return
{artist.name}
\n00468| }\n00469| ```\n00470| \n00471| Start multiple requests by calling `fetch`, then await them with [`Promise.all`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all). Requests begin as soon as `fetch` is called.\n00472| \n00473| ```tsx filename=\"app/artist/[username]/page.tsx\" highlight={3,8,24} switcher\n00474| import Albums from './albums'\n00475| \n00476| async function getArtist(username: string) {\n00477| const res = await fetch(`https://api.example.com/artist/${username}`)\n00478| return res.json()\n00479| }\n00480| \n00481| async function getAlbums(username: string) {\n00482| const res = await fetch(`https://api.example.com/artist/${username}/albums`)\n00483| return res.json()\n00484| }\n00485| \n00486| export default async function Page({\n00487| params,\n00488| }: {\n00489| params: Promise<{ username: string }>\n00490| }) {\n00491| const { username } = await params\n00492| \n00493| // Initiate requests\n00494| const artistData = getArtist(username)\n00495| const albumsData = getAlbums(username)\n00496| \n00497| const [artist, albums] = await Promise.all([artistData, albumsData])\n00498| \n00499| return (\n00500| <>\n00501|
\n00533| \n00534| >\n00535| )\n00536| }\n00537| ```\n00538| \n00539| > **Good to know:** If one request fails when using `Promise.all`, the entire operation will fail. To handle this, you can use the [`Promise.allSettled`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled) method instead.\n00540| \n00541| ### Sharing data with context and `React.cache`\n00542| \n00543| You can share fetched data across both Server and Client Components by combining [`React.cache`](https://react.dev/reference/react/cache) with context providers.\n00544| \n00545| Create a cached function that fetches data:\n00546| \n00547| ```ts filename=\"app/lib/user.ts\" switcher\n00548| import { cache } from 'react'\n00549| \n00550| export const getUser = cache(async () => {\n00551| const res = await fetch('https://api.example.com/user')\n00552| return res.json()\n00553| })\n00554| ```\n00555| \n00556| ```js filename=\"app/lib/user.js\" switcher\n00557| import { cache } from 'react'\n00558| \n00559| export const getUser = cache(async () => {\n00560| const res = await fetch('https://api.example.com/user')\n00561| return res.json()\n00562| })\n00563| ```\n00564| \n00565| Create a context provider that stores the promise:\n00566| \n00567| ```tsx filename=\"app/user-provider.tsx\" switcher\n00568| 'use client'\n00569| \n00570| import { createContext } from 'react'\n00571| \n00572| type User = {\n00573| id: string\n00574| name: string\n00575| }\n00576| \n00577| export const UserContext = createContext | null>(null)\n00578| \n00579| export default function UserProvider({\n00580| children,\n00581| userPromise,\n00582| }: {\n00583| children: React.ReactNode\n00584| userPromise: Promise\n00585| }) {\n00586| return {children}\n00587| }\n00588| ```\n00589| \n00590| ```jsx filename=\"app/user-provider.js\" switcher\n00591| 'use client'\n00592| \n00593| import { createContext } from 'react'\n00594| \n00595| export const UserContext = createContext(null)\n00596| \n00597| export default function UserProvider({ children, userPromise }) {\n00598| return {children}\n00599| }\n00600| ```\n00601| \n00602| In a layout, pass the promise to the provider without awaiting:\n00603| \n00604| ```tsx filename=\"app/layout.tsx\" switcher\n00605| import UserProvider from './user-provider'\n00606| import { getUser } from './lib/user'\n00607| \n00608| export default function RootLayout({\n00609| children,\n00610| }: {\n00611| children: React.ReactNode\n00612| }) {\n00613| const userPromise = getUser() // Don't await\n00614| \n00615| return (\n00616| \n00617| \n00618| {children}\n00619| \n00620| \n00621| )\n00622| }\n00623| ```\n00624| \n00625| ```jsx filename=\"app/layout.js\" switcher\n00626| import UserProvider from './user-provider'\n00627| import { getUser } from './lib/user'\n00628| \n00629| export default function RootLayout({ children }) {\n00630| const userPromise = getUser() // Don't await\n00631| \n00632| return (\n00633| \n00634| \n00635| {children}\n00636| \n00637| \n00638| )\n00639| }\n00640| ```\n00641| \n00642| Client Components use [`use()`](https://react.dev/reference/react/use) to resolve the promise from context, wrapped in `` for fallback UI:\n00643| \n00644| ```tsx filename=\"app/ui/profile.tsx\" switcher\n00645| 'use client'\n00646| \n00647| import { use, useContext } from 'react'\n00648| import { UserContext } from '../user-provider'\n00649| \n00650| export function Profile() {\n00651| const userPromise = useContext(UserContext)\n00652| if (!userPromise) {\n00653| throw new Error('useContext must be used within a UserProvider')\n00654| }\n00655| const user = use(userPromise)\n00656| return
Welcome, {user.name}
\n00657| }\n00658| ```\n00659| \n00660| ```jsx filename=\"app/ui/profile.js\" switcher\n00661| 'use client'\n00662| \n00663| import { use, useContext } from 'react'\n00664| import { UserContext } from '../user-provider'\n00665| \n00666| export function Profile() {\n00667| const userPromise = useContext(UserContext)\n00668| if (!userPromise) {\n00669| throw new Error('useContext must be used within a UserProvider')\n00670| }\n00671| const user = use(userPromise)\n00672| return
Welcome, {user.name}
\n00673| }\n00674| ```\n00675| \n00676| ```tsx filename=\"app/page.tsx\" switcher\n00677| import { Suspense } from 'react'\n00678| import { Profile } from './ui/profile'\n00679| \n00680| export default function Page() {\n00681| return (\n00682| Loading profile...}>\n00683| \n00684| \n00685| )\n00686| }\n00687| ```\n00688| \n00689| ```jsx filename=\"app/page.js\" switcher\n00690| import { Suspense } from 'react'\n00691| import { Profile } from './ui/profile'\n00692| \n00693| export default function Page() {\n00694| return (\n00695| Loading profile...}>\n00696| \n00697| \n00698| )\n00699| }\n00700| ```\n00701| \n00702| Server Components can also call `getUser()` directly:\n00703| \n00704| ```tsx filename=\"app/dashboard/page.tsx\" switcher\n00705| import { getUser } from '../lib/user'\n00706| \n00707| export default async function DashboardPage() {\n00708| const user = await getUser() // Cached - same request, no duplicate fetch\n00709| return
Dashboard for {user.name}
\n00710| }\n00711| ```\n00712| \n00713| ```jsx filename=\"app/dashboard/page.js\" switcher\n00714| import { getUser } from '../lib/user'\n00715| \n00716| export default async function DashboardPage() {\n00717| const user = await getUser() // Cached - same request, no duplicate fetch\n00718| return
Dashboard for {user.name}
\n00719| }\n00720| ```\n00721| \n00722| Since `getUser` is wrapped with `React.cache`, multiple calls within the same request return the same memoized result, whether called directly in Server Components or resolved via context in Client Components.\n00723| \n00724| > **Good to know**: `React.cache` is scoped to the current request only. Each request gets its own memoization scope with no sharing between requests.\n00725| \n\n(End of file - total 725 lines)\n","title":"node_modules/next/dist/docs/01-app/01-getting-started/06-fetching-data.md","metadata":{"preview":"---\ntitle: Fetching Data\ndescription: Learn how to fetch data and stream content that depends on data.\nrelated:\n title: API Reference\n description: Learn more about the features mentioned in this page by reading the API Reference.\n links:\n - app/guides/data-security\n - app/api-reference/functions/fetch\n - app/api-reference/file-conventions/loading\n - app/api-reference/config/next-config-js/logging\n - app/api-reference/config/next-config-js/taint\n---\n\nThis page will walk you through how you can fetch data in [Server](#server-components) and [Client](#client-components) Components, and how to [stream](#streaming) components that depend on uncached data.\n\n## Fetching data\n\n### Server Components\n"},"time":{"start":1781392538406,"end":1781392538415}}}}
+{"type":"tool_use","timestamp":1781392538913,"sessionID":"ses_13cbb6bbfffe8dTGye7IwIMgqy","part":{"id":"prt_ec344fb2d001ownh8HwmtXJxdD","sessionID":"ses_13cbb6bbfffe8dTGye7IwIMgqy","messageID":"msg_ec344e6be001aL8VqS6oWys5kr","type":"tool","callID":"read_24","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/node_modules/next/dist/docs/01-app/01-getting-started/09-revalidating.md"},"output":"\n00001| ---\n00002| title: Revalidating\n00003| description: Learn how to revalidate cached data using time-based and on-demand strategies.\n00004| related:\n00005| title: API Reference\n00006| description: Learn more about the APIs mentioned on this page.\n00007| links:\n00008| - app/api-reference/functions/cacheLife\n00009| - app/api-reference/functions/cacheTag\n00010| - app/api-reference/functions/revalidateTag\n00011| - app/api-reference/functions/updateTag\n00012| - app/api-reference/functions/revalidatePath\n00013| ---\n00014| \n00015| > This page covers revalidation with [Cache Components](/docs/app/api-reference/config/next-config-js/cacheComponents), enabled by setting [`cacheComponents: true`](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.ts` file. If you're not using Cache Components, see the [Caching and Revalidating (Previous Model)](/docs/app/guides/caching-without-cache-components) guide.\n00016| \n00017| Revalidation is the process of updating cached data. It lets you keep serving fast, cached responses while ensuring content stays fresh. There are two strategies:\n00018| \n00019| - **Time-based revalidation**: Automatically refresh cached data after a set duration using [`cacheLife`](#cachelife).\n00020| - **On-demand revalidation**: Manually invalidate cached data after a mutation using [`revalidateTag`](#revalidatetag), [`updateTag`](#updatetag), or [`revalidatePath`](#revalidatepath).\n00021| \n00022| ## `cacheLife`\n00023| \n00024| [`cacheLife`](/docs/app/api-reference/functions/cacheLife) controls how long cached data remains valid. Use it inside a [`use cache`](/docs/app/api-reference/directives/use-cache) scope to set the cache lifetime.\n00025| \n00026| ```tsx filename=\"app/lib/data.ts\" highlight={1,4,5}\n00027| import { cacheLife } from 'next/cache'\n00028| \n00029| export async function getProducts() {\n00030| 'use cache'\n00031| cacheLife('hours')\n00032| return db.query('SELECT * FROM products')\n00033| }\n00034| ```\n00035| \n00036| `cacheLife` accepts a profile name or a custom configuration object:\n00037| \n00038| | Profile | `stale` | `revalidate` | `expire` |\n00039| | --------- | ------- | ------------ | -------- |\n00040| | `default` | 5m | 15m | never |\n00041| | `seconds` | 30s | 1s | 60s |\n00042| | `minutes` | 5m | 1m | 1h |\n00043| | `hours` | 5m | 1h | 1d |\n00044| | `days` | 5m | 1d | 1w |\n00045| | `weeks` | 5m | 1w | 30d |\n00046| | `max` | 5m | 30d | 1y |\n00047| \n00048| For fine-grained control, pass an object:\n00049| \n00050| ```tsx highlight={2-6}\n00051| 'use cache'\n00052| cacheLife({\n00053| stale: 3600, // 1 hour until considered stale\n00054| revalidate: 7200, // 2 hours until revalidated\n00055| expire: 86400, // 1 day until expired\n00056| })\n00057| ```\n00058| \n00059| > **Good to know:** A cache is considered \"short-lived\" when it uses the `seconds` profile, `revalidate: 0`, or `expire` under 5 minutes. Short-lived caches are automatically excluded from prerenders and become dynamic holes instead. See [Prerendering behavior](/docs/app/api-reference/functions/cacheLife#prerendering-behavior) for details.\n00060| \n00061| See the [`cacheLife` API reference](/docs/app/api-reference/functions/cacheLife) for all profiles and custom configuration options.\n00062| \n00063| ## `cacheTag`\n00064| \n00065| [`cacheTag`](/docs/app/api-reference/functions/cacheTag) lets you tag cached data so it can be invalidated on-demand. Use it inside a [`use cache`](/docs/app/api-reference/directives/use-cache) scope:\n00066| \n00067| ```tsx filename=\"app/lib/data.ts\" switcher\n00068| import { cacheTag } from 'next/cache'\n00069| \n00070| export async function getProducts() {\n00071| 'use cache'\n00072| cacheTag('products')\n00073| return db.query('SELECT * FROM products')\n00074| }\n00075| ```\n00076| \n00077| ```jsx filename=\"app/lib/data.js\" switcher\n00078| import { cacheTag } from 'next/cache'\n00079| \n00080| export async function getProducts() {\n00081| 'use cache'\n00082| cacheTag('products')\n00083| return db.query('SELECT * FROM products')\n00084| }\n00085| ```\n00086| \n00087| Once tagged, invalidate the cache using [`revalidateTag`](#revalidatetag) or [`updateTag`](#updatetag).\n00088| \n00089| See the [`cacheTag` API reference](/docs/app/api-reference/functions/cacheTag) to learn more.\n00090| \n00091| ## `revalidateTag`\n00092| \n00093| `revalidateTag` invalidates cache entries by tag using stale-while-revalidate semantics — stale content is served immediately while fresh content loads in the background. This is ideal for content where a slight delay in updates is acceptable, like blog posts or product catalogs.\n00094| \n00095| ```tsx filename=\"app/lib/actions.ts\" highlight={1,5} switcher\n00096| import { revalidateTag } from 'next/cache'\n00097| \n00098| export async function updateUser(id: string) {\n00099| // Mutate data\n00100| revalidateTag('user', 'max') // Recommended: stale-while-revalidate\n00101| }\n00102| ```\n00103| \n00104| ```jsx filename=\"app/lib/actions.js\" highlight={1,5} switcher\n00105| import { revalidateTag } from 'next/cache'\n00106| \n00107| export async function updateUser(id) {\n00108| // Mutate data\n00109| revalidateTag('user', 'max') // Recommended: stale-while-revalidate\n00110| }\n00111| ```\n00112| \n00113| You can reuse the same tag in multiple functions to revalidate them all at once. Call `revalidateTag` in a [Server Action](/docs/app/getting-started/mutating-data) or [Route Handler](/docs/app/api-reference/file-conventions/route).\n00114| \n00115| > **Good to know:** The second argument sets how long stale content can be served while fresh content generates in the background. Once it expires, subsequent requests block until fresh content is ready. Using `'max'` gives the longest stale window.\n00116| \n00117| See the [`revalidateTag` API reference](/docs/app/api-reference/functions/revalidateTag) to learn more.\n00118| \n00119| ## `updateTag`\n00120| \n00121| `updateTag` immediately expires cached data for read-your-own-writes scenarios — the user sees their change right away instead of stale content. Unlike `revalidateTag`, it can only be used in [Server Actions](/docs/app/getting-started/mutating-data).\n00122| \n00123| ```tsx filename=\"app/lib/actions.ts\" highlight={1,12} switcher\n00124| import { updateTag } from 'next/cache'\n00125| import { redirect } from 'next/navigation'\n00126| \n00127| export async function createPost(formData: FormData) {\n00128| const post = await db.post.create({\n00129| data: {\n00130| title: formData.get('title'),\n00131| content: formData.get('content'),\n00132| },\n00133| })\n00134| \n00135| updateTag('posts')\n00136| redirect(`/posts/${post.id}`)\n00137| }\n00138| ```\n00139| \n00140| ```jsx filename=\"app/lib/actions.js\" highlight={1,12} switcher\n00141| import { updateTag } from 'next/cache'\n00142| import { redirect } from 'next/navigation'\n00143| \n00144| export async function createPost(formData) {\n00145| const post = await db.post.create({\n00146| data: {\n00147| title: formData.get('title'),\n00148| content: formData.get('content'),\n00149| },\n00150| })\n00151| \n00152| updateTag('posts')\n00153| redirect(`/posts/${post.id}`)\n00154| }\n00155| ```\n00156| \n00157| | | `updateTag` | `revalidateTag` |\n00158| | ------------ | --------------------------------------------- | ------------------------------------ |\n00159| | **Where** | Server Actions only | Server Actions and Route Handlers |\n00160| | **Behavior** | Immediately expires cache | Stale-while-revalidate |\n00161| | **Use case** | Read-your-own-writes (user sees their change) | Background refresh (slight delay OK) |\n00162| \n00163| See the [`updateTag` API reference](/docs/app/api-reference/functions/updateTag) to learn more.\n00164| \n00165| ## `revalidatePath`\n00166| \n00167| `revalidatePath` invalidates all cached data for a specific route path. Use it when you want to revalidate a route without knowing which tags are associated with it.\n00168| \n00169| ```tsx filename=\"app/lib/actions.ts\" highlight={1,5} switcher\n00170| import { revalidatePath } from 'next/cache'\n00171| \n00172| export async function updateUser(id: string) {\n00173| // Mutate data\n00174| revalidatePath('/profile')\n00175| }\n00176| ```\n00177| \n00178| ```jsx filename=\"app/lib/actions.js\" highlight={1,5} switcher\n00179| import { revalidatePath } from 'next/cache'\n00180| \n00181| export async function updateUser(id) {\n00182| // Mutate data\n00183| revalidatePath('/profile')\n00184| }\n00185| ```\n00186| \n00187| > **Good to know**: Prefer tag-based revalidation (`revalidateTag`/`updateTag`) over path-based when possible — it's more precise and avoids over-invalidating.\n00188| \n00189| See the [`revalidatePath` API reference](/docs/app/api-reference/functions/revalidatePath) to learn more.\n00190| \n00191| ## What should I cache?\n00192| \n00193| Cache data that doesn't depend on [runtime data](/docs/app/getting-started/caching#working-with-runtime-apis) and that you're OK serving from cache for a period of time. Use `use cache` with `cacheLife` to describe that behavior.\n00194| \n00195| For content management systems with update mechanisms, use tags with longer cache durations and rely on `revalidateTag` to refresh content when it actually changes, rather than expiring the cache preemptively.\n00196| \n00197| > **Good to know:** In serverless environments, in-memory cache entries may not persist across revalidations. See [runtime caching considerations](/docs/app/api-reference/directives/use-cache#runtime-caching-considerations) for details.\n00198| \n\n(End of file - total 198 lines)\n","title":"node_modules/next/dist/docs/01-app/01-getting-started/09-revalidating.md","metadata":{"preview":"---\ntitle: Revalidating\ndescription: Learn how to revalidate cached data using time-based and on-demand strategies.\nrelated:\n title: API Reference\n description: Learn more about the APIs mentioned on this page.\n links:\n - app/api-reference/functions/cacheLife\n - app/api-reference/functions/cacheTag\n - app/api-reference/functions/revalidateTag\n - app/api-reference/functions/updateTag\n - app/api-reference/functions/revalidatePath\n---\n\n> This page covers revalidation with [Cache Components](/docs/app/api-reference/config/next-config-js/cacheComponents), enabled by setting [`cacheComponents: true`](/docs/app/api-reference/config/next-config-js/cacheComponents) in your `next.config.ts` file. If you're not using Cache Components, see the [Caching and Revalidating (Previous Model)](/docs/app/guides/caching-without-cache-components) guide.\n\nRevalidation is the process of updating cached data. It lets you keep serving fast, cached responses while ensuring content stays fresh. There are two strategies:\n\n- **Time-based revalidation**: Automatically refresh cached data after a set duration using [`cacheLife`](#cachelife).\n- **On-demand revalidation**: Manually invalidate cached data after a mutation using [`revalidateTag`](#revalidatetag), [`updateTag`](#updatetag), or [`revalidatePath`](#revalidatepath)."},"time":{"start":1781392538899,"end":1781392538911}}}}
+{"type":"tool_use","timestamp":1781392539363,"sessionID":"ses_13cbb6bbfffe8dTGye7IwIMgqy","part":{"id":"prt_ec344fd1d001PNCIxr686liImO","sessionID":"ses_13cbb6bbfffe8dTGye7IwIMgqy","messageID":"msg_ec344e6be001aL8VqS6oWys5kr","type":"tool","callID":"read_25","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/node_modules/next/dist/docs/01-app/01-getting-started/15-route-handlers.md"},"output":"\n00001| ---\n00002| title: Route Handlers\n00003| nav_title: Route Handlers\n00004| description: Learn how to use Route Handlers\n00005| related:\n00006| title: API Reference\n00007| description: Learn more about Route Handlers\n00008| links:\n00009| - app/api-reference/file-conventions/route\n00010| - app/guides/backend-for-frontend\n00011| ---\n00012| \n00013| ## Route Handlers\n00014| \n00015| Route Handlers allow you to create custom request handlers for a given route using the Web [Request](https://developer.mozilla.org/docs/Web/API/Request) and [Response](https://developer.mozilla.org/docs/Web/API/Response) APIs.\n00016| \n00017| \n00024| \n00025| > **Good to know**: Route Handlers are only available inside the `app` directory. They are the equivalent of [API Routes](/docs/pages/building-your-application/routing/api-routes) inside the `pages` directory meaning you **do not** need to use API Routes and Route Handlers together.\n00026| \n00027| ### Convention\n00028| \n00029| Route Handlers are defined in a [`route.js|ts` file](/docs/app/api-reference/file-conventions/route) inside the `app` directory:\n00030| \n00031| ```ts filename=\"app/api/route.ts\" switcher\n00032| export async function GET(request: Request) {}\n00033| ```\n00034| \n00035| ```js filename=\"app/api/route.js\" switcher\n00036| export async function GET(request) {}\n00037| ```\n00038| \n00039| Route Handlers can be nested anywhere inside the `app` directory, similar to `page.js` and `layout.js`. But there **cannot** be a `route.js` file at the same route segment level as `page.js`.\n00040| \n00041| ### Supported HTTP Methods\n00042| \n00043| The following [HTTP methods](https://developer.mozilla.org/docs/Web/HTTP/Methods) are supported: `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, `HEAD`, and `OPTIONS`. If an unsupported method is called, Next.js will return a `405 Method Not Allowed` response.\n00044| \n00045| ### Extended `NextRequest` and `NextResponse` APIs\n00046| \n00047| In addition to supporting the native [Request](https://developer.mozilla.org/docs/Web/API/Request) and [Response](https://developer.mozilla.org/docs/Web/API/Response) APIs, Next.js extends them with [`NextRequest`](/docs/app/api-reference/functions/next-request) and [`NextResponse`](/docs/app/api-reference/functions/next-response) to provide convenient helpers for advanced use cases.\n00048| \n00049| ### Caching\n00050| \n00051| Route Handlers are not cached by default. You can, however, opt into caching for `GET` methods. Other supported HTTP methods are **not** cached. To cache a `GET` method, use a [route config option](/docs/app/guides/caching-without-cache-components#dynamic) such as `export const dynamic = 'force-static'` in your Route Handler file.\n00052| \n00053| ```ts filename=\"app/items/route.ts\" switcher\n00054| export const dynamic = 'force-static'\n00055| \n00056| export async function GET() {\n00057| const res = await fetch('https://data.mongodb-api.com/...', {\n00058| headers: {\n00059| 'Content-Type': 'application/json',\n00060| 'API-Key': process.env.DATA_API_KEY,\n00061| },\n00062| })\n00063| const data = await res.json()\n00064| \n00065| return Response.json({ data })\n00066| }\n00067| ```\n00068| \n00069| ```js filename=\"app/items/route.js\" switcher\n00070| export const dynamic = 'force-static'\n00071| \n00072| export async function GET() {\n00073| const res = await fetch('https://data.mongodb-api.com/...', {\n00074| headers: {\n00075| 'Content-Type': 'application/json',\n00076| 'API-Key': process.env.DATA_API_KEY,\n00077| },\n00078| })\n00079| const data = await res.json()\n00080| \n00081| return Response.json({ data })\n00082| }\n00083| ```\n00084| \n00085| > **Good to know**: Other supported HTTP methods are **not** cached, even if they are placed alongside a `GET` method that is cached, in the same file.\n00086| \n00087| #### With Cache Components\n00088| \n00089| When [Cache Components](/docs/app/getting-started/caching) is enabled, `GET` Route Handlers follow the same model as normal UI routes in your application. They run at request time by default, can be prerendered when they don't access uncached or runtime data, and you can use `use cache` to include uncached data in the static response.\n00090| \n00091| **Static example** - doesn't access uncached or runtime data, so it will be prerendered at build time:\n00092| \n00093| ```tsx filename=\"app/api/project-info/route.ts\"\n00094| export async function GET() {\n00095| return Response.json({\n00096| projectName: 'Next.js',\n00097| })\n00098| }\n00099| ```\n00100| \n00101| **Dynamic example** - accesses non-deterministic operations. During the build, prerendering stops when `Math.random()` is called, deferring to request-time rendering:\n00102| \n00103| ```tsx filename=\"app/api/random-number/route.ts\"\n00104| export async function GET() {\n00105| return Response.json({\n00106| randomNumber: Math.random(),\n00107| })\n00108| }\n00109| ```\n00110| \n00111| **Runtime data example** - accesses request-specific data. Prerendering terminates when runtime APIs like `headers()` are called:\n00112| \n00113| ```tsx filename=\"app/api/user-agent/route.ts\"\n00114| import { headers } from 'next/headers'\n00115| \n00116| export async function GET() {\n00117| const headersList = await headers()\n00118| const userAgent = headersList.get('user-agent')\n00119| \n00120| return Response.json({ userAgent })\n00121| }\n00122| ```\n00123| \n00124| > **Good to know**: Prerendering stops if the `GET` handler accesses network requests, database queries, async file system operations, request object properties (like `req.url`, `request.headers`, `request.cookies`, `request.body`), runtime APIs like [`cookies()`](/docs/app/api-reference/functions/cookies), [`headers()`](/docs/app/api-reference/functions/headers), [`connection()`](/docs/app/api-reference/functions/connection), or non-deterministic operations.\n00125| \n00126| **Cached example** - accesses uncached data (database query) but caches it with `use cache`, allowing it to be included in the prerendered response:\n00127| \n00128| ```tsx filename=\"app/api/products/route.ts\"\n00129| import { cacheLife } from 'next/cache'\n00130| \n00131| export async function GET() {\n00132| const products = await getProducts()\n00133| return Response.json(products)\n00134| }\n00135| \n00136| async function getProducts() {\n00137| 'use cache'\n00138| cacheLife('hours')\n00139| \n00140| return await db.query('SELECT * FROM products')\n00141| }\n00142| ```\n00143| \n00144| > **Good to know**: `use cache` cannot be used directly inside a Route Handler body; extract it to a helper function. Cached responses revalidate according to `cacheLife` when a new request arrives.\n00145| \n00146| ### Special Route Handlers\n00147| \n00148| Special Route Handlers like [`sitemap.ts`](/docs/app/api-reference/file-conventions/metadata/sitemap), [`opengraph-image.tsx`](/docs/app/api-reference/file-conventions/metadata/opengraph-image), and [`icon.tsx`](/docs/app/api-reference/file-conventions/metadata/app-icons), and other [metadata files](/docs/app/api-reference/file-conventions/metadata) remain static by default unless they use Request-time APIs or dynamic config options.\n00149| \n00150| ### Route Resolution\n00151| \n00152| You can consider a `route` the lowest level routing primitive.\n00153| \n00154| - They **do not** participate in layouts or client-side navigations like `page`.\n00155| - There **cannot** be a `route.js` file at the same route as `page.js`.\n00156| \n00157| | Page | Route | Result |\n00158| | -------------------- | ------------------ | ---------------------------- |\n00159| | `app/page.js` | `app/route.js` | Conflict |\n00160| | `app/page.js` | `app/api/route.js` | Valid |\n00161| | `app/[user]/page.js` | `app/api/route.js` | Valid |\n00162| \n00163| Each `route.js` or `page.js` file takes over all HTTP verbs for that route.\n00164| \n00165| ```ts filename=\"app/page.ts\" switcher\n00166| export default function Page() {\n00167| return
\n00178| }\n00179| \n00180| // Conflict\n00181| // `app/route.js`\n00182| export async function POST(request) {}\n00183| ```\n00184| \n00185| Read more about how Route Handlers [complement your frontend application](/docs/app/guides/backend-for-frontend), or explore the Route Handlers [API Reference](/docs/app/api-reference/file-conventions/route).\n00186| \n00187| ### Route Context Helper\n00188| \n00189| In TypeScript, you can type the `context` parameter for Route Handlers with the globally available [`RouteContext`](/docs/app/api-reference/file-conventions/route#route-context-helper) helper:\n00190| \n00191| ```ts filename=\"app/users/[id]/route.ts\" switcher\n00192| import type { NextRequest } from 'next/server'\n00193| \n00194| export async function GET(_req: NextRequest, ctx: RouteContext<'/users/[id]'>) {\n00195| const { id } = await ctx.params\n00196| return Response.json({ id })\n00197| }\n00198| ```\n00199| \n00200| > **Good to know**\n00201| >\n00202| > - Types are generated during `next dev`, `next build` or `next typegen`.\n00203| \n\n(End of file - total 203 lines)\n","title":"node_modules/next/dist/docs/01-app/01-getting-started/15-route-handlers.md","metadata":{"preview":"---\ntitle: Route Handlers\nnav_title: Route Handlers\ndescription: Learn how to use Route Handlers\nrelated:\n title: API Reference\n description: Learn more about Route Handlers\n links:\n - app/api-reference/file-conventions/route\n - app/guides/backend-for-frontend\n---\n\n## Route Handlers\n\nRoute Handlers allow you to create custom request handlers for a given route using the Web [Request](https://developer.mozilla.org/docs/Web/API/Request) and [Response](https://developer.mozilla.org/docs/Web/API/Response) APIs.\n\n\n00001| ---\n00002| title: Error Handling\n00003| description: Learn how to display expected errors and handle uncaught exceptions.\n00004| related:\n00005| title: API Reference\n00006| description: Learn more about the features mentioned in this page by reading the API Reference.\n00007| links:\n00008| - app/api-reference/functions/redirect\n00009| - app/api-reference/file-conventions/error\n00010| - app/api-reference/functions/catchError\n00011| - app/api-reference/functions/not-found\n00012| - app/api-reference/file-conventions/not-found\n00013| ---\n00014| \n00015| Errors can be divided into two categories: [expected errors](#handling-expected-errors) and [uncaught exceptions](#handling-uncaught-exceptions). This page will walk you through how you can handle these errors in your Next.js application.\n00016| \n00017| ## Handling expected errors\n00018| \n00019| Expected errors are those that can occur during the normal operation of the application, such as those from [server-side form validation](/docs/app/guides/forms) or failed requests. These errors should be handled explicitly and returned to the client.\n00020| \n00021| ### Server Functions\n00022| \n00023| You can use the [`useActionState`](https://react.dev/reference/react/useActionState) hook to handle expected errors in [Server Functions](https://react.dev/reference/rsc/server-functions).\n00024| \n00025| For these errors, avoid using `try`/`catch` blocks and throw errors. Instead, model expected errors as return values.\n00026| \n00027| ```ts filename=\"app/actions.ts\" switcher\n00028| 'use server'\n00029| \n00030| export async function createPost(prevState: any, formData: FormData) {\n00031| const title = formData.get('title')\n00032| const content = formData.get('content')\n00033| \n00034| const res = await fetch('https://api.vercel.app/posts', {\n00035| method: 'POST',\n00036| body: { title, content },\n00037| })\n00038| const json = await res.json()\n00039| \n00040| if (!res.ok) {\n00041| return { message: 'Failed to create post' }\n00042| }\n00043| }\n00044| ```\n00045| \n00046| ```js filename=\"app/actions.js\" switcher\n00047| 'use server'\n00048| \n00049| export async function createPost(prevState, formData) {\n00050| const title = formData.get('title')\n00051| const content = formData.get('content')\n00052| \n00053| const res = await fetch('https://api.vercel.app/posts', {\n00054| method: 'POST',\n00055| body: { title, content },\n00056| })\n00057| const json = await res.json()\n00058| \n00059| if (!res.ok) {\n00060| return { message: 'Failed to create post' }\n00061| }\n00062| }\n00063| ```\n00064| \n00065| You can pass your action to the `useActionState` hook and use the returned `state` to display an error message.\n00066| \n00067| ```tsx filename=\"app/ui/form.tsx\" highlight={11,19} switcher\n00068| 'use client'\n00069| \n00070| import { useActionState } from 'react'\n00071| import { createPost } from '@/app/actions'\n00072| \n00073| const initialState = {\n00074| message: '',\n00075| }\n00076| \n00077| export function Form() {\n00078| const [state, formAction, pending] = useActionState(createPost, initialState)\n00079| \n00080| return (\n00081|
\n00115| )\n00116| }\n00117| ```\n00118| \n00119| ### Server Components\n00120| \n00121| When fetching data inside of a Server Component, you can use the response to conditionally render an error message or [`redirect`](/docs/app/api-reference/functions/redirect).\n00122| \n00123| ```tsx filename=\"app/page.tsx\" switcher\n00124| export default async function Page() {\n00125| const res = await fetch(`https://...`)\n00126| const data = await res.json()\n00127| \n00128| if (!res.ok) {\n00129| return 'There was an error.'\n00130| }\n00131| \n00132| return '...'\n00133| }\n00134| ```\n00135| \n00136| ```jsx filename=\"app/page.js\" switcher\n00137| export default async function Page() {\n00138| const res = await fetch(`https://...`)\n00139| const data = await res.json()\n00140| \n00141| if (!res.ok) {\n00142| return 'There was an error.'\n00143| }\n00144| \n00145| return '...'\n00146| }\n00147| ```\n00148| \n00149| ### Not found\n00150| \n00151| You can call the [`notFound`](/docs/app/api-reference/functions/not-found) function within a route segment and use the [`not-found.js`](/docs/app/api-reference/file-conventions/not-found) file to show a 404 UI.\n00152| \n00153| ```tsx filename=\"app/blog/[slug]/page.tsx\" switcher\n00154| import { notFound } from 'next/navigation'\n00155| import { getPostBySlug } from '@/lib/posts'\n00156| \n00157| export default async function Page({\n00158| params,\n00159| }: {\n00160| params: Promise<{ slug: string }>\n00161| }) {\n00162| const { slug } = await params\n00163| const post = getPostBySlug(slug)\n00164| \n00165| if (!post) {\n00166| notFound()\n00167| }\n00168| \n00169| return
{post.title}
\n00170| }\n00171| ```\n00172| \n00173| ```jsx filename=\"app/blog/[slug]/page.js\" switcher\n00174| import { notFound } from 'next/navigation'\n00175| import { getPostBySlug } from '@/lib/posts'\n00176| \n00177| export default async function Page({ params }) {\n00178| const { slug } = await params\n00179| const post = getPostBySlug(slug)\n00180| \n00181| if (!post) {\n00182| notFound()\n00183| }\n00184| \n00185| return
\n00198| }\n00199| ```\n00200| \n00201| ## Handling uncaught exceptions\n00202| \n00203| Uncaught exceptions are unexpected errors that indicate bugs or issues that should not occur during the normal flow of your application. These should be handled by throwing errors, which will then be caught by error boundaries.\n00204| \n00205| ### Nested error boundaries\n00206| \n00207| Next.js uses error boundaries to handle uncaught exceptions. Error boundaries catch errors in their child components and display a fallback UI instead of the component tree that crashed.\n00208| \n00209| Create an error boundary by adding an [`error.js`](/docs/app/api-reference/file-conventions/error) file inside a route segment and exporting a React component:\n00210| \n00211| ```tsx filename=\"app/dashboard/error.tsx\" switcher\n00212| 'use client' // Error boundaries must be Client Components\n00213| \n00214| import { useEffect } from 'react'\n00215| \n00216| export default function ErrorPage({\n00217| error,\n00218| retry,\n00219| }: {\n00220| error: Error & { digest?: string }\n00221| retry: () => void\n00222| }) {\n00223| useEffect(() => {\n00224| // Log the error to an error reporting service\n00225| console.error(error)\n00226| }, [error])\n00227| \n00228| return (\n00229|
\n00267| )\n00268| }\n00269| ```\n00270| \n00271| Errors will bubble up to the nearest parent error boundary. This allows for granular error handling by placing `error.tsx` files at different levels in the [route hierarchy](/docs/app/getting-started/project-structure#component-hierarchy).\n00272| \n00273| \n00280| \n00281| For component-level error recovery, the [`catchError`](/docs/app/api-reference/functions/catchError) function lets you create error boundaries that can wrap any part of your component tree:\n00282| \n00283| ```tsx filename=\"app/custom-error-boundary.tsx\" switcher\n00284| 'use client'\n00285| \n00286| import { catchError, type ErrorInfo } from 'next/error'\n00287| \n00288| function ErrorFallback(props: { title: string }, { error, retry }: ErrorInfo) {\n00289| return (\n00290|
\n00313| )\n00314| }\n00315| \n00316| export default catchError(ErrorFallback)\n00317| ```\n00318| \n00319| Then use the returned component as a wrapper in any layout or page:\n00320| \n00321| ```tsx filename=\"app/some-component.tsx\" switcher\n00322| import ErrorBoundary from './custom-error-boundary'\n00323| \n00324| export default function Component({ children }: { children: React.ReactNode }) {\n00325| return {children}\n00326| }\n00327| ```\n00328| \n00329| ```jsx filename=\"app/some-component.js\" switcher\n00330| import ErrorBoundary from './custom-error-boundary'\n00331| \n00332| export default function Component({ children }) {\n00333| return {children}\n00334| }\n00335| ```\n00336| \n00337| Error boundaries don't catch errors inside event handlers. They're designed to catch errors [during rendering](https://react.dev/reference/react/Component#static-getderivedstatefromerror) to show a **fallback UI** instead of crashing the whole app.\n00338| \n00339| In general, errors in event handlers or async code aren’t handled by error boundaries because they run after rendering.\n00340| \n00341| To handle these cases, catch the error manually and store it using `useState` or `useReducer`, then update the UI to inform the user.\n00342| \n00343| ```tsx\n00344| 'use client'\n00345| \n00346| import { useState } from 'react'\n00347| \n00348| export function Button() {\n00349| const [error, setError] = useState(null)\n00350| \n00351| const handleClick = () => {\n00352| try {\n00353| // do some work that might fail\n00354| throw new Error('Exception')\n00355| } catch (reason) {\n00356| setError(reason)\n00357| }\n00358| }\n00359| \n00360| if (error) {\n00361| /* render fallback UI */\n00362| }\n00363| \n00364| return (\n00365| \n00366| Click me\n00367| \n00368| )\n00369| }\n00370| ```\n00371| \n00372| Note that unhandled errors inside `startTransition` from `useTransition`, will bubble up to the nearest error boundary.\n00373| \n00374| ```tsx\n00375| 'use client'\n00376| \n00377| import { useTransition } from 'react'\n00378| \n00379| export function Button() {\n00380| const [pending, startTransition] = useTransition()\n00381| \n00382| const handleClick = () =>\n00383| startTransition(() => {\n00384| throw new Error('Exception')\n00385| })\n00386| \n00387| return (\n00388| \n00389| Click me\n00390| \n00391| )\n00392| }\n00393| ```\n00394| \n00395| ### Global errors\n00396| \n00397| While less common, you can handle errors in the root layout using the [`global-error.js`](/docs/app/api-reference/file-conventions/error#global-error) file, located in the root app directory, even when leveraging [internationalization](/docs/app/guides/internationalization). Global error UI must define its own `` and `` tags, since it is replacing the root layout or template when active.\n00398| \n00399| ```tsx filename=\"app/global-error.tsx\" switcher\n00400| 'use client' // Error boundaries must be Client Components\n00401| \n00402| export default function GlobalError({\n00403| error,\n00404| retry,\n00405| }: {\n00406| error: Error & { digest?: string }\n00407| retry: () => void\n00408| }) {\n00409| return (\n00410| // global-error must include html and body tags\n00411| \n00412| \n00413|
Something went wrong!
\n00414| retry()}>Try again\n00415| \n00416| \n00417| )\n00418| }\n00419| ```\n00420| \n00421| ```jsx filename=\"app/global-error.js\" switcher\n00422| 'use client' // Error boundaries must be Client Components\n00423| \n00424| export default function GlobalError({ error, retry }) {\n00425| return (\n00426| // global-error must include html and body tags\n00427| \n00428| \n00429|
Something went wrong!
\n00430| retry()}>Try again\n00431| \n00432| \n00433| )\n00434| }\n00435| ```\n00436| \n\n(End of file - total 436 lines)\n","title":"node_modules/next/dist/docs/01-app/01-getting-started/10-error-handling.md","metadata":{"preview":"---\ntitle: Error Handling\ndescription: Learn how to display expected errors and handle uncaught exceptions.\nrelated:\n title: API Reference\n description: Learn more about the features mentioned in this page by reading the API Reference.\n links:\n - app/api-reference/functions/redirect\n - app/api-reference/file-conventions/error\n - app/api-reference/functions/catchError\n - app/api-reference/functions/not-found\n - app/api-reference/file-conventions/not-found\n---\n\nErrors can be divided into two categories: [expected errors](#handling-expected-errors) and [uncaught exceptions](#handling-uncaught-exceptions). This page will walk you through how you can handle these errors in your Next.js application.\n\n## Handling expected errors\n\nExpected errors are those that can occur during the normal operation of the application, such as those from [server-side form validation](/docs/app/guides/forms) or failed requests. These errors should be handled explicitly and returned to the client.\n"},"time":{"start":1781392539846,"end":1781392539852}}}}
+{"type":"tool_use","timestamp":1781392540299,"sessionID":"ses_13cbb6bbfffe8dTGye7IwIMgqy","part":{"id":"prt_ec34500ca001wxiaPTTaleE7df","sessionID":"ses_13cbb6bbfffe8dTGye7IwIMgqy","messageID":"msg_ec344e6be001aL8VqS6oWys5kr","type":"tool","callID":"read_27","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/node_modules/next/dist/docs/01-app/01-getting-started/14-metadata-and-og-images.md"},"output":"\n00001| ---\n00002| title: Metadata and OG images\n00003| description: Learn how to add metadata to your pages and create dynamic OG images.\n00004| related:\n00005| title: API Reference\n00006| description: Learn more about the Metadata APIs mentioned in this page.\n00007| links:\n00008| - app/api-reference/functions/generate-metadata\n00009| - app/api-reference/functions/generate-viewport\n00010| - app/api-reference/functions/image-response\n00011| - app/api-reference/file-conventions/metadata\n00012| - app/api-reference/file-conventions/metadata/app-icons\n00013| - app/api-reference/file-conventions/metadata/opengraph-image\n00014| - app/api-reference/file-conventions/metadata/robots\n00015| - app/api-reference/file-conventions/metadata/sitemap\n00016| - app/api-reference/config/next-config-js/htmlLimitedBots\n00017| ---\n00018| \n00019| The Metadata APIs can be used to define your application metadata for improved SEO and web shareability and include:\n00020| \n00021| 1. [The static `metadata` object](#static-metadata)\n00022| 2. [The dynamic `generateMetadata` function](#generated-metadata)\n00023| 3. Special [file conventions](/docs/app/api-reference/file-conventions/metadata) that can be used to add static or dynamically generated [favicons](#favicons) and [OG images](#static-open-graph-images).\n00024| \n00025| With all the options above, Next.js will automatically generate the relevant `` tags for your page, which can be inspected in the browser's developer tools.\n00026| \n00027| The `metadata` object and `generateMetadata` function exports are only supported in Server Components.\n00028| \n00029| ## Default fields\n00030| \n00031| There are two default `meta` tags that are always added even if a route doesn't define metadata:\n00032| \n00033| - The [meta charset tag](https://developer.mozilla.org/docs/Web/HTML/Element/meta#attr-charset) sets the character encoding for the website.\n00034| - The [meta viewport tag](https://developer.mozilla.org/docs/Web/HTML/Viewport_meta_tag) sets the viewport width and scale for the website to adjust for different devices.\n00035| \n00036| ```html\n00037| \n00038| \n00039| ```\n00040| \n00041| The other metadata fields can be defined with the `Metadata` object (for [static metadata](#static-metadata)) or the `generateMetadata` function (for [generated metadata](#generated-metadata)).\n00042| \n00043| ## Static metadata\n00044| \n00045| To define static metadata, export a [`Metadata` object](/docs/app/api-reference/functions/generate-metadata#metadata-object) from a static [`layout.js`](/docs/app/api-reference/file-conventions/layout) or [`page.js`](/docs/app/api-reference/file-conventions/page) file. For example, to add a title and description to the blog route:\n00046| \n00047| ```tsx filename=\"app/blog/layout.tsx\" switcher\n00048| import type { Metadata } from 'next'\n00049| \n00050| export const metadata: Metadata = {\n00051| title: 'My Blog',\n00052| description: '...',\n00053| }\n00054| \n00055| export default function Layout() {}\n00056| ```\n00057| \n00058| ```jsx filename=\"app/blog/layout.js\" switcher\n00059| export const metadata = {\n00060| title: 'My Blog',\n00061| description: '...',\n00062| }\n00063| \n00064| export default function Layout() {}\n00065| ```\n00066| \n00067| You can view a full list of available options, in the [`generateMetadata` documentation](/docs/app/api-reference/functions/generate-metadata#metadata-fields).\n00068| \n00069| ## Generated metadata\n00070| \n00071| You can use [`generateMetadata`](/docs/app/api-reference/functions/generate-metadata) function to `fetch` metadata that depends on data. For example, to fetch the title and description for a specific blog post:\n00072| \n00073| ```tsx filename=\"app/blog/[slug]/page.tsx\" switcher\n00074| import type { Metadata, ResolvingMetadata } from 'next'\n00075| \n00076| type Props = {\n00077| params: Promise<{ slug: string }>\n00078| searchParams: Promise<{ [key: string]: string | string[] | undefined }>\n00079| }\n00080| \n00081| export async function generateMetadata(\n00082| { params, searchParams }: Props,\n00083| parent: ResolvingMetadata\n00084| ): Promise {\n00085| const slug = (await params).slug\n00086| \n00087| // fetch post information\n00088| const post = await fetch(`https://api.vercel.app/blog/${slug}`).then((res) =>\n00089| res.json()\n00090| )\n00091| \n00092| return {\n00093| title: post.title,\n00094| description: post.description,\n00095| }\n00096| }\n00097| \n00098| export default function Page({ params, searchParams }: Props) {}\n00099| ```\n00100| \n00101| ```jsx filename=\"app/blog/[slug]/page.js\" switcher\n00102| export async function generateMetadata({ params, searchParams }, parent) {\n00103| const slug = (await params).slug\n00104| \n00105| // fetch post information\n00106| const post = await fetch(`https://api.vercel.app/blog/${slug}`).then((res) =>\n00107| res.json()\n00108| )\n00109| \n00110| return {\n00111| title: post.title,\n00112| description: post.description,\n00113| }\n00114| }\n00115| \n00116| export default function Page({ params, searchParams }) {}\n00117| ```\n00118| \n00119| ### Streaming metadata\n00120| \n00121| For dynamically rendered pages, Next.js streams metadata separately, injecting it into the HTML once `generateMetadata` resolves, without blocking UI rendering.\n00122| \n00123| Streaming metadata improves perceived performance by allowing visual content to stream first.\n00124| \n00125| Streaming metadata is **disabled for bots and crawlers** that expect metadata to be in the `` tag (e.g. `Twitterbot`, `Slackbot`, `Bingbot`). These are detected by using the User Agent header from the incoming request.\n00126| \n00127| 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.\n00128| \n00129| Prerendered pages don’t use streaming since metadata is resolved at build time.\n00130| \n00131| Learn more about [streaming metadata](/docs/app/api-reference/functions/generate-metadata#streaming-metadata).\n00132| \n00133| ### Memoizing data requests\n00134| \n00135| There may be cases where you need to fetch the **same** data for metadata and the page itself. To avoid duplicate requests, you can use React's [`cache` function](https://react.dev/reference/react/cache) to memoize the return value and only fetch the data once. For example, to fetch the blog post information for both the metadata and the page:\n00136| \n00137| ```ts filename=\"app/lib/data.ts\" highlight={5} switcher\n00138| import { cache } from 'react'\n00139| import { db } from '@/app/lib/db'\n00140| \n00141| // getPost will be used twice, but execute only once\n00142| export const getPost = cache(async (slug: string) => {\n00143| const res = await db.query.posts.findFirst({ where: eq(posts.slug, slug) })\n00144| return res\n00145| })\n00146| ```\n00147| \n00148| ```js filename=\"app/lib/data.js\" highlight={5} switcher\n00149| import { cache } from 'react'\n00150| import { db } from '@/app/lib/db'\n00151| \n00152| // getPost will be used twice, but execute only once\n00153| export const getPost = cache(async (slug) => {\n00154| const res = await db.query.posts.findFirst({ where: eq(posts.slug, slug) })\n00155| return res\n00156| })\n00157| ```\n00158| \n00159| ```tsx filename=\"app/blog/[slug]/page.tsx\" switcher\n00160| import { getPost } from '@/app/lib/data'\n00161| \n00162| export async function generateMetadata({\n00163| params,\n00164| }: {\n00165| params: Promise<{ slug: string }>\n00166| }) {\n00167| const { slug } = await params\n00168| const post = await getPost(slug)\n00169| return {\n00170| title: post.title,\n00171| description: post.description,\n00172| }\n00173| }\n00174| \n00175| export default async function Page({\n00176| params,\n00177| }: {\n00178| params: Promise<{ slug: string }>\n00179| }) {\n00180| const { slug } = await params\n00181| const post = await getPost(slug)\n00182| return
\n00202| }\n00203| ```\n00204| \n00205| ## File-based metadata\n00206| \n00207| The following special files are available for metadata:\n00208| \n00209| - [favicon.ico, apple-icon.jpg, and icon.jpg](/docs/app/api-reference/file-conventions/metadata/app-icons)\n00210| - [opengraph-image.jpg and twitter-image.jpg](/docs/app/api-reference/file-conventions/metadata/opengraph-image)\n00211| - [robots.txt](/docs/app/api-reference/file-conventions/metadata/robots)\n00212| - [sitemap.xml](/docs/app/api-reference/file-conventions/metadata/sitemap)\n00213| \n00214| You can use these for static metadata, or you can programmatically generate these files with code.\n00215| \n00216| ## Favicons\n00217| \n00218| Favicons are small icons that represent your site in bookmarks and search results. To add a favicon to your application, create a `favicon.ico` and add to the root of the app folder.\n00219| \n00220| \n00227| \n00228| > You can also programmatically generate favicons using code. See the [favicon docs](/docs/app/api-reference/file-conventions/metadata/app-icons) for more information.\n00229| \n00230| ## Static Open Graph images\n00231| \n00232| Open Graph (OG) images are images that represent your site in social media. To add a static OG image to your application, create a `opengraph-image.jpg` file in the root of the app folder.\n00233| \n00234| \n00241| \n00242| You can also add OG images for specific routes by creating a `opengraph-image.jpg` deeper down the folder structure. For example, to create an OG image specific to the `/blog` route, add a `opengraph-image.jpg` file inside the `blog` folder.\n00243| \n00244| \n00251| \n00252| The more specific image will take precedence over any OG images above it in the folder structure.\n00253| \n00254| > Other image formats such as `jpeg`, `png`, and `gif` are also supported. See the [Open Graph Image docs](/docs/app/api-reference/file-conventions/metadata/opengraph-image) for more information.\n00255| \n00256| ## Generated Open Graph images\n00257| \n00258| The [`ImageResponse` constructor](/docs/app/api-reference/functions/image-response) allows you to generate dynamic images using JSX and CSS. This is useful for OG images that depend on data.\n00259| \n00260| For example, to generate a unique OG image for each blog post, add a `opengraph-image.tsx` file inside the `blog` folder, and import the `ImageResponse` constructor from `next/og`:\n00261| \n00262| ```tsx filename=\"app/blog/[slug]/opengraph-image.tsx\" switcher\n00263| import { ImageResponse } from 'next/og'\n00264| import { getPost } from '@/app/lib/data'\n00265| \n00266| // Image metadata\n00267| export const size = {\n00268| width: 1200,\n00269| height: 630,\n00270| }\n00271| \n00272| export const contentType = 'image/png'\n00273| \n00274| // Image generation\n00275| export default async function Image({\n00276| params,\n00277| }: {\n00278| params: Promise<{ slug: string }>\n00279| }) {\n00280| const { slug } = await params\n00281| const post = await getPost(slug)\n00282| \n00283| return new ImageResponse(\n00284| (\n00285| // ImageResponse JSX element\n00286|
\n00337| )\n00338| )\n00339| }\n00340| ```\n00341| \n00342| `ImageResponse` supports common CSS properties including flexbox and absolute positioning, custom fonts, text wrapping, centering, and nested images. [See the full list of supported CSS properties](/docs/app/api-reference/functions/image-response).\n00343| \n00344| > **Good to know**:\n00345| >\n00346| > - Examples are available in the [Vercel OG Playground](https://og-playground.vercel.app/).\n00347| > - `ImageResponse` uses [`@vercel/og`](https://vercel.com/docs/og-image-generation), [`satori`](https://github.com/vercel/satori), and `resvg` to convert HTML and CSS into PNG.\n00348| > - Only flexbox and a subset of CSS properties are supported. Advanced layouts (e.g. `display: grid`) will not work.\n00349| \n\n(End of file - total 349 lines)\n","title":"node_modules/next/dist/docs/01-app/01-getting-started/14-metadata-and-og-images.md","metadata":{"preview":"---\ntitle: Metadata and OG images\ndescription: Learn how to add metadata to your pages and create dynamic OG images.\nrelated:\n title: API Reference\n description: Learn more about the Metadata APIs mentioned in this page.\n links:\n - app/api-reference/functions/generate-metadata\n - app/api-reference/functions/generate-viewport\n - app/api-reference/functions/image-response\n - app/api-reference/file-conventions/metadata\n - app/api-reference/file-conventions/metadata/app-icons\n - app/api-reference/file-conventions/metadata/opengraph-image\n - app/api-reference/file-conventions/metadata/robots\n - app/api-reference/file-conventions/metadata/sitemap\n - app/api-reference/config/next-config-js/htmlLimitedBots\n---\n\nThe Metadata APIs can be used to define your application metadata for improved SEO and web shareability and include:\n"},"time":{"start":1781392540292,"end":1781392540298}}}}
+{"type":"tool_use","timestamp":1781392540322,"sessionID":"ses_13cbb6bbfffe8dTGye7IwIMgqy","part":{"id":"prt_ec3450288001BRWdBEwH00E4c1","sessionID":"ses_13cbb6bbfffe8dTGye7IwIMgqy","messageID":"msg_ec344e6be001aL8VqS6oWys5kr","type":"tool","callID":"read_28","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/node_modules/next/dist/docs/01-app/02-guides/migrating/app-router-migration.md"},"output":"\n00001| ---\n00002| title: How to migrate from Pages to the App Router\n00003| nav_title: App Router\n00004| description: Learn how to upgrade your existing Next.js application from the Pages Router to the App Router.\n00005| ---\n00006| \n00007| This guide will help you:\n00008| \n00009| - [Update your Next.js application from version 12 to version 13](#nextjs-version)\n00010| - [Upgrade features that work in both the `pages` and the `app` directories](#upgrading-new-features)\n00011| - [Incrementally migrate your existing application from `pages` to `app`](#migrating-from-pages-to-app)\n00012| \n00013| ## Upgrading\n00014| \n00015| ### Node.js Version\n00016| \n00017| The minimum Node.js version is now **v18.17**. See the [Node.js documentation](https://nodejs.org/docs/latest-v18.x/api/) for more information.\n00018| \n00019| ### Next.js Version\n00020| \n00021| To update to Next.js version 13, run the following command using your preferred package manager:\n00022| \n00023| ```bash package=\"pnpm\"\n00024| pnpm add next@latest react@latest react-dom@latest\n00025| ```\n00026| \n00027| ```bash package=\"npm\"\n00028| npm install next@latest react@latest react-dom@latest\n00029| ```\n00030| \n00031| ```bash package=\"yarn\"\n00032| yarn add next@latest react@latest react-dom@latest\n00033| ```\n00034| \n00035| ```bash package=\"bun\"\n00036| bun add next@latest react@latest react-dom@latest\n00037| ```\n00038| \n00039| ### ESLint Version\n00040| \n00041| If you're using ESLint, you need to upgrade your ESLint version:\n00042| \n00043| ```bash package=\"pnpm\"\n00044| pnpm add -D eslint-config-next@latest\n00045| ```\n00046| \n00047| ```bash package=\"npm\"\n00048| npm install -D eslint-config-next@latest\n00049| ```\n00050| \n00051| ```bash package=\"yarn\"\n00052| yarn add -D eslint-config-next@latest\n00053| ```\n00054| \n00055| ```bash package=\"bun\"\n00056| bun add -D eslint-config-next@latest\n00057| ```\n00058| \n00059| > **Good to know**: You may need to restart the ESLint server in VS Code for the ESLint changes to take effect. Open the Command Palette (`cmd+shift+p` on Mac; `ctrl+shift+p` on Windows) and search for `ESLint: Restart ESLint Server`.\n00060| \n00061| ## Next Steps\n00062| \n00063| After you've updated, see the following sections for next steps:\n00064| \n00065| - [Upgrade new features](#upgrading-new-features): A guide to help you upgrade to new features such as the improved Image and Link Components.\n00066| - [Migrate from the `pages` to `app` directory](#migrating-from-pages-to-app): A step-by-step guide to help you incrementally migrate from the `pages` to the `app` directory.\n00067| \n00068| ## Upgrading New Features\n00069| \n00070| Next.js 13 introduced the new [App Router](/docs/app) with new features and conventions. The new Router is available in the `app` directory and co-exists with the `pages` directory.\n00071| \n00072| Upgrading to Next.js 13 does **not** require using the App Router. You can continue using `pages` with new features that work in both directories, such as the updated [Image component](#image-component), [Link component](#link-component), [Script component](#script-component), and [Font optimization](#font-optimization).\n00073| \n00074| ### `` Component\n00075| \n00076| Next.js 12 introduced new improvements to the Image Component with a temporary import: `next/future/image`. These improvements included less client-side JavaScript, easier ways to extend and style images, better accessibility, and native browser lazy loading.\n00077| \n00078| In version 13, this new behavior is now the default for `next/image`.\n00079| \n00080| There are two codemods to help you migrate to the new Image Component:\n00081| \n00082| - [**`next-image-to-legacy-image` codemod**](/docs/app/guides/upgrading/codemods#next-image-to-legacy-image): Safely and automatically renames `next/image` imports to `next/legacy/image`. Existing components will maintain the same behavior.\n00083| - [**`next-image-experimental` codemod**](/docs/app/guides/upgrading/codemods#next-image-experimental): Dangerously adds inline styles and removes unused props. This will change the behavior of existing components to match the new defaults. To use this codemod, you need to run the `next-image-to-legacy-image` codemod first.\n00084| \n00085| ### `` Component\n00086| \n00087| The [`` Component](/docs/app/api-reference/components/link) no longer requires manually adding an `` tag as a child. This behavior was added as an experimental option in [version 12.2](https://nextjs.org/blog/next-12-2) and is now the default. In Next.js 13, `` always renders `` and allows you to forward props to the underlying tag.\n00088| \n00089| For example:\n00090| \n00091| ```jsx\n00092| import Link from 'next/link'\n00093| \n00094| // Next.js 12: `` has to be nested otherwise it's excluded\n00095| \n00096| About\n00097| \n00098| \n00099| // Next.js 13: `` always renders `` under the hood\n00100| \n00101| About\n00102| \n00103| ```\n00104| \n00105| To upgrade your links to Next.js 13, you can use the [`new-link` codemod](/docs/app/guides/upgrading/codemods#new-link).\n00106| \n00107| ### `Functions: after | Next.jsSkip to content
after allows you to schedule work to be executed after a response (or prerender) is finished. This is useful for tasks and other side effects that should not block the response, such as logging and analytics.
The function accepts a callback that will be executed after the response (or prerender) is finished:
\\n
app/layout.tsx
TypeScript
import { after } from 'next/server'\\n// Custom logging function\\nimport { log } from '@/app/utils'\\n\\nexport default function Layout({ children }: { children: React.ReactNode }) {\\n after(() => {\\n // Execute after the layout is rendered and sent to the user\\n log()\\n })\\n return <>{children}</>\\n}
\\n\\n
\\n
Good to know:after is not a Request-time API and calling it does not cause a route to become dynamic. If it's used within a static page, the callback will execute at build time, or whenever a page is revalidated.
\\n
\\n
Reference
\\n
Parameters
\\n
\\n
A callback function which will be executed after the response (or prerender) is finished.
\\n
\\n
Duration
\\n
after will run for the platform's default or configured max duration of your route. If your platform supports it, you can configure the timeout limit using the maxDuration route segment config.
\\n
Good to know
\\n
\\n
after will be executed even if the response didn't complete successfully. Including when an error is thrown or when notFound or redirect is called.
\\n
You can use React cache to deduplicate functions called inside after.
\\n
after can be nested inside other after calls, for example, you can create utility functions that wrap after calls to add additional functionality.
\\n
\\n
Examples
\\n
With request APIs
\\n
Whether you can use request APIs like cookies and headers inside after depends on where after is called from.
\\n
In Route Handlers and Server Functions
\\n
You can call cookies and headers directly inside the after callback when used in Route Handlers and Server Functions. This is useful for logging activity after a mutation or API request. For example:
\\n
app/api/route.ts
TypeScript
import { after } from 'next/server'\\nimport { cookies, headers } from 'next/headers'\\nimport { logUserAction } from '@/app/utils'\\n\\nexport async function POST(request: Request) {\\n // Perform mutation\\n // ...\\n\\n // Log user activity for analytics\\n after(async () => {\\n const userAgent = (await headers()).get('user-agent') || 'unknown'\\n const sessionCookie =\\n (await cookies()).get('session-id')?.value || 'anonymous'\\n\\n logUserAction({ sessionCookie, userAgent })\\n })\\n\\n return new Response(JSON.stringify({ status: 'success' }), {\\n status: 200,\\n headers: { 'Content-Type': 'application/json' },\\n })\\n}
\\n\\n
In Server Components (pages and layouts)
\\n
Server Components (including pages, layouts, and generateMetadata) cannot use cookies, headers, or other Request-time APIs inside after. This is because Next.js needs to know which part of the component tree accesses request data to support Partial Prerendering and Cache Components, but after runs after React's rendering lifecycle.
\\n
If you need request data inside an after callback in a Server Component, read it beforehand and pass the values in:
\\n
app/page.tsx
TypeScript
import { after } from 'next/server'\\nimport { cookies, headers } from 'next/headers'\\nimport { logUserAction } from '@/app/utils'\\n\\nexport default async function Page() {\\n // Read request data before `after` — this is allowed\\n // These calls will be read during the component's rendering lifecycle\\n const userAgent = (await headers()).get('user-agent') || 'unknown'\\n const sessionCookie =\\n (await cookies()).get('session-id')?.value || 'anonymous'\\n\\n after(() => {\\n // Use the values read above\\n logUserAction({ sessionCookie, userAgent })\\n })\\n\\n return <h1>My Page</h1>\\n}
\\n\\n
Calling cookies() or headers() inside the after callback in a Server Component will throw a runtime error.
\\n
With Cache Components
\\n
When using Cache Components, components that access request data like cookies or headers must be wrapped in <Suspense> so the rest of the page can be prerendered into a static shell.
\\n
You can combine this pattern with after by reading request data in a dynamic component and passing it into after:
\\n
app/page.tsx
TypeScript
import { Suspense } from 'react'\\nimport { after } from 'next/server'\\nimport { cookies } from 'next/headers'\\nimport { logUserAction } from '@/app/utils'\\n\\nexport default function Page() {\\n return (\\n <>\\n <h1>Part of the static shell</h1>\\n <Suspense fallback={<p>Loading...</p>}>\\n <DynamicContent />\\n </Suspense>\\n </>\\n )\\n}\\n\\nasync function DynamicContent() {\\n const sessionCookie =\\n (await cookies()).get('session-id')?.value || 'anonymous'\\n\\n // Schedule work after the response is sent\\n after(() => {\\n logUserAction({ sessionCookie })\\n })\\n\\n return <p>Your session: {sessionCookie}</p>\\n}
\\n\\n
In this example, <h1> and the <Suspense> fallback are included in the static shell. DynamicContent reads the cookie during rendering and passes it into after via closure. Since cookies() is called outside the after callback (during the component's render), this works correctly.
\\nReference: supporting after for serverless platforms
Using after in a serverless context requires waiting for asynchronous tasks to finish after the response has been sent. In Next.js and Vercel, this is achieved using a primitive called waitUntil(promise), which extends the lifetime of a serverless invocation until all promises passed to waitUntil have settled.
If you want your users to be able to run after, you will have to provide your implementation of waitUntil that behaves in an analogous way.
When after is called, Next.js will access waitUntil like this:
\",\"title\":\"https://nextjs.org/docs/app/api-reference/functions/after (text/html; charset=utf-8)\",\"metadata\":{},\"time\":{\"start\":1781390564697,\"end\":1781390564802}}}}\n{\"type\":\"step_finish\",\"timestamp\":1781390564842,\"sessionID\":\"ses_13cdaecaeffePMVRAqAFJ3Ea2y\",\"part\":{\"id\":\"prt_ec326ddca001u54JxNWeknPUhc\",\"sessionID\":\"ses_13cdaecaeffePMVRAqAFJ3Ea2y\",\"messageID\":\"msg_ec3269e00001tBMUt4VcJ7WttM\",\"type\":\"step-finish\",\"reason\":\"tool-calls\",\"snapshot\":\"56c903bdd03b310f65cb061c1cc1689c258eb58e\",\"cost\":0.00694735,\"tokens\":{\"input\":449,\"output\":811,\"reasoning\":0,\"cache\":{\"read\":20480,\"write\":0}}}}\n{\"type\":\"error\",\"timestamp\":1781390566044,\"sessionID\":\"ses_13cdaecaeffePMVRAqAFJ3Ea2y\",\"error\":{\"name\":\"APIError\",\"data\":{\"message\":\"GatewayInternalServerError: Invalid request: Your request exceeded model token limit: 262144 (requested: 285568)\",\"statusCode\":400,\"isRetryable\":false,\"responseHeaders\":{\"cache-control\":\"public, max-age=0, must-revalidate\",\"content-type\":\"application/json\",\"date\":\"Sat, 13 Jun 2026 22:42:46 GMT\",\"server\":\"Vercel\",\"strict-transport-security\":\"max-age=63072000; includeSubDomains; preload\",\"transfer-encoding\":\"chunked\",\"vary\":\"rsc, next-router-state-tree, next-router-prefetch, next-router-segment-prefetch\",\"x-matched-path\":\"/v1/ai/language-model\",\"x-vercel-cache\":\"MISS\",\"x-vercel-id\":\"iad1::iad1::p5ct7-1781390564914-da7d28f90d39\"},\"responseBody\":\"{\\\"error\\\":{\\\"message\\\":\\\"Invalid request: Your request exceeded model token limit: 262144 (requested: 285568)\\\",\\\"type\\\":\\\"AI_APICallError\\\",\\\"param\\\":{\\\"error\\\":\\\"Invalid request: Your request exceeded model token limit: 262144 (requested: 285568)\\\",\\\"statusCode\\\":400,\\\"name\\\":\\\"AI_APICallError\\\",\\\"message\\\":\\\"Invalid request: Your request exceeded model token limit: 262144 (requested: 285568)\\\",\\\"isRetryable\\\":false,\\\"type\\\":\\\"AI_APICallError\\\"}},\\\"providerMetadata\\\":{\\\"gateway\\\":{\\\"routing\\\":{\\\"originalModelId\\\":\\\"moonshotai/kimi-k2.7-code\\\",\\\"resolvedProvider\\\":\\\"moonshotai\\\",\\\"fallbacksAvailable\\\":[],\\\"canonicalSlug\\\":\\\"moonshotai/kimi-k2.7-code\\\",\\\"modelAttemptCount\\\":1,\\\"modelAttempts\\\":[{\\\"canonicalSlug\\\":\\\"moonshotai/kimi-k2.7-code\\\",\\\"success\\\":false,\\\"providerAttemptCount\\\":1,\\\"providerAttempts\\\":[{\\\"provider\\\":\\\"moonshotai\\\",\\\"credentialType\\\":\\\"system\\\",\\\"success\\\":false,\\\"error\\\":\\\"Invalid request: Your request exceeded model token limit: 262144 (requested: 285568)\\\",\\\"startTime\\\":1781390564976,\\\"endTime\\\":1781390566020,\\\"statusCode\\\":400}]}],\\\"totalProviderAttemptCount\\\":1},\\\"generationId\\\":\\\"gen_01KV1JDQJMHGR953TA5AJ5BX8A\\\"}}}\",\"metadata\":{\"url\":\"https://ai-gateway.vercel.sh/v1/ai/language-model\",\"requestBody\":\"{\\\"maxOutputTokens\\\":32000,\\\"temperature\\\":1,\\\"tools\\\":[{\\\"type\\\":\\\"function\\\",\\\"name\\\":\\\"bash\\\",\\\"description\\\":\\\"Executes a given bash command in a persistent shell session with optional timeout, ensuring proper handling and security measures.\\\\n\\\\nAll commands run in /workspace by default. Use the `workdir` parameter if you need to run a command in a different directory. AVOID using `cd && ` patterns - use `workdir` instead.\\\\n\\\\nIMPORTANT: This tool is for terminal operations like git, npm, docker, etc. DO NOT use it for file operations (reading, writing, editing, searching, finding files) - use the specialized tools for this instead.\\\\n\\\\nBefore executing the command, please follow these steps:\\\\n\\\\n1. Directory Verification:\\\\n - If the command will create new directories or files, first use `ls` to verify the parent directory exists and is the correct location\\\\n - For example, before running \\\\\\\"mkdir foo/bar\\\\\\\", first use `ls foo` to check that \\\\\\\"foo\\\\\\\" exists and is the intended parent directory\\\\n\\\\n2. Command Execution:\\\\n - Always quote file paths that contain spaces with double quotes (e.g., rm \\\\\\\"path with spaces/file.txt\\\\\\\")\\\\n - Examples of proper quoting:\\\\n - mkdir \\\\\\\"/Users/name/My Documents\\\\\\\" (correct)\\\\n - mkdir /Users/name/My Documents (incorrect - will fail)\\\\n - python \\\\\\\"/path/with spaces/script.py\\\\\\\" (correct)\\\\n - python /path/with spaces/script.py (incorrect - will fail)\\\\n - After ensuring proper quoting, execute the command.\\\\n - Capture the output of the command.\\\\n\\\\nUsage notes:\\\\n - The command argument is required.\\\\n - You can specify an optional timeout in milliseconds (up to 600000ms / 10 minutes). If not specified, commands will time out after 120000ms (2 minutes).\\\\n - It is very helpful if you write a clear, concise description of what this command does in 5-10 words.\\\\n - If the output exceeds 30000 characters, output will be truncated before being returned to you.\\\\n - You can use the `run_in_background` parameter to run the command in the background, which allows you to continue working while the command runs. You can monitor the output using the Bash tool as it becomes available. You do not need to use '&' at the end of the command when using this parameter.\\\\n\\\\n - Avoid using Bash with the `find`, `grep`, `cat`, `head`, `tail`, `sed`, `awk`, or `echo` commands, unless explicitly instructed or when these commands are truly necessary for the task. Instead, always prefer using the dedicated tools for these commands:\\\\n - File search: Use Glob (NOT find or ls)\\\\n - Content search: Use Grep (NOT grep or rg)\\\\n - Read files: Use Read (NOT cat/head/tail)\\\\n - Edit files: Use Edit (NOT sed/awk)\\\\n - Write files: Use Write (NOT echo >/cat < && `. Use the `workdir` parameter to change directories instead.\\\\n \\\\n Use workdir=\\\\\\\"/foo/bar\\\\\\\" with command: pytest tests\\\\n \\\\n \\\\n cd /foo/bar && pytest tests\\\\n \\\\n\\\\n# Committing changes with git\\\\n\\\\nOnly create commits when requested by the user. If unclear, ask first. When the user asks you to create a new git commit, follow these steps carefully:\\\\n\\\\nGit Safety Protocol:\\\\n- NEVER update the git config\\\\n- NEVER run destructive/irreversible git commands (like push --force, hard reset, etc) unless the user explicitly requests them\\\\n- NEVER skip hooks (--no-verify, --no-gpg-sign, etc) unless the user explicitly requests it\\\\n- NEVER run force push to main/master, warn the user if they request it\\\\n- Avoid git commit --amend. ONLY use --amend when ALL conditions are met:\\\\n (1) User explicitly requested amend, OR commit SUCCEEDED but pre-commit hook auto-modified files that need including\\\\n (2) HEAD commit was created by you in this conversation (verify: git log -1 --format='%an %ae')\\\\n (3) Commit has NOT been pushed to remote (verify: git status shows \\\\\\\"Your branch is ahead\\\\\\\")\\\\n- CRITICAL: If commit FAILED or was REJECTED by hook, NEVER amend - fix the issue and create a NEW commit\\\\n- CRITICAL: If you already pushed to remote, NEVER amend unless user explicitly requests it (requires force push)\\\\n- NEVER commit changes unless the user explicitly asks you to. It is VERY IMPORTANT to only commit when explicitly asked, otherwise the user will feel that you are being too proactive.\\\\n\\\\n1. You can call multiple tools in a single response. When multiple independent pieces of information are requested and all commands are likely to succeed, run multiple tool calls in parallel for optimal performance. run the following bash commands in parallel, each using the Bash tool:\\\\n - Run a git status command to see all untracked files.\\\\n - Run a git diff command to see both staged and unstaged changes that will be committed.\\\\n - Run a git log command to see recent commit messages, so that you can follow this repository's commit message style.\\\\n2. Analyze all staged changes (both previously staged and newly added) and draft a commit message:\\\\n - Summarize the nature of the changes (eg. new feature, enhancement to an existing feature, bug fix, refactoring, test, docs, etc.). Ensure the message accurately reflects the changes and their purpose (i.e. \\\\\\\"add\\\\\\\" means a wholly new feature, \\\\\\\"update\\\\\\\" means an enhancement to an existing feature, \\\\\\\"fix\\\\\\\" means a bug fix, etc.).\\\\n - Do not commit files that likely contain secrets (.env, credentials.json, etc.). Warn the user if they specifically request to commit those files\\\\n - Draft a concise (1-2 sentences) commit message that focuses on the \\\\\\\"why\\\\\\\" rather than the \\\\\\\"what\\\\\\\"\\\\n - Ensure it accurately reflects the changes and their purpose\\\\n3. You can call multiple tools in a single response. When multiple independent pieces of information are requested and all commands are likely to succeed, run multiple tool calls in parallel for optimal performance. run the following commands:\\\\n - Add relevant untracked files to the staging area.\\\\n - Create the commit with a message\\\\n - Run git status after the commit completes to verify success.\\\\n Note: git status depends on the commit completing, so run it sequentially after the commit.\\\\n4. If the commit fails due to pre-commit hook, fix the issue and create a NEW commit (see amend rules above)\\\\n\\\\nImportant notes:\\\\n- NEVER run additional commands to read or explore code, besides git bash commands\\\\n- NEVER use the TodoWrite or Task tools\\\\n- DO NOT push to the remote repository unless the user explicitly asks you to do so\\\\n- IMPORTANT: Never use git commands with the -i flag (like git rebase -i or git add -i) since they require interactive input which is not supported.\\\\n- If there are no changes to commit (i.e., no untracked files and no modifications), do not create an empty commit\\\\n\\\\n# Creating pull requests\\\\nUse the gh command via the Bash tool for ALL GitHub-related tasks including working with issues, pull requests, checks, and releases. If given a Github URL use the gh command to get the information needed.\\\\n\\\\nIMPORTANT: When the user asks you to create a pull request, follo\"}}}}",
+ "duration": 157.239,
+ "model": "vercel/moonshotai/kimi-k2.7-code",
+ "transcriptPath": "./transcript.json",
+ "transcriptRawPath": "./transcript-raw.jsonl",
+ "o11y": {
+ "totalTurns": 0,
+ "toolCalls": {
+ "file_read": 9,
+ "file_write": 0,
+ "file_edit": 0,
+ "shell": 5,
+ "web_fetch": 0,
+ "web_search": 0,
+ "glob": 3,
+ "grep": 1,
+ "list_dir": 0,
+ "agent_task": 0,
+ "unknown": 1
+ },
+ "totalToolCalls": 19,
+ "webFetches": [],
+ "filesRead": [
+ "/workspace/package.json",
+ "/workspace/next.config.ts",
+ "/workspace/app/layout.tsx",
+ "/workspace/app/page.tsx",
+ "/workspace/lib/db.js",
+ "/workspace/node_modules/next/dist/server/after/after.d.ts",
+ "/workspace/node_modules/next/dist/server/web/spec-extension/unstable-cache.d.ts",
+ "/workspace/node_modules/next/dist/server/web/spec-extension/revalidate.d.ts",
+ "/workspace/node_modules/next/cache.d.ts"
+ ],
+ "filesModified": [],
+ "shellCommands": [
+ {
+ "command": "ls -la /workspace",
+ "success": true
+ },
+ {
+ "command": "ls -la /workspace/app /workspace/lib",
+ "success": true
+ },
+ {
+ "command": "node -e \"const { revalidateTag } = require('next/cache'); console.log(revalidateTag.length)\"",
+ "success": true
+ },
+ {
+ "command": "node -e \"const { updateTag } = require('next/cache'); console.log(updateTag.length)\"",
+ "success": true
+ },
+ {
+ "command": "node -e \"const { revalidateTag } = require('next/cache'); try { revalidateTag('products'); console.log('ok'); } catch(e) { console.error(e.message); }\"",
+ "success": true
+ }
+ ],
+ "errors": [],
+ "thinkingBlocks": 0
+ }
+}
\ No newline at end of file
diff --git a/results/kimi-k2.7-code/2026-06-13T22-40-06.944Z/agent-029-use-cache-directive/run-3/transcript-raw.jsonl b/results/kimi-k2.7-code/2026-06-13T22-40-06.944Z/agent-029-use-cache-directive/run-3/transcript-raw.jsonl
new file mode 100644
index 000000000..d379910d8
--- /dev/null
+++ b/results/kimi-k2.7-code/2026-06-13T22-40-06.944Z/agent-029-use-cache-directive/run-3/transcript-raw.jsonl
@@ -0,0 +1,40 @@
+{"type":"step_start","timestamp":1781390449004,"sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","part":{"id":"prt_ec3251965001c1I0OhKX0Xa03b","sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","messageID":"msg_ec32513a8001lkYqH3kUsaOaKM","type":"step-start","snapshot":"56c903bdd03b310f65cb061c1cc1689c258eb58e"}}
+{"type":"tool_use","timestamp":1781390452132,"sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","part":{"id":"prt_ec32523f0001AASMbssQvWjb3O","sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","messageID":"msg_ec32513a8001lkYqH3kUsaOaKM","type":"tool","callID":"bash_0","tool":"bash","state":{"status":"completed","input":{"command":"ls -la /workspace","description":"List workspace contents"},"output":"total 184\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 187 Jun 13 22:40 .\ndrwxr-xr-x 20 root root 286 Jun 13 22:40 ..\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 154 Jun 13 22:40 .git\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 14 Jun 13 22:40 .gitignore\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 40 Jun 13 22:40 app\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 19 Jun 13 22:40 lib\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 101 Jun 13 22:40 next.config.ts\ndrwxr-xr-x 179 vercel-sandbox vercel-sandbox 8192 Jun 13 22:40 node_modules\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 1549 Jun 13 22:40 opencode.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 154377 Jun 13 22:40 package-lock.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 603 Jun 13 22:40 package.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 599 Jun 13 22:40 tsconfig.json\n","title":"List workspace contents","metadata":{"output":"total 184\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 187 Jun 13 22:40 .\ndrwxr-xr-x 20 root root 286 Jun 13 22:40 ..\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 154 Jun 13 22:40 .git\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 14 Jun 13 22:40 .gitignore\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 40 Jun 13 22:40 app\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 19 Jun 13 22:40 lib\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 101 Jun 13 22:40 next.config.ts\ndrwxr-xr-x 179 vercel-sandbox vercel-sandbox 8192 Jun 13 22:40 node_modules\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 1549 Jun 13 22:40 opencode.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 154377 Jun 13 22:40 package-lock.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 603 Jun 13 22:40 package.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 599 Jun 13 22:40 tsconfig.json\n","exit":0,"description":"List workspace contents"},"time":{"start":1781390452076,"end":1781390452124}}}}
+{"type":"step_finish","timestamp":1781390452142,"sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","part":{"id":"prt_ec32525a2001H7wC29Z51b2H3O","sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","messageID":"msg_ec32513a8001lkYqH3kUsaOaKM","type":"step-finish","reason":"tool-calls","snapshot":"56c903bdd03b310f65cb061c1cc1689c258eb58e","cost":0.00248751,"tokens":{"input":321,"output":177,"reasoning":0,"cache":{"read":9216,"write":0}}}}
+{"type":"step_start","timestamp":1781390453619,"sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","part":{"id":"prt_ec3252b6f001bNfiJKQyIMC3lW","sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","messageID":"msg_ec32525bf001troEFpkgE7X6jN","type":"step-start","snapshot":"56c903bdd03b310f65cb061c1cc1689c258eb58e"}}
+{"type":"tool_use","timestamp":1781390454204,"sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","part":{"id":"prt_ec3252b72001BD5zFhBn3p8v6A","sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","messageID":"msg_ec32525bf001troEFpkgE7X6jN","type":"tool","callID":"bash_1","tool":"bash","state":{"status":"completed","input":{"command":"ls -la /workspace/app /workspace/lib","description":"List app and lib directories"},"output":"/workspace/app:\ntotal 8\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 40 Jun 13 22:40 .\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 187 Jun 13 22:40 ..\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 329 Jun 13 22:40 layout.tsx\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 91 Jun 13 22:40 page.tsx\n\n/workspace/lib:\ntotal 4\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 19 Jun 13 22:40 .\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 187 Jun 13 22:40 ..\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 364 Jun 13 22:40 db.js\n","title":"List app and lib directories","metadata":{"output":"/workspace/app:\ntotal 8\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 40 Jun 13 22:40 .\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 187 Jun 13 22:40 ..\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 329 Jun 13 22:40 layout.tsx\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 91 Jun 13 22:40 page.tsx\n\n/workspace/lib:\ntotal 4\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 19 Jun 13 22:40 .\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 187 Jun 13 22:40 ..\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 364 Jun 13 22:40 db.js\n","exit":0,"description":"List app and lib directories"},"time":{"start":1781390454187,"end":1781390454203}}}}
+{"type":"tool_use","timestamp":1781390454432,"sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","part":{"id":"prt_ec3252dba001Za48kalIcg8bgv","sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","messageID":"msg_ec32525bf001troEFpkgE7X6jN","type":"tool","callID":"read_2","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/package.json"},"output":"\n00001| {\n00002| \"private\": true,\n00003| \"type\": \"module\",\n00004| \"scripts\": {\n00005| \"dev\": \"next dev\",\n00006| \"build\": \"next build\",\n00007| \"start\": \"next start\"\n00008| },\n00009| \"dependencies\": {\n00010| \"@ai-sdk/react\": \"2.0.0-beta.28\",\n00011| \"@modelcontextprotocol/sdk\": \"^1.17.0\",\n00012| \"ai\": \"5.0.59\",\n00013| \"next\": \"^16.3.0-canary.50\",\n00014| \"react\": \"19.1.0\",\n00015| \"react-dom\": \"19.1.0\",\n00016| \"zod\": \"^4.0.10\"\n00017| },\n00018| \"devDependencies\": {\n00019| \"@types/node\": \"^20\",\n00020| \"@types/react\": \"^19\",\n00021| \"@types/react-dom\": \"^19\",\n00022| \"@vitejs/plugin-react\": \"^4.4.1\",\n00023| \"typescript\": \"^5\",\n00024| \"vite-tsconfig-paths\": \"^5.1.4\",\n00025| \"vitest\": \"^3.1.3\"\n00026| }\n00027| }\n00028| \n\n(End of file - total 28 lines)\n","title":"package.json","metadata":{"preview":"{\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"next dev\",\n \"build\": \"next build\",\n \"start\": \"next start\"\n },\n \"dependencies\": {\n \"@ai-sdk/react\": \"2.0.0-beta.28\",\n \"@modelcontextprotocol/sdk\": \"^1.17.0\",\n \"ai\": \"5.0.59\",\n \"next\": \"^16.3.0-canary.50\",\n \"react\": \"19.1.0\",\n \"react-dom\": \"19.1.0\",\n \"zod\": \"^4.0.10\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^20\",\n \"@types/react\": \"^19\","},"time":{"start":1781390454425,"end":1781390454428}}}}
+{"type":"tool_use","timestamp":1781390454629,"sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","part":{"id":"prt_ec3252e9c001qQutKuKwJL2UAZ","sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","messageID":"msg_ec32525bf001troEFpkgE7X6jN","type":"tool","callID":"read_3","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/next.config.ts"},"output":"\n00001| import type { NextConfig } from 'next'\n00002| \n00003| const nextConfig: NextConfig = {}\n00004| \n00005| export default nextConfig\n00006| \n\n(End of file - total 6 lines)\n","title":"next.config.ts","metadata":{"preview":"import type { NextConfig } from 'next'\n\nconst nextConfig: NextConfig = {}\n\nexport default nextConfig\n"},"time":{"start":1781390454620,"end":1781390454622}}}}
+{"type":"step_finish","timestamp":1781390454631,"sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","part":{"id":"prt_ec3252f5f001777my8Rm4ICzRW","sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","messageID":"msg_ec32525bf001troEFpkgE7X6jN","type":"step-finish","reason":"tool-calls","snapshot":"56c903bdd03b310f65cb061c1cc1689c258eb58e","cost":0.00239977,"tokens":{"input":615,"output":75,"reasoning":0,"cache":{"read":9472,"write":0}}}}
+{"type":"step_start","timestamp":1781390456368,"sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","part":{"id":"prt_ec3253629001qxDQgRD0Or78oh","sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","messageID":"msg_ec3252f780013sOh0c5BXwHxWg","type":"step-start","snapshot":"56c903bdd03b310f65cb061c1cc1689c258eb58e"}}
+{"type":"tool_use","timestamp":1781390456684,"sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","part":{"id":"prt_ec325362d001lNzbni6VBf8PH3","sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","messageID":"msg_ec3252f780013sOh0c5BXwHxWg","type":"tool","callID":"read_4","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/app/layout.tsx"},"output":"\n00001| import type { Metadata } from 'next'\n00002| \n00003| export const metadata: Metadata = {\n00004| title: 'Create Next App',\n00005| description: 'Generated by create next app',\n00006| }\n00007| \n00008| export default function RootLayout({\n00009| children,\n00010| }: Readonly<{\n00011| children: React.ReactNode\n00012| }>) {\n00013| return (\n00014| \n00015| {children}\n00016| \n00017| )\n00018| }\n00019| \n\n(End of file - total 19 lines)\n","title":"app/layout.tsx","metadata":{"preview":"import type { Metadata } from 'next'\n\nexport const metadata: Metadata = {\n title: 'Create Next App',\n description: 'Generated by create next app',\n}\n\nexport default function RootLayout({\n children,\n}: Readonly<{\n children: React.ReactNode\n}>) {\n return (\n \n {children}\n \n )\n}\n"},"time":{"start":1781390456657,"end":1781390456667}}}}
+{"type":"tool_use","timestamp":1781390456961,"sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","part":{"id":"prt_ec325375b001V4QAGPdRLXIJ56","sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","messageID":"msg_ec3252f780013sOh0c5BXwHxWg","type":"tool","callID":"read_5","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/app/page.tsx"},"output":"\n00001| export default function Page() {\n00002| return (\n00003|
\n00004|
Home
\n00005|
\n00006| )\n00007| }\n00008| \n\n(End of file - total 8 lines)\n","title":"app/page.tsx","metadata":{"preview":"export default function Page() {\n return (\n
\n
Home
\n
\n )\n}\n"},"time":{"start":1781390456955,"end":1781390456957}}}}
+{"type":"tool_use","timestamp":1781390457150,"sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","part":{"id":"prt_ec325387d001iGud227A8wOzjl","sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","messageID":"msg_ec3252f780013sOh0c5BXwHxWg","type":"tool","callID":"read_6","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/lib/db.js"},"output":"\n00001| export async function getAllProducts() {\n00002| // Simulate database delay\n00003| await new Promise((resolve) => setTimeout(resolve, 100))\n00004| \n00005| return [\n00006| { id: 1, name: 'Laptop', price: 999 },\n00007| { id: 2, name: 'Phone', price: 699 },\n00008| { id: 3, name: 'Tablet', price: 499 },\n00009| { id: 4, name: 'Headphones', price: 199 },\n00010| { id: 5, name: 'Watch', price: 299 },\n00011| ]\n00012| }\n00013| \n\n(End of file - total 13 lines)\n","title":"lib/db.js","metadata":{"preview":"export async function getAllProducts() {\n // Simulate database delay\n await new Promise((resolve) => setTimeout(resolve, 100))\n\n return [\n { id: 1, name: 'Laptop', price: 999 },\n { id: 2, name: 'Phone', price: 699 },\n { id: 3, name: 'Tablet', price: 499 },\n { id: 4, name: 'Headphones', price: 199 },\n { id: 5, name: 'Watch', price: 299 },\n ]\n}\n"},"time":{"start":1781390457132,"end":1781390457140}}}}
+{"type":"step_finish","timestamp":1781390457167,"sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","part":{"id":"prt_ec3253936001DRaV1nEU93v15f","sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","messageID":"msg_ec3252f780013sOh0c5BXwHxWg","type":"step-finish","reason":"tool-calls","snapshot":"56c903bdd03b310f65cb061c1cc1689c258eb58e","cost":0.00300077,"tokens":{"input":1315,"output":59,"reasoning":0,"cache":{"read":9472,"write":0}}}}
+{"type":"step_start","timestamp":1781390458603,"sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","part":{"id":"prt_ec3253ee4001KMXHFwHla3ro6B","sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","messageID":"msg_ec32539800018qxs3RF6MiIm9q","type":"step-start","snapshot":"56c903bdd03b310f65cb061c1cc1689c258eb58e"}}
+{"type":"tool_use","timestamp":1781390469338,"sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","part":{"id":"prt_ec3256644001KL95MbLtf2mVsp","sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","messageID":"msg_ec32539800018qxs3RF6MiIm9q","type":"tool","callID":"grep_7","tool":"grep","state":{"status":"completed","input":{"pattern":"after|unstable_after|revalidateTag|unstable_cache|cache\\(","path":"/workspace/node_modules/next","include":"*.d.ts"},"output":"Found 100 matches\n/workspace/node_modules/next/dist/server/app-render/work-unit-async-storage.external.d.ts:\n Line 19: export type WorkUnitPhase = 'action' | 'render' | 'after';\n Line 141: * The render signal is aborted after React's `prerender` function is aborted\n Line 145: * 2. When the final prerender is aborted immediately after the prerender was\n Line 157: * are no longer in the prerender phase of rendering. Typically this is after\n Line 247: * `unstable_cache`, which doesn't carry root params. Currently, `\"use cache\"`\n Line 248: * inside `unstable_cache` is allowed, so this case must be handled. The error\n Line 282: * Always `undefined` for `unstable_cache` — root params are not available in\n Line 283: * this context. If a `\"use cache\"` function nested inside `unstable_cache`\n Line 290: * unstable_cache context. A cache store shadows an outer request store (if\n\n/workspace/node_modules/next/dist/server/app-render/work-async-storage.external.d.ts:\n Line 6: import type { AfterContext } from '../after/after-context';\n Line 39: readonly afterContext: AfterContext;\n Line 87: * `use-cache-probe-worker.ts`) to switch `cache()` into a one-shot fill\n Line 95: * Max wall time the probe fill may take. `cache()` enforces this with\n Line 124: * `React.cache()`.\n\n/workspace/node_modules/next/dist/server/app-render/vary-params.d.ts:\n Line 9: * during render. Call `finishTrackingVaryParams()` after rendering to resolve\n Line 65: * their final vary params. Call this after rendering is complete.\n\n/workspace/node_modules/next/dist/next-devtools/dev-overlay/hooks/use-delayed-render.d.ts:\n Line 9: * unmount of a React component until after a delay.\n\n/workspace/node_modules/next/dist/next-devtools/dev-overlay/hooks/use-debounced-value.d.ts:\n Line 15: * the returned value is updated only after `ms` has elapsed without further\n\n/workspace/node_modules/next/dist/server/use-cache/use-cache-wrapper.d.ts:\n Line 80: * Used to compute the specific cache key after generation completes.\n Line 88: * eagerly at that inner invocation's `cache()` entry. Used as `cause` for the\n Line 95: export declare function cache(kind: string, id: string, boundArgsLength: number, originalFn: (...args: unknown[]) => Promise, args: unknown[]): Promise;\n\n/workspace/node_modules/next/dist/server/use-cache/use-cache-errors.d.ts:\n Line 10: * life up to the outer cache. Constructed eagerly in `cache()` while the caller\n\n/workspace/node_modules/next/dist/server/response-cache/types.d.ts:\n Line 105: * timestamp in milliseconds to revalidate after\n Line 205: revalidateTag(tags: string | string[], durations?: {\n\n/workspace/node_modules/next/dist/server/web/spec-extension/unstable-cache.d.ts:\n Line 5: * Read more: [Next.js Docs: `unstable_cache`](https://nextjs.org/docs/app/api-reference/functions/unstable_cache)\n Line 7: export declare function unstable_cache(cb: T, keyParts?: string[], options?: {\n\n/workspace/node_modules/next/dist/build/swc/types.d.ts:\n Line 236: * end of the build, after `writeAllEntrypointsToDisk`. The Rust implementation\n\n/workspace/node_modules/next/dist/server/app-render/stale-time.d.ts:\n Line 25: * each update (after applying selectStaleTime) through the iterable. This\n\n/workspace/node_modules/next/server.d.ts:\n Line 21: export { after } from 'next/dist/server/after'\n\n/workspace/node_modules/next/dist/client/components/router-reducer/set-cache-busting-search-param.d.ts:\n Line 11: * URL after: https://example.com/path?query=1&_rsc=abc123\n Line 29: * URL after: https://example.com/path?query=1&_rsc=abc123\n\n/workspace/node_modules/next/dist/server/server-utils.d.ts:\n Line 22: afterFiles?: ReadonlyArray;\n\n/workspace/node_modules/next/dist/client/script.d.ts:\n Line 4: strategy?: 'afterInteractive' | 'lazyOnload' | 'beforeInteractive' | 'worker';\n\n/workspace/node_modules/next/dist/lib/scheduler.d.ts:\n Line 4: * Schedules a function to be called on the next tick after the other promises\n Line 25: * specific timing tricks to try to schedule work after React has rendered. This is especially\n\n/workspace/node_modules/next/dist/client/components/router-reducer/router-reducer-types.d.ts:\n Line 25: * Testing API to preserve prefetched data when refreshing after an MPA\n\n/workspace/node_modules/next/dist/client/components/segment-cache/scheduler.d.ts:\n Line 27: * does not support PPR after doing the initial route prefetch.\n Line 66: * They are reset after each iteration of the task queue.\n\n/workspace/node_modules/next/dist/server/after/run-with-after.d.ts:\n Line 1: import type { AfterContextOpts } from './after-context';\n\n/workspace/node_modules/next/dist/lib/route-pattern-normalizer.d.ts:\n Line 48: * Used by both server and client code to clean up parameters after route matching.\n\n/workspace/node_modules/next/dist/server/route-matcher-managers/route-matcher-manager.d.ts:\n Line 27: * Reloads the matchers from the providers. This should be done after all the\n\n/workspace/node_modules/next/dist/server/web/spec-extension/revalidate.d.ts:\n Line 11: * Read more: [Next.js Docs: `revalidateTag`](https://nextjs.org/docs/app/api-reference/functions/revalidateTag)\n Line 13: export declare function revalidateTag(tag: string, profile: string | CacheLifeConfig): undefined;\n\n/workspace/node_modules/next/dist/shared/lib/router/utils/resolve-rewrites.d.ts:\n Line 8: afterFiles: Rewrite[];\n\n/workspace/node_modules/next/dist/server/request-meta.d.ts:\n Line 230: * The query after resolving routes\n Line 234: * The params after resolving routes\n Line 263: * DEV only: Server action log info to be logged after the request log\n\n/workspace/node_modules/next/dist/server/render-result.d.ts:\n Line 133: * will be piped one after the other.\n Line 142: * one after the other.\n\n/workspace/node_modules/next/dist/client/lib/promise.d.ts:\n Line 1: /** Resolve a promise that times out after given amount of milliseconds. */\n\n/workspace/node_modules/next/dist/build/polyfills/polyfill-module.d.ts:\n Line 1: // imports polyfill from `@next/polyfill-module` after build.\n\n/workspace/node_modules/next/dist/esm/build/polyfills/polyfill-module.d.ts:\n Line 1: // imports polyfill from `@next/polyfill-module` after build.\n\n/workspace/node_modules/next/dist/client/components/segment-cache/optimistic-routes.d.ts:\n Line 20: * 1. discoverKnownRoute: Called after receiving a route tree from the server.\n Line 52: * Called after receiving a route tree from the server (initial load, navigation,\n\n/workspace/node_modules/next/dist/server/stream-utils/node-web-streams-helper.d.ts:\n Line 53: * Suffix to inject after the buffered data, but before the close tags.\n\n/workspace/node_modules/next/dist/server/web/spec-extension/adapters/next-request.d.ts:\n Line 24: * will \"close\" the readable stream and nothing fires after that).\n\n/workspace/node_modules/next/dist/server/next-server.d.ts:\n Line 17: import type { WaitUntil } from './after/builtin-request-context';\n\n/workspace/node_modules/next/dist/lib/multi-file-writer.d.ts:\n Line 4: * guarantees that all files will be written after their containing directory\n Line 29: * Appends a file to the writer to be written after its containing directory\n Line 30: * is created. The file writer should be awaited after all the files have been\n\n/workspace/node_modules/next/dist/server/route-modules/app-route/module.d.ts:\n Line 138: * Must be called after ensureUserland() has resolved so that _methods is\n\n/workspace/node_modules/next/dist/lib/metadata/types/metadata-types.d.ts:\n Line 51: unavailable_after?: string | undefined;\n\n/workspace/node_modules/next/dist/lib/metadata/types/metadata-interface.d.ts:\n Line 486: * ResolvedMetadataWithURLs represents the fully processed metadata after\n Line 543: * ResolvedMetadata represents the fully processed metadata after defaults are\n\n/workspace/node_modules/next/dist/server/lib/lru-cache.d.ts:\n Line 29: * Adds a node immediately after the head (marks as most recently used).\n\n/workspace/node_modules/next/dist/build/lockfile.d.ts:\n Line 44: * on Windows where it may take some time after process exit for the operating\n\n/workspace/node_modules/next/dist/lib/load-custom-routes.d.ts:\n Line 59: afterFiles: Rewrite[];\n\n/workspace/node_modules/next/dist/server/load-components.d.ts:\n Line 15: * This manifest prevents removing server rendered tags after client\n\n/workspace/node_modules/next/dist/next-devtools/dev-overlay/components/instant-navs/instant-nav-cookie.d.ts:\n Line 9: * The \"to\" tree may be null initially and updated after the prefetch resolves.\n\n/workspace/node_modules/next/dist/server/lib/install-code-frame.d.ts:\n Line 5: * Should be called early in dev/build initialization, after native bindings are loaded.\n\n/workspace/node_modules/next/dist/server/lib/router-utils/instrumentation-node-extensions.d.ts:\n Line 2: * This extension augments opentelemetry after registration if applicable.\n Line 5: export declare function afterRegistration(): void;\n\n/workspace/node_modules/next/dist/server/lib/incremental-cache/index.d.ts:\n Line 26: revalidateTag(_tags: string | string[], _durations?: {\n Line 67: revalidateTag(tags: string | string[], durations?: {\n\n/workspace/node_modules/next/dist/server/after/index.d.ts:\n Line 1: export * from './after';\n\n/workspace/node_modules/next/dist/server/web/exports/index.d.ts:\n Line 6: export { after } from '../../after';\n\n/workspace/node_modules/next/dist/build/webpack/plugins/next-types-plugin/index.d.ts:\n Line 6: afterFiles: Rewrite[];\n\n/workspace/node_modules/next/dist/build/index.d.ts:\n Line 30: * - unstable_cache\n Line 180: afterFiles: Array;\n\n/workspace/node_modules/next/dist/shared/lib/html-context.shared-runtime.d.ts:\n Line 38: afterInteractive?: string[];\n\n/workspace/node_modules/next/dist/server/dev/hot-reloader-webpack.d.ts:\n Line 92: protected afterCompile(_multiCompiler: webpack.MultiCompiler): Promise;\n\n/workspace/node_modules/next/dist/server/dev/hot-reloader-rspack.d.ts:\n Line 18: * - Track successfully built page entries after each compilation\n Line 27: afterCompile(multiCompiler: MultiCompiler): Promise;\n\n/workspace/node_modules/next/dist/client/head-manager.d.ts:\n Line 11: * comparing it to `oldTag`, restoring it afterwards.\n\n/workspace/node_modules/next/dist/build/swc/generated-native.d.ts:\n Line 254: /** App-router page routes that should be built after non-deferred routes. */\n Line 490: * Intended to be called once at the end of a build, after `writeAllEntrypointsToDisk`. The\n Line 741: afterFiles: Array\n\n/workspace/node_modules/next/dist/esm/build/swc/generated-native.d.ts:\n Line 254: /** App-router page routes that should be built after non-deferred routes. */\n Line 490: * Intended to be called once at the end of a build, after `writeAllEntrypointsToDisk`. The\n Line 741: afterFiles: Array\n\n/workspace/node_modules/next/dist/server/lib/incremental-cache/file-system-cache.d.ts:\n Line 17: revalidateTag(tags: string | string[], durations?: {\n\n/workspace/node_modules/next/dist/server/lib/router-utils/filesystem.d.ts:\n Line 49: afterFiles: (Rewrite & {\n\n/workspace/node_modules/next/dist/server/node-environment-extensions/fast-set-immediate.external.d.ts:\n Line 7: * All calls captured in this way will be executed after the current task\n Line 8: * (after callbacks from `process.nextTick()`, microtasks, and nextTicks scheduled from microtasks).\n Line 66: * This should always be called a task after `DANGEROUSLY_runPendingImmediatesAfterCurrentTask`\n\n/workspace/node_modules/next/dist/server/web/spec-extension/fetch-event.d.ts:\n Line 1: import type { WaitUntil } from '../../after/builtin-request-context';\n\n/workspace/node_modules/next/dist/server/app-render/dynamic-rendering.d.ts:\n Line 13: * inside unstable_cache it can still be cached. This type of indication can be removed if we ever\n Line 19: * unstable_cache should error. If you want to use some dynamic data inside unstable_cache you should\n\n/workspace/node_modules/next/dist/shared/lib/router/utils/disable-smooth-scroll.d.ts:\n Line 3: * This css change will be reverted after the function finishes.\n\n/workspace/node_modules/next/dist/build/define-env.d.ts:\n Line 24: afterFiles: Rewrite[];\n\n(Results are truncated. Consider using a more specific path or pattern.)","title":"after|unstable_after|revalidateTag|unstable_cache|cache\\(","metadata":{"matches":100,"truncated":true},"time":{"start":1781390469268,"end":1781390469335}}}}
+{"type":"step_finish","timestamp":1781390469342,"sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","part":{"id":"prt_ec32568d9001yzAjSUsRciXpyM","sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","messageID":"msg_ec32539800018qxs3RF6MiIm9q","type":"step-finish","reason":"tool-calls","snapshot":"56c903bdd03b310f65cb061c1cc1689c258eb58e","cost":0.00505427,"tokens":{"input":541,"output":705,"reasoning":0,"cache":{"read":10752,"write":0}}}}
+{"type":"step_start","timestamp":1781390471230,"sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","part":{"id":"prt_ec3257037001u0IPTcoX4BkRjT","sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","messageID":"msg_ec32568e7001vOUFbadE7K4IxM","type":"step-start","snapshot":"56c903bdd03b310f65cb061c1cc1689c258eb58e"}}
+{"type":"tool_use","timestamp":1781390472350,"sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","part":{"id":"prt_ec3257181001j1p4bEgTA2XNU4","sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","messageID":"msg_ec32568e7001vOUFbadE7K4IxM","type":"tool","callID":"read_8","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/node_modules/next/dist/server/after/after.d.ts"},"output":"\n00001| export type AfterTask = Promise | AfterCallback;\n00002| export type AfterCallback = () => T | Promise;\n00003| /**\n00004| * This function allows you to schedule callbacks to be executed after the current request finishes.\n00005| */\n00006| export declare function after(task: AfterTask): void;\n00007| \n\n(End of file - total 7 lines)\n","title":"node_modules/next/dist/server/after/after.d.ts","metadata":{"preview":"export type AfterTask = Promise | AfterCallback;\nexport type AfterCallback = () => T | Promise;\n/**\n * This function allows you to schedule callbacks to be executed after the current request finishes.\n */\nexport declare function after(task: AfterTask): void;\n"},"time":{"start":1781390472346,"end":1781390472349}}}}
+{"type":"tool_use","timestamp":1781390472852,"sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","part":{"id":"prt_ec325749c001bXTcRz9Ijaj50h","sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","messageID":"msg_ec32568e7001vOUFbadE7K4IxM","type":"tool","callID":"read_9","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/node_modules/next/dist/server/web/spec-extension/unstable-cache.d.ts"},"output":"\n00001| type Callback = (...args: any[]) => Promise;\n00002| /**\n00003| * This function allows you to cache the results of expensive operations, like database queries, and reuse them across multiple requests.\n00004| *\n00005| * Read more: [Next.js Docs: `unstable_cache`](https://nextjs.org/docs/app/api-reference/functions/unstable_cache)\n00006| */\n00007| export declare function unstable_cache(cb: T, keyParts?: string[], options?: {\n00008| /**\n00009| * The revalidation interval in seconds.\n00010| */\n00011| revalidate?: number | false;\n00012| tags?: string[];\n00013| }): T;\n00014| export {};\n00015| \n\n(End of file - total 15 lines)\n","title":"node_modules/next/dist/server/web/spec-extension/unstable-cache.d.ts","metadata":{"preview":"type Callback = (...args: any[]) => Promise;\n/**\n * This function allows you to cache the results of expensive operations, like database queries, and reuse them across multiple requests.\n *\n * Read more: [Next.js Docs: `unstable_cache`](https://nextjs.org/docs/app/api-reference/functions/unstable_cache)\n */\nexport declare function unstable_cache(cb: T, keyParts?: string[], options?: {\n /**\n * The revalidation interval in seconds.\n */\n revalidate?: number | false;\n tags?: string[];\n}): T;\nexport {};\n"},"time":{"start":1781390472848,"end":1781390472851}}}}
+{"type":"tool_use","timestamp":1781390472928,"sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","part":{"id":"prt_ec32576920013DlO7V4yvpphv5","sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","messageID":"msg_ec32568e7001vOUFbadE7K4IxM","type":"tool","callID":"read_10","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/node_modules/next/dist/server/web/spec-extension/revalidate.d.ts"},"output":"\n00001| type CacheLifeConfig = {\n00002| expire?: number;\n00003| };\n00004| /**\n00005| * This function allows you to purge [cached data](https://nextjs.org/docs/app/building-your-application/caching) on-demand for a specific cache tag.\n00006| *\n00007| * The second argument specifies a [`cacheLife`](https://nextjs.org/docs/app/api-reference/functions/cacheLife#reference) profile\n00008| * (e.g. `\"max\"`), or a `{ expire }` object. For immediate expiration in Server Actions, use\n00009| * [`updateTag`](https://nextjs.org/docs/app/api-reference/functions/updateTag) instead.\n00010| *\n00011| * Read more: [Next.js Docs: `revalidateTag`](https://nextjs.org/docs/app/api-reference/functions/revalidateTag)\n00012| */\n00013| export declare function revalidateTag(tag: string, profile: string | CacheLifeConfig): undefined;\n00014| /**\n00015| * This function allows you to update [cached data](https://nextjs.org/docs/app/building-your-application/caching) on-demand for a specific cache tag.\n00016| * This can only be called from within a Server Action to enable read-your-own-writes semantics.\n00017| *\n00018| * Read more: [Next.js Docs: `updateTag`](https://nextjs.org/docs/app/api-reference/functions/updateTag)\n00019| */\n00020| export declare function updateTag(tag: string): undefined;\n00021| /**\n00022| * This function allows you to refresh client cache from server actions.\n00023| * It's useful as dynamic data can be cached on the client which won't\n00024| * be refreshed by updateTag\n00025| */\n00026| export declare function refresh(): void;\n00027| /**\n00028| * This function allows you to purge [cached data](https://nextjs.org/docs/app/building-your-application/caching) on-demand for a specific path.\n00029| *\n00030| * Read more: [Next.js Docs: `revalidatePath`](https://nextjs.org/docs/app/api-reference/functions/revalidatePath)\n00031| */\n00032| export declare function revalidatePath(originalPath: string, type?: 'layout' | 'page'): undefined;\n00033| export {};\n00034| \n\n(End of file - total 34 lines)\n","title":"node_modules/next/dist/server/web/spec-extension/revalidate.d.ts","metadata":{"preview":"type CacheLifeConfig = {\n expire?: number;\n};\n/**\n * This function allows you to purge [cached data](https://nextjs.org/docs/app/building-your-application/caching) on-demand for a specific cache tag.\n *\n * The second argument specifies a [`cacheLife`](https://nextjs.org/docs/app/api-reference/functions/cacheLife#reference) profile\n * (e.g. `\"max\"`), or a `{ expire }` object. For immediate expiration in Server Actions, use\n * [`updateTag`](https://nextjs.org/docs/app/api-reference/functions/updateTag) instead.\n *\n * Read more: [Next.js Docs: `revalidateTag`](https://nextjs.org/docs/app/api-reference/functions/revalidateTag)\n */\nexport declare function revalidateTag(tag: string, profile: string | CacheLifeConfig): undefined;\n/**\n * This function allows you to update [cached data](https://nextjs.org/docs/app/building-your-application/caching) on-demand for a specific cache tag.\n * This can only be called from within a Server Action to enable read-your-own-writes semantics.\n *\n * Read more: [Next.js Docs: `updateTag`](https://nextjs.org/docs/app/api-reference/functions/updateTag)\n */\nexport declare function updateTag(tag: string): undefined;"},"time":{"start":1781390472921,"end":1781390472924}}}}
+{"type":"step_finish","timestamp":1781390472930,"sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","part":{"id":"prt_ec32576dd001JeJ4PzfrUbV647","sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","messageID":"msg_ec32568e7001vOUFbadE7K4IxM","type":"step-finish","reason":"tool-calls","snapshot":"56c903bdd03b310f65cb061c1cc1689c258eb58e","cost":0.00567614,"tokens":{"input":3682,"output":94,"reasoning":0,"cache":{"read":11264,"write":0}}}}
+{"type":"step_start","timestamp":1781390474555,"sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","part":{"id":"prt_ec3257d38001sWN8qoCok6VzXo","sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","messageID":"msg_ec32576ee001573SGft7nXfzff","type":"step-start","snapshot":"56c903bdd03b310f65cb061c1cc1689c258eb58e"}}
+{"type":"tool_use","timestamp":1781390501242,"sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","part":{"id":"prt_ec325e49c001DZQZ27QAoOR6fz","sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","messageID":"msg_ec32576ee001573SGft7nXfzff","type":"tool","callID":"glob_11","tool":"glob","state":{"status":"completed","input":{"pattern":"**/*.test.*"},"output":"No files found","title":"","metadata":{"count":0,"truncated":false},"time":{"start":1781390501235,"end":1781390501241}}}}
+{"type":"tool_use","timestamp":1781390501566,"sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","part":{"id":"prt_ec325e5750012TFU9rTFEhFM0L","sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","messageID":"msg_ec32576ee001573SGft7nXfzff","type":"tool","callID":"glob_12","tool":"glob","state":{"status":"completed","input":{"pattern":"**/*.spec.*"},"output":"No files found","title":"","metadata":{"count":0,"truncated":false},"time":{"start":1781390501560,"end":1781390501565}}}}
+{"type":"tool_use","timestamp":1781390501569,"sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","part":{"id":"prt_ec325e6bb001LxFZR6v5leRXT5","sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","messageID":"msg_ec32576ee001573SGft7nXfzff","type":"tool","callID":"glob_13","tool":"glob","state":{"status":"completed","input":{"pattern":"**/e2e/**"},"output":"No files found","title":"","metadata":{"count":0,"truncated":false},"time":{"start":1781390501564,"end":1781390501567}}}}
+{"type":"step_finish","timestamp":1781390501575,"sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","part":{"id":"prt_ec325e6c0001rP6COv2osUaRsK","sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","messageID":"msg_ec32576ee001573SGft7nXfzff","type":"step-finish","reason":"tool-calls","snapshot":"56c903bdd03b310f65cb061c1cc1689c258eb58e","cost":0.00628193,"tokens":{"input":1055,"output":726,"reasoning":0,"cache":{"read":14848,"write":0}}}}
+{"type":"step_start","timestamp":1781390503057,"sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","part":{"id":"prt_ec325ec89001js83YNsOxxotSd","sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","messageID":"msg_ec325e6ce001v0pA6O0RTcQ9UG","type":"step-start","snapshot":"56c903bdd03b310f65cb061c1cc1689c258eb58e"}}
+{"type":"tool_use","timestamp":1781390537213,"sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","part":{"id":"prt_ec32670ba0016CJVYjk6mwk1My","sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","messageID":"msg_ec325e6ce001v0pA6O0RTcQ9UG","type":"tool","callID":"read_14","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/node_modules/next/cache.d.ts"},"output":"\n00001| export { unstable_cache } from 'next/dist/server/web/spec-extension/unstable-cache'\n00002| \n00003| export {\n00004| revalidatePath,\n00005| revalidateTag,\n00006| updateTag,\n00007| refresh,\n00008| } from 'next/dist/server/web/spec-extension/revalidate'\n00009| \n00010| export { unstable_noStore } from 'next/dist/server/web/spec-extension/unstable-no-store'\n00011| \n00012| export { io } from 'next/dist/server/request/io'\n00013| \n00014| import { cacheTag } from 'next/dist/server/use-cache/cache-tag'\n00015| \n00016| export { cacheTag }\n00017| \n00018| /**\n00019| * Cache this `\"use cache\"` for a timespan defined by the `\"default\"` profile.\n00020| * ```\n00021| * stale: 300 seconds (5 minutes)\n00022| * revalidate: 900 seconds (15 minutes)\n00023| * expire: never\n00024| * ```\n00025| *\n00026| * This cache may be stale on clients for 5 minutes before checking with the server.\n00027| * If the server receives a new request after 15 minutes, start revalidating new values in the background.\n00028| * It lives for the maximum age of the server cache. If this entry has no traffic for a while, it may serve an old value the next request.\n00029| */\n00030| export function cacheLife(profile: 'default'): void\n00031| \n00032| /**\n00033| * Cache this `\"use cache\"` for a timespan defined by the `\"seconds\"` profile.\n00034| * ```\n00035| * stale: 30 seconds\n00036| * revalidate: 1 second\n00037| * expire: 1 minute\n00038| * ```\n00039| *\n00040| * This cache may be stale on clients for 30 seconds before checking with the server.\n00041| * If the server receives a new request after 1 second, start revalidating new values in the background.\n00042| * If this entry has no traffic for 1 minute it will expire. The next request will recompute it.\n00043| */\n00044| export function cacheLife(profile: 'seconds'): void\n00045| \n00046| /**\n00047| * Cache this `\"use cache\"` for a timespan defined by the `\"minutes\"` profile.\n00048| * ```\n00049| * stale: 300 seconds (5 minutes)\n00050| * revalidate: 60 seconds (1 minute)\n00051| * expire: 3600 seconds (1 hour)\n00052| * ```\n00053| *\n00054| * This cache may be stale on clients for 5 minutes before checking with the server.\n00055| * If the server receives a new request after 1 minute, start revalidating new values in the background.\n00056| * If this entry has no traffic for 1 hour it will expire. The next request will recompute it.\n00057| */\n00058| export function cacheLife(profile: 'minutes'): void\n00059| \n00060| /**\n00061| * Cache this `\"use cache\"` for a timespan defined by the `\"hours\"` profile.\n00062| * ```\n00063| * stale: 300 seconds (5 minutes)\n00064| * revalidate: 3600 seconds (1 hour)\n00065| * expire: 86400 seconds (1 day)\n00066| * ```\n00067| *\n00068| * This cache may be stale on clients for 5 minutes before checking with the server.\n00069| * If the server receives a new request after 1 hour, start revalidating new values in the background.\n00070| * If this entry has no traffic for 1 day it will expire. The next request will recompute it.\n00071| */\n00072| export function cacheLife(profile: 'hours'): void\n00073| \n00074| /**\n00075| * Cache this `\"use cache\"` for a timespan defined by the `\"days\"` profile.\n00076| * ```\n00077| * stale: 300 seconds (5 minutes)\n00078| * revalidate: 86400 seconds (1 day)\n00079| * expire: 604800 seconds (1 week)\n00080| * ```\n00081| *\n00082| * This cache may be stale on clients for 5 minutes before checking with the server.\n00083| * If the server receives a new request after 1 day, start revalidating new values in the background.\n00084| * If this entry has no traffic for 1 week it will expire. The next request will recompute it.\n00085| */\n00086| export function cacheLife(profile: 'days'): void\n00087| \n00088| /**\n00089| * Cache this `\"use cache\"` for a timespan defined by the `\"weeks\"` profile.\n00090| * ```\n00091| * stale: 300 seconds (5 minutes)\n00092| * revalidate: 604800 seconds (1 week)\n00093| * expire: 2592000 seconds (30 days)\n00094| * ```\n00095| *\n00096| * This cache may be stale on clients for 5 minutes before checking with the server.\n00097| * If the server receives a new request after 1 week, start revalidating new values in the background.\n00098| * If this entry has no traffic for 30 days it will expire. The next request will recompute it.\n00099| */\n00100| export function cacheLife(profile: 'weeks'): void\n00101| \n00102| /**\n00103| * Cache this `\"use cache\"` for a timespan defined by the `\"max\"` profile.\n00104| * ```\n00105| * stale: 300 seconds (5 minutes)\n00106| * revalidate: 2592000 seconds (30 days)\n00107| * expire: never\n00108| * ```\n00109| *\n00110| * This cache may be stale on clients for 5 minutes before checking with the server.\n00111| * If the server receives a new request after 30 days, start revalidating new values in the background.\n00112| * It lives for the maximum age of the server cache. If this entry has no traffic for a while, it may serve an old value the next request.\n00113| */\n00114| export function cacheLife(profile: 'max'): void\n00115| \n00116| /**\n00117| * Cache this `\"use cache\"` using a custom profile \"...\".\n00118| * ```\n00119| * stale: ... // seconds\n00120| * revalidate: ... // seconds\n00121| * expire: ... // seconds\n00122| * ```\n00123| *\n00124| * You can define custom profiles in `next.config.ts`.\n00125| */\n00126| export function cacheLife(profile: string): void\n00127| \n00128| /**\n00129| * Cache this `\"use cache\"` using a custom timespan.\n00130| * ```\n00131| * stale: ... // seconds\n00132| * revalidate: ... // seconds\n00133| * expire: ... // seconds\n00134| * ```\n00135| *\n00136| * This is similar to Cache-Control: max-age=`stale`,s-max-age=`revalidate`,stale-while-revalidate=`expire-revalidate`\n00137| *\n00138| * If a value is left out, the lowest of other cacheLife() calls or the default, is used instead.\n00139| */\n00140| export function cacheLife(profile: {\n00141| /**\n00142| * This cache may be stale on clients for ... seconds before checking with the server.\n00143| */\n00144| stale?: number\n00145| /**\n00146| * If the server receives a new request after ... seconds, start revalidating new values in the background.\n00147| */\n00148| revalidate?: number\n00149| /**\n00150| * If this entry has no traffic for ... seconds it will expire. The next request will recompute it.\n00151| */\n00152| expire?: number\n00153| }): void\n00154| \n00155| export const unstable_cacheLife: typeof cacheLife\n00156| export const unstable_cacheTag: typeof cacheTag\n00157| \n\n(End of file - total 157 lines)\n","title":"node_modules/next/cache.d.ts","metadata":{"preview":"export { unstable_cache } from 'next/dist/server/web/spec-extension/unstable-cache'\n\nexport {\n revalidatePath,\n revalidateTag,\n updateTag,\n refresh,\n} from 'next/dist/server/web/spec-extension/revalidate'\n\nexport { unstable_noStore } from 'next/dist/server/web/spec-extension/unstable-no-store'\n\nexport { io } from 'next/dist/server/request/io'\n\nimport { cacheTag } from 'next/dist/server/use-cache/cache-tag'\n\nexport { cacheTag }\n\n/**\n * Cache this `\"use cache\"` for a timespan defined by the `\"default\"` profile.\n * ```"},"time":{"start":1781390537209,"end":1781390537212}}}}
+{"type":"tool_use","timestamp":1781390538130,"sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","part":{"id":"prt_ec32671fb0018pw9tqvOR4Kp05","sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","messageID":"msg_ec325e6ce001v0pA6O0RTcQ9UG","type":"tool","callID":"bash_15","tool":"bash","state":{"status":"completed","input":{"command":"node -e \"const { revalidateTag } = require('next/cache'); console.log(revalidateTag.length)\"","workdir":"/workspace","description":"Check revalidateTag arity"},"output":"2\n","title":"Check revalidateTag arity","metadata":{"output":"2\n","exit":0,"description":"Check revalidateTag arity"},"time":{"start":1781390537977,"end":1781390538127}}}}
+{"type":"step_finish","timestamp":1781390538133,"sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","part":{"id":"prt_ec32675900017EDVAvO5KGdIUy","sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","messageID":"msg_ec325e6ce001v0pA6O0RTcQ9UG","type":"step-finish","reason":"tool-calls","snapshot":"56c903bdd03b310f65cb061c1cc1689c258eb58e","cost":0.01018298,"tokens":{"input":550,"output":1770,"reasoning":0,"cache":{"read":16128,"write":0}}}}
+{"type":"step_start","timestamp":1781390540205,"sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","part":{"id":"prt_ec3267da9001gMy9fDbFDBZnJy","sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","messageID":"msg_ec32675a4001v4uu5adGERecpf","type":"step-start","snapshot":"56c903bdd03b310f65cb061c1cc1689c258eb58e"}}
+{"type":"tool_use","timestamp":1781390543597,"sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","part":{"id":"prt_ec32688390014sLzDWwtif1SLA","sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","messageID":"msg_ec32675a4001v4uu5adGERecpf","type":"tool","callID":"bash_16","tool":"bash","state":{"status":"completed","input":{"command":"node -e \"const { updateTag } = require('next/cache'); console.log(updateTag.length)\"","workdir":"/workspace","description":"Check updateTag arity"},"output":"1\n","title":"Check updateTag arity","metadata":{"output":"1\n","exit":0,"description":"Check updateTag arity"},"time":{"start":1781390543468,"end":1781390543595}}}}
+{"type":"step_finish","timestamp":1781390543600,"sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","part":{"id":"prt_ec3268aec001pG8evdPzLzqA05","sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","messageID":"msg_ec32675a4001v4uu5adGERecpf","type":"step-finish","reason":"tool-calls","snapshot":"56c903bdd03b310f65cb061c1cc1689c258eb58e","cost":0.0070484,"tokens":{"input":3800,"output":194,"reasoning":0,"cache":{"read":16640,"write":0}}}}
+{"type":"step_start","timestamp":1781390545127,"sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","part":{"id":"prt_ec32690e4001oVhzmB4J3aDdmQ","sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","messageID":"msg_ec3268af7001X14tCDC4LEjMgt","type":"step-start","snapshot":"56c903bdd03b310f65cb061c1cc1689c258eb58e"}}
+{"type":"tool_use","timestamp":1781390548464,"sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","part":{"id":"prt_ec32699c60015MoW03xzcZfXwz","sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","messageID":"msg_ec3268af7001X14tCDC4LEjMgt","type":"tool","callID":"bash_17","tool":"bash","state":{"status":"completed","input":{"command":"node -e \"const { revalidateTag } = require('next/cache'); try { revalidateTag('products'); console.log('ok'); } catch(e) { console.error(e.message); }\"","workdir":"/workspace","description":"Test revalidateTag with one arg"},"output":"\"revalidateTag\" without the second argument is now deprecated, add second argument of \"max\" or use \"updateTag\". See more info here: https://nextjs.org/docs/messages/revalidate-tag-single-arg\nInvariant: static generation store missing in revalidateTag products\n","title":"Test revalidateTag with one arg","metadata":{"output":"\"revalidateTag\" without the second argument is now deprecated, add second argument of \"max\" or use \"updateTag\". See more info here: https://nextjs.org/docs/messages/revalidate-tag-single-arg\nInvariant: static generation store missing in revalidateTag products\n","exit":0,"description":"Test revalidateTag with one arg"},"time":{"start":1781390548340,"end":1781390548462}}}}
+{"type":"step_finish","timestamp":1781390548467,"sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","part":{"id":"prt_ec3269def001fWfyWFH2xb6fvW","sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","messageID":"msg_ec3268af7001X14tCDC4LEjMgt","type":"step-finish","reason":"tool-calls","snapshot":"56c903bdd03b310f65cb061c1cc1689c258eb58e","cost":0.00445139,"tokens":{"input":429,"output":202,"reasoning":0,"cache":{"read":20224,"write":0}}}}
+{"type":"step_start","timestamp":1781390550048,"sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","part":{"id":"prt_ec326a41c001vxoUQ80R7z78T7","sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","messageID":"msg_ec3269e00001tBMUt4VcJ7WttM","type":"step-start","snapshot":"56c903bdd03b310f65cb061c1cc1689c258eb58e"}}
+{"type":"tool_use","timestamp":1781390564828,"sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","part":{"id":"prt_ec326dc0b001B9hmeazY2aE2OE","sessionID":"ses_13cdaecaeffePMVRAqAFJ3Ea2y","messageID":"msg_ec3269e00001tBMUt4VcJ7WttM","type":"tool","callID":"webfetch_18","tool":"webfetch","state":{"status":"completed","input":{"url":"https://nextjs.org/docs/app/api-reference/functions/after"},"output":"Functions: after | Next.jsSkip to content
after allows you to schedule work to be executed after a response (or prerender) is finished. This is useful for tasks and other side effects that should not block the response, such as logging and analytics.
The function accepts a callback that will be executed after the response (or prerender) is finished:
\n
app/layout.tsx
TypeScript
import { after } from 'next/server'\n// Custom logging function\nimport { log } from '@/app/utils'\n\nexport default function Layout({ children }: { children: React.ReactNode }) {\n after(() => {\n // Execute after the layout is rendered and sent to the user\n log()\n })\n return <>{children}</>\n}
\n\n
\n
Good to know:after is not a Request-time API and calling it does not cause a route to become dynamic. If it's used within a static page, the callback will execute at build time, or whenever a page is revalidated.
\n
\n
Reference
\n
Parameters
\n
\n
A callback function which will be executed after the response (or prerender) is finished.
\n
\n
Duration
\n
after will run for the platform's default or configured max duration of your route. If your platform supports it, you can configure the timeout limit using the maxDuration route segment config.
\n
Good to know
\n
\n
after will be executed even if the response didn't complete successfully. Including when an error is thrown or when notFound or redirect is called.
\n
You can use React cache to deduplicate functions called inside after.
\n
after can be nested inside other after calls, for example, you can create utility functions that wrap after calls to add additional functionality.
\n
\n
Examples
\n
With request APIs
\n
Whether you can use request APIs like cookies and headers inside after depends on where after is called from.
\n
In Route Handlers and Server Functions
\n
You can call cookies and headers directly inside the after callback when used in Route Handlers and Server Functions. This is useful for logging activity after a mutation or API request. For example:
\n
app/api/route.ts
TypeScript
import { after } from 'next/server'\nimport { cookies, headers } from 'next/headers'\nimport { logUserAction } from '@/app/utils'\n\nexport async function POST(request: Request) {\n // Perform mutation\n // ...\n\n // Log user activity for analytics\n after(async () => {\n const userAgent = (await headers()).get('user-agent') || 'unknown'\n const sessionCookie =\n (await cookies()).get('session-id')?.value || 'anonymous'\n\n logUserAction({ sessionCookie, userAgent })\n })\n\n return new Response(JSON.stringify({ status: 'success' }), {\n status: 200,\n headers: { 'Content-Type': 'application/json' },\n })\n}
\n\n
In Server Components (pages and layouts)
\n
Server Components (including pages, layouts, and generateMetadata) cannot use cookies, headers, or other Request-time APIs inside after. This is because Next.js needs to know which part of the component tree accesses request data to support Partial Prerendering and Cache Components, but after runs after React's rendering lifecycle.
\n
If you need request data inside an after callback in a Server Component, read it beforehand and pass the values in:
\n
app/page.tsx
TypeScript
import { after } from 'next/server'\nimport { cookies, headers } from 'next/headers'\nimport { logUserAction } from '@/app/utils'\n\nexport default async function Page() {\n // Read request data before `after` — this is allowed\n // These calls will be read during the component's rendering lifecycle\n const userAgent = (await headers()).get('user-agent') || 'unknown'\n const sessionCookie =\n (await cookies()).get('session-id')?.value || 'anonymous'\n\n after(() => {\n // Use the values read above\n logUserAction({ sessionCookie, userAgent })\n })\n\n return <h1>My Page</h1>\n}
\n\n
Calling cookies() or headers() inside the after callback in a Server Component will throw a runtime error.
\n
With Cache Components
\n
When using Cache Components, components that access request data like cookies or headers must be wrapped in <Suspense> so the rest of the page can be prerendered into a static shell.
\n
You can combine this pattern with after by reading request data in a dynamic component and passing it into after:
\n
app/page.tsx
TypeScript
import { Suspense } from 'react'\nimport { after } from 'next/server'\nimport { cookies } from 'next/headers'\nimport { logUserAction } from '@/app/utils'\n\nexport default function Page() {\n return (\n <>\n <h1>Part of the static shell</h1>\n <Suspense fallback={<p>Loading...</p>}>\n <DynamicContent />\n </Suspense>\n </>\n )\n}\n\nasync function DynamicContent() {\n const sessionCookie =\n (await cookies()).get('session-id')?.value || 'anonymous'\n\n // Schedule work after the response is sent\n after(() => {\n logUserAction({ sessionCookie })\n })\n\n return <p>Your session: {sessionCookie}</p>\n}
\n\n
In this example, <h1> and the <Suspense> fallback are included in the static shell. DynamicContent reads the cookie during rendering and passes it into after via closure. Since cookies() is called outside the after callback (during the component's render), this works correctly.
\nReference: supporting after for serverless platforms
Using after in a serverless context requires waiting for asynchronous tasks to finish after the response has been sent. In Next.js and Vercel, this is achieved using a primitive called waitUntil(promise), which extends the lifetime of a serverless invocation until all promises passed to waitUntil have settled.
If you want your users to be able to run after, you will have to provide your implementation of waitUntil that behaves in an analogous way.
When after is called, Next.js will access waitUntil like this:
\n00006| )\n00007| }\n00008| \n\n(End of file - total 8 lines)\n",
+ "title": "app/page.tsx",
+ "metadata": {
+ "preview": "export default function Page() {\n return (\n
\n
Home
\n
\n )\n}\n"
+ },
+ "time": {
+ "start": 1781390456955,
+ "end": 1781390456957
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T22:40:57.150Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "args": {
+ "filePath": "/workspace/lib/db.js",
+ "_extractedPath": "/workspace/lib/db.js"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781390457150,
+ "sessionID": "ses_13cdaecaeffePMVRAqAFJ3Ea2y",
+ "part": {
+ "id": "prt_ec325387d001iGud227A8wOzjl",
+ "sessionID": "ses_13cdaecaeffePMVRAqAFJ3Ea2y",
+ "messageID": "msg_ec3252f780013sOh0c5BXwHxWg",
+ "type": "tool",
+ "callID": "read_6",
+ "tool": "read",
+ "state": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/lib/db.js"
+ },
+ "output": "\n00001| export async function getAllProducts() {\n00002| // Simulate database delay\n00003| await new Promise((resolve) => setTimeout(resolve, 100))\n00004| \n00005| return [\n00006| { id: 1, name: 'Laptop', price: 999 },\n00007| { id: 2, name: 'Phone', price: 699 },\n00008| { id: 3, name: 'Tablet', price: 499 },\n00009| { id: 4, name: 'Headphones', price: 199 },\n00010| { id: 5, name: 'Watch', price: 299 },\n00011| ]\n00012| }\n00013| \n\n(End of file - total 13 lines)\n",
+ "title": "lib/db.js",
+ "metadata": {
+ "preview": "export async function getAllProducts() {\n // Simulate database delay\n await new Promise((resolve) => setTimeout(resolve, 100))\n\n return [\n { id: 1, name: 'Laptop', price: 999 },\n { id: 2, name: 'Phone', price: 699 },\n { id: 3, name: 'Tablet', price: 499 },\n { id: 4, name: 'Headphones', price: 199 },\n { id: 5, name: 'Watch', price: 299 },\n ]\n}\n"
+ },
+ "time": {
+ "start": 1781390457132,
+ "end": 1781390457140
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T22:40:57.150Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| export async function getAllProducts() {\n00002| // Simulate database delay\n00003| await new Promise((resolve) => setTimeout(resolve, 100))\n00004| \n00005| return [\n00006| { id: 1, name: 'Laptop', price: 999 },\n00007| { id: 2, name: 'Phone', price: 699 },\n00008| { id: 3, name: 'Tablet', price: 499 },\n00009| { id: 4, name: 'Headphones', price: 199 },\n00010| { id: 5, name: 'Watch', price: 299 },\n00011| ]\n00012| }\n00013| \n\n(End of file - total 13 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/lib/db.js"
+ },
+ "output": "\n00001| export async function getAllProducts() {\n00002| // Simulate database delay\n00003| await new Promise((resolve) => setTimeout(resolve, 100))\n00004| \n00005| return [\n00006| { id: 1, name: 'Laptop', price: 999 },\n00007| { id: 2, name: 'Phone', price: 699 },\n00008| { id: 3, name: 'Tablet', price: 499 },\n00009| { id: 4, name: 'Headphones', price: 199 },\n00010| { id: 5, name: 'Watch', price: 299 },\n00011| ]\n00012| }\n00013| \n\n(End of file - total 13 lines)\n",
+ "title": "lib/db.js",
+ "metadata": {
+ "preview": "export async function getAllProducts() {\n // Simulate database delay\n await new Promise((resolve) => setTimeout(resolve, 100))\n\n return [\n { id: 1, name: 'Laptop', price: 999 },\n { id: 2, name: 'Phone', price: 699 },\n { id: 3, name: 'Tablet', price: 499 },\n { id: 4, name: 'Headphones', price: 199 },\n { id: 5, name: 'Watch', price: 299 },\n ]\n}\n"
+ },
+ "time": {
+ "start": 1781390457132,
+ "end": 1781390457140
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T22:41:09.338Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "grep",
+ "originalName": "grep",
+ "args": {
+ "pattern": "after|unstable_after|revalidateTag|unstable_cache|cache\\(",
+ "path": "/workspace/node_modules/next",
+ "include": "*.d.ts"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781390469338,
+ "sessionID": "ses_13cdaecaeffePMVRAqAFJ3Ea2y",
+ "part": {
+ "id": "prt_ec3256644001KL95MbLtf2mVsp",
+ "sessionID": "ses_13cdaecaeffePMVRAqAFJ3Ea2y",
+ "messageID": "msg_ec32539800018qxs3RF6MiIm9q",
+ "type": "tool",
+ "callID": "grep_7",
+ "tool": "grep",
+ "state": {
+ "status": "completed",
+ "input": {
+ "pattern": "after|unstable_after|revalidateTag|unstable_cache|cache\\(",
+ "path": "/workspace/node_modules/next",
+ "include": "*.d.ts"
+ },
+ "output": "Found 100 matches\n/workspace/node_modules/next/dist/server/app-render/work-unit-async-storage.external.d.ts:\n Line 19: export type WorkUnitPhase = 'action' | 'render' | 'after';\n Line 141: * The render signal is aborted after React's `prerender` function is aborted\n Line 145: * 2. When the final prerender is aborted immediately after the prerender was\n Line 157: * are no longer in the prerender phase of rendering. Typically this is after\n Line 247: * `unstable_cache`, which doesn't carry root params. Currently, `\"use cache\"`\n Line 248: * inside `unstable_cache` is allowed, so this case must be handled. The error\n Line 282: * Always `undefined` for `unstable_cache` — root params are not available in\n Line 283: * this context. If a `\"use cache\"` function nested inside `unstable_cache`\n Line 290: * unstable_cache context. A cache store shadows an outer request store (if\n\n/workspace/node_modules/next/dist/server/app-render/work-async-storage.external.d.ts:\n Line 6: import type { AfterContext } from '../after/after-context';\n Line 39: readonly afterContext: AfterContext;\n Line 87: * `use-cache-probe-worker.ts`) to switch `cache()` into a one-shot fill\n Line 95: * Max wall time the probe fill may take. `cache()` enforces this with\n Line 124: * `React.cache()`.\n\n/workspace/node_modules/next/dist/server/app-render/vary-params.d.ts:\n Line 9: * during render. Call `finishTrackingVaryParams()` after rendering to resolve\n Line 65: * their final vary params. Call this after rendering is complete.\n\n/workspace/node_modules/next/dist/next-devtools/dev-overlay/hooks/use-delayed-render.d.ts:\n Line 9: * unmount of a React component until after a delay.\n\n/workspace/node_modules/next/dist/next-devtools/dev-overlay/hooks/use-debounced-value.d.ts:\n Line 15: * the returned value is updated only after `ms` has elapsed without further\n\n/workspace/node_modules/next/dist/server/use-cache/use-cache-wrapper.d.ts:\n Line 80: * Used to compute the specific cache key after generation completes.\n Line 88: * eagerly at that inner invocation's `cache()` entry. Used as `cause` for the\n Line 95: export declare function cache(kind: string, id: string, boundArgsLength: number, originalFn: (...args: unknown[]) => Promise, args: unknown[]): Promise;\n\n/workspace/node_modules/next/dist/server/use-cache/use-cache-errors.d.ts:\n Line 10: * life up to the outer cache. Constructed eagerly in `cache()` while the caller\n\n/workspace/node_modules/next/dist/server/response-cache/types.d.ts:\n Line 105: * timestamp in milliseconds to revalidate after\n Line 205: revalidateTag(tags: string | string[], durations?: {\n\n/workspace/node_modules/next/dist/server/web/spec-extension/unstable-cache.d.ts:\n Line 5: * Read more: [Next.js Docs: `unstable_cache`](https://nextjs.org/docs/app/api-reference/functions/unstable_cache)\n Line 7: export declare function unstable_cache(cb: T, keyParts?: string[], options?: {\n\n/workspace/node_modules/next/dist/build/swc/types.d.ts:\n Line 236: * end of the build, after `writeAllEntrypointsToDisk`. The Rust implementation\n\n/workspace/node_modules/next/dist/server/app-render/stale-time.d.ts:\n Line 25: * each update (after applying selectStaleTime) through the iterable. This\n\n/workspace/node_modules/next/server.d.ts:\n Line 21: export { after } from 'next/dist/server/after'\n\n/workspace/node_modules/next/dist/client/components/router-reducer/set-cache-busting-search-param.d.ts:\n Line 11: * URL after: https://example.com/path?query=1&_rsc=abc123\n Line 29: * URL after: https://example.com/path?query=1&_rsc=abc123\n\n/workspace/node_modules/next/dist/server/server-utils.d.ts:\n Line 22: afterFiles?: ReadonlyArray;\n\n/workspace/node_modules/next/dist/client/script.d.ts:\n Line 4: strategy?: 'afterInteractive' | 'lazyOnload' | 'beforeInteractive' | 'worker';\n\n/workspace/node_modules/next/dist/lib/scheduler.d.ts:\n Line 4: * Schedules a function to be called on the next tick after the other promises\n Line 25: * specific timing tricks to try to schedule work after React has rendered. This is especially\n\n/workspace/node_modules/next/dist/client/components/router-reducer/router-reducer-types.d.ts:\n Line 25: * Testing API to preserve prefetched data when refreshing after an MPA\n\n/workspace/node_modules/next/dist/client/components/segment-cache/scheduler.d.ts:\n Line 27: * does not support PPR after doing the initial route prefetch.\n Line 66: * They are reset after each iteration of the task queue.\n\n/workspace/node_modules/next/dist/server/after/run-with-after.d.ts:\n Line 1: import type { AfterContextOpts } from './after-context';\n\n/workspace/node_modules/next/dist/lib/route-pattern-normalizer.d.ts:\n Line 48: * Used by both server and client code to clean up parameters after route matching.\n\n/workspace/node_modules/next/dist/server/route-matcher-managers/route-matcher-manager.d.ts:\n Line 27: * Reloads the matchers from the providers. This should be done after all the\n\n/workspace/node_modules/next/dist/server/web/spec-extension/revalidate.d.ts:\n Line 11: * Read more: [Next.js Docs: `revalidateTag`](https://nextjs.org/docs/app/api-reference/functions/revalidateTag)\n Line 13: export declare function revalidateTag(tag: string, profile: string | CacheLifeConfig): undefined;\n\n/workspace/node_modules/next/dist/shared/lib/router/utils/resolve-rewrites.d.ts:\n Line 8: afterFiles: Rewrite[];\n\n/workspace/node_modules/next/dist/server/request-meta.d.ts:\n Line 230: * The query after resolving routes\n Line 234: * The params after resolving routes\n Line 263: * DEV only: Server action log info to be logged after the request log\n\n/workspace/node_modules/next/dist/server/render-result.d.ts:\n Line 133: * will be piped one after the other.\n Line 142: * one after the other.\n\n/workspace/node_modules/next/dist/client/lib/promise.d.ts:\n Line 1: /** Resolve a promise that times out after given amount of milliseconds. */\n\n/workspace/node_modules/next/dist/build/polyfills/polyfill-module.d.ts:\n Line 1: // imports polyfill from `@next/polyfill-module` after build.\n\n/workspace/node_modules/next/dist/esm/build/polyfills/polyfill-module.d.ts:\n Line 1: // imports polyfill from `@next/polyfill-module` after build.\n\n/workspace/node_modules/next/dist/client/components/segment-cache/optimistic-routes.d.ts:\n Line 20: * 1. discoverKnownRoute: Called after receiving a route tree from the server.\n Line 52: * Called after receiving a route tree from the server (initial load, navigation,\n\n/workspace/node_modules/next/dist/server/stream-utils/node-web-streams-helper.d.ts:\n Line 53: * Suffix to inject after the buffered data, but before the close tags.\n\n/workspace/node_modules/next/dist/server/web/spec-extension/adapters/next-request.d.ts:\n Line 24: * will \"close\" the readable stream and nothing fires after that).\n\n/workspace/node_modules/next/dist/server/next-server.d.ts:\n Line 17: import type { WaitUntil } from './after/builtin-request-context';\n\n/workspace/node_modules/next/dist/lib/multi-file-writer.d.ts:\n Line 4: * guarantees that all files will be written after their containing directory\n Line 29: * Appends a file to the writer to be written after its containing directory\n Line 30: * is created. The file writer should be awaited after all the files have been\n\n/workspace/node_modules/next/dist/server/route-modules/app-route/module.d.ts:\n Line 138: * Must be called after ensureUserland() has resolved so that _methods is\n\n/workspace/node_modules/next/dist/lib/metadata/types/metadata-types.d.ts:\n Line 51: unavailable_after?: string | undefined;\n\n/workspace/node_modules/next/dist/lib/metadata/types/metadata-interface.d.ts:\n Line 486: * ResolvedMetadataWithURLs represents the fully processed metadata after\n Line 543: * ResolvedMetadata represents the fully processed metadata after defaults are\n\n/workspace/node_modules/next/dist/server/lib/lru-cache.d.ts:\n Line 29: * Adds a node immediately after the head (marks as most recently used).\n\n/workspace/node_modules/next/dist/build/lockfile.d.ts:\n Line 44: * on Windows where it may take some time after process exit for the operating\n\n/workspace/node_modules/next/dist/lib/load-custom-routes.d.ts:\n Line 59: afterFiles: Rewrite[];\n\n/workspace/node_modules/next/dist/server/load-components.d.ts:\n Line 15: * This manifest prevents removing server rendered tags after client\n\n/workspace/node_modules/next/dist/next-devtools/dev-overlay/components/instant-navs/instant-nav-cookie.d.ts:\n Line 9: * The \"to\" tree may be null initially and updated after the prefetch resolves.\n\n/workspace/node_modules/next/dist/server/lib/install-code-frame.d.ts:\n Line 5: * Should be called early in dev/build initialization, after native bindings are loaded.\n\n/workspace/node_modules/next/dist/server/lib/router-utils/instrumentation-node-extensions.d.ts:\n Line 2: * This extension augments opentelemetry after registration if applicable.\n Line 5: export declare function afterRegistration(): void;\n\n/workspace/node_modules/next/dist/server/lib/incremental-cache/index.d.ts:\n Line 26: revalidateTag(_tags: string | string[], _durations?: {\n Line 67: revalidateTag(tags: string | string[], durations?: {\n\n/workspace/node_modules/next/dist/server/after/index.d.ts:\n Line 1: export * from './after';\n\n/workspace/node_modules/next/dist/server/web/exports/index.d.ts:\n Line 6: export { after } from '../../after';\n\n/workspace/node_modules/next/dist/build/webpack/plugins/next-types-plugin/index.d.ts:\n Line 6: afterFiles: Rewrite[];\n\n/workspace/node_modules/next/dist/build/index.d.ts:\n Line 30: * - unstable_cache\n Line 180: afterFiles: Array;\n\n/workspace/node_modules/next/dist/shared/lib/html-context.shared-runtime.d.ts:\n Line 38: afterInteractive?: string[];\n\n/workspace/node_modules/next/dist/server/dev/hot-reloader-webpack.d.ts:\n Line 92: protected afterCompile(_multiCompiler: webpack.MultiCompiler): Promise;\n\n/workspace/node_modules/next/dist/server/dev/hot-reloader-rspack.d.ts:\n Line 18: * - Track successfully built page entries after each compilation\n Line 27: afterCompile(multiCompiler: MultiCompiler): Promise;\n\n/workspace/node_modules/next/dist/client/head-manager.d.ts:\n Line 11: * comparing it to `oldTag`, restoring it afterwards.\n\n/workspace/node_modules/next/dist/build/swc/generated-native.d.ts:\n Line 254: /** App-router page routes that should be built after non-deferred routes. */\n Line 490: * Intended to be called once at the end of a build, after `writeAllEntrypointsToDisk`. The\n Line 741: afterFiles: Array\n\n/workspace/node_modules/next/dist/esm/build/swc/generated-native.d.ts:\n Line 254: /** App-router page routes that should be built after non-deferred routes. */\n Line 490: * Intended to be called once at the end of a build, after `writeAllEntrypointsToDisk`. The\n Line 741: afterFiles: Array\n\n/workspace/node_modules/next/dist/server/lib/incremental-cache/file-system-cache.d.ts:\n Line 17: revalidateTag(tags: string | string[], durations?: {\n\n/workspace/node_modules/next/dist/server/lib/router-utils/filesystem.d.ts:\n Line 49: afterFiles: (Rewrite & {\n\n/workspace/node_modules/next/dist/server/node-environment-extensions/fast-set-immediate.external.d.ts:\n Line 7: * All calls captured in this way will be executed after the current task\n Line 8: * (after callbacks from `process.nextTick()`, microtasks, and nextTicks scheduled from microtasks).\n Line 66: * This should always be called a task after `DANGEROUSLY_runPendingImmediatesAfterCurrentTask`\n\n/workspace/node_modules/next/dist/server/web/spec-extension/fetch-event.d.ts:\n Line 1: import type { WaitUntil } from '../../after/builtin-request-context';\n\n/workspace/node_modules/next/dist/server/app-render/dynamic-rendering.d.ts:\n Line 13: * inside unstable_cache it can still be cached. This type of indication can be removed if we ever\n Line 19: * unstable_cache should error. If you want to use some dynamic data inside unstable_cache you should\n\n/workspace/node_modules/next/dist/shared/lib/router/utils/disable-smooth-scroll.d.ts:\n Line 3: * This css change will be reverted after the function finishes.\n\n/workspace/node_modules/next/dist/build/define-env.d.ts:\n Line 24: afterFiles: Rewrite[];\n\n(Results are truncated. Consider using a more specific path or pattern.)",
+ "title": "after|unstable_after|revalidateTag|unstable_cache|cache\\(",
+ "metadata": {
+ "matches": 100,
+ "truncated": true
+ },
+ "time": {
+ "start": 1781390469268,
+ "end": 1781390469335
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T22:41:09.338Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "grep",
+ "originalName": "grep",
+ "result": "Found 100 matches\n/workspace/node_modules/next/dist/server/app-render/work-unit-async-storage.external.d.ts:\n Line 19: export type WorkUnitPhase = 'action' | 'render' | 'after';\n Line 141: * The render signal is aborted after React's `prerender` function is aborted\n Line 145: * 2. When the final prerender is aborted immediately after the prerender was\n Line 157: * are no longer in the prerender phase of rendering. Typically this is after\n Line 247: * `unstable_cache`, which doesn't carry root params. Currently, `\"use cache\"`\n Line 248: * inside `unstable_cache` is allowed, so this case must be handled. The error\n Line 282: * Always `undefined` for `unstable_cache` — root params are not available in\n Line 283: * this context. If a `\"use cache\"` function nested inside `unstable_cache`\n Line 290: * unstable_cache context. A cache store shadows an outer request store (if\n\n/workspace/node_modules/next/dist/server/app-render/work-async-storage.external.d.ts:\n Line 6: import type { AfterContext } from '../after/after-context';\n Line 39: readonly afterContext: AfterContext;\n Line 87: * `use-cache-probe-worker.ts`) to switch `cache()` into a one-shot fill\n Line 95: * Max wall time the probe fill may take. `cache()` enforces this with\n Line 124: * `React.cache()`.\n\n/workspace/node_modules/next/dist/server/app-render/vary-params.d.ts:\n Line 9: * during render. Call `finishTrackingVaryParams()` after rendering to resolve\n Line 65: * their final vary params. Call this after rendering is complete.\n\n/workspace/node_modules/next/dist/next-devtools/dev-overlay/hooks/use-delayed-render.d.ts:\n Line 9: * unmount of a React component until after a delay.\n\n/workspace/node_modules/next/dist/next-devtools/dev-overlay/hooks/use-debounced-value.d.ts:\n Line 15: * the returned value is updated only after `ms` has elapsed without further\n\n/workspace/node_modules/next/dist/server/use-cache/use-cache-wrapper.d.ts:\n Line 80: * Used to compute the specific cache key after generation completes.\n Line 88: * eagerly at that inner invocation's `cache()` entry. Used as `cause` for the\n Line 95: export declare function cache(kind: string, id: string, boundArgsLength: number, originalFn: (...args: unknown[]) => Promise, args: unknown[]): Promise;\n\n/workspace/node_modules/next/dist/server/use-cache/use-cache-errors.d.ts:\n Line 10: * life up to the outer cache. Constructed eagerly in `cache()` while the caller\n\n/workspace/node_modules/next/dist/server/response-cache/types.d.ts:\n Line 105: * timestamp in milliseconds to revalidate after\n Line 205: revalidateTag(tags: string | string[], durations?: {\n\n/workspace/node_modules/next/dist/server/web/spec-extension/unstable-cache.d.ts:\n Line 5: * Read more: [Next.js Docs: `unstable_cache`](https://nextjs.org/docs/app/api-reference/functions/unstable_cache)\n Line 7: export declare function unstable_cache(cb: T, keyParts?: string[], options?: {\n\n/workspace/node_modules/next/dist/build/swc/types.d.ts:\n Line 236: * end of the build, after `writeAllEntrypointsToDisk`. The Rust implementation\n\n/workspace/node_modules/next/dist/server/app-render/stale-time.d.ts:\n Line 25: * each update (after applying selectStaleTime) through the iterable. This\n\n/workspace/node_modules/next/server.d.ts:\n Line 21: export { after } from 'next/dist/server/after'\n\n/workspace/node_modules/next/dist/client/components/router-reducer/set-cache-busting-search-param.d.ts:\n Line 11: * URL after: https://example.com/path?query=1&_rsc=abc123\n Line 29: * URL after: https://example.com/path?query=1&_rsc=abc123\n\n/workspace/node_modules/next/dist/server/server-utils.d.ts:\n Line 22: afterFiles?: ReadonlyArray;\n\n/workspace/node_modules/next/dist/client/script.d.ts:\n Line 4: strategy?: 'afterInteractive' | 'lazyOnload' | 'beforeInteractive' | 'worker';\n\n/workspace/node_modules/next/dist/lib/scheduler.d.ts:\n Line 4: * Schedules a function to be called on the next tick after the other promises\n Line 25: * specific timing tricks to try to schedule work after React has rendered. This is especially\n\n/workspace/node_modules/next/dist/client/components/router-reducer/router-reducer-types.d.ts:\n Line 25: * Testing API to preserve prefetched data when refreshing after an MPA\n\n/workspace/node_modules/next/dist/client/components/segment-cache/scheduler.d.ts:\n Line 27: * does not support PPR after doing the initial route prefetch.\n Line 66: * They are reset after each iteration of the task queue.\n\n/workspace/node_modules/next/dist/server/after/run-with-after.d.ts:\n Line 1: import type { AfterContextOpts } from './after-context';\n\n/workspace/node_modules/next/dist/lib/route-pattern-normalizer.d.ts:\n Line 48: * Used by both server and client code to clean up parameters after route matching.\n\n/workspace/node_modules/next/dist/server/route-matcher-managers/route-matcher-manager.d.ts:\n Line 27: * Reloads the matchers from the providers. This should be done after all the\n\n/workspace/node_modules/next/dist/server/web/spec-extension/revalidate.d.ts:\n Line 11: * Read more: [Next.js Docs: `revalidateTag`](https://nextjs.org/docs/app/api-reference/functions/revalidateTag)\n Line 13: export declare function revalidateTag(tag: string, profile: string | CacheLifeConfig): undefined;\n\n/workspace/node_modules/next/dist/shared/lib/router/utils/resolve-rewrites.d.ts:\n Line 8: afterFiles: Rewrite[];\n\n/workspace/node_modules/next/dist/server/request-meta.d.ts:\n Line 230: * The query after resolving routes\n Line 234: * The params after resolving routes\n Line 263: * DEV only: Server action log info to be logged after the request log\n\n/workspace/node_modules/next/dist/server/render-result.d.ts:\n Line 133: * will be piped one after the other.\n Line 142: * one after the other.\n\n/workspace/node_modules/next/dist/client/lib/promise.d.ts:\n Line 1: /** Resolve a promise that times out after given amount of milliseconds. */\n\n/workspace/node_modules/next/dist/build/polyfills/polyfill-module.d.ts:\n Line 1: // imports polyfill from `@next/polyfill-module` after build.\n\n/workspace/node_modules/next/dist/esm/build/polyfills/polyfill-module.d.ts:\n Line 1: // imports polyfill from `@next/polyfill-module` after build.\n\n/workspace/node_modules/next/dist/client/components/segment-cache/optimistic-routes.d.ts:\n Line 20: * 1. discoverKnownRoute: Called after receiving a route tree from the server.\n Line 52: * Called after receiving a route tree from the server (initial load, navigation,\n\n/workspace/node_modules/next/dist/server/stream-utils/node-web-streams-helper.d.ts:\n Line 53: * Suffix to inject after the buffered data, but before the close tags.\n\n/workspace/node_modules/next/dist/server/web/spec-extension/adapters/next-request.d.ts:\n Line 24: * will \"close\" the readable stream and nothing fires after that).\n\n/workspace/node_modules/next/dist/server/next-server.d.ts:\n Line 17: import type { WaitUntil } from './after/builtin-request-context';\n\n/workspace/node_modules/next/dist/lib/multi-file-writer.d.ts:\n Line 4: * guarantees that all files will be written after their containing directory\n Line 29: * Appends a file to the writer to be written after its containing directory\n Line 30: * is created. The file writer should be awaited after all the files have been\n\n/workspace/node_modules/next/dist/server/route-modules/app-route/module.d.ts:\n Line 138: * Must be called after ensureUserland() has resolved so that _methods is\n\n/workspace/node_modules/next/dist/lib/metadata/types/metadata-types.d.ts:\n Line 51: unavailable_after?: string | undefined;\n\n/workspace/node_modules/next/dist/lib/metadata/types/metadata-interface.d.ts:\n Line 486: * ResolvedMetadataWithURLs represents the fully processed metadata after\n Line 543: * ResolvedMetadata represents the fully processed metadata after defaults are\n\n/workspace/node_modules/next/dist/server/lib/lru-cache.d.ts:\n Line 29: * Adds a node immediately after the head (marks as most recently used).\n\n/workspace/node_modules/next/dist/build/lockfile.d.ts:\n Line 44: * on Windows where it may take some time after process exit for the operating\n\n/workspace/node_modules/next/dist/lib/load-custom-routes.d.ts:\n Line 59: afterFiles: Rewrite[];\n\n/workspace/node_modules/next/dist/server/load-components.d.ts:\n Line 15: * This manifest prevents removing server rendered tags after client\n\n/workspace/node_modules/next/dist/next-devtools/dev-overlay/components/instant-navs/instant-nav-cookie.d.ts:\n Line 9: * The \"to\" tree may be null initially and updated after the prefetch resolves.\n\n/workspace/node_modules/next/dist/server/lib/install-code-frame.d.ts:\n Line 5: * Should be called early in dev/build initialization, after native bindings are loaded.\n\n/workspace/node_modules/next/dist/server/lib/router-utils/instrumentation-node-extensions.d.ts:\n Line 2: * This extension augments opentelemetry after registration if applicable.\n Line 5: export declare function afterRegistration(): void;\n\n/workspace/node_modules/next/dist/server/lib/incremental-cache/index.d.ts:\n Line 26: revalidateTag(_tags: string | string[], _durations?: {\n Line 67: revalidateTag(tags: string | string[], durations?: {\n\n/workspace/node_modules/next/dist/server/after/index.d.ts:\n Line 1: export * from './after';\n\n/workspace/node_modules/next/dist/server/web/exports/index.d.ts:\n Line 6: export { after } from '../../after';\n\n/workspace/node_modules/next/dist/build/webpack/plugins/next-types-plugin/index.d.ts:\n Line 6: afterFiles: Rewrite[];\n\n/workspace/node_modules/next/dist/build/index.d.ts:\n Line 30: * - unstable_cache\n Line 180: afterFiles: Array;\n\n/workspace/node_modules/next/dist/shared/lib/html-context.shared-runtime.d.ts:\n Line 38: afterInteractive?: string[];\n\n/workspace/node_modules/next/dist/server/dev/hot-reloader-webpack.d.ts:\n Line 92: protected afterCompile(_multiCompiler: webpack.MultiCompiler): Promise;\n\n/workspace/node_modules/next/dist/server/dev/hot-reloader-rspack.d.ts:\n Line 18: * - Track successfully built page entries after each compilation\n Line 27: afterCompile(multiCompiler: MultiCompiler): Promise;\n\n/workspace/node_modules/next/dist/client/head-manager.d.ts:\n Line 11: * comparing it to `oldTag`, restoring it afterwards.\n\n/workspace/node_modules/next/dist/build/swc/generated-native.d.ts:\n Line 254: /** App-router page routes that should be built after non-deferred routes. */\n Line 490: * Intended to be called once at the end of a build, after `writeAllEntrypointsToDisk`. The\n Line 741: afterFiles: Array\n\n/workspace/node_modules/next/dist/esm/build/swc/generated-native.d.ts:\n Line 254: /** App-router page routes that should be built after non-deferred routes. */\n Line 490: * Intended to be called once at the end of a build, after `writeAllEntrypointsToDisk`. The\n Line 741: afterFiles: Array\n\n/workspace/node_modules/next/dist/server/lib/incremental-cache/file-system-cache.d.ts:\n Line 17: revalidateTag(tags: string | string[], durations?: {\n\n/workspace/node_modules/next/dist/server/lib/router-utils/filesystem.d.ts:\n Line 49: afterFiles: (Rewrite & {\n\n/workspace/node_modules/next/dist/server/node-environment-extensions/fast-set-immediate.external.d.ts:\n Line 7: * All calls captured in this way will be executed after the current task\n Line 8: * (after callbacks from `process.nextTick()`, microtasks, and nextTicks scheduled from microtasks).\n Line 66: * This should always be called a task after `DANGEROUSLY_runPendingImmediatesAfterCurrentTask`\n\n/workspace/node_modules/next/dist/server/web/spec-extension/fetch-event.d.ts:\n Line 1: import type { WaitUntil } from '../../after/builtin-request-context';\n\n/workspace/node_modules/next/dist/server/app-render/dynamic-rendering.d.ts:\n Line 13: * inside unstable_cache it can still be cached. This type of indication can be removed if we ever\n Line 19: * unstable_cache should error. If you want to use some dynamic data inside unstable_cache you should\n\n/workspace/node_modules/next/dist/shared/lib/router/utils/disable-smooth-scroll.d.ts:\n Line 3: * This css change will be reverted after the function finishes.\n\n/workspace/node_modules/next/dist/build/define-env.d.ts:\n Line 24: afterFiles: Rewrite[];\n\n(Results are truncated. Consider using a more specific path or pattern.)",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "pattern": "after|unstable_after|revalidateTag|unstable_cache|cache\\(",
+ "path": "/workspace/node_modules/next",
+ "include": "*.d.ts"
+ },
+ "output": "Found 100 matches\n/workspace/node_modules/next/dist/server/app-render/work-unit-async-storage.external.d.ts:\n Line 19: export type WorkUnitPhase = 'action' | 'render' | 'after';\n Line 141: * The render signal is aborted after React's `prerender` function is aborted\n Line 145: * 2. When the final prerender is aborted immediately after the prerender was\n Line 157: * are no longer in the prerender phase of rendering. Typically this is after\n Line 247: * `unstable_cache`, which doesn't carry root params. Currently, `\"use cache\"`\n Line 248: * inside `unstable_cache` is allowed, so this case must be handled. The error\n Line 282: * Always `undefined` for `unstable_cache` — root params are not available in\n Line 283: * this context. If a `\"use cache\"` function nested inside `unstable_cache`\n Line 290: * unstable_cache context. A cache store shadows an outer request store (if\n\n/workspace/node_modules/next/dist/server/app-render/work-async-storage.external.d.ts:\n Line 6: import type { AfterContext } from '../after/after-context';\n Line 39: readonly afterContext: AfterContext;\n Line 87: * `use-cache-probe-worker.ts`) to switch `cache()` into a one-shot fill\n Line 95: * Max wall time the probe fill may take. `cache()` enforces this with\n Line 124: * `React.cache()`.\n\n/workspace/node_modules/next/dist/server/app-render/vary-params.d.ts:\n Line 9: * during render. Call `finishTrackingVaryParams()` after rendering to resolve\n Line 65: * their final vary params. Call this after rendering is complete.\n\n/workspace/node_modules/next/dist/next-devtools/dev-overlay/hooks/use-delayed-render.d.ts:\n Line 9: * unmount of a React component until after a delay.\n\n/workspace/node_modules/next/dist/next-devtools/dev-overlay/hooks/use-debounced-value.d.ts:\n Line 15: * the returned value is updated only after `ms` has elapsed without further\n\n/workspace/node_modules/next/dist/server/use-cache/use-cache-wrapper.d.ts:\n Line 80: * Used to compute the specific cache key after generation completes.\n Line 88: * eagerly at that inner invocation's `cache()` entry. Used as `cause` for the\n Line 95: export declare function cache(kind: string, id: string, boundArgsLength: number, originalFn: (...args: unknown[]) => Promise, args: unknown[]): Promise;\n\n/workspace/node_modules/next/dist/server/use-cache/use-cache-errors.d.ts:\n Line 10: * life up to the outer cache. Constructed eagerly in `cache()` while the caller\n\n/workspace/node_modules/next/dist/server/response-cache/types.d.ts:\n Line 105: * timestamp in milliseconds to revalidate after\n Line 205: revalidateTag(tags: string | string[], durations?: {\n\n/workspace/node_modules/next/dist/server/web/spec-extension/unstable-cache.d.ts:\n Line 5: * Read more: [Next.js Docs: `unstable_cache`](https://nextjs.org/docs/app/api-reference/functions/unstable_cache)\n Line 7: export declare function unstable_cache(cb: T, keyParts?: string[], options?: {\n\n/workspace/node_modules/next/dist/build/swc/types.d.ts:\n Line 236: * end of the build, after `writeAllEntrypointsToDisk`. The Rust implementation\n\n/workspace/node_modules/next/dist/server/app-render/stale-time.d.ts:\n Line 25: * each update (after applying selectStaleTime) through the iterable. This\n\n/workspace/node_modules/next/server.d.ts:\n Line 21: export { after } from 'next/dist/server/after'\n\n/workspace/node_modules/next/dist/client/components/router-reducer/set-cache-busting-search-param.d.ts:\n Line 11: * URL after: https://example.com/path?query=1&_rsc=abc123\n Line 29: * URL after: https://example.com/path?query=1&_rsc=abc123\n\n/workspace/node_modules/next/dist/server/server-utils.d.ts:\n Line 22: afterFiles?: ReadonlyArray;\n\n/workspace/node_modules/next/dist/client/script.d.ts:\n Line 4: strategy?: 'afterInteractive' | 'lazyOnload' | 'beforeInteractive' | 'worker';\n\n/workspace/node_modules/next/dist/lib/scheduler.d.ts:\n Line 4: * Schedules a function to be called on the next tick after the other promises\n Line 25: * specific timing tricks to try to schedule work after React has rendered. This is especially\n\n/workspace/node_modules/next/dist/client/components/router-reducer/router-reducer-types.d.ts:\n Line 25: * Testing API to preserve prefetched data when refreshing after an MPA\n\n/workspace/node_modules/next/dist/client/components/segment-cache/scheduler.d.ts:\n Line 27: * does not support PPR after doing the initial route prefetch.\n Line 66: * They are reset after each iteration of the task queue.\n\n/workspace/node_modules/next/dist/server/after/run-with-after.d.ts:\n Line 1: import type { AfterContextOpts } from './after-context';\n\n/workspace/node_modules/next/dist/lib/route-pattern-normalizer.d.ts:\n Line 48: * Used by both server and client code to clean up parameters after route matching.\n\n/workspace/node_modules/next/dist/server/route-matcher-managers/route-matcher-manager.d.ts:\n Line 27: * Reloads the matchers from the providers. This should be done after all the\n\n/workspace/node_modules/next/dist/server/web/spec-extension/revalidate.d.ts:\n Line 11: * Read more: [Next.js Docs: `revalidateTag`](https://nextjs.org/docs/app/api-reference/functions/revalidateTag)\n Line 13: export declare function revalidateTag(tag: string, profile: string | CacheLifeConfig): undefined;\n\n/workspace/node_modules/next/dist/shared/lib/router/utils/resolve-rewrites.d.ts:\n Line 8: afterFiles: Rewrite[];\n\n/workspace/node_modules/next/dist/server/request-meta.d.ts:\n Line 230: * The query after resolving routes\n Line 234: * The params after resolving routes\n Line 263: * DEV only: Server action log info to be logged after the request log\n\n/workspace/node_modules/next/dist/server/render-result.d.ts:\n Line 133: * will be piped one after the other.\n Line 142: * one after the other.\n\n/workspace/node_modules/next/dist/client/lib/promise.d.ts:\n Line 1: /** Resolve a promise that times out after given amount of milliseconds. */\n\n/workspace/node_modules/next/dist/build/polyfills/polyfill-module.d.ts:\n Line 1: // imports polyfill from `@next/polyfill-module` after build.\n\n/workspace/node_modules/next/dist/esm/build/polyfills/polyfill-module.d.ts:\n Line 1: // imports polyfill from `@next/polyfill-module` after build.\n\n/workspace/node_modules/next/dist/client/components/segment-cache/optimistic-routes.d.ts:\n Line 20: * 1. discoverKnownRoute: Called after receiving a route tree from the server.\n Line 52: * Called after receiving a route tree from the server (initial load, navigation,\n\n/workspace/node_modules/next/dist/server/stream-utils/node-web-streams-helper.d.ts:\n Line 53: * Suffix to inject after the buffered data, but before the close tags.\n\n/workspace/node_modules/next/dist/server/web/spec-extension/adapters/next-request.d.ts:\n Line 24: * will \"close\" the readable stream and nothing fires after that).\n\n/workspace/node_modules/next/dist/server/next-server.d.ts:\n Line 17: import type { WaitUntil } from './after/builtin-request-context';\n\n/workspace/node_modules/next/dist/lib/multi-file-writer.d.ts:\n Line 4: * guarantees that all files will be written after their containing directory\n Line 29: * Appends a file to the writer to be written after its containing directory\n Line 30: * is created. The file writer should be awaited after all the files have been\n\n/workspace/node_modules/next/dist/server/route-modules/app-route/module.d.ts:\n Line 138: * Must be called after ensureUserland() has resolved so that _methods is\n\n/workspace/node_modules/next/dist/lib/metadata/types/metadata-types.d.ts:\n Line 51: unavailable_after?: string | undefined;\n\n/workspace/node_modules/next/dist/lib/metadata/types/metadata-interface.d.ts:\n Line 486: * ResolvedMetadataWithURLs represents the fully processed metadata after\n Line 543: * ResolvedMetadata represents the fully processed metadata after defaults are\n\n/workspace/node_modules/next/dist/server/lib/lru-cache.d.ts:\n Line 29: * Adds a node immediately after the head (marks as most recently used).\n\n/workspace/node_modules/next/dist/build/lockfile.d.ts:\n Line 44: * on Windows where it may take some time after process exit for the operating\n\n/workspace/node_modules/next/dist/lib/load-custom-routes.d.ts:\n Line 59: afterFiles: Rewrite[];\n\n/workspace/node_modules/next/dist/server/load-components.d.ts:\n Line 15: * This manifest prevents removing server rendered tags after client\n\n/workspace/node_modules/next/dist/next-devtools/dev-overlay/components/instant-navs/instant-nav-cookie.d.ts:\n Line 9: * The \"to\" tree may be null initially and updated after the prefetch resolves.\n\n/workspace/node_modules/next/dist/server/lib/install-code-frame.d.ts:\n Line 5: * Should be called early in dev/build initialization, after native bindings are loaded.\n\n/workspace/node_modules/next/dist/server/lib/router-utils/instrumentation-node-extensions.d.ts:\n Line 2: * This extension augments opentelemetry after registration if applicable.\n Line 5: export declare function afterRegistration(): void;\n\n/workspace/node_modules/next/dist/server/lib/incremental-cache/index.d.ts:\n Line 26: revalidateTag(_tags: string | string[], _durations?: {\n Line 67: revalidateTag(tags: string | string[], durations?: {\n\n/workspace/node_modules/next/dist/server/after/index.d.ts:\n Line 1: export * from './after';\n\n/workspace/node_modules/next/dist/server/web/exports/index.d.ts:\n Line 6: export { after } from '../../after';\n\n/workspace/node_modules/next/dist/build/webpack/plugins/next-types-plugin/index.d.ts:\n Line 6: afterFiles: Rewrite[];\n\n/workspace/node_modules/next/dist/build/index.d.ts:\n Line 30: * - unstable_cache\n Line 180: afterFiles: Array;\n\n/workspace/node_modules/next/dist/shared/lib/html-context.shared-runtime.d.ts:\n Line 38: afterInteractive?: string[];\n\n/workspace/node_modules/next/dist/server/dev/hot-reloader-webpack.d.ts:\n Line 92: protected afterCompile(_multiCompiler: webpack.MultiCompiler): Promise;\n\n/workspace/node_modules/next/dist/server/dev/hot-reloader-rspack.d.ts:\n Line 18: * - Track successfully built page entries after each compilation\n Line 27: afterCompile(multiCompiler: MultiCompiler): Promise;\n\n/workspace/node_modules/next/dist/client/head-manager.d.ts:\n Line 11: * comparing it to `oldTag`, restoring it afterwards.\n\n/workspace/node_modules/next/dist/build/swc/generated-native.d.ts:\n Line 254: /** App-router page routes that should be built after non-deferred routes. */\n Line 490: * Intended to be called once at the end of a build, after `writeAllEntrypointsToDisk`. The\n Line 741: afterFiles: Array\n\n/workspace/node_modules/next/dist/esm/build/swc/generated-native.d.ts:\n Line 254: /** App-router page routes that should be built after non-deferred routes. */\n Line 490: * Intended to be called once at the end of a build, after `writeAllEntrypointsToDisk`. The\n Line 741: afterFiles: Array\n\n/workspace/node_modules/next/dist/server/lib/incremental-cache/file-system-cache.d.ts:\n Line 17: revalidateTag(tags: string | string[], durations?: {\n\n/workspace/node_modules/next/dist/server/lib/router-utils/filesystem.d.ts:\n Line 49: afterFiles: (Rewrite & {\n\n/workspace/node_modules/next/dist/server/node-environment-extensions/fast-set-immediate.external.d.ts:\n Line 7: * All calls captured in this way will be executed after the current task\n Line 8: * (after callbacks from `process.nextTick()`, microtasks, and nextTicks scheduled from microtasks).\n Line 66: * This should always be called a task after `DANGEROUSLY_runPendingImmediatesAfterCurrentTask`\n\n/workspace/node_modules/next/dist/server/web/spec-extension/fetch-event.d.ts:\n Line 1: import type { WaitUntil } from '../../after/builtin-request-context';\n\n/workspace/node_modules/next/dist/server/app-render/dynamic-rendering.d.ts:\n Line 13: * inside unstable_cache it can still be cached. This type of indication can be removed if we ever\n Line 19: * unstable_cache should error. If you want to use some dynamic data inside unstable_cache you should\n\n/workspace/node_modules/next/dist/shared/lib/router/utils/disable-smooth-scroll.d.ts:\n Line 3: * This css change will be reverted after the function finishes.\n\n/workspace/node_modules/next/dist/build/define-env.d.ts:\n Line 24: afterFiles: Rewrite[];\n\n(Results are truncated. Consider using a more specific path or pattern.)",
+ "title": "after|unstable_after|revalidateTag|unstable_cache|cache\\(",
+ "metadata": {
+ "matches": 100,
+ "truncated": true
+ },
+ "time": {
+ "start": 1781390469268,
+ "end": 1781390469335
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T22:41:12.350Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "args": {
+ "filePath": "/workspace/node_modules/next/dist/server/after/after.d.ts",
+ "_extractedPath": "/workspace/node_modules/next/dist/server/after/after.d.ts"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781390472350,
+ "sessionID": "ses_13cdaecaeffePMVRAqAFJ3Ea2y",
+ "part": {
+ "id": "prt_ec3257181001j1p4bEgTA2XNU4",
+ "sessionID": "ses_13cdaecaeffePMVRAqAFJ3Ea2y",
+ "messageID": "msg_ec32568e7001vOUFbadE7K4IxM",
+ "type": "tool",
+ "callID": "read_8",
+ "tool": "read",
+ "state": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/server/after/after.d.ts"
+ },
+ "output": "\n00001| export type AfterTask = Promise | AfterCallback;\n00002| export type AfterCallback = () => T | Promise;\n00003| /**\n00004| * This function allows you to schedule callbacks to be executed after the current request finishes.\n00005| */\n00006| export declare function after(task: AfterTask): void;\n00007| \n\n(End of file - total 7 lines)\n",
+ "title": "node_modules/next/dist/server/after/after.d.ts",
+ "metadata": {
+ "preview": "export type AfterTask = Promise | AfterCallback;\nexport type AfterCallback = () => T | Promise;\n/**\n * This function allows you to schedule callbacks to be executed after the current request finishes.\n */\nexport declare function after(task: AfterTask): void;\n"
+ },
+ "time": {
+ "start": 1781390472346,
+ "end": 1781390472349
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T22:41:12.350Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| export type AfterTask = Promise | AfterCallback;\n00002| export type AfterCallback = () => T | Promise;\n00003| /**\n00004| * This function allows you to schedule callbacks to be executed after the current request finishes.\n00005| */\n00006| export declare function after(task: AfterTask): void;\n00007| \n\n(End of file - total 7 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/server/after/after.d.ts"
+ },
+ "output": "\n00001| export type AfterTask = Promise | AfterCallback;\n00002| export type AfterCallback = () => T | Promise;\n00003| /**\n00004| * This function allows you to schedule callbacks to be executed after the current request finishes.\n00005| */\n00006| export declare function after(task: AfterTask): void;\n00007| \n\n(End of file - total 7 lines)\n",
+ "title": "node_modules/next/dist/server/after/after.d.ts",
+ "metadata": {
+ "preview": "export type AfterTask = Promise | AfterCallback;\nexport type AfterCallback = () => T | Promise;\n/**\n * This function allows you to schedule callbacks to be executed after the current request finishes.\n */\nexport declare function after(task: AfterTask): void;\n"
+ },
+ "time": {
+ "start": 1781390472346,
+ "end": 1781390472349
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T22:41:12.852Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "args": {
+ "filePath": "/workspace/node_modules/next/dist/server/web/spec-extension/unstable-cache.d.ts",
+ "_extractedPath": "/workspace/node_modules/next/dist/server/web/spec-extension/unstable-cache.d.ts"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781390472852,
+ "sessionID": "ses_13cdaecaeffePMVRAqAFJ3Ea2y",
+ "part": {
+ "id": "prt_ec325749c001bXTcRz9Ijaj50h",
+ "sessionID": "ses_13cdaecaeffePMVRAqAFJ3Ea2y",
+ "messageID": "msg_ec32568e7001vOUFbadE7K4IxM",
+ "type": "tool",
+ "callID": "read_9",
+ "tool": "read",
+ "state": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/server/web/spec-extension/unstable-cache.d.ts"
+ },
+ "output": "\n00001| type Callback = (...args: any[]) => Promise;\n00002| /**\n00003| * This function allows you to cache the results of expensive operations, like database queries, and reuse them across multiple requests.\n00004| *\n00005| * Read more: [Next.js Docs: `unstable_cache`](https://nextjs.org/docs/app/api-reference/functions/unstable_cache)\n00006| */\n00007| export declare function unstable_cache(cb: T, keyParts?: string[], options?: {\n00008| /**\n00009| * The revalidation interval in seconds.\n00010| */\n00011| revalidate?: number | false;\n00012| tags?: string[];\n00013| }): T;\n00014| export {};\n00015| \n\n(End of file - total 15 lines)\n",
+ "title": "node_modules/next/dist/server/web/spec-extension/unstable-cache.d.ts",
+ "metadata": {
+ "preview": "type Callback = (...args: any[]) => Promise;\n/**\n * This function allows you to cache the results of expensive operations, like database queries, and reuse them across multiple requests.\n *\n * Read more: [Next.js Docs: `unstable_cache`](https://nextjs.org/docs/app/api-reference/functions/unstable_cache)\n */\nexport declare function unstable_cache(cb: T, keyParts?: string[], options?: {\n /**\n * The revalidation interval in seconds.\n */\n revalidate?: number | false;\n tags?: string[];\n}): T;\nexport {};\n"
+ },
+ "time": {
+ "start": 1781390472848,
+ "end": 1781390472851
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T22:41:12.852Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| type Callback = (...args: any[]) => Promise;\n00002| /**\n00003| * This function allows you to cache the results of expensive operations, like database queries, and reuse them across multiple requests.\n00004| *\n00005| * Read more: [Next.js Docs: `unstable_cache`](https://nextjs.org/docs/app/api-reference/functions/unstable_cache)\n00006| */\n00007| export declare function unstable_cache(cb: T, keyParts?: string[], options?: {\n00008| /**\n00009| * The revalidation interval in seconds.\n00010| */\n00011| revalidate?: number | false;\n00012| tags?: string[];\n00013| }): T;\n00014| export {};\n00015| \n\n(End of file - total 15 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/server/web/spec-extension/unstable-cache.d.ts"
+ },
+ "output": "\n00001| type Callback = (...args: any[]) => Promise;\n00002| /**\n00003| * This function allows you to cache the results of expensive operations, like database queries, and reuse them across multiple requests.\n00004| *\n00005| * Read more: [Next.js Docs: `unstable_cache`](https://nextjs.org/docs/app/api-reference/functions/unstable_cache)\n00006| */\n00007| export declare function unstable_cache(cb: T, keyParts?: string[], options?: {\n00008| /**\n00009| * The revalidation interval in seconds.\n00010| */\n00011| revalidate?: number | false;\n00012| tags?: string[];\n00013| }): T;\n00014| export {};\n00015| \n\n(End of file - total 15 lines)\n",
+ "title": "node_modules/next/dist/server/web/spec-extension/unstable-cache.d.ts",
+ "metadata": {
+ "preview": "type Callback = (...args: any[]) => Promise;\n/**\n * This function allows you to cache the results of expensive operations, like database queries, and reuse them across multiple requests.\n *\n * Read more: [Next.js Docs: `unstable_cache`](https://nextjs.org/docs/app/api-reference/functions/unstable_cache)\n */\nexport declare function unstable_cache(cb: T, keyParts?: string[], options?: {\n /**\n * The revalidation interval in seconds.\n */\n revalidate?: number | false;\n tags?: string[];\n}): T;\nexport {};\n"
+ },
+ "time": {
+ "start": 1781390472848,
+ "end": 1781390472851
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T22:41:12.928Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "args": {
+ "filePath": "/workspace/node_modules/next/dist/server/web/spec-extension/revalidate.d.ts",
+ "_extractedPath": "/workspace/node_modules/next/dist/server/web/spec-extension/revalidate.d.ts"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781390472928,
+ "sessionID": "ses_13cdaecaeffePMVRAqAFJ3Ea2y",
+ "part": {
+ "id": "prt_ec32576920013DlO7V4yvpphv5",
+ "sessionID": "ses_13cdaecaeffePMVRAqAFJ3Ea2y",
+ "messageID": "msg_ec32568e7001vOUFbadE7K4IxM",
+ "type": "tool",
+ "callID": "read_10",
+ "tool": "read",
+ "state": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/server/web/spec-extension/revalidate.d.ts"
+ },
+ "output": "\n00001| type CacheLifeConfig = {\n00002| expire?: number;\n00003| };\n00004| /**\n00005| * This function allows you to purge [cached data](https://nextjs.org/docs/app/building-your-application/caching) on-demand for a specific cache tag.\n00006| *\n00007| * The second argument specifies a [`cacheLife`](https://nextjs.org/docs/app/api-reference/functions/cacheLife#reference) profile\n00008| * (e.g. `\"max\"`), or a `{ expire }` object. For immediate expiration in Server Actions, use\n00009| * [`updateTag`](https://nextjs.org/docs/app/api-reference/functions/updateTag) instead.\n00010| *\n00011| * Read more: [Next.js Docs: `revalidateTag`](https://nextjs.org/docs/app/api-reference/functions/revalidateTag)\n00012| */\n00013| export declare function revalidateTag(tag: string, profile: string | CacheLifeConfig): undefined;\n00014| /**\n00015| * This function allows you to update [cached data](https://nextjs.org/docs/app/building-your-application/caching) on-demand for a specific cache tag.\n00016| * This can only be called from within a Server Action to enable read-your-own-writes semantics.\n00017| *\n00018| * Read more: [Next.js Docs: `updateTag`](https://nextjs.org/docs/app/api-reference/functions/updateTag)\n00019| */\n00020| export declare function updateTag(tag: string): undefined;\n00021| /**\n00022| * This function allows you to refresh client cache from server actions.\n00023| * It's useful as dynamic data can be cached on the client which won't\n00024| * be refreshed by updateTag\n00025| */\n00026| export declare function refresh(): void;\n00027| /**\n00028| * This function allows you to purge [cached data](https://nextjs.org/docs/app/building-your-application/caching) on-demand for a specific path.\n00029| *\n00030| * Read more: [Next.js Docs: `revalidatePath`](https://nextjs.org/docs/app/api-reference/functions/revalidatePath)\n00031| */\n00032| export declare function revalidatePath(originalPath: string, type?: 'layout' | 'page'): undefined;\n00033| export {};\n00034| \n\n(End of file - total 34 lines)\n",
+ "title": "node_modules/next/dist/server/web/spec-extension/revalidate.d.ts",
+ "metadata": {
+ "preview": "type CacheLifeConfig = {\n expire?: number;\n};\n/**\n * This function allows you to purge [cached data](https://nextjs.org/docs/app/building-your-application/caching) on-demand for a specific cache tag.\n *\n * The second argument specifies a [`cacheLife`](https://nextjs.org/docs/app/api-reference/functions/cacheLife#reference) profile\n * (e.g. `\"max\"`), or a `{ expire }` object. For immediate expiration in Server Actions, use\n * [`updateTag`](https://nextjs.org/docs/app/api-reference/functions/updateTag) instead.\n *\n * Read more: [Next.js Docs: `revalidateTag`](https://nextjs.org/docs/app/api-reference/functions/revalidateTag)\n */\nexport declare function revalidateTag(tag: string, profile: string | CacheLifeConfig): undefined;\n/**\n * This function allows you to update [cached data](https://nextjs.org/docs/app/building-your-application/caching) on-demand for a specific cache tag.\n * This can only be called from within a Server Action to enable read-your-own-writes semantics.\n *\n * Read more: [Next.js Docs: `updateTag`](https://nextjs.org/docs/app/api-reference/functions/updateTag)\n */\nexport declare function updateTag(tag: string): undefined;"
+ },
+ "time": {
+ "start": 1781390472921,
+ "end": 1781390472924
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T22:41:12.928Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| type CacheLifeConfig = {\n00002| expire?: number;\n00003| };\n00004| /**\n00005| * This function allows you to purge [cached data](https://nextjs.org/docs/app/building-your-application/caching) on-demand for a specific cache tag.\n00006| *\n00007| * The second argument specifies a [`cacheLife`](https://nextjs.org/docs/app/api-reference/functions/cacheLife#reference) profile\n00008| * (e.g. `\"max\"`), or a `{ expire }` object. For immediate expiration in Server Actions, use\n00009| * [`updateTag`](https://nextjs.org/docs/app/api-reference/functions/updateTag) instead.\n00010| *\n00011| * Read more: [Next.js Docs: `revalidateTag`](https://nextjs.org/docs/app/api-reference/functions/revalidateTag)\n00012| */\n00013| export declare function revalidateTag(tag: string, profile: string | CacheLifeConfig): undefined;\n00014| /**\n00015| * This function allows you to update [cached data](https://nextjs.org/docs/app/building-your-application/caching) on-demand for a specific cache tag.\n00016| * This can only be called from within a Server Action to enable read-your-own-writes semantics.\n00017| *\n00018| * Read more: [Next.js Docs: `updateTag`](https://nextjs.org/docs/app/api-reference/functions/updateTag)\n00019| */\n00020| export declare function updateTag(tag: string): undefined;\n00021| /**\n00022| * This function allows you to refresh client cache from server actions.\n00023| * It's useful as dynamic data can be cached on the client which won't\n00024| * be refreshed by updateTag\n00025| */\n00026| export declare function refresh(): void;\n00027| /**\n00028| * This function allows you to purge [cached data](https://nextjs.org/docs/app/building-your-application/caching) on-demand for a specific path.\n00029| *\n00030| * Read more: [Next.js Docs: `revalidatePath`](https://nextjs.org/docs/app/api-reference/functions/revalidatePath)\n00031| */\n00032| export declare function revalidatePath(originalPath: string, type?: 'layout' | 'page'): undefined;\n00033| export {};\n00034| \n\n(End of file - total 34 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/dist/server/web/spec-extension/revalidate.d.ts"
+ },
+ "output": "\n00001| type CacheLifeConfig = {\n00002| expire?: number;\n00003| };\n00004| /**\n00005| * This function allows you to purge [cached data](https://nextjs.org/docs/app/building-your-application/caching) on-demand for a specific cache tag.\n00006| *\n00007| * The second argument specifies a [`cacheLife`](https://nextjs.org/docs/app/api-reference/functions/cacheLife#reference) profile\n00008| * (e.g. `\"max\"`), or a `{ expire }` object. For immediate expiration in Server Actions, use\n00009| * [`updateTag`](https://nextjs.org/docs/app/api-reference/functions/updateTag) instead.\n00010| *\n00011| * Read more: [Next.js Docs: `revalidateTag`](https://nextjs.org/docs/app/api-reference/functions/revalidateTag)\n00012| */\n00013| export declare function revalidateTag(tag: string, profile: string | CacheLifeConfig): undefined;\n00014| /**\n00015| * This function allows you to update [cached data](https://nextjs.org/docs/app/building-your-application/caching) on-demand for a specific cache tag.\n00016| * This can only be called from within a Server Action to enable read-your-own-writes semantics.\n00017| *\n00018| * Read more: [Next.js Docs: `updateTag`](https://nextjs.org/docs/app/api-reference/functions/updateTag)\n00019| */\n00020| export declare function updateTag(tag: string): undefined;\n00021| /**\n00022| * This function allows you to refresh client cache from server actions.\n00023| * It's useful as dynamic data can be cached on the client which won't\n00024| * be refreshed by updateTag\n00025| */\n00026| export declare function refresh(): void;\n00027| /**\n00028| * This function allows you to purge [cached data](https://nextjs.org/docs/app/building-your-application/caching) on-demand for a specific path.\n00029| *\n00030| * Read more: [Next.js Docs: `revalidatePath`](https://nextjs.org/docs/app/api-reference/functions/revalidatePath)\n00031| */\n00032| export declare function revalidatePath(originalPath: string, type?: 'layout' | 'page'): undefined;\n00033| export {};\n00034| \n\n(End of file - total 34 lines)\n",
+ "title": "node_modules/next/dist/server/web/spec-extension/revalidate.d.ts",
+ "metadata": {
+ "preview": "type CacheLifeConfig = {\n expire?: number;\n};\n/**\n * This function allows you to purge [cached data](https://nextjs.org/docs/app/building-your-application/caching) on-demand for a specific cache tag.\n *\n * The second argument specifies a [`cacheLife`](https://nextjs.org/docs/app/api-reference/functions/cacheLife#reference) profile\n * (e.g. `\"max\"`), or a `{ expire }` object. For immediate expiration in Server Actions, use\n * [`updateTag`](https://nextjs.org/docs/app/api-reference/functions/updateTag) instead.\n *\n * Read more: [Next.js Docs: `revalidateTag`](https://nextjs.org/docs/app/api-reference/functions/revalidateTag)\n */\nexport declare function revalidateTag(tag: string, profile: string | CacheLifeConfig): undefined;\n/**\n * This function allows you to update [cached data](https://nextjs.org/docs/app/building-your-application/caching) on-demand for a specific cache tag.\n * This can only be called from within a Server Action to enable read-your-own-writes semantics.\n *\n * Read more: [Next.js Docs: `updateTag`](https://nextjs.org/docs/app/api-reference/functions/updateTag)\n */\nexport declare function updateTag(tag: string): undefined;"
+ },
+ "time": {
+ "start": 1781390472921,
+ "end": 1781390472924
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T22:41:41.242Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "glob",
+ "originalName": "glob",
+ "args": {
+ "pattern": "**/*.test.*"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781390501242,
+ "sessionID": "ses_13cdaecaeffePMVRAqAFJ3Ea2y",
+ "part": {
+ "id": "prt_ec325e49c001DZQZ27QAoOR6fz",
+ "sessionID": "ses_13cdaecaeffePMVRAqAFJ3Ea2y",
+ "messageID": "msg_ec32576ee001573SGft7nXfzff",
+ "type": "tool",
+ "callID": "glob_11",
+ "tool": "glob",
+ "state": {
+ "status": "completed",
+ "input": {
+ "pattern": "**/*.test.*"
+ },
+ "output": "No files found",
+ "title": "",
+ "metadata": {
+ "count": 0,
+ "truncated": false
+ },
+ "time": {
+ "start": 1781390501235,
+ "end": 1781390501241
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T22:41:41.242Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "glob",
+ "originalName": "glob",
+ "result": "No files found",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "pattern": "**/*.test.*"
+ },
+ "output": "No files found",
+ "title": "",
+ "metadata": {
+ "count": 0,
+ "truncated": false
+ },
+ "time": {
+ "start": 1781390501235,
+ "end": 1781390501241
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T22:41:41.566Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "glob",
+ "originalName": "glob",
+ "args": {
+ "pattern": "**/*.spec.*"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781390501566,
+ "sessionID": "ses_13cdaecaeffePMVRAqAFJ3Ea2y",
+ "part": {
+ "id": "prt_ec325e5750012TFU9rTFEhFM0L",
+ "sessionID": "ses_13cdaecaeffePMVRAqAFJ3Ea2y",
+ "messageID": "msg_ec32576ee001573SGft7nXfzff",
+ "type": "tool",
+ "callID": "glob_12",
+ "tool": "glob",
+ "state": {
+ "status": "completed",
+ "input": {
+ "pattern": "**/*.spec.*"
+ },
+ "output": "No files found",
+ "title": "",
+ "metadata": {
+ "count": 0,
+ "truncated": false
+ },
+ "time": {
+ "start": 1781390501560,
+ "end": 1781390501565
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T22:41:41.566Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "glob",
+ "originalName": "glob",
+ "result": "No files found",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "pattern": "**/*.spec.*"
+ },
+ "output": "No files found",
+ "title": "",
+ "metadata": {
+ "count": 0,
+ "truncated": false
+ },
+ "time": {
+ "start": 1781390501560,
+ "end": 1781390501565
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T22:41:41.569Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "glob",
+ "originalName": "glob",
+ "args": {
+ "pattern": "**/e2e/**"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781390501569,
+ "sessionID": "ses_13cdaecaeffePMVRAqAFJ3Ea2y",
+ "part": {
+ "id": "prt_ec325e6bb001LxFZR6v5leRXT5",
+ "sessionID": "ses_13cdaecaeffePMVRAqAFJ3Ea2y",
+ "messageID": "msg_ec32576ee001573SGft7nXfzff",
+ "type": "tool",
+ "callID": "glob_13",
+ "tool": "glob",
+ "state": {
+ "status": "completed",
+ "input": {
+ "pattern": "**/e2e/**"
+ },
+ "output": "No files found",
+ "title": "",
+ "metadata": {
+ "count": 0,
+ "truncated": false
+ },
+ "time": {
+ "start": 1781390501564,
+ "end": 1781390501567
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T22:41:41.569Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "glob",
+ "originalName": "glob",
+ "result": "No files found",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "pattern": "**/e2e/**"
+ },
+ "output": "No files found",
+ "title": "",
+ "metadata": {
+ "count": 0,
+ "truncated": false
+ },
+ "time": {
+ "start": 1781390501564,
+ "end": 1781390501567
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T22:42:17.213Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "args": {
+ "filePath": "/workspace/node_modules/next/cache.d.ts",
+ "_extractedPath": "/workspace/node_modules/next/cache.d.ts"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781390537213,
+ "sessionID": "ses_13cdaecaeffePMVRAqAFJ3Ea2y",
+ "part": {
+ "id": "prt_ec32670ba0016CJVYjk6mwk1My",
+ "sessionID": "ses_13cdaecaeffePMVRAqAFJ3Ea2y",
+ "messageID": "msg_ec325e6ce001v0pA6O0RTcQ9UG",
+ "type": "tool",
+ "callID": "read_14",
+ "tool": "read",
+ "state": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/cache.d.ts"
+ },
+ "output": "\n00001| export { unstable_cache } from 'next/dist/server/web/spec-extension/unstable-cache'\n00002| \n00003| export {\n00004| revalidatePath,\n00005| revalidateTag,\n00006| updateTag,\n00007| refresh,\n00008| } from 'next/dist/server/web/spec-extension/revalidate'\n00009| \n00010| export { unstable_noStore } from 'next/dist/server/web/spec-extension/unstable-no-store'\n00011| \n00012| export { io } from 'next/dist/server/request/io'\n00013| \n00014| import { cacheTag } from 'next/dist/server/use-cache/cache-tag'\n00015| \n00016| export { cacheTag }\n00017| \n00018| /**\n00019| * Cache this `\"use cache\"` for a timespan defined by the `\"default\"` profile.\n00020| * ```\n00021| * stale: 300 seconds (5 minutes)\n00022| * revalidate: 900 seconds (15 minutes)\n00023| * expire: never\n00024| * ```\n00025| *\n00026| * This cache may be stale on clients for 5 minutes before checking with the server.\n00027| * If the server receives a new request after 15 minutes, start revalidating new values in the background.\n00028| * It lives for the maximum age of the server cache. If this entry has no traffic for a while, it may serve an old value the next request.\n00029| */\n00030| export function cacheLife(profile: 'default'): void\n00031| \n00032| /**\n00033| * Cache this `\"use cache\"` for a timespan defined by the `\"seconds\"` profile.\n00034| * ```\n00035| * stale: 30 seconds\n00036| * revalidate: 1 second\n00037| * expire: 1 minute\n00038| * ```\n00039| *\n00040| * This cache may be stale on clients for 30 seconds before checking with the server.\n00041| * If the server receives a new request after 1 second, start revalidating new values in the background.\n00042| * If this entry has no traffic for 1 minute it will expire. The next request will recompute it.\n00043| */\n00044| export function cacheLife(profile: 'seconds'): void\n00045| \n00046| /**\n00047| * Cache this `\"use cache\"` for a timespan defined by the `\"minutes\"` profile.\n00048| * ```\n00049| * stale: 300 seconds (5 minutes)\n00050| * revalidate: 60 seconds (1 minute)\n00051| * expire: 3600 seconds (1 hour)\n00052| * ```\n00053| *\n00054| * This cache may be stale on clients for 5 minutes before checking with the server.\n00055| * If the server receives a new request after 1 minute, start revalidating new values in the background.\n00056| * If this entry has no traffic for 1 hour it will expire. The next request will recompute it.\n00057| */\n00058| export function cacheLife(profile: 'minutes'): void\n00059| \n00060| /**\n00061| * Cache this `\"use cache\"` for a timespan defined by the `\"hours\"` profile.\n00062| * ```\n00063| * stale: 300 seconds (5 minutes)\n00064| * revalidate: 3600 seconds (1 hour)\n00065| * expire: 86400 seconds (1 day)\n00066| * ```\n00067| *\n00068| * This cache may be stale on clients for 5 minutes before checking with the server.\n00069| * If the server receives a new request after 1 hour, start revalidating new values in the background.\n00070| * If this entry has no traffic for 1 day it will expire. The next request will recompute it.\n00071| */\n00072| export function cacheLife(profile: 'hours'): void\n00073| \n00074| /**\n00075| * Cache this `\"use cache\"` for a timespan defined by the `\"days\"` profile.\n00076| * ```\n00077| * stale: 300 seconds (5 minutes)\n00078| * revalidate: 86400 seconds (1 day)\n00079| * expire: 604800 seconds (1 week)\n00080| * ```\n00081| *\n00082| * This cache may be stale on clients for 5 minutes before checking with the server.\n00083| * If the server receives a new request after 1 day, start revalidating new values in the background.\n00084| * If this entry has no traffic for 1 week it will expire. The next request will recompute it.\n00085| */\n00086| export function cacheLife(profile: 'days'): void\n00087| \n00088| /**\n00089| * Cache this `\"use cache\"` for a timespan defined by the `\"weeks\"` profile.\n00090| * ```\n00091| * stale: 300 seconds (5 minutes)\n00092| * revalidate: 604800 seconds (1 week)\n00093| * expire: 2592000 seconds (30 days)\n00094| * ```\n00095| *\n00096| * This cache may be stale on clients for 5 minutes before checking with the server.\n00097| * If the server receives a new request after 1 week, start revalidating new values in the background.\n00098| * If this entry has no traffic for 30 days it will expire. The next request will recompute it.\n00099| */\n00100| export function cacheLife(profile: 'weeks'): void\n00101| \n00102| /**\n00103| * Cache this `\"use cache\"` for a timespan defined by the `\"max\"` profile.\n00104| * ```\n00105| * stale: 300 seconds (5 minutes)\n00106| * revalidate: 2592000 seconds (30 days)\n00107| * expire: never\n00108| * ```\n00109| *\n00110| * This cache may be stale on clients for 5 minutes before checking with the server.\n00111| * If the server receives a new request after 30 days, start revalidating new values in the background.\n00112| * It lives for the maximum age of the server cache. If this entry has no traffic for a while, it may serve an old value the next request.\n00113| */\n00114| export function cacheLife(profile: 'max'): void\n00115| \n00116| /**\n00117| * Cache this `\"use cache\"` using a custom profile \"...\".\n00118| * ```\n00119| * stale: ... // seconds\n00120| * revalidate: ... // seconds\n00121| * expire: ... // seconds\n00122| * ```\n00123| *\n00124| * You can define custom profiles in `next.config.ts`.\n00125| */\n00126| export function cacheLife(profile: string): void\n00127| \n00128| /**\n00129| * Cache this `\"use cache\"` using a custom timespan.\n00130| * ```\n00131| * stale: ... // seconds\n00132| * revalidate: ... // seconds\n00133| * expire: ... // seconds\n00134| * ```\n00135| *\n00136| * This is similar to Cache-Control: max-age=`stale`,s-max-age=`revalidate`,stale-while-revalidate=`expire-revalidate`\n00137| *\n00138| * If a value is left out, the lowest of other cacheLife() calls or the default, is used instead.\n00139| */\n00140| export function cacheLife(profile: {\n00141| /**\n00142| * This cache may be stale on clients for ... seconds before checking with the server.\n00143| */\n00144| stale?: number\n00145| /**\n00146| * If the server receives a new request after ... seconds, start revalidating new values in the background.\n00147| */\n00148| revalidate?: number\n00149| /**\n00150| * If this entry has no traffic for ... seconds it will expire. The next request will recompute it.\n00151| */\n00152| expire?: number\n00153| }): void\n00154| \n00155| export const unstable_cacheLife: typeof cacheLife\n00156| export const unstable_cacheTag: typeof cacheTag\n00157| \n\n(End of file - total 157 lines)\n",
+ "title": "node_modules/next/cache.d.ts",
+ "metadata": {
+ "preview": "export { unstable_cache } from 'next/dist/server/web/spec-extension/unstable-cache'\n\nexport {\n revalidatePath,\n revalidateTag,\n updateTag,\n refresh,\n} from 'next/dist/server/web/spec-extension/revalidate'\n\nexport { unstable_noStore } from 'next/dist/server/web/spec-extension/unstable-no-store'\n\nexport { io } from 'next/dist/server/request/io'\n\nimport { cacheTag } from 'next/dist/server/use-cache/cache-tag'\n\nexport { cacheTag }\n\n/**\n * Cache this `\"use cache\"` for a timespan defined by the `\"default\"` profile.\n * ```"
+ },
+ "time": {
+ "start": 1781390537209,
+ "end": 1781390537212
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T22:42:17.213Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| export { unstable_cache } from 'next/dist/server/web/spec-extension/unstable-cache'\n00002| \n00003| export {\n00004| revalidatePath,\n00005| revalidateTag,\n00006| updateTag,\n00007| refresh,\n00008| } from 'next/dist/server/web/spec-extension/revalidate'\n00009| \n00010| export { unstable_noStore } from 'next/dist/server/web/spec-extension/unstable-no-store'\n00011| \n00012| export { io } from 'next/dist/server/request/io'\n00013| \n00014| import { cacheTag } from 'next/dist/server/use-cache/cache-tag'\n00015| \n00016| export { cacheTag }\n00017| \n00018| /**\n00019| * Cache this `\"use cache\"` for a timespan defined by the `\"default\"` profile.\n00020| * ```\n00021| * stale: 300 seconds (5 minutes)\n00022| * revalidate: 900 seconds (15 minutes)\n00023| * expire: never\n00024| * ```\n00025| *\n00026| * This cache may be stale on clients for 5 minutes before checking with the server.\n00027| * If the server receives a new request after 15 minutes, start revalidating new values in the background.\n00028| * It lives for the maximum age of the server cache. If this entry has no traffic for a while, it may serve an old value the next request.\n00029| */\n00030| export function cacheLife(profile: 'default'): void\n00031| \n00032| /**\n00033| * Cache this `\"use cache\"` for a timespan defined by the `\"seconds\"` profile.\n00034| * ```\n00035| * stale: 30 seconds\n00036| * revalidate: 1 second\n00037| * expire: 1 minute\n00038| * ```\n00039| *\n00040| * This cache may be stale on clients for 30 seconds before checking with the server.\n00041| * If the server receives a new request after 1 second, start revalidating new values in the background.\n00042| * If this entry has no traffic for 1 minute it will expire. The next request will recompute it.\n00043| */\n00044| export function cacheLife(profile: 'seconds'): void\n00045| \n00046| /**\n00047| * Cache this `\"use cache\"` for a timespan defined by the `\"minutes\"` profile.\n00048| * ```\n00049| * stale: 300 seconds (5 minutes)\n00050| * revalidate: 60 seconds (1 minute)\n00051| * expire: 3600 seconds (1 hour)\n00052| * ```\n00053| *\n00054| * This cache may be stale on clients for 5 minutes before checking with the server.\n00055| * If the server receives a new request after 1 minute, start revalidating new values in the background.\n00056| * If this entry has no traffic for 1 hour it will expire. The next request will recompute it.\n00057| */\n00058| export function cacheLife(profile: 'minutes'): void\n00059| \n00060| /**\n00061| * Cache this `\"use cache\"` for a timespan defined by the `\"hours\"` profile.\n00062| * ```\n00063| * stale: 300 seconds (5 minutes)\n00064| * revalidate: 3600 seconds (1 hour)\n00065| * expire: 86400 seconds (1 day)\n00066| * ```\n00067| *\n00068| * This cache may be stale on clients for 5 minutes before checking with the server.\n00069| * If the server receives a new request after 1 hour, start revalidating new values in the background.\n00070| * If this entry has no traffic for 1 day it will expire. The next request will recompute it.\n00071| */\n00072| export function cacheLife(profile: 'hours'): void\n00073| \n00074| /**\n00075| * Cache this `\"use cache\"` for a timespan defined by the `\"days\"` profile.\n00076| * ```\n00077| * stale: 300 seconds (5 minutes)\n00078| * revalidate: 86400 seconds (1 day)\n00079| * expire: 604800 seconds (1 week)\n00080| * ```\n00081| *\n00082| * This cache may be stale on clients for 5 minutes before checking with the server.\n00083| * If the server receives a new request after 1 day, start revalidating new values in the background.\n00084| * If this entry has no traffic for 1 week it will expire. The next request will recompute it.\n00085| */\n00086| export function cacheLife(profile: 'days'): void\n00087| \n00088| /**\n00089| * Cache this `\"use cache\"` for a timespan defined by the `\"weeks\"` profile.\n00090| * ```\n00091| * stale: 300 seconds (5 minutes)\n00092| * revalidate: 604800 seconds (1 week)\n00093| * expire: 2592000 seconds (30 days)\n00094| * ```\n00095| *\n00096| * This cache may be stale on clients for 5 minutes before checking with the server.\n00097| * If the server receives a new request after 1 week, start revalidating new values in the background.\n00098| * If this entry has no traffic for 30 days it will expire. The next request will recompute it.\n00099| */\n00100| export function cacheLife(profile: 'weeks'): void\n00101| \n00102| /**\n00103| * Cache this `\"use cache\"` for a timespan defined by the `\"max\"` profile.\n00104| * ```\n00105| * stale: 300 seconds (5 minutes)\n00106| * revalidate: 2592000 seconds (30 days)\n00107| * expire: never\n00108| * ```\n00109| *\n00110| * This cache may be stale on clients for 5 minutes before checking with the server.\n00111| * If the server receives a new request after 30 days, start revalidating new values in the background.\n00112| * It lives for the maximum age of the server cache. If this entry has no traffic for a while, it may serve an old value the next request.\n00113| */\n00114| export function cacheLife(profile: 'max'): void\n00115| \n00116| /**\n00117| * Cache this `\"use cache\"` using a custom profile \"...\".\n00118| * ```\n00119| * stale: ... // seconds\n00120| * revalidate: ... // seconds\n00121| * expire: ... // seconds\n00122| * ```\n00123| *\n00124| * You can define custom profiles in `next.config.ts`.\n00125| */\n00126| export function cacheLife(profile: string): void\n00127| \n00128| /**\n00129| * Cache this `\"use cache\"` using a custom timespan.\n00130| * ```\n00131| * stale: ... // seconds\n00132| * revalidate: ... // seconds\n00133| * expire: ... // seconds\n00134| * ```\n00135| *\n00136| * This is similar to Cache-Control: max-age=`stale`,s-max-age=`revalidate`,stale-while-revalidate=`expire-revalidate`\n00137| *\n00138| * If a value is left out, the lowest of other cacheLife() calls or the default, is used instead.\n00139| */\n00140| export function cacheLife(profile: {\n00141| /**\n00142| * This cache may be stale on clients for ... seconds before checking with the server.\n00143| */\n00144| stale?: number\n00145| /**\n00146| * If the server receives a new request after ... seconds, start revalidating new values in the background.\n00147| */\n00148| revalidate?: number\n00149| /**\n00150| * If this entry has no traffic for ... seconds it will expire. The next request will recompute it.\n00151| */\n00152| expire?: number\n00153| }): void\n00154| \n00155| export const unstable_cacheLife: typeof cacheLife\n00156| export const unstable_cacheTag: typeof cacheTag\n00157| \n\n(End of file - total 157 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/node_modules/next/cache.d.ts"
+ },
+ "output": "\n00001| export { unstable_cache } from 'next/dist/server/web/spec-extension/unstable-cache'\n00002| \n00003| export {\n00004| revalidatePath,\n00005| revalidateTag,\n00006| updateTag,\n00007| refresh,\n00008| } from 'next/dist/server/web/spec-extension/revalidate'\n00009| \n00010| export { unstable_noStore } from 'next/dist/server/web/spec-extension/unstable-no-store'\n00011| \n00012| export { io } from 'next/dist/server/request/io'\n00013| \n00014| import { cacheTag } from 'next/dist/server/use-cache/cache-tag'\n00015| \n00016| export { cacheTag }\n00017| \n00018| /**\n00019| * Cache this `\"use cache\"` for a timespan defined by the `\"default\"` profile.\n00020| * ```\n00021| * stale: 300 seconds (5 minutes)\n00022| * revalidate: 900 seconds (15 minutes)\n00023| * expire: never\n00024| * ```\n00025| *\n00026| * This cache may be stale on clients for 5 minutes before checking with the server.\n00027| * If the server receives a new request after 15 minutes, start revalidating new values in the background.\n00028| * It lives for the maximum age of the server cache. If this entry has no traffic for a while, it may serve an old value the next request.\n00029| */\n00030| export function cacheLife(profile: 'default'): void\n00031| \n00032| /**\n00033| * Cache this `\"use cache\"` for a timespan defined by the `\"seconds\"` profile.\n00034| * ```\n00035| * stale: 30 seconds\n00036| * revalidate: 1 second\n00037| * expire: 1 minute\n00038| * ```\n00039| *\n00040| * This cache may be stale on clients for 30 seconds before checking with the server.\n00041| * If the server receives a new request after 1 second, start revalidating new values in the background.\n00042| * If this entry has no traffic for 1 minute it will expire. The next request will recompute it.\n00043| */\n00044| export function cacheLife(profile: 'seconds'): void\n00045| \n00046| /**\n00047| * Cache this `\"use cache\"` for a timespan defined by the `\"minutes\"` profile.\n00048| * ```\n00049| * stale: 300 seconds (5 minutes)\n00050| * revalidate: 60 seconds (1 minute)\n00051| * expire: 3600 seconds (1 hour)\n00052| * ```\n00053| *\n00054| * This cache may be stale on clients for 5 minutes before checking with the server.\n00055| * If the server receives a new request after 1 minute, start revalidating new values in the background.\n00056| * If this entry has no traffic for 1 hour it will expire. The next request will recompute it.\n00057| */\n00058| export function cacheLife(profile: 'minutes'): void\n00059| \n00060| /**\n00061| * Cache this `\"use cache\"` for a timespan defined by the `\"hours\"` profile.\n00062| * ```\n00063| * stale: 300 seconds (5 minutes)\n00064| * revalidate: 3600 seconds (1 hour)\n00065| * expire: 86400 seconds (1 day)\n00066| * ```\n00067| *\n00068| * This cache may be stale on clients for 5 minutes before checking with the server.\n00069| * If the server receives a new request after 1 hour, start revalidating new values in the background.\n00070| * If this entry has no traffic for 1 day it will expire. The next request will recompute it.\n00071| */\n00072| export function cacheLife(profile: 'hours'): void\n00073| \n00074| /**\n00075| * Cache this `\"use cache\"` for a timespan defined by the `\"days\"` profile.\n00076| * ```\n00077| * stale: 300 seconds (5 minutes)\n00078| * revalidate: 86400 seconds (1 day)\n00079| * expire: 604800 seconds (1 week)\n00080| * ```\n00081| *\n00082| * This cache may be stale on clients for 5 minutes before checking with the server.\n00083| * If the server receives a new request after 1 day, start revalidating new values in the background.\n00084| * If this entry has no traffic for 1 week it will expire. The next request will recompute it.\n00085| */\n00086| export function cacheLife(profile: 'days'): void\n00087| \n00088| /**\n00089| * Cache this `\"use cache\"` for a timespan defined by the `\"weeks\"` profile.\n00090| * ```\n00091| * stale: 300 seconds (5 minutes)\n00092| * revalidate: 604800 seconds (1 week)\n00093| * expire: 2592000 seconds (30 days)\n00094| * ```\n00095| *\n00096| * This cache may be stale on clients for 5 minutes before checking with the server.\n00097| * If the server receives a new request after 1 week, start revalidating new values in the background.\n00098| * If this entry has no traffic for 30 days it will expire. The next request will recompute it.\n00099| */\n00100| export function cacheLife(profile: 'weeks'): void\n00101| \n00102| /**\n00103| * Cache this `\"use cache\"` for a timespan defined by the `\"max\"` profile.\n00104| * ```\n00105| * stale: 300 seconds (5 minutes)\n00106| * revalidate: 2592000 seconds (30 days)\n00107| * expire: never\n00108| * ```\n00109| *\n00110| * This cache may be stale on clients for 5 minutes before checking with the server.\n00111| * If the server receives a new request after 30 days, start revalidating new values in the background.\n00112| * It lives for the maximum age of the server cache. If this entry has no traffic for a while, it may serve an old value the next request.\n00113| */\n00114| export function cacheLife(profile: 'max'): void\n00115| \n00116| /**\n00117| * Cache this `\"use cache\"` using a custom profile \"...\".\n00118| * ```\n00119| * stale: ... // seconds\n00120| * revalidate: ... // seconds\n00121| * expire: ... // seconds\n00122| * ```\n00123| *\n00124| * You can define custom profiles in `next.config.ts`.\n00125| */\n00126| export function cacheLife(profile: string): void\n00127| \n00128| /**\n00129| * Cache this `\"use cache\"` using a custom timespan.\n00130| * ```\n00131| * stale: ... // seconds\n00132| * revalidate: ... // seconds\n00133| * expire: ... // seconds\n00134| * ```\n00135| *\n00136| * This is similar to Cache-Control: max-age=`stale`,s-max-age=`revalidate`,stale-while-revalidate=`expire-revalidate`\n00137| *\n00138| * If a value is left out, the lowest of other cacheLife() calls or the default, is used instead.\n00139| */\n00140| export function cacheLife(profile: {\n00141| /**\n00142| * This cache may be stale on clients for ... seconds before checking with the server.\n00143| */\n00144| stale?: number\n00145| /**\n00146| * If the server receives a new request after ... seconds, start revalidating new values in the background.\n00147| */\n00148| revalidate?: number\n00149| /**\n00150| * If this entry has no traffic for ... seconds it will expire. The next request will recompute it.\n00151| */\n00152| expire?: number\n00153| }): void\n00154| \n00155| export const unstable_cacheLife: typeof cacheLife\n00156| export const unstable_cacheTag: typeof cacheTag\n00157| \n\n(End of file - total 157 lines)\n",
+ "title": "node_modules/next/cache.d.ts",
+ "metadata": {
+ "preview": "export { unstable_cache } from 'next/dist/server/web/spec-extension/unstable-cache'\n\nexport {\n revalidatePath,\n revalidateTag,\n updateTag,\n refresh,\n} from 'next/dist/server/web/spec-extension/revalidate'\n\nexport { unstable_noStore } from 'next/dist/server/web/spec-extension/unstable-no-store'\n\nexport { io } from 'next/dist/server/request/io'\n\nimport { cacheTag } from 'next/dist/server/use-cache/cache-tag'\n\nexport { cacheTag }\n\n/**\n * Cache this `\"use cache\"` for a timespan defined by the `\"default\"` profile.\n * ```"
+ },
+ "time": {
+ "start": 1781390537209,
+ "end": 1781390537212
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T22:42:18.130Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "shell",
+ "originalName": "bash",
+ "args": {
+ "command": "node -e \"const { revalidateTag } = require('next/cache'); console.log(revalidateTag.length)\"",
+ "workdir": "/workspace",
+ "description": "Check revalidateTag arity",
+ "_extractedCommand": "node -e \"const { revalidateTag } = require('next/cache'); console.log(revalidateTag.length)\""
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781390538130,
+ "sessionID": "ses_13cdaecaeffePMVRAqAFJ3Ea2y",
+ "part": {
+ "id": "prt_ec32671fb0018pw9tqvOR4Kp05",
+ "sessionID": "ses_13cdaecaeffePMVRAqAFJ3Ea2y",
+ "messageID": "msg_ec325e6ce001v0pA6O0RTcQ9UG",
+ "type": "tool",
+ "callID": "bash_15",
+ "tool": "bash",
+ "state": {
+ "status": "completed",
+ "input": {
+ "command": "node -e \"const { revalidateTag } = require('next/cache'); console.log(revalidateTag.length)\"",
+ "workdir": "/workspace",
+ "description": "Check revalidateTag arity"
+ },
+ "output": "2\n",
+ "title": "Check revalidateTag arity",
+ "metadata": {
+ "output": "2\n",
+ "exit": 0,
+ "description": "Check revalidateTag arity"
+ },
+ "time": {
+ "start": 1781390537977,
+ "end": 1781390538127
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T22:42:18.130Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "shell",
+ "originalName": "bash",
+ "result": "2\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "command": "node -e \"const { revalidateTag } = require('next/cache'); console.log(revalidateTag.length)\"",
+ "workdir": "/workspace",
+ "description": "Check revalidateTag arity"
+ },
+ "output": "2\n",
+ "title": "Check revalidateTag arity",
+ "metadata": {
+ "output": "2\n",
+ "exit": 0,
+ "description": "Check revalidateTag arity"
+ },
+ "time": {
+ "start": 1781390537977,
+ "end": 1781390538127
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T22:42:23.597Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "shell",
+ "originalName": "bash",
+ "args": {
+ "command": "node -e \"const { updateTag } = require('next/cache'); console.log(updateTag.length)\"",
+ "workdir": "/workspace",
+ "description": "Check updateTag arity",
+ "_extractedCommand": "node -e \"const { updateTag } = require('next/cache'); console.log(updateTag.length)\""
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781390543597,
+ "sessionID": "ses_13cdaecaeffePMVRAqAFJ3Ea2y",
+ "part": {
+ "id": "prt_ec32688390014sLzDWwtif1SLA",
+ "sessionID": "ses_13cdaecaeffePMVRAqAFJ3Ea2y",
+ "messageID": "msg_ec32675a4001v4uu5adGERecpf",
+ "type": "tool",
+ "callID": "bash_16",
+ "tool": "bash",
+ "state": {
+ "status": "completed",
+ "input": {
+ "command": "node -e \"const { updateTag } = require('next/cache'); console.log(updateTag.length)\"",
+ "workdir": "/workspace",
+ "description": "Check updateTag arity"
+ },
+ "output": "1\n",
+ "title": "Check updateTag arity",
+ "metadata": {
+ "output": "1\n",
+ "exit": 0,
+ "description": "Check updateTag arity"
+ },
+ "time": {
+ "start": 1781390543468,
+ "end": 1781390543595
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T22:42:23.597Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "shell",
+ "originalName": "bash",
+ "result": "1\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "command": "node -e \"const { updateTag } = require('next/cache'); console.log(updateTag.length)\"",
+ "workdir": "/workspace",
+ "description": "Check updateTag arity"
+ },
+ "output": "1\n",
+ "title": "Check updateTag arity",
+ "metadata": {
+ "output": "1\n",
+ "exit": 0,
+ "description": "Check updateTag arity"
+ },
+ "time": {
+ "start": 1781390543468,
+ "end": 1781390543595
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T22:42:28.464Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "shell",
+ "originalName": "bash",
+ "args": {
+ "command": "node -e \"const { revalidateTag } = require('next/cache'); try { revalidateTag('products'); console.log('ok'); } catch(e) { console.error(e.message); }\"",
+ "workdir": "/workspace",
+ "description": "Test revalidateTag with one arg",
+ "_extractedCommand": "node -e \"const { revalidateTag } = require('next/cache'); try { revalidateTag('products'); console.log('ok'); } catch(e) { console.error(e.message); }\""
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781390548464,
+ "sessionID": "ses_13cdaecaeffePMVRAqAFJ3Ea2y",
+ "part": {
+ "id": "prt_ec32699c60015MoW03xzcZfXwz",
+ "sessionID": "ses_13cdaecaeffePMVRAqAFJ3Ea2y",
+ "messageID": "msg_ec3268af7001X14tCDC4LEjMgt",
+ "type": "tool",
+ "callID": "bash_17",
+ "tool": "bash",
+ "state": {
+ "status": "completed",
+ "input": {
+ "command": "node -e \"const { revalidateTag } = require('next/cache'); try { revalidateTag('products'); console.log('ok'); } catch(e) { console.error(e.message); }\"",
+ "workdir": "/workspace",
+ "description": "Test revalidateTag with one arg"
+ },
+ "output": "\"revalidateTag\" without the second argument is now deprecated, add second argument of \"max\" or use \"updateTag\". See more info here: https://nextjs.org/docs/messages/revalidate-tag-single-arg\nInvariant: static generation store missing in revalidateTag products\n",
+ "title": "Test revalidateTag with one arg",
+ "metadata": {
+ "output": "\"revalidateTag\" without the second argument is now deprecated, add second argument of \"max\" or use \"updateTag\". See more info here: https://nextjs.org/docs/messages/revalidate-tag-single-arg\nInvariant: static generation store missing in revalidateTag products\n",
+ "exit": 0,
+ "description": "Test revalidateTag with one arg"
+ },
+ "time": {
+ "start": 1781390548340,
+ "end": 1781390548462
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T22:42:28.464Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "shell",
+ "originalName": "bash",
+ "result": "\"revalidateTag\" without the second argument is now deprecated, add second argument of \"max\" or use \"updateTag\". See more info here: https://nextjs.org/docs/messages/revalidate-tag-single-arg\nInvariant: static generation store missing in revalidateTag products\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "command": "node -e \"const { revalidateTag } = require('next/cache'); try { revalidateTag('products'); console.log('ok'); } catch(e) { console.error(e.message); }\"",
+ "workdir": "/workspace",
+ "description": "Test revalidateTag with one arg"
+ },
+ "output": "\"revalidateTag\" without the second argument is now deprecated, add second argument of \"max\" or use \"updateTag\". See more info here: https://nextjs.org/docs/messages/revalidate-tag-single-arg\nInvariant: static generation store missing in revalidateTag products\n",
+ "title": "Test revalidateTag with one arg",
+ "metadata": {
+ "output": "\"revalidateTag\" without the second argument is now deprecated, add second argument of \"max\" or use \"updateTag\". See more info here: https://nextjs.org/docs/messages/revalidate-tag-single-arg\nInvariant: static generation store missing in revalidateTag products\n",
+ "exit": 0,
+ "description": "Test revalidateTag with one arg"
+ },
+ "time": {
+ "start": 1781390548340,
+ "end": 1781390548462
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T22:42:44.828Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "unknown",
+ "originalName": "webfetch",
+ "args": {
+ "url": "https://nextjs.org/docs/app/api-reference/functions/after"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781390564828,
+ "sessionID": "ses_13cdaecaeffePMVRAqAFJ3Ea2y",
+ "part": {
+ "id": "prt_ec326dc0b001B9hmeazY2aE2OE",
+ "sessionID": "ses_13cdaecaeffePMVRAqAFJ3Ea2y",
+ "messageID": "msg_ec3269e00001tBMUt4VcJ7WttM",
+ "type": "tool",
+ "callID": "webfetch_18",
+ "tool": "webfetch",
+ "state": {
+ "status": "completed",
+ "input": {
+ "url": "https://nextjs.org/docs/app/api-reference/functions/after"
+ },
+ "output": "Functions: after | Next.jsSkip to content
after allows you to schedule work to be executed after a response (or prerender) is finished. This is useful for tasks and other side effects that should not block the response, such as logging and analytics.
The function accepts a callback that will be executed after the response (or prerender) is finished:
\n
app/layout.tsx
TypeScript
import { after } from 'next/server'\n// Custom logging function\nimport { log } from '@/app/utils'\n\nexport default function Layout({ children }: { children: React.ReactNode }) {\n after(() => {\n // Execute after the layout is rendered and sent to the user\n log()\n })\n return <>{children}</>\n}
\n\n
\n
Good to know:after is not a Request-time API and calling it does not cause a route to become dynamic. If it's used within a static page, the callback will execute at build time, or whenever a page is revalidated.
\n
\n
Reference
\n
Parameters
\n
\n
A callback function which will be executed after the response (or prerender) is finished.
\n
\n
Duration
\n
after will run for the platform's default or configured max duration of your route. If your platform supports it, you can configure the timeout limit using the maxDuration route segment config.
\n
Good to know
\n
\n
after will be executed even if the response didn't complete successfully. Including when an error is thrown or when notFound or redirect is called.
\n
You can use React cache to deduplicate functions called inside after.
\n
after can be nested inside other after calls, for example, you can create utility functions that wrap after calls to add additional functionality.
\n
\n
Examples
\n
With request APIs
\n
Whether you can use request APIs like cookies and headers inside after depends on where after is called from.
\n
In Route Handlers and Server Functions
\n
You can call cookies and headers directly inside the after callback when used in Route Handlers and Server Functions. This is useful for logging activity after a mutation or API request. For example:
\n
app/api/route.ts
TypeScript
import { after } from 'next/server'\nimport { cookies, headers } from 'next/headers'\nimport { logUserAction } from '@/app/utils'\n\nexport async function POST(request: Request) {\n // Perform mutation\n // ...\n\n // Log user activity for analytics\n after(async () => {\n const userAgent = (await headers()).get('user-agent') || 'unknown'\n const sessionCookie =\n (await cookies()).get('session-id')?.value || 'anonymous'\n\n logUserAction({ sessionCookie, userAgent })\n })\n\n return new Response(JSON.stringify({ status: 'success' }), {\n status: 200,\n headers: { 'Content-Type': 'application/json' },\n })\n}
\n\n
In Server Components (pages and layouts)
\n
Server Components (including pages, layouts, and generateMetadata) cannot use cookies, headers, or other Request-time APIs inside after. This is because Next.js needs to know which part of the component tree accesses request data to support Partial Prerendering and Cache Components, but after runs after React's rendering lifecycle.
\n
If you need request data inside an after callback in a Server Component, read it beforehand and pass the values in:
\n
app/page.tsx
TypeScript
import { after } from 'next/server'\nimport { cookies, headers } from 'next/headers'\nimport { logUserAction } from '@/app/utils'\n\nexport default async function Page() {\n // Read request data before `after` — this is allowed\n // These calls will be read during the component's rendering lifecycle\n const userAgent = (await headers()).get('user-agent') || 'unknown'\n const sessionCookie =\n (await cookies()).get('session-id')?.value || 'anonymous'\n\n after(() => {\n // Use the values read above\n logUserAction({ sessionCookie, userAgent })\n })\n\n return <h1>My Page</h1>\n}
\n\n
Calling cookies() or headers() inside the after callback in a Server Component will throw a runtime error.
\n
With Cache Components
\n
When using Cache Components, components that access request data like cookies or headers must be wrapped in <Suspense> so the rest of the page can be prerendered into a static shell.
\n
You can combine this pattern with after by reading request data in a dynamic component and passing it into after:
\n
app/page.tsx
TypeScript
import { Suspense } from 'react'\nimport { after } from 'next/server'\nimport { cookies } from 'next/headers'\nimport { logUserAction } from '@/app/utils'\n\nexport default function Page() {\n return (\n <>\n <h1>Part of the static shell</h1>\n <Suspense fallback={<p>Loading...</p>}>\n <DynamicContent />\n </Suspense>\n </>\n )\n}\n\nasync function DynamicContent() {\n const sessionCookie =\n (await cookies()).get('session-id')?.value || 'anonymous'\n\n // Schedule work after the response is sent\n after(() => {\n logUserAction({ sessionCookie })\n })\n\n return <p>Your session: {sessionCookie}</p>\n}
\n\n
In this example, <h1> and the <Suspense> fallback are included in the static shell. DynamicContent reads the cookie during rendering and passes it into after via closure. Since cookies() is called outside the after callback (during the component's render), this works correctly.
\nReference: supporting after for serverless platforms
Using after in a serverless context requires waiting for asynchronous tasks to finish after the response has been sent. In Next.js and Vercel, this is achieved using a primitive called waitUntil(promise), which extends the lifetime of a serverless invocation until all promises passed to waitUntil have settled.
If you want your users to be able to run after, you will have to provide your implementation of waitUntil that behaves in an analogous way.
When after is called, Next.js will access waitUntil like this:
after allows you to schedule work to be executed after a response (or prerender) is finished. This is useful for tasks and other side effects that should not block the response, such as logging and analytics.
The function accepts a callback that will be executed after the response (or prerender) is finished:
\n
app/layout.tsx
TypeScript
import { after } from 'next/server'\n// Custom logging function\nimport { log } from '@/app/utils'\n\nexport default function Layout({ children }: { children: React.ReactNode }) {\n after(() => {\n // Execute after the layout is rendered and sent to the user\n log()\n })\n return <>{children}</>\n}
\n\n
\n
Good to know:after is not a Request-time API and calling it does not cause a route to become dynamic. If it's used within a static page, the callback will execute at build time, or whenever a page is revalidated.
\n
\n
Reference
\n
Parameters
\n
\n
A callback function which will be executed after the response (or prerender) is finished.
\n
\n
Duration
\n
after will run for the platform's default or configured max duration of your route. If your platform supports it, you can configure the timeout limit using the maxDuration route segment config.
\n
Good to know
\n
\n
after will be executed even if the response didn't complete successfully. Including when an error is thrown or when notFound or redirect is called.
\n
You can use React cache to deduplicate functions called inside after.
\n
after can be nested inside other after calls, for example, you can create utility functions that wrap after calls to add additional functionality.
\n
\n
Examples
\n
With request APIs
\n
Whether you can use request APIs like cookies and headers inside after depends on where after is called from.
\n
In Route Handlers and Server Functions
\n
You can call cookies and headers directly inside the after callback when used in Route Handlers and Server Functions. This is useful for logging activity after a mutation or API request. For example:
\n
app/api/route.ts
TypeScript
import { after } from 'next/server'\nimport { cookies, headers } from 'next/headers'\nimport { logUserAction } from '@/app/utils'\n\nexport async function POST(request: Request) {\n // Perform mutation\n // ...\n\n // Log user activity for analytics\n after(async () => {\n const userAgent = (await headers()).get('user-agent') || 'unknown'\n const sessionCookie =\n (await cookies()).get('session-id')?.value || 'anonymous'\n\n logUserAction({ sessionCookie, userAgent })\n })\n\n return new Response(JSON.stringify({ status: 'success' }), {\n status: 200,\n headers: { 'Content-Type': 'application/json' },\n })\n}
\n\n
In Server Components (pages and layouts)
\n
Server Components (including pages, layouts, and generateMetadata) cannot use cookies, headers, or other Request-time APIs inside after. This is because Next.js needs to know which part of the component tree accesses request data to support Partial Prerendering and Cache Components, but after runs after React's rendering lifecycle.
\n
If you need request data inside an after callback in a Server Component, read it beforehand and pass the values in:
\n
app/page.tsx
TypeScript
import { after } from 'next/server'\nimport { cookies, headers } from 'next/headers'\nimport { logUserAction } from '@/app/utils'\n\nexport default async function Page() {\n // Read request data before `after` — this is allowed\n // These calls will be read during the component's rendering lifecycle\n const userAgent = (await headers()).get('user-agent') || 'unknown'\n const sessionCookie =\n (await cookies()).get('session-id')?.value || 'anonymous'\n\n after(() => {\n // Use the values read above\n logUserAction({ sessionCookie, userAgent })\n })\n\n return <h1>My Page</h1>\n}
\n\n
Calling cookies() or headers() inside the after callback in a Server Component will throw a runtime error.
\n
With Cache Components
\n
When using Cache Components, components that access request data like cookies or headers must be wrapped in <Suspense> so the rest of the page can be prerendered into a static shell.
\n
You can combine this pattern with after by reading request data in a dynamic component and passing it into after:
\n
app/page.tsx
TypeScript
import { Suspense } from 'react'\nimport { after } from 'next/server'\nimport { cookies } from 'next/headers'\nimport { logUserAction } from '@/app/utils'\n\nexport default function Page() {\n return (\n <>\n <h1>Part of the static shell</h1>\n <Suspense fallback={<p>Loading...</p>}>\n <DynamicContent />\n </Suspense>\n </>\n )\n}\n\nasync function DynamicContent() {\n const sessionCookie =\n (await cookies()).get('session-id')?.value || 'anonymous'\n\n // Schedule work after the response is sent\n after(() => {\n logUserAction({ sessionCookie })\n })\n\n return <p>Your session: {sessionCookie}</p>\n}
\n\n
In this example, <h1> and the <Suspense> fallback are included in the static shell. DynamicContent reads the cookie during rendering and passes it into after via closure. Since cookies() is called outside the after callback (during the component's render), this works correctly.
\nReference: supporting after for serverless platforms
Using after in a serverless context requires waiting for asynchronous tasks to finish after the response has been sent. In Next.js and Vercel, this is achieved using a primitive called waitUntil(promise), which extends the lifetime of a serverless invocation until all promises passed to waitUntil have settled.
If you want your users to be able to run after, you will have to provide your implementation of waitUntil that behaves in an analogous way.
When after is called, Next.js will access waitUntil like this:
after allows you to schedule work to be executed after a response (or prerender) is finished. This is useful for tasks and other side effects that should not block the response, such as logging and analytics.
The function accepts a callback that will be executed after the response (or prerender) is finished:
\n
app/layout.tsx
TypeScript
import { after } from 'next/server'\n// Custom logging function\nimport { log } from '@/app/utils'\n\nexport default function Layout({ children }: { children: React.ReactNode }) {\n after(() => {\n // Execute after the layout is rendered and sent to the user\n log()\n })\n return <>{children}</>\n}
\n\n
\n
Good to know:after is not a Request-time API and calling it does not cause a route to become dynamic. If it's used within a static page, the callback will execute at build time, or whenever a page is revalidated.
\n
\n
Reference
\n
Parameters
\n
\n
A callback function which will be executed after the response (or prerender) is finished.
\n
\n
Duration
\n
after will run for the platform's default or configured max duration of your route. If your platform supports it, you can configure the timeout limit using the maxDuration route segment config.
\n
Good to know
\n
\n
after will be executed even if the response didn't complete successfully. Including when an error is thrown or when notFound or redirect is called.
\n
You can use React cache to deduplicate functions called inside after.
\n
after can be nested inside other after calls, for example, you can create utility functions that wrap after calls to add additional functionality.
\n
\n
Examples
\n
With request APIs
\n
Whether you can use request APIs like cookies and headers inside after depends on where after is called from.
\n
In Route Handlers and Server Functions
\n
You can call cookies and headers directly inside the after callback when used in Route Handlers and Server Functions. This is useful for logging activity after a mutation or API request. For example:
\n
app/api/route.ts
TypeScript
import { after } from 'next/server'\nimport { cookies, headers } from 'next/headers'\nimport { logUserAction } from '@/app/utils'\n\nexport async function POST(request: Request) {\n // Perform mutation\n // ...\n\n // Log user activity for analytics\n after(async () => {\n const userAgent = (await headers()).get('user-agent') || 'unknown'\n const sessionCookie =\n (await cookies()).get('session-id')?.value || 'anonymous'\n\n logUserAction({ sessionCookie, userAgent })\n })\n\n return new Response(JSON.stringify({ status: 'success' }), {\n status: 200,\n headers: { 'Content-Type': 'application/json' },\n })\n}
\n\n
In Server Components (pages and layouts)
\n
Server Components (including pages, layouts, and generateMetadata) cannot use cookies, headers, or other Request-time APIs inside after. This is because Next.js needs to know which part of the component tree accesses request data to support Partial Prerendering and Cache Components, but after runs after React's rendering lifecycle.
\n
If you need request data inside an after callback in a Server Component, read it beforehand and pass the values in:
\n
app/page.tsx
TypeScript
import { after } from 'next/server'\nimport { cookies, headers } from 'next/headers'\nimport { logUserAction } from '@/app/utils'\n\nexport default async function Page() {\n // Read request data before `after` — this is allowed\n // These calls will be read during the component's rendering lifecycle\n const userAgent = (await headers()).get('user-agent') || 'unknown'\n const sessionCookie =\n (await cookies()).get('session-id')?.value || 'anonymous'\n\n after(() => {\n // Use the values read above\n logUserAction({ sessionCookie, userAgent })\n })\n\n return <h1>My Page</h1>\n}
\n\n
Calling cookies() or headers() inside the after callback in a Server Component will throw a runtime error.
\n
With Cache Components
\n
When using Cache Components, components that access request data like cookies or headers must be wrapped in <Suspense> so the rest of the page can be prerendered into a static shell.
\n
You can combine this pattern with after by reading request data in a dynamic component and passing it into after:
\n
app/page.tsx
TypeScript
import { Suspense } from 'react'\nimport { after } from 'next/server'\nimport { cookies } from 'next/headers'\nimport { logUserAction } from '@/app/utils'\n\nexport default function Page() {\n return (\n <>\n <h1>Part of the static shell</h1>\n <Suspense fallback={<p>Loading...</p>}>\n <DynamicContent />\n </Suspense>\n </>\n )\n}\n\nasync function DynamicContent() {\n const sessionCookie =\n (await cookies()).get('session-id')?.value || 'anonymous'\n\n // Schedule work after the response is sent\n after(() => {\n logUserAction({ sessionCookie })\n })\n\n return <p>Your session: {sessionCookie}</p>\n}
\n\n
In this example, <h1> and the <Suspense> fallback are included in the static shell. DynamicContent reads the cookie during rendering and passes it into after via closure. Since cookies() is called outside the after callback (during the component's render), this works correctly.
\nReference: supporting after for serverless platforms
Using after in a serverless context requires waiting for asynchronous tasks to finish after the response has been sent. In Next.js and Vercel, this is achieved using a primitive called waitUntil(promise), which extends the lifetime of a serverless invocation until all promises passed to waitUntil have settled.
If you want your users to be able to run after, you will have to provide your implementation of waitUntil that behaves in an analogous way.
When after is called, Next.js will access waitUntil like this:
",
+ "title": "https://nextjs.org/docs/app/api-reference/functions/after (text/html; charset=utf-8)",
+ "metadata": {},
+ "time": {
+ "start": 1781390564697,
+ "end": 1781390564802
+ }
+ }
+ },
+ {
+ "timestamp": 1781390566044,
+ "type": "error",
+ "raw": {
+ "type": "error",
+ "timestamp": 1781390566044,
+ "sessionID": "ses_13cdaecaeffePMVRAqAFJ3Ea2y",
+ "error": {
+ "name": "APIError",
+ "data": {
+ "message": "GatewayInternalServerError: Invalid request: Your request exceeded model token limit: 262144 (requested: 285568)",
+ "statusCode": 400,
+ "isRetryable": false,
+ "responseHeaders": {
+ "cache-control": "public, max-age=0, must-revalidate",
+ "content-type": "application/json",
+ "date": "Sat, 13 Jun 2026 22:42:46 GMT",
+ "server": "Vercel",
+ "strict-transport-security": "max-age=63072000; includeSubDomains; preload",
+ "transfer-encoding": "chunked",
+ "vary": "rsc, next-router-state-tree, next-router-prefetch, next-router-segment-prefetch",
+ "x-matched-path": "/v1/ai/language-model",
+ "x-vercel-cache": "MISS",
+ "x-vercel-id": "iad1::iad1::p5ct7-1781390564914-da7d28f90d39"
+ },
+ "responseBody": "{\"error\":{\"message\":\"Invalid request: Your request exceeded model token limit: 262144 (requested: 285568)\",\"type\":\"AI_APICallError\",\"param\":{\"error\":\"Invalid request: Your request exceeded model token limit: 262144 (requested: 285568)\",\"statusCode\":400,\"name\":\"AI_APICallError\",\"message\":\"Invalid request: Your request exceeded model token limit: 262144 (requested: 285568)\",\"isRetryable\":false,\"type\":\"AI_APICallError\"}},\"providerMetadata\":{\"gateway\":{\"routing\":{\"originalModelId\":\"moonshotai/kimi-k2.7-code\",\"resolvedProvider\":\"moonshotai\",\"fallbacksAvailable\":[],\"canonicalSlug\":\"moonshotai/kimi-k2.7-code\",\"modelAttemptCount\":1,\"modelAttempts\":[{\"canonicalSlug\":\"moonshotai/kimi-k2.7-code\",\"success\":false,\"providerAttemptCount\":1,\"providerAttempts\":[{\"provider\":\"moonshotai\",\"credentialType\":\"system\",\"success\":false,\"error\":\"Invalid request: Your request exceeded model token limit: 262144 (requested: 285568)\",\"startTime\":1781390564976,\"endTime\":1781390566020,\"statusCode\":400}]}],\"totalProviderAttemptCount\":1},\"generationId\":\"gen_01KV1JDQJMHGR953TA5AJ5BX8A\"}}}",
+ "metadata": {
+ "url": "https://ai-gateway.vercel.sh/v1/ai/language-model",
+ "requestBody": "{\"maxOutputTokens\":32000,\"temperature\":1,\"tools\":[{\"type\":\"function\",\"name\":\"bash\",\"description\":\"Executes a given bash command in a persistent shell session with optional timeout, ensuring proper handling and security measures.\\n\\nAll commands run in /workspace by default. Use the `workdir` parameter if you need to run a command in a different directory. AVOID using `cd && ` patterns - use `workdir` instead.\\n\\nIMPORTANT: This tool is for terminal operations like git, npm, docker, etc. DO NOT use it for file operations (reading, writing, editing, searching, finding files) - use the specialized tools for this instead.\\n\\nBefore executing the command, please follow these steps:\\n\\n1. Directory Verification:\\n - If the command will create new directories or files, first use `ls` to verify the parent directory exists and is the correct location\\n - For example, before running \\\"mkdir foo/bar\\\", first use `ls foo` to check that \\\"foo\\\" exists and is the intended parent directory\\n\\n2. Command Execution:\\n - Always quote file paths that contain spaces with double quotes (e.g., rm \\\"path with spaces/file.txt\\\")\\n - Examples of proper quoting:\\n - mkdir \\\"/Users/name/My Documents\\\" (correct)\\n - mkdir /Users/name/My Documents (incorrect - will fail)\\n - python \\\"/path/with spaces/script.py\\\" (correct)\\n - python /path/with spaces/script.py (incorrect - will fail)\\n - After ensuring proper quoting, execute the command.\\n - Capture the output of the command.\\n\\nUsage notes:\\n - The command argument is required.\\n - You can specify an optional timeout in milliseconds (up to 600000ms / 10 minutes). If not specified, commands will time out after 120000ms (2 minutes).\\n - It is very helpful if you write a clear, concise description of what this command does in 5-10 words.\\n - If the output exceeds 30000 characters, output will be truncated before being returned to you.\\n - You can use the `run_in_background` parameter to run the command in the background, which allows you to continue working while the command runs. You can monitor the output using the Bash tool as it becomes available. You do not need to use '&' at the end of the command when using this parameter.\\n\\n - Avoid using Bash with the `find`, `grep`, `cat`, `head`, `tail`, `sed`, `awk`, or `echo` commands, unless explicitly instructed or when these commands are truly necessary for the task. Instead, always prefer using the dedicated tools for these commands:\\n - File search: Use Glob (NOT find or ls)\\n - Content search: Use Grep (NOT grep or rg)\\n - Read files: Use Read (NOT cat/head/tail)\\n - Edit files: Use Edit (NOT sed/awk)\\n - Write files: Use Write (NOT echo >/cat < && `. Use the `workdir` parameter to change directories instead.\\n \\n Use workdir=\\\"/foo/bar\\\" with command: pytest tests\\n \\n \\n cd /foo/bar && pytest tests\\n \\n\\n# Committing changes with git\\n\\nOnly create commits when requested by the user. If unclear, ask first. When the user asks you to create a new git commit, follow these steps carefully:\\n\\nGit Safety Protocol:\\n- NEVER update the git config\\n- NEVER run destructive/irreversible git commands (like push --force, hard reset, etc) unless the user explicitly requests them\\n- NEVER skip hooks (--no-verify, --no-gpg-sign, etc) unless the user explicitly requests it\\n- NEVER run force push to main/master, warn the user if they request it\\n- Avoid git commit --amend. ONLY use --amend when ALL conditions are met:\\n (1) User explicitly requested amend, OR commit SUCCEEDED but pre-commit hook auto-modified files that need including\\n (2) HEAD commit was created by you in this conversation (verify: git log -1 --format='%an %ae')\\n (3) Commit has NOT been pushed to remote (verify: git status shows \\\"Your branch is ahead\\\")\\n- CRITICAL: If commit FAILED or was REJECTED by hook, NEVER amend - fix the issue and create a NEW commit\\n- CRITICAL: If you already pushed to remote, NEVER amend unless user explicitly requests it (requires force push)\\n- NEVER commit changes unless the user explicitly asks you to. It is VERY IMPORTANT to only commit when explicitly asked, otherwise the user will feel that you are being too proactive.\\n\\n1. You can call multiple tools in a single response. When multiple independent pieces of information are requested and all commands are likely to succeed, run multiple tool calls in parallel for optimal performance. run the following bash commands in parallel, each using the Bash tool:\\n - Run a git status command to see all untracked files.\\n - Run a git diff command to see both staged and unstaged changes that will be committed.\\n - Run a git log command to see recent commit messages, so that you can follow this repository's commit message style.\\n2. Analyze all staged changes (both previously staged and newly added) and draft a commit message:\\n - Summarize the nature of the changes (eg. new feature, enhancement to an existing feature, bug fix, refactoring, test, docs, etc.). Ensure the message accurately reflects the changes and their purpose (i.e. \\\"add\\\" means a wholly new feature, \\\"update\\\" means an enhancement to an existing feature, \\\"fix\\\" means a bug fix, etc.).\\n - Do not commit files that likely contain secrets (.env, credentials.json, etc.). Warn the user if they specifically request to commit those files\\n - Draft a concise (1-2 sentences) commit message that focuses on the \\\"why\\\" rather than the \\\"what\\\"\\n - Ensure it accurately reflects the changes and their purpose\\n3. You can call multiple tools in a single response. When multiple independent pieces of information are requested and all commands are likely to succeed, run multiple tool calls in parallel for optimal performance. run the following commands:\\n - Add relevant untracked files to the staging area.\\n - Create the commit with a message\\n - Run git status after the commit completes to verify success.\\n Note: git status depends on the commit completing, so run it sequentially after the commit.\\n4. If the commit fails due to pre-commit hook, fix the issue and create a NEW commit (see amend rules above)\\n\\nImportant notes:\\n- NEVER run additional commands to read or explore code, besides git bash commands\\n- NEVER use the TodoWrite or Task tools\\n- DO NOT push to the remote repository unless the user explicitly asks you to do so\\n- IMPORTANT: Never use git commands with the -i flag (like git rebase -i or git add -i) since they require interactive input which is not supported.\\n- If there are no changes to commit (i.e., no untracked files and no modifications), do not create an empty commit\\n\\n# Creating pull requests\\nUse the gh command via the Bash tool for ALL GitHub-related tasks including working with issues, pull requests, checks, and releases. If given a Github URL use the gh command to get the information needed.\\n\\nIMPORTANT: When the user asks you to create a pull request, follo"
+ }
+ }
+ }
+ }
+ }
+ ],
+ "summary": {
+ "totalTurns": 0,
+ "toolCalls": {
+ "file_read": 9,
+ "file_write": 0,
+ "file_edit": 0,
+ "shell": 5,
+ "web_fetch": 0,
+ "web_search": 0,
+ "glob": 3,
+ "grep": 1,
+ "list_dir": 0,
+ "agent_task": 0,
+ "unknown": 1
+ },
+ "totalToolCalls": 19,
+ "webFetches": [],
+ "filesRead": [
+ "/workspace/package.json",
+ "/workspace/next.config.ts",
+ "/workspace/app/layout.tsx",
+ "/workspace/app/page.tsx",
+ "/workspace/lib/db.js",
+ "/workspace/node_modules/next/dist/server/after/after.d.ts",
+ "/workspace/node_modules/next/dist/server/web/spec-extension/unstable-cache.d.ts",
+ "/workspace/node_modules/next/dist/server/web/spec-extension/revalidate.d.ts",
+ "/workspace/node_modules/next/cache.d.ts"
+ ],
+ "filesModified": [],
+ "shellCommands": [
+ {
+ "command": "ls -la /workspace",
+ "success": true
+ },
+ {
+ "command": "ls -la /workspace/app /workspace/lib",
+ "success": true
+ },
+ {
+ "command": "node -e \"const { revalidateTag } = require('next/cache'); console.log(revalidateTag.length)\"",
+ "success": true
+ },
+ {
+ "command": "node -e \"const { updateTag } = require('next/cache'); console.log(updateTag.length)\"",
+ "success": true
+ },
+ {
+ "command": "node -e \"const { revalidateTag } = require('next/cache'); try { revalidateTag('products'); console.log('ok'); } catch(e) { console.error(e.message); }\"",
+ "success": true
+ }
+ ],
+ "errors": [],
+ "thinkingBlocks": 0
+ },
+ "parseSuccess": true
+}
\ No newline at end of file
diff --git a/results/kimi-k2.7-code/2026-06-13T22-40-06.944Z/agent-029-use-cache-directive/run-4/outputs/eval.txt b/results/kimi-k2.7-code/2026-06-13T22-40-06.944Z/agent-029-use-cache-directive/run-4/outputs/eval.txt
new file mode 100644
index 000000000..98af1499d
--- /dev/null
+++ b/results/kimi-k2.7-code/2026-06-13T22-40-06.944Z/agent-029-use-cache-directive/run-4/outputs/eval.txt
@@ -0,0 +1,163 @@
+
+ RUN v3.2.6 /workspace
+
+ ❯ EVAL.ts (4 tests | 2 failed) 10ms
+ × Catalog reads use use-cache directive and products cache tag 8ms
+ → expected 'import type { Metadata } from \'next\…' to match /['"]use cache['"];?/
+ ✓ Page fetches products via lib/db 0ms
+ ✓ Inline form-triggered Server Action flow exists 0ms
+ × Server Action revalidates products using revalidateTag profile 1ms
+ → Expected source to call revalidateTag: expected undefined to be defined
+
+ Test Files 1 failed (1)
+ Tests 2 failed | 2 passed (4)
+ Start at 22:45:08
+ Duration 298ms (transform 37ms, setup 0ms, collect 34ms, tests 10ms, environment 0ms, prepare 83ms)
+
+
+⎯⎯⎯⎯⎯⎯⎯ Failed Tests 2 ⎯⎯⎯⎯⎯⎯⎯
+
+ FAIL EVAL.ts > Catalog reads use use-cache directive and products cache tag
+AssertionError: expected 'import type { Metadata } from \'next\…' to match /['"]use cache['"];?/
+
+[32m- Expected:[39m
+/['"]use cache['"];?/
+
+[31m+ Received:[39m
+"import type { Metadata } from 'next'
+
+export const metadata: Metadata = {
+ title: 'Create Next App',
+ description: 'Generated by create next app',
+}
+
+export default function RootLayout({
+ children,
+}: Readonly<{
+ children: React.ReactNode
+}>) {
+ return (
+
+ {children}
+
+ )
+}
+
+import { updateTag } from 'next/cache'
+import { getProducts } from '@/lib/products'
+
+export default async function CatalogPage() {
+ const products = await getProducts()
+
+ async function syncCatalog() {
+ 'use server'
+ updateTag('products')
+ }
+
+ return (
+
+
+
Product Catalog
+
+ Sync latest catalog
+
+
+
+
+
+
+
ID
+
Name
+
Price
+
+
+
+ {products.map((product) => (
+
+
{product.id}
+
{product.name}
+
+ ${product.price}
+
+
+ ))}
+
+
+
+ )
+}
+
+export async function getAllProducts() {
+ // Simulate database delay
+ await new Promise((resolve) => setTimeout(resolve, 100))
+
+ return [
+ { id: 1, name: 'Laptop', price: 999 },
+ { id: 2, name: 'Phone', price: 699 },
+ { id: 3, name: 'Tablet', price: 499 },
+ { id: 4, name: 'Headphones', price: 199 },
+ { id: 5, name: 'Watch', price: 299 },
+ ]
+}
+
+import { unstable_cache } from 'next/cache'
+import { getAllProducts } from '@/lib/db'
+
+export type Product = {
+ id: number
+ name: string
+ price: number
+}
+
+export const getProducts = unstable_cache(
+ async (): Promise => getAllProducts(),
+ ['products'],
+ { tags: ['products'] }
+)
+
+///
+///
+import \"./.next/types/routes.d.ts\";
+import \"./.next/types/root-params.d.ts\";
+
+// NOTE: This file should not be edited
+// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
+
+import type { NextConfig } from 'next'
+
+const nextConfig: NextConfig = {}
+
+export default nextConfig
+
+
+import { defineConfig } from 'vitest/config';
+export default defineConfig({
+ test: {
+ include: ['EVAL.ts'],
+ globals: false,
+ },
+});
+"
+
+ ❯ EVAL.ts:66:18
+ 64| test('Catalog reads use use-cache directive and products cache tag', (…
+ 65| // Allow caching logic to live in app or lib helper modules.
+ 66| expect(source).toMatch(/['"]use cache['"];?/)
+ | ^
+ 67|
+ 68| // Tagged invalidation should target the required products key.
+
+⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/2]⎯
+
+ FAIL EVAL.ts > Server Action revalidates products using revalidateTag profile
+AssertionError: Expected source to call revalidateTag: expected undefined to be defined
+ ❯ EVAL.ts:96:67
+ 94| test('Server Action revalidates products using revalidateTag profile',…
+ 95| const revalidateFile = fileWith(/revalidateTag\s*\(/)
+ 96| expect(revalidateFile, 'Expected source to call revalidateTag').toBe…
+ | ^
+ 97|
+ 98| // The chosen API should be revalidateTag in this workflow.
+
+⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[2/2]⎯
+
diff --git a/results/kimi-k2.7-code/2026-06-13T22-40-06.944Z/agent-029-use-cache-directive/run-4/outputs/scripts/build.txt b/results/kimi-k2.7-code/2026-06-13T22-40-06.944Z/agent-029-use-cache-directive/run-4/outputs/scripts/build.txt
new file mode 100644
index 000000000..d94dbff5f
--- /dev/null
+++ b/results/kimi-k2.7-code/2026-06-13T22-40-06.944Z/agent-029-use-cache-directive/run-4/outputs/scripts/build.txt
@@ -0,0 +1,22 @@
+
+> build
+> next build
+
+▲ Next.js 16.3.0-canary.50 (Turbopack)
+
+ Creating an optimized production build ...
+✓ Compiled successfully in 5.6s
+ Running TypeScript ...
+ Finished TypeScript in 2.5s ...
+ Collecting page data using 1 worker ...
+ Generating static pages using 1 worker (0/3) ...
+✓ Generating static pages using 1 worker (3/3) in 134ms
+ Finalizing page optimization ...
+
+Route (app)
+┌ ○ /
+└ ○ /_not-found
+
+
+○ (Static) prerendered as static content
+
diff --git a/results/kimi-k2.7-code/2026-06-13T22-40-06.944Z/agent-029-use-cache-directive/run-4/result.json b/results/kimi-k2.7-code/2026-06-13T22-40-06.944Z/agent-029-use-cache-directive/run-4/result.json
new file mode 100644
index 000000000..3318a2b52
--- /dev/null
+++ b/results/kimi-k2.7-code/2026-06-13T22-40-06.944Z/agent-029-use-cache-directive/run-4/result.json
@@ -0,0 +1,61 @@
+{
+ "status": "failed",
+ "duration": 399.48,
+ "model": "vercel/moonshotai/kimi-k2.7-code",
+ "transcriptPath": "./transcript.json",
+ "transcriptRawPath": "./transcript-raw.jsonl",
+ "o11y": {
+ "totalTurns": 1,
+ "toolCalls": {
+ "file_read": 9,
+ "file_write": 3,
+ "file_edit": 0,
+ "shell": 3,
+ "web_fetch": 0,
+ "web_search": 0,
+ "glob": 0,
+ "grep": 5,
+ "list_dir": 0,
+ "agent_task": 0,
+ "unknown": 3
+ },
+ "totalToolCalls": 23,
+ "webFetches": [],
+ "filesRead": [
+ "/workspace/package.json",
+ "/workspace/next.config.ts",
+ "/workspace/app/layout.tsx",
+ "/workspace/app/page.tsx",
+ "/workspace/lib/db.js",
+ "/workspace/tsconfig.json",
+ "/workspace/node_modules/next/dist/server/web/spec-extension/revalidate.js",
+ "/workspace/node_modules/next/dist/server/web/spec-extension/unstable-cache.d.ts"
+ ],
+ "filesModified": [
+ "/workspace/lib/products.ts",
+ "/workspace/app/page.tsx"
+ ],
+ "shellCommands": [
+ {
+ "command": "ls -la",
+ "success": true
+ },
+ {
+ "command": "ls -la app lib",
+ "success": true
+ },
+ {
+ "command": "npm run build",
+ "success": true
+ }
+ ],
+ "errors": [],
+ "thinkingBlocks": 0
+ },
+ "outputPaths": {
+ "eval": "./outputs/eval.txt",
+ "scripts": {
+ "build": "./outputs/scripts/build.txt"
+ }
+ }
+}
\ No newline at end of file
diff --git a/results/kimi-k2.7-code/2026-06-13T22-40-06.944Z/agent-029-use-cache-directive/run-4/transcript-raw.jsonl b/results/kimi-k2.7-code/2026-06-13T22-40-06.944Z/agent-029-use-cache-directive/run-4/transcript-raw.jsonl
new file mode 100644
index 000000000..984c7fd5c
--- /dev/null
+++ b/results/kimi-k2.7-code/2026-06-13T22-40-06.944Z/agent-029-use-cache-directive/run-4/transcript-raw.jsonl
@@ -0,0 +1,64 @@
+{"type":"step_start","timestamp":1781390456241,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec32535a7001uywKtiYWdWr5SV","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec3252d2000177Wzw5soein6hy","type":"step-start","snapshot":"56c903bdd03b310f65cb061c1cc1689c258eb58e"}}
+{"type":"tool_use","timestamp":1781390458478,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec3253c91001hFc386nwxwVbjB","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec3252d2000177Wzw5soein6hy","type":"tool","callID":"bash_0","tool":"bash","state":{"status":"completed","input":{"command":"ls -la","description":"List workspace files"},"output":"total 184\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 187 Jun 13 22:40 .\ndrwxr-xr-x 20 root root 286 Jun 13 22:40 ..\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 154 Jun 13 22:40 .git\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 14 Jun 13 22:40 .gitignore\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 40 Jun 13 22:40 app\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 19 Jun 13 22:40 lib\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 101 Jun 13 22:40 next.config.ts\ndrwxr-xr-x 179 vercel-sandbox vercel-sandbox 8192 Jun 13 22:40 node_modules\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 1549 Jun 13 22:40 opencode.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 154377 Jun 13 22:40 package-lock.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 603 Jun 13 22:40 package.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 599 Jun 13 22:40 tsconfig.json\n","title":"List workspace files","metadata":{"output":"total 184\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 187 Jun 13 22:40 .\ndrwxr-xr-x 20 root root 286 Jun 13 22:40 ..\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 154 Jun 13 22:40 .git\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 14 Jun 13 22:40 .gitignore\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 40 Jun 13 22:40 app\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 19 Jun 13 22:40 lib\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 101 Jun 13 22:40 next.config.ts\ndrwxr-xr-x 179 vercel-sandbox vercel-sandbox 8192 Jun 13 22:40 node_modules\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 1549 Jun 13 22:40 opencode.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 154377 Jun 13 22:40 package-lock.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 603 Jun 13 22:40 package.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 599 Jun 13 22:40 tsconfig.json\n","exit":0,"description":"List workspace files"},"time":{"start":1781390458380,"end":1781390458444}}}}
+{"type":"step_finish","timestamp":1781390458482,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec3253e5e0017CLz0WbTZz0uYs","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec3252d2000177Wzw5soein6hy","type":"step-finish","reason":"tool-calls","snapshot":"56c903bdd03b310f65cb061c1cc1689c258eb58e","cost":0.00181792,"tokens":{"input":0,"output":73,"reasoning":0,"cache":{"read":9537,"write":0}}}}
+{"type":"step_start","timestamp":1781390459869,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec32543d5001OeQTXwMM2JDb3t","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec3253e7a001Nh4IjSPSNsvuda","type":"step-start","snapshot":"56c903bdd03b310f65cb061c1cc1689c258eb58e"}}
+{"type":"tool_use","timestamp":1781390460560,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec32544d7001wPs324WYy8RS6I","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec3253e7a001Nh4IjSPSNsvuda","type":"tool","callID":"bash_1","tool":"bash","state":{"status":"completed","input":{"command":"ls -la app lib","description":"List app and lib directories"},"output":"app:\ntotal 8\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 40 Jun 13 22:40 .\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 187 Jun 13 22:40 ..\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 329 Jun 13 22:40 layout.tsx\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 91 Jun 13 22:40 page.tsx\n\nlib:\ntotal 4\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 19 Jun 13 22:40 .\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 187 Jun 13 22:40 ..\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 364 Jun 13 22:40 db.js\n","title":"List app and lib directories","metadata":{"output":"app:\ntotal 8\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 40 Jun 13 22:40 .\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 187 Jun 13 22:40 ..\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 329 Jun 13 22:40 layout.tsx\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 91 Jun 13 22:40 page.tsx\n\nlib:\ntotal 4\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 19 Jun 13 22:40 .\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 187 Jun 13 22:40 ..\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 364 Jun 13 22:40 db.js\n","exit":0,"description":"List app and lib directories"},"time":{"start":1781390460552,"end":1781390460559}}}}
+{"type":"tool_use","timestamp":1781390460793,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec325468e001cLhlb60y9eNZIX","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec3253e7a001Nh4IjSPSNsvuda","type":"tool","callID":"read_2","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/package.json"},"output":"\n00001| {\n00002| \"private\": true,\n00003| \"type\": \"module\",\n00004| \"scripts\": {\n00005| \"dev\": \"next dev\",\n00006| \"build\": \"next build\",\n00007| \"start\": \"next start\"\n00008| },\n00009| \"dependencies\": {\n00010| \"@ai-sdk/react\": \"2.0.0-beta.28\",\n00011| \"@modelcontextprotocol/sdk\": \"^1.17.0\",\n00012| \"ai\": \"5.0.59\",\n00013| \"next\": \"^16.3.0-canary.50\",\n00014| \"react\": \"19.1.0\",\n00015| \"react-dom\": \"19.1.0\",\n00016| \"zod\": \"^4.0.10\"\n00017| },\n00018| \"devDependencies\": {\n00019| \"@types/node\": \"^20\",\n00020| \"@types/react\": \"^19\",\n00021| \"@types/react-dom\": \"^19\",\n00022| \"@vitejs/plugin-react\": \"^4.4.1\",\n00023| \"typescript\": \"^5\",\n00024| \"vite-tsconfig-paths\": \"^5.1.4\",\n00025| \"vitest\": \"^3.1.3\"\n00026| }\n00027| }\n00028| \n\n(End of file - total 28 lines)\n","title":"package.json","metadata":{"preview":"{\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"next dev\",\n \"build\": \"next build\",\n \"start\": \"next start\"\n },\n \"dependencies\": {\n \"@ai-sdk/react\": \"2.0.0-beta.28\",\n \"@modelcontextprotocol/sdk\": \"^1.17.0\",\n \"ai\": \"5.0.59\",\n \"next\": \"^16.3.0-canary.50\",\n \"react\": \"19.1.0\",\n \"react-dom\": \"19.1.0\",\n \"zod\": \"^4.0.10\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^20\",\n \"@types/react\": \"^19\","},"time":{"start":1781390460774,"end":1781390460790}}}}
+{"type":"tool_use","timestamp":1781390460901,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec3254775001R0DCRYQwjcdkHA","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec3253e7a001Nh4IjSPSNsvuda","type":"tool","callID":"read_3","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/next.config.ts"},"output":"\n00001| import type { NextConfig } from 'next'\n00002| \n00003| const nextConfig: NextConfig = {}\n00004| \n00005| export default nextConfig\n00006| \n\n(End of file - total 6 lines)\n","title":"next.config.ts","metadata":{"preview":"import type { NextConfig } from 'next'\n\nconst nextConfig: NextConfig = {}\n\nexport default nextConfig\n"},"time":{"start":1781390460887,"end":1781390460892}}}}
+{"type":"step_finish","timestamp":1781390460912,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec32547dc001vXgMuUuH2ccVCB","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec3253e7a001Nh4IjSPSNsvuda","type":"step-finish","reason":"tool-calls","snapshot":"56c903bdd03b310f65cb061c1cc1689c258eb58e","cost":0.00231297,"tokens":{"input":511,"output":78,"reasoning":0,"cache":{"read":9472,"write":0}}}}
+{"type":"step_start","timestamp":1781390462405,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec3254dc0001AFCGlbiZKducai","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec3254801001FuxDQyZJpSzYFd","type":"step-start","snapshot":"56c903bdd03b310f65cb061c1cc1689c258eb58e"}}
+{"type":"tool_use","timestamp":1781390462600,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec3254dc4001XgRhGGbZjVXmBD","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec3254801001FuxDQyZJpSzYFd","type":"tool","callID":"read_4","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/app/layout.tsx"},"output":"\n00001| import type { Metadata } from 'next'\n00002| \n00003| export const metadata: Metadata = {\n00004| title: 'Create Next App',\n00005| description: 'Generated by create next app',\n00006| }\n00007| \n00008| export default function RootLayout({\n00009| children,\n00010| }: Readonly<{\n00011| children: React.ReactNode\n00012| }>) {\n00013| return (\n00014| \n00015| {children}\n00016| \n00017| )\n00018| }\n00019| \n\n(End of file - total 19 lines)\n","title":"app/layout.tsx","metadata":{"preview":"import type { Metadata } from 'next'\n\nexport const metadata: Metadata = {\n title: 'Create Next App',\n description: 'Generated by create next app',\n}\n\nexport default function RootLayout({\n children,\n}: Readonly<{\n children: React.ReactNode\n}>) {\n return (\n \n {children}\n \n )\n}\n"},"time":{"start":1781390462587,"end":1781390462598}}}}
+{"type":"tool_use","timestamp":1781390462813,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec3254e85001MaiKzyLfwE4bWM","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec3254801001FuxDQyZJpSzYFd","type":"tool","callID":"read_5","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/app/page.tsx"},"output":"\n00001| export default function Page() {\n00002| return (\n00003|
\n00004|
Home
\n00005|
\n00006| )\n00007| }\n00008| \n\n(End of file - total 8 lines)\n","title":"app/page.tsx","metadata":{"preview":"export default function Page() {\n return (\n
\n \n )\n}\n"},"output":"\nThis file has errors, please fix\n\nERROR [9:5] Expected 2 arguments, but got 1.\n\n","title":"app/page.tsx","metadata":{"diagnostics":{"/workspace/app/layout.tsx":[],"/workspace/app/page.tsx":[{"range":{"start":{"line":8,"character":4},"end":{"line":8,"character":17}},"message":"Expected 2 arguments, but got 1.","severity":1,"code":2554,"source":"typescript","relatedInformation":[{"location":{"uri":"file:///workspace/node_modules/next/dist/server/web/spec-extension/revalidate.d.ts","range":{"start":{"line":12,"character":51},"end":{"line":12,"character":84}}},"message":"An argument for 'profile' was not provided."}]}],"/workspace/lib/db.js":[],"/workspace/next.config.ts":[],"/workspace/lib/products.ts":[]},"filepath":"/workspace/app/page.tsx","exists":true},"time":{"start":1781390530306,"end":1781390531593}}}}
+{"type":"step_finish","timestamp":1781390531601,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec3265c0b001kIsJtsVXvj4pcj","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec3262d580012t4S0MIHKEG1CT","type":"step-finish","reason":"tool-calls","snapshot":"a73cc177aa6be3b38387792c45a1506702be7a41","cost":0.00459037,"tokens":{"input":611,"output":470,"reasoning":0,"cache":{"read":13312,"write":0}}}}
+{"type":"step_start","timestamp":1781390533216,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec3266258001nyfRUTNhBz7ESd","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec3265c1b0011MQIUmxcjVa1Tw","type":"step-start","snapshot":"a73cc177aa6be3b38387792c45a1506702be7a41"}}
+{"type":"tool_use","timestamp":1781390536741,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec3266b77001O9hJ4oDzHJjhoJ","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec3265c1b0011MQIUmxcjVa1Tw","type":"tool","callID":"grep_12","tool":"grep","state":{"status":"completed","input":{"path":"/workspace/node_modules/next","pattern":"export.*revalidateTag"},"output":"Found 70 matches\n/workspace/node_modules/next/dist/server/web/spec-extension/revalidate.d.ts:\n Line 13: export declare function revalidateTag(tag: string, profile: string | CacheLifeConfig): undefined;\n\n/workspace/node_modules/next/dist/compiled/next-server/use-cache-probe-worker.runtime.dev.js.map:\n Line 1: {\"version\":3,\"file\":\"use-cache-probe-worker.runtime.dev.js\",\"sources\":[\"webpack://next/./dist/compiled/@edge-runtime/cookies/index.js\",\"webpack://next/./dist/compiled/cookie/index.js\",\"webpack://next/./dist/compiled/p-queue/index.js\",\"webpack://next/./dist/compiled/react-dom/cjs/react-dom.react-server.development.js\",\"webpack://next/./dist/compiled/react-dom/react-dom.react-server.js\",\"webpack://next/./dist/compiled/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.development.js\",\"webpack://next/./dist/compiled/react-server-dom-webpack/server.node.js\",\"webpack://next/./dist/compiled/react/cjs/react.react-server.development.js\",\"webpack://next/./dist/compiled/react/react.react-server.js\",\"webpack://next/./src/server/node-environment-baseline.ts\",\"webpack://next/./src/shared/lib/modern-browserslist-target.js\",\"webpack://next/webpack/runtime/compat_get_default_export\",\"webpack://next/webpack/runtime/define_property_getters\",\"webpack://next/webpack/runtime/ensure_chunk\",\"webpack://next/webpack/runtime/has_own_property\",\"webpack://next/webpack/runtime/make_namespace_object\",\"webpack://next/./src/server/patch-error-inspect.ts\",\"webpack://next/./src/server/node-environment-extensions/web-crypto.tsx\",\"webpack://next/./src/server/require-hook.ts\",\"webpack://next/./src/server/app-render/staged-rendering.ts\",\"webpack://next/./src/server/node-environment-extensions/date.tsx\",\"webpack://next/./src/server/lib/trace/constants.ts\",\"webpack://next/./src/lib/picocolors.ts\",\"webpack://next/./src/server/lib/lru-cache.ts\",\"webpack://next/./src/server/lib/source-maps.ts\",\"webpack://next/./src/server/lib/parse-stack.ts\",\"webpack://next/./src/server/node-environment-extensions/error-inspect.tsx\",\"webpack://next/./src/server/dev/browser-logs/file-logger.ts\",\"webpack://next/./src/client/lib/console.ts\",\"webpack://next/./src/server/node-environment-extensions/console-file.tsx\",\"webpack://next/./src/server/node-environment-extensions/console-exit.tsx\",\"webpack://next/./src/sha...\n\n/workspace/node_modules/next/dist/compiled/next-server/use-cache-probe-worker-turbo.runtime.dev.js.map:\n Line 1: {\"version\":3,\"file\":\"use-cache-probe-worker-turbo.runtime.dev.js\",\"sources\":[\"webpack://next/./dist/compiled/@edge-runtime/cookies/index.js\",\"webpack://next/./dist/compiled/cookie/index.js\",\"webpack://next/./dist/compiled/p-queue/index.js\",\"webpack://next/./dist/compiled/react-dom/cjs/react-dom.react-server.development.js\",\"webpack://next/./dist/compiled/react-dom/react-dom.react-server.js\",\"webpack://next/./dist/compiled/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.node.development.js\",\"webpack://next/./dist/compiled/react-server-dom-turbopack/server.node.js\",\"webpack://next/./dist/compiled/react/cjs/react.react-server.development.js\",\"webpack://next/./dist/compiled/react/react.react-server.js\",\"webpack://next/./src/server/node-environment-baseline.ts\",\"webpack://next/./src/shared/lib/modern-browserslist-target.js\",\"webpack://next/webpack/runtime/compat_get_default_export\",\"webpack://next/webpack/runtime/define_property_getters\",\"webpack://next/webpack/runtime/has_own_property\",\"webpack://next/webpack/runtime/make_namespace_object\",\"webpack://next/./src/server/patch-error-inspect.ts\",\"webpack://next/./src/server/node-environment-extensions/web-crypto.tsx\",\"webpack://next/./src/server/require-hook.ts\",\"webpack://next/./src/server/app-render/staged-rendering.ts\",\"webpack://next/./src/server/node-environment-extensions/date.tsx\",\"webpack://next/./src/server/lib/trace/constants.ts\",\"webpack://next/./src/lib/picocolors.ts\",\"webpack://next/./src/server/lib/lru-cache.ts\",\"webpack://next/./src/server/lib/source-maps.ts\",\"webpack://next/./src/server/lib/parse-stack.ts\",\"webpack://next/./src/server/node-environment-extensions/error-inspect.tsx\",\"webpack://next/./src/server/dev/browser-logs/file-logger.ts\",\"webpack://next/./src/client/lib/console.ts\",\"webpack://next/./src/server/node-environment-extensions/console-file.tsx\",\"webpack://next/./src/server/node-environment-extensions/console-exit.tsx\",\"webpack://next/./src/shared/lib/invariant-error.ts\",\"webpa...\n\n/workspace/node_modules/next/dist/compiled/next-server/use-cache-probe-worker-turbo-experimental.runtime.dev.js.map:\n Line 1: {\"version\":3,\"file\":\"use-cache-probe-worker-turbo-experimental.runtime.dev.js\",\"sources\":[\"webpack://next/./dist/compiled/@edge-runtime/cookies/index.js\",\"webpack://next/./dist/compiled/cookie/index.js\",\"webpack://next/./dist/compiled/p-queue/index.js\",\"webpack://next/./dist/compiled/react-dom-experimental/cjs/react-dom.react-server.development.js\",\"webpack://next/./dist/compiled/react-dom-experimental/react-dom.react-server.js\",\"webpack://next/./dist/compiled/react-experimental/cjs/react.react-server.development.js\",\"webpack://next/./dist/compiled/react-experimental/react.react-server.js\",\"webpack://next/./dist/compiled/react-server-dom-turbopack-experimental/cjs/react-server-dom-turbopack-server.node.development.js\",\"webpack://next/./dist/compiled/react-server-dom-turbopack-experimental/server.node.js\",\"webpack://next/./src/server/node-environment-baseline.ts\",\"webpack://next/./src/shared/lib/modern-browserslist-target.js\",\"webpack://next/webpack/runtime/compat_get_default_export\",\"webpack://next/webpack/runtime/define_property_getters\",\"webpack://next/webpack/runtime/has_own_property\",\"webpack://next/webpack/runtime/make_namespace_object\",\"webpack://next/./src/server/patch-error-inspect.ts\",\"webpack://next/./src/server/node-environment-extensions/web-crypto.tsx\",\"webpack://next/./src/server/require-hook.ts\",\"webpack://next/./src/server/app-render/staged-rendering.ts\",\"webpack://next/./src/server/node-environment-extensions/date.tsx\",\"webpack://next/./src/server/lib/trace/constants.ts\",\"webpack://next/./src/lib/picocolors.ts\",\"webpack://next/./src/server/lib/lru-cache.ts\",\"webpack://next/./src/server/lib/source-maps.ts\",\"webpack://next/./src/server/lib/parse-stack.ts\",\"webpack://next/./src/server/node-environment-extensions/error-inspect.tsx\",\"webpack://next/./src/server/dev/browser-logs/file-logger.ts\",\"webpack://next/./src/client/lib/console.ts\",\"webpack://next/./src/server/node-environment-extensions/console-file.tsx\",\"webpack://next/./src/server/node-environme...\n\n/workspace/node_modules/next/dist/compiled/next-server/use-cache-probe-worker-experimental.runtime.dev.js.map:\n Line 1: {\"version\":3,\"file\":\"use-cache-probe-worker-experimental.runtime.dev.js\",\"sources\":[\"webpack://next/./dist/compiled/@edge-runtime/cookies/index.js\",\"webpack://next/./dist/compiled/cookie/index.js\",\"webpack://next/./dist/compiled/p-queue/index.js\",\"webpack://next/./dist/compiled/react-dom-experimental/cjs/react-dom.react-server.development.js\",\"webpack://next/./dist/compiled/react-dom-experimental/react-dom.react-server.js\",\"webpack://next/./dist/compiled/react-experimental/cjs/react.react-server.development.js\",\"webpack://next/./dist/compiled/react-experimental/react.react-server.js\",\"webpack://next/./dist/compiled/react-server-dom-webpack-experimental/cjs/react-server-dom-webpack-server.node.development.js\",\"webpack://next/./dist/compiled/react-server-dom-webpack-experimental/server.node.js\",\"webpack://next/./src/server/node-environment-baseline.ts\",\"webpack://next/./src/shared/lib/modern-browserslist-target.js\",\"webpack://next/webpack/runtime/compat_get_default_export\",\"webpack://next/webpack/runtime/define_property_getters\",\"webpack://next/webpack/runtime/ensure_chunk\",\"webpack://next/webpack/runtime/has_own_property\",\"webpack://next/webpack/runtime/make_namespace_object\",\"webpack://next/./src/server/patch-error-inspect.ts\",\"webpack://next/./src/server/node-environment-extensions/web-crypto.tsx\",\"webpack://next/./src/server/require-hook.ts\",\"webpack://next/./src/server/app-render/staged-rendering.ts\",\"webpack://next/./src/server/node-environment-extensions/date.tsx\",\"webpack://next/./src/server/lib/trace/constants.ts\",\"webpack://next/./src/lib/picocolors.ts\",\"webpack://next/./src/server/lib/lru-cache.ts\",\"webpack://next/./src/server/lib/source-maps.ts\",\"webpack://next/./src/server/lib/parse-stack.ts\",\"webpack://next/./src/server/node-environment-extensions/error-inspect.tsx\",\"webpack://next/./src/server/dev/browser-logs/file-logger.ts\",\"webpack://next/./src/client/lib/console.ts\",\"webpack://next/./src/server/node-environment-extensions/console-file.tsx\",\"webpack:...\n\n/workspace/node_modules/next/dist/server/response-cache/types.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../../src/server/response-cache/types.ts\"],\"sourcesContent\":[\"import type { OutgoingHttpHeaders } from 'http'\\nimport type RenderResult from '../render-result'\\nimport type { CacheControl, Revalidate } from '../lib/cache-control'\\nimport type { RouteKind } from '../route-kind'\\n\\nexport interface ResponseCacheBase {\\n get(\\n key: string | null,\\n responseGenerator: ResponseGenerator,\\n context: {\\n isOnDemandRevalidate?: boolean\\n isPrefetch?: boolean\\n incrementalCache: IncrementalCache\\n /**\\n * This is a hint to the cache to help it determine what kind of route\\n * this is so it knows where to look up the cache entry from. If not\\n * provided it will test the filesystem to check.\\n */\\n routeKind: RouteKind\\n\\n /**\\n * True if this is a fallback request.\\n */\\n isFallback?: boolean\\n\\n /**\\n * True if the route is enabled for PPR.\\n */\\n isRoutePPREnabled?: boolean\\n }\\n ): Promise\\n}\\n\\n// The server components HMR cache might store other data as well in the future,\\n// at which point this should be refactored to a discriminated union type.\\nexport interface ServerComponentsHmrCache {\\n get(key: string): CachedFetchData | undefined\\n set(key: string, data: CachedFetchData): void\\n}\\n\\nexport type CachedFetchData = {\\n headers: Record\\n body: string\\n url: string\\n status?: number\\n}\\n\\nexport const enum CachedRouteKind {\\n APP_PAGE = 'APP_PAGE',\\n APP_ROUTE = 'APP_ROUTE',\\n PAGES = 'PAGES',\\n FETCH = 'FETCH',\\n REDIRECT = 'REDIRECT',\\n IMAGE = 'IMAGE',\\n}\\n\\nexport interface CachedFetchValue {\\n kind: CachedRouteKind.FETCH\\n data: CachedFetchData\\n // tags are only present with file-system-cache\\n // fetch cache stores tags outside of cache entry\\n tags?: string[]\\n revalidate: number\\n}\\n\\nexport interface CachedRedirectValue {\\n kind: CachedRouteKind.REDIRECT\\n prop...\n\n/workspace/node_modules/next/dist/esm/server/response-cache/types.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../../../src/server/response-cache/types.ts\"],\"sourcesContent\":[\"import type { OutgoingHttpHeaders } from 'http'\\nimport type RenderResult from '../render-result'\\nimport type { CacheControl, Revalidate } from '../lib/cache-control'\\nimport type { RouteKind } from '../route-kind'\\n\\nexport interface ResponseCacheBase {\\n get(\\n key: string | null,\\n responseGenerator: ResponseGenerator,\\n context: {\\n isOnDemandRevalidate?: boolean\\n isPrefetch?: boolean\\n incrementalCache: IncrementalCache\\n /**\\n * This is a hint to the cache to help it determine what kind of route\\n * this is so it knows where to look up the cache entry from. If not\\n * provided it will test the filesystem to check.\\n */\\n routeKind: RouteKind\\n\\n /**\\n * True if this is a fallback request.\\n */\\n isFallback?: boolean\\n\\n /**\\n * True if the route is enabled for PPR.\\n */\\n isRoutePPREnabled?: boolean\\n }\\n ): Promise\\n}\\n\\n// The server components HMR cache might store other data as well in the future,\\n// at which point this should be refactored to a discriminated union type.\\nexport interface ServerComponentsHmrCache {\\n get(key: string): CachedFetchData | undefined\\n set(key: string, data: CachedFetchData): void\\n}\\n\\nexport type CachedFetchData = {\\n headers: Record\\n body: string\\n url: string\\n status?: number\\n}\\n\\nexport const enum CachedRouteKind {\\n APP_PAGE = 'APP_PAGE',\\n APP_ROUTE = 'APP_ROUTE',\\n PAGES = 'PAGES',\\n FETCH = 'FETCH',\\n REDIRECT = 'REDIRECT',\\n IMAGE = 'IMAGE',\\n}\\n\\nexport interface CachedFetchValue {\\n kind: CachedRouteKind.FETCH\\n data: CachedFetchData\\n // tags are only present with file-system-cache\\n // fetch cache stores tags outside of cache entry\\n tags?: string[]\\n revalidate: number\\n}\\n\\nexport interface CachedRedirectValue {\\n kind: CachedRouteKind.REDIRECT\\n p...\n\n/workspace/node_modules/next/dist/compiled/next-server/server.runtime.prod.js.map:\n Line 1: {\"version\":3,\"file\":\"server.runtime.prod.js\",\"sources\":[\"webpack://next/../../node_modules/.pnpm/react@19.3.0-canary-43bcbf80-20260603/node_modules/react/cjs/react.production.js\",\"webpack://next/../../node_modules/.pnpm/react@19.3.0-canary-43bcbf80-20260603/node_modules/react/index.js\",\"webpack://next/../next-env/dist/index.js\",\"webpack://next/./dist/compiled/@edge-runtime/cookies/index.js\",\"webpack://next/./dist/compiled/bytes/index.js\",\"webpack://next/./dist/compiled/ci-info/index.js\",\"webpack://next/./dist/compiled/cookie/index.js\",\"webpack://next/./dist/compiled/fresh/index.js\",\"webpack://next/./dist/compiled/p-queue/index.js\",\"webpack://next/./dist/compiled/path-to-regexp/index.js\",\"webpack://next/./src/lib/format-server-error.ts\",\"webpack://next/./src/server/node-environment-baseline.ts\",\"webpack://next/./src/server/node-polyfill-crypto.ts\",\"webpack://next/./src/shared/lib/isomorphic/path.js\",\"webpack://next/./src/shared/lib/modern-browserslist-target.js\",\"webpack://next/webpack/runtime/compat_get_default_export\",\"webpack://next/webpack/runtime/define_property_getters\",\"webpack://next/webpack/runtime/has_own_property\",\"webpack://next/webpack/runtime/make_namespace_object\",\"webpack://next/./src/server/patch-error-inspect.ts\",\"webpack://next/./src/server/node-environment-extensions/web-crypto.tsx\",\"webpack://next/./src/server/lib/streaming-metadata.ts\",\"webpack://next/./src/server/app-render/staged-rendering.ts\",\"webpack://next/./src/server/node-environment-extensions/date.tsx\",\"webpack://next/./src/server/lib/trace/constants.ts\",\"webpack://next/./src/client/components/redirect-status-code.ts\",\"webpack://next/./src/server/route-kind.ts\",\"webpack://next/./src/server/response-cache/types.ts\",\"webpack://next/./src/lib/picocolors.ts\",\"webpack://next/./src/server/lib/lru-cache.ts\",\"webpack://next/./src/server/lib/source-maps.ts\",\"webpack://next/./src/server/lib/parse-stack.ts\",\"webpack://next/./src/server/node-environment-extensions/error-inspect.tsx\",\"webpack://next...\n\n/workspace/node_modules/next/dist/server/web/spec-extension/revalidate.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../../../src/server/web/spec-extension/revalidate.ts\"],\"sourcesContent\":[\"import {\\n abortAndThrowOnSynchronousRequestDataAccess,\\n postponeWithTracking,\\n} from '../../app-render/dynamic-rendering'\\nimport { isDynamicRoute } from '../../../shared/lib/router/utils'\\nimport {\\n NEXT_CACHE_IMPLICIT_TAG_ID,\\n NEXT_CACHE_SOFT_TAG_MAX_LENGTH,\\n} from '../../../lib/constants'\\nimport { workAsyncStorage } from '../../app-render/work-async-storage.external'\\nimport { workUnitAsyncStorage } from '../../app-render/work-unit-async-storage.external'\\nimport { DynamicServerError } from '../../../client/components/hooks-server-context'\\nimport { InvariantError } from '../../../shared/lib/invariant-error'\\nimport {\\n ActionDidRevalidateDynamicOnly,\\n ActionDidRevalidateStaticAndDynamic as ActionDidRevalidate,\\n} from '../../../shared/lib/action-revalidation-kind'\\nimport { removeTrailingSlash } from '../../../shared/lib/router/utils/remove-trailing-slash'\\nimport { encodeCacheTag } from '../../lib/encode-cache-tag'\\n\\ntype CacheLifeConfig = {\\n expire?: number\\n}\\n\\n/**\\n * This function allows you to purge [cached data](https://nextjs.org/docs/app/building-your-application/caching) on-demand for a specific cache tag.\\n *\\n * The second argument specifies a [`cacheLife`](https://nextjs.org/docs/app/api-reference/functions/cacheLife#reference) profile\\n * (e.g. `\\\"max\\\"`), or a `{ expire }` object. For immediate expiration in Server Actions, use\\n * [`updateTag`](https://nextjs.org/docs/app/api-reference/functions/updateTag) instead.\\n *\\n * Read more: [Next.js Docs: `revalidateTag`](https://nextjs.org/docs/app/api-reference/functions/revalidateTag)\\n */\\nexport function revalidateTag(tag: string, profile: string | CacheLifeConfig) {\\n if (!profile) {\\n console.warn(\\n '\\\"revalidateTag\\\" without the second argument is now deprecated, add second argument of \\\"max\\\" or use \\\"updateTag\\\". See more info here: https://nextjs.org/docs/messages/...\n\n/workspace/node_modules/next/dist/server/revalidation-utils.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../src/server/revalidation-utils.ts\"],\"sourcesContent\":[\"import type { WorkStore } from './app-render/work-async-storage.external'\\nimport type { IncrementalCache } from './lib/incremental-cache'\\nimport { getCacheHandlers } from './use-cache/handlers'\\n\\n/** Run a callback, and execute any *new* revalidations added during its runtime. */\\nexport async function withExecuteRevalidates(\\n store: WorkStore | undefined,\\n callback: () => Promise\\n): Promise {\\n if (!store) {\\n return callback()\\n }\\n // If we executed any revalidates during the request, then we don't want to execute them again.\\n // save the state so we can check if anything changed after we're done running callbacks.\\n const savedRevalidationState = cloneRevalidationState(store)\\n try {\\n return await callback()\\n } finally {\\n // Check if we have any new revalidates, and if so, wait until they are all resolved.\\n const newRevalidates = diffRevalidationState(\\n savedRevalidationState,\\n cloneRevalidationState(store)\\n )\\n await executeRevalidates(store, newRevalidates)\\n }\\n}\\n\\ntype RevalidationState = Required<\\n Pick<\\n WorkStore,\\n 'pendingRevalidatedTags' | 'pendingRevalidates' | 'pendingRevalidateWrites'\\n >\\n>\\n\\nfunction cloneRevalidationState(store: WorkStore): RevalidationState {\\n return {\\n pendingRevalidatedTags: store.pendingRevalidatedTags\\n ? [...store.pendingRevalidatedTags]\\n : [],\\n pendingRevalidates: { ...store.pendingRevalidates },\\n pendingRevalidateWrites: store.pendingRevalidateWrites\\n ? [...store.pendingRevalidateWrites]\\n : [],\\n }\\n}\\n\\nfunction diffRevalidationState(\\n prev: RevalidationState,\\n curr: RevalidationState\\n): RevalidationState {\\n const prevTagsWithProfile = new Set(\\n prev.pendingRevalidatedTags.map((item) => {\\n const profileKey =\\n typeof item.profile === 'object'\\n ? JSON.stringify(item.profile)\\n : item.pro...\n\n/workspace/node_modules/next/dist/esm/server/revalidation-utils.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../../src/server/revalidation-utils.ts\"],\"sourcesContent\":[\"import type { WorkStore } from './app-render/work-async-storage.external'\\nimport type { IncrementalCache } from './lib/incremental-cache'\\nimport { getCacheHandlers } from './use-cache/handlers'\\n\\n/** Run a callback, and execute any *new* revalidations added during its runtime. */\\nexport async function withExecuteRevalidates(\\n store: WorkStore | undefined,\\n callback: () => Promise\\n): Promise {\\n if (!store) {\\n return callback()\\n }\\n // If we executed any revalidates during the request, then we don't want to execute them again.\\n // save the state so we can check if anything changed after we're done running callbacks.\\n const savedRevalidationState = cloneRevalidationState(store)\\n try {\\n return await callback()\\n } finally {\\n // Check if we have any new revalidates, and if so, wait until they are all resolved.\\n const newRevalidates = diffRevalidationState(\\n savedRevalidationState,\\n cloneRevalidationState(store)\\n )\\n await executeRevalidates(store, newRevalidates)\\n }\\n}\\n\\ntype RevalidationState = Required<\\n Pick<\\n WorkStore,\\n 'pendingRevalidatedTags' | 'pendingRevalidates' | 'pendingRevalidateWrites'\\n >\\n>\\n\\nfunction cloneRevalidationState(store: WorkStore): RevalidationState {\\n return {\\n pendingRevalidatedTags: store.pendingRevalidatedTags\\n ? [...store.pendingRevalidatedTags]\\n : [],\\n pendingRevalidates: { ...store.pendingRevalidates },\\n pendingRevalidateWrites: store.pendingRevalidateWrites\\n ? [...store.pendingRevalidateWrites]\\n : [],\\n }\\n}\\n\\nfunction diffRevalidationState(\\n prev: RevalidationState,\\n curr: RevalidationState\\n): RevalidationState {\\n const prevTagsWithProfile = new Set(\\n prev.pendingRevalidatedTags.map((item) => {\\n const profileKey =\\n typeof item.profile === 'object'\\n ? JSON.stringify(item.profile)\\n : item....\n\n/workspace/node_modules/next/dist/esm/server/web/spec-extension/revalidate.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../../../../src/server/web/spec-extension/revalidate.ts\"],\"sourcesContent\":[\"import {\\n abortAndThrowOnSynchronousRequestDataAccess,\\n postponeWithTracking,\\n} from '../../app-render/dynamic-rendering'\\nimport { isDynamicRoute } from '../../../shared/lib/router/utils'\\nimport {\\n NEXT_CACHE_IMPLICIT_TAG_ID,\\n NEXT_CACHE_SOFT_TAG_MAX_LENGTH,\\n} from '../../../lib/constants'\\nimport { workAsyncStorage } from '../../app-render/work-async-storage.external'\\nimport { workUnitAsyncStorage } from '../../app-render/work-unit-async-storage.external'\\nimport { DynamicServerError } from '../../../client/components/hooks-server-context'\\nimport { InvariantError } from '../../../shared/lib/invariant-error'\\nimport {\\n ActionDidRevalidateDynamicOnly,\\n ActionDidRevalidateStaticAndDynamic as ActionDidRevalidate,\\n} from '../../../shared/lib/action-revalidation-kind'\\nimport { removeTrailingSlash } from '../../../shared/lib/router/utils/remove-trailing-slash'\\nimport { encodeCacheTag } from '../../lib/encode-cache-tag'\\n\\ntype CacheLifeConfig = {\\n expire?: number\\n}\\n\\n/**\\n * This function allows you to purge [cached data](https://nextjs.org/docs/app/building-your-application/caching) on-demand for a specific cache tag.\\n *\\n * The second argument specifies a [`cacheLife`](https://nextjs.org/docs/app/api-reference/functions/cacheLife#reference) profile\\n * (e.g. `\\\"max\\\"`), or a `{ expire }` object. For immediate expiration in Server Actions, use\\n * [`updateTag`](https://nextjs.org/docs/app/api-reference/functions/updateTag) instead.\\n *\\n * Read more: [Next.js Docs: `revalidateTag`](https://nextjs.org/docs/app/api-reference/functions/revalidateTag)\\n */\\nexport function revalidateTag(tag: string, profile: string | CacheLifeConfig) {\\n if (!profile) {\\n console.warn(\\n '\\\"revalidateTag\\\" without the second argument is now deprecated, add second argument of \\\"max\\\" or use \\\"updateTag\\\". See more info here: https://nextjs.org/docs/messag...\n\n/workspace/node_modules/next/dist/compiled/next-server/pages.runtime.prod.js.map:\n Line 1: {\"version\":3,\"file\":\"pages.runtime.prod.js\",\"sources\":[\"webpack://next/webpack/runtime/create_fake_namespace_object\",\"webpack://next/./dist/compiled/@edge-runtime/cookies/index.js\",\"webpack://next/./dist/compiled/cookie/index.js\",\"webpack://next/./dist/compiled/path-to-regexp/index.js\",\"webpack://next/./dist/compiled/strip-ansi/index.js\",\"webpack://next/./src/build/output/log.ts\",\"webpack://next/./src/lib/constants.ts\",\"webpack://next/./src/lib/format-dynamic-import-path.ts\",\"webpack://next/./src/lib/picocolors.ts\",\"webpack://next/./src/server/api-utils/index.ts\",\"webpack://next/./src/server/api-utils/node/try-get-preview-data.ts\",\"webpack://next/./src/server/crypto-utils.ts\",\"webpack://next/./src/server/lib/lru-cache.ts\",\"webpack://next/./src/server/lib/node-fs-methods.ts\",\"webpack://next/./src/server/lib/trace/constants.ts\",\"webpack://next/./src/server/lib/router-utils/is-postpone.ts\",\"webpack://next/./src/server/node-environment-extensions/process-error-handlers.ts\",\"webpack://next/./src/lib/non-nullable.ts\",\"webpack://next/./src/server/post-process.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/reflect.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/headers.ts\",\"webpack://next/./src/shared/lib/isomorphic/path.js\",\"webpack://next/./src/shared/lib/modern-browserslist-target.js\",\"webpack://next/./src/server/ReactDOMServerPages.js\",\"webpack://next/webpack/runtime/compat_get_default_export\",\"webpack://next/webpack/runtime/define_property_getters\",\"webpack://next/webpack/runtime/has_own_property\",\"webpack://next/webpack/runtime/make_namespace_object\",\"webpack://next/./src/server/render.tsx\",\"webpack://next/./src/server/response-cache/types.ts\",\"webpack://next/./src/server/route-kind.ts\",\"webpack://next/./src/client/components/redirect-status-code.ts\",\"webpack://next/./src/shared/lib/constants.ts\",\"webpack://next/./src/lib/url.ts\",\"webpack://next/./src/shared/lib/i18n/normalize-locale-path.ts\",\"webpack://next/./src/shared/lib/page-path/ensure...\n\n/workspace/node_modules/next/dist/compiled/next-server/pages.runtime.dev.js.map:\n Line 1: {\"version\":3,\"file\":\"pages.runtime.dev.js\",\"sources\":[\"webpack://next/webpack/runtime/create_fake_namespace_object\",\"webpack://next/./dist/compiled/@edge-runtime/cookies/index.js\",\"webpack://next/./dist/compiled/cookie/index.js\",\"webpack://next/./dist/compiled/path-to-regexp/index.js\",\"webpack://next/./dist/compiled/react-is/cjs/react-is.development.js\",\"webpack://next/./dist/compiled/react-is/index.js\",\"webpack://next/./dist/compiled/strip-ansi/index.js\",\"webpack://next/./src/build/output/log.ts\",\"webpack://next/./src/lib/constants.ts\",\"webpack://next/./src/lib/format-dynamic-import-path.ts\",\"webpack://next/./src/lib/picocolors.ts\",\"webpack://next/./src/server/api-utils/index.ts\",\"webpack://next/./src/server/api-utils/node/try-get-preview-data.ts\",\"webpack://next/./src/server/crypto-utils.ts\",\"webpack://next/./src/server/lib/lru-cache.ts\",\"webpack://next/./src/server/lib/node-fs-methods.ts\",\"webpack://next/./src/server/lib/trace/constants.ts\",\"webpack://next/./src/server/lib/router-utils/is-postpone.ts\",\"webpack://next/./src/server/node-environment-extensions/process-error-handlers.ts\",\"webpack://next/./src/lib/non-nullable.ts\",\"webpack://next/./src/server/post-process.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/headers.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/reflect.ts\",\"webpack://next/./src/shared/lib/isomorphic/path.js\",\"webpack://next/./src/shared/lib/modern-browserslist-target.js\",\"webpack://next/./src/server/ReactDOMServerPages.js\",\"webpack://next/webpack/runtime/compat_get_default_export\",\"webpack://next/webpack/runtime/define_property_getters\",\"webpack://next/webpack/runtime/has_own_property\",\"webpack://next/webpack/runtime/make_namespace_object\",\"webpack://next/./src/server/render.tsx\",\"webpack://next/./src/server/response-cache/types.ts\",\"webpack://next/./src/server/route-kind.ts\",\"webpack://next/./src/client/components/redirect-status-code.ts\",\"webpack://next/./src/shared/lib/constants.ts\",\"webpack://next/./src/lib/u...\n\n/workspace/node_modules/next/dist/compiled/next-server/pages-turbo.runtime.prod.js.map:\n Line 1: {\"version\":3,\"file\":\"pages-turbo.runtime.prod.js\",\"sources\":[\"webpack://next/webpack/runtime/create_fake_namespace_object\",\"webpack://next/./dist/compiled/@edge-runtime/cookies/index.js\",\"webpack://next/./dist/compiled/cookie/index.js\",\"webpack://next/./dist/compiled/path-to-regexp/index.js\",\"webpack://next/./dist/compiled/strip-ansi/index.js\",\"webpack://next/./src/build/output/log.ts\",\"webpack://next/./src/lib/constants.ts\",\"webpack://next/./src/lib/format-dynamic-import-path.ts\",\"webpack://next/./src/lib/picocolors.ts\",\"webpack://next/./src/server/api-utils/index.ts\",\"webpack://next/./src/server/api-utils/node/try-get-preview-data.ts\",\"webpack://next/./src/server/crypto-utils.ts\",\"webpack://next/./src/server/lib/lru-cache.ts\",\"webpack://next/./src/server/lib/node-fs-methods.ts\",\"webpack://next/./src/server/lib/trace/constants.ts\",\"webpack://next/./src/server/lib/router-utils/is-postpone.ts\",\"webpack://next/./src/server/node-environment-extensions/process-error-handlers.ts\",\"webpack://next/./src/lib/non-nullable.ts\",\"webpack://next/./src/server/post-process.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/reflect.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/headers.ts\",\"webpack://next/./src/shared/lib/isomorphic/path.js\",\"webpack://next/./src/shared/lib/modern-browserslist-target.js\",\"webpack://next/./src/server/ReactDOMServerPages.js\",\"webpack://next/webpack/runtime/compat_get_default_export\",\"webpack://next/webpack/runtime/define_property_getters\",\"webpack://next/webpack/runtime/has_own_property\",\"webpack://next/webpack/runtime/make_namespace_object\",\"webpack://next/./src/server/render.tsx\",\"webpack://next/./src/server/response-cache/types.ts\",\"webpack://next/./src/server/route-kind.ts\",\"webpack://next/./src/client/components/redirect-status-code.ts\",\"webpack://next/./src/shared/lib/constants.ts\",\"webpack://next/./src/lib/url.ts\",\"webpack://next/./src/shared/lib/i18n/normalize-locale-path.ts\",\"webpack://next/./src/shared/lib/page-path/...\n\n/workspace/node_modules/next/dist/compiled/next-server/pages-turbo.runtime.dev.js.map:\n Line 1: {\"version\":3,\"file\":\"pages-turbo.runtime.dev.js\",\"sources\":[\"webpack://next/webpack/runtime/create_fake_namespace_object\",\"webpack://next/./dist/compiled/@edge-runtime/cookies/index.js\",\"webpack://next/./dist/compiled/cookie/index.js\",\"webpack://next/./dist/compiled/path-to-regexp/index.js\",\"webpack://next/./dist/compiled/react-is/cjs/react-is.development.js\",\"webpack://next/./dist/compiled/react-is/index.js\",\"webpack://next/./dist/compiled/strip-ansi/index.js\",\"webpack://next/./src/build/output/log.ts\",\"webpack://next/./src/lib/constants.ts\",\"webpack://next/./src/lib/format-dynamic-import-path.ts\",\"webpack://next/./src/lib/picocolors.ts\",\"webpack://next/./src/server/api-utils/index.ts\",\"webpack://next/./src/server/api-utils/node/try-get-preview-data.ts\",\"webpack://next/./src/server/crypto-utils.ts\",\"webpack://next/./src/server/lib/lru-cache.ts\",\"webpack://next/./src/server/lib/node-fs-methods.ts\",\"webpack://next/./src/server/lib/trace/constants.ts\",\"webpack://next/./src/server/lib/router-utils/is-postpone.ts\",\"webpack://next/./src/server/node-environment-extensions/process-error-handlers.ts\",\"webpack://next/./src/lib/non-nullable.ts\",\"webpack://next/./src/server/post-process.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/headers.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/reflect.ts\",\"webpack://next/./src/shared/lib/isomorphic/path.js\",\"webpack://next/./src/shared/lib/modern-browserslist-target.js\",\"webpack://next/./src/server/ReactDOMServerPages.js\",\"webpack://next/webpack/runtime/compat_get_default_export\",\"webpack://next/webpack/runtime/define_property_getters\",\"webpack://next/webpack/runtime/has_own_property\",\"webpack://next/webpack/runtime/make_namespace_object\",\"webpack://next/./src/server/render.tsx\",\"webpack://next/./src/server/response-cache/types.ts\",\"webpack://next/./src/server/route-kind.ts\",\"webpack://next/./src/client/components/redirect-status-code.ts\",\"webpack://next/./src/shared/lib/constants.ts\",\"webpack://next/./src...\n\n/workspace/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js.map:\n Line 1: {\"version\":3,\"file\":\"pages-api.runtime.prod.js\",\"sources\":[\"webpack://next/webpack/runtime/create_fake_namespace_object\",\"webpack://next/./dist/compiled/@edge-runtime/cookies/index.js\",\"webpack://next/./dist/compiled/bytes/index.js\",\"webpack://next/./dist/compiled/content-type/index.js\",\"webpack://next/./dist/compiled/cookie/index.js\",\"webpack://next/./dist/compiled/fresh/index.js\",\"webpack://next/./dist/compiled/path-to-regexp/index.js\",\"webpack://next/./src/lib/constants.ts\",\"webpack://next/./src/lib/format-dynamic-import-path.ts\",\"webpack://next/./src/server/api-utils/index.ts\",\"webpack://next/./src/server/api-utils/node/try-get-preview-data.ts\",\"webpack://next/./src/server/crypto-utils.ts\",\"webpack://next/./src/server/lib/node-fs-methods.ts\",\"webpack://next/./src/server/lib/trace/constants.ts\",\"webpack://next/./src/server/lib/router-utils/is-postpone.ts\",\"webpack://next/./src/server/node-environment-extensions/process-error-handlers.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/reflect.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/headers.ts\",\"webpack://next/./src/shared/lib/isomorphic/path.js\",\"webpack://next/./src/shared/lib/modern-browserslist-target.js\",\"webpack://next/webpack/runtime/compat_get_default_export\",\"webpack://next/webpack/runtime/define_property_getters\",\"webpack://next/webpack/runtime/has_own_property\",\"webpack://next/webpack/runtime/make_namespace_object\",\"webpack://next/./src/server/response-cache/types.ts\",\"webpack://next/./src/server/route-kind.ts\",\"webpack://next/./src/lib/picocolors.ts\",\"webpack://next/./src/shared/lib/constants.ts\",\"webpack://next/./src/lib/url.ts\",\"webpack://next/./src/shared/lib/i18n/normalize-locale-path.ts\",\"webpack://next/./src/shared/lib/page-path/ensure-leading-slash.ts\",\"webpack://next/./src/shared/lib/router/utils/app-paths.ts\",\"webpack://next/./src/shared/lib/segment.ts\",\"webpack://next/./src/shared/lib/router/utils/interception-routes.ts\",\"webpack://next/./src/shared/lib/router/ut...\n\n/workspace/node_modules/next/dist/compiled/next-server/pages-api.runtime.dev.js.map:\n Line 1: {\"version\":3,\"file\":\"pages-api.runtime.dev.js\",\"sources\":[\"webpack://next/webpack/runtime/create_fake_namespace_object\",\"webpack://next/./dist/compiled/@edge-runtime/cookies/index.js\",\"webpack://next/./dist/compiled/bytes/index.js\",\"webpack://next/./dist/compiled/content-type/index.js\",\"webpack://next/./dist/compiled/cookie/index.js\",\"webpack://next/./dist/compiled/fresh/index.js\",\"webpack://next/./dist/compiled/path-to-regexp/index.js\",\"webpack://next/./src/lib/constants.ts\",\"webpack://next/./src/lib/format-dynamic-import-path.ts\",\"webpack://next/./src/server/api-utils/index.ts\",\"webpack://next/./src/server/api-utils/node/try-get-preview-data.ts\",\"webpack://next/./src/server/crypto-utils.ts\",\"webpack://next/./src/server/lib/node-fs-methods.ts\",\"webpack://next/./src/server/lib/trace/constants.ts\",\"webpack://next/./src/server/lib/router-utils/is-postpone.ts\",\"webpack://next/./src/server/node-environment-extensions/process-error-handlers.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/headers.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/reflect.ts\",\"webpack://next/./src/shared/lib/isomorphic/path.js\",\"webpack://next/./src/shared/lib/modern-browserslist-target.js\",\"webpack://next/webpack/runtime/compat_get_default_export\",\"webpack://next/webpack/runtime/define_property_getters\",\"webpack://next/webpack/runtime/has_own_property\",\"webpack://next/webpack/runtime/make_namespace_object\",\"webpack://next/./src/server/response-cache/types.ts\",\"webpack://next/./src/server/route-kind.ts\",\"webpack://next/./src/lib/picocolors.ts\",\"webpack://next/./src/shared/lib/constants.ts\",\"webpack://next/./src/lib/url.ts\",\"webpack://next/./src/shared/lib/i18n/normalize-locale-path.ts\",\"webpack://next/./src/shared/lib/page-path/ensure-leading-slash.ts\",\"webpack://next/./src/shared/lib/router/utils/app-paths.ts\",\"webpack://next/./src/shared/lib/segment.ts\",\"webpack://next/./src/shared/lib/router/utils/interception-routes.ts\",\"webpack://next/./src/shared/lib/router/uti...\n\n/workspace/node_modules/next/dist/compiled/next-server/pages-api-turbo.runtime.prod.js.map:\n Line 1: {\"version\":3,\"file\":\"pages-api-turbo.runtime.prod.js\",\"sources\":[\"webpack://next/webpack/runtime/create_fake_namespace_object\",\"webpack://next/./dist/compiled/@edge-runtime/cookies/index.js\",\"webpack://next/./dist/compiled/bytes/index.js\",\"webpack://next/./dist/compiled/content-type/index.js\",\"webpack://next/./dist/compiled/cookie/index.js\",\"webpack://next/./dist/compiled/fresh/index.js\",\"webpack://next/./dist/compiled/path-to-regexp/index.js\",\"webpack://next/./src/lib/constants.ts\",\"webpack://next/./src/lib/format-dynamic-import-path.ts\",\"webpack://next/./src/server/api-utils/index.ts\",\"webpack://next/./src/server/api-utils/node/try-get-preview-data.ts\",\"webpack://next/./src/server/crypto-utils.ts\",\"webpack://next/./src/server/lib/node-fs-methods.ts\",\"webpack://next/./src/server/lib/trace/constants.ts\",\"webpack://next/./src/server/lib/router-utils/is-postpone.ts\",\"webpack://next/./src/server/node-environment-extensions/process-error-handlers.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/reflect.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/headers.ts\",\"webpack://next/./src/shared/lib/isomorphic/path.js\",\"webpack://next/./src/shared/lib/modern-browserslist-target.js\",\"webpack://next/webpack/runtime/compat_get_default_export\",\"webpack://next/webpack/runtime/define_property_getters\",\"webpack://next/webpack/runtime/has_own_property\",\"webpack://next/webpack/runtime/make_namespace_object\",\"webpack://next/./src/server/response-cache/types.ts\",\"webpack://next/./src/server/route-kind.ts\",\"webpack://next/./src/lib/picocolors.ts\",\"webpack://next/./src/shared/lib/constants.ts\",\"webpack://next/./src/lib/url.ts\",\"webpack://next/./src/shared/lib/i18n/normalize-locale-path.ts\",\"webpack://next/./src/shared/lib/page-path/ensure-leading-slash.ts\",\"webpack://next/./src/shared/lib/router/utils/app-paths.ts\",\"webpack://next/./src/shared/lib/segment.ts\",\"webpack://next/./src/shared/lib/router/utils/interception-routes.ts\",\"webpack://next/./src/shared/lib/rou...\n\n/workspace/node_modules/next/dist/compiled/next-server/pages-api-turbo.runtime.dev.js.map:\n Line 1: {\"version\":3,\"file\":\"pages-api-turbo.runtime.dev.js\",\"sources\":[\"webpack://next/webpack/runtime/create_fake_namespace_object\",\"webpack://next/./dist/compiled/@edge-runtime/cookies/index.js\",\"webpack://next/./dist/compiled/bytes/index.js\",\"webpack://next/./dist/compiled/content-type/index.js\",\"webpack://next/./dist/compiled/cookie/index.js\",\"webpack://next/./dist/compiled/fresh/index.js\",\"webpack://next/./dist/compiled/path-to-regexp/index.js\",\"webpack://next/./src/lib/constants.ts\",\"webpack://next/./src/lib/format-dynamic-import-path.ts\",\"webpack://next/./src/server/api-utils/index.ts\",\"webpack://next/./src/server/api-utils/node/try-get-preview-data.ts\",\"webpack://next/./src/server/crypto-utils.ts\",\"webpack://next/./src/server/lib/node-fs-methods.ts\",\"webpack://next/./src/server/lib/trace/constants.ts\",\"webpack://next/./src/server/lib/router-utils/is-postpone.ts\",\"webpack://next/./src/server/node-environment-extensions/process-error-handlers.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/headers.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/reflect.ts\",\"webpack://next/./src/shared/lib/isomorphic/path.js\",\"webpack://next/./src/shared/lib/modern-browserslist-target.js\",\"webpack://next/webpack/runtime/compat_get_default_export\",\"webpack://next/webpack/runtime/define_property_getters\",\"webpack://next/webpack/runtime/has_own_property\",\"webpack://next/webpack/runtime/make_namespace_object\",\"webpack://next/./src/server/response-cache/types.ts\",\"webpack://next/./src/server/route-kind.ts\",\"webpack://next/./src/lib/picocolors.ts\",\"webpack://next/./src/shared/lib/constants.ts\",\"webpack://next/./src/lib/url.ts\",\"webpack://next/./src/shared/lib/i18n/normalize-locale-path.ts\",\"webpack://next/./src/shared/lib/page-path/ensure-leading-slash.ts\",\"webpack://next/./src/shared/lib/router/utils/app-paths.ts\",\"webpack://next/./src/shared/lib/segment.ts\",\"webpack://next/./src/shared/lib/router/utils/interception-routes.ts\",\"webpack://next/./src/shared/lib/rout...\n\n/workspace/node_modules/next/dist/server/lib/incremental-cache/index.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../../../src/server/lib/incremental-cache/index.ts\"],\"sourcesContent\":[\"import type { CacheFs } from '../../../shared/lib/utils'\\nimport type { PrerenderManifest } from '../../../build'\\nimport {\\n type IncrementalCacheValue,\\n type IncrementalCacheEntry,\\n type IncrementalCache as IncrementalCacheType,\\n IncrementalCacheKind,\\n CachedRouteKind,\\n type IncrementalResponseCacheEntry,\\n type IncrementalFetchCacheEntry,\\n type GetIncrementalFetchCacheContext,\\n type GetIncrementalResponseCacheContext,\\n type CachedFetchValue,\\n type SetIncrementalFetchCacheContext,\\n type SetIncrementalResponseCacheContext,\\n} from '../../response-cache'\\nimport type { DeepReadonly } from '../../../shared/lib/deep-readonly'\\nimport FileSystemCache from './file-system-cache'\\nimport { normalizePagePath } from '../../../shared/lib/page-path/normalize-page-path'\\n\\nimport {\\n CACHE_ONE_YEAR_SECONDS,\\n NEXT_CACHE_TAGS_HEADER,\\n PRERENDER_REVALIDATE_HEADER,\\n} from '../../../lib/constants'\\nimport { toRoute } from '../to-route'\\nimport { SharedCacheControls } from './shared-cache-controls.external'\\nimport {\\n getResumeDataCache,\\n workUnitAsyncStorage,\\n} from '../../app-render/work-unit-async-storage.external'\\nimport { InvariantError } from '../../../shared/lib/invariant-error'\\nimport type { Revalidate } from '../cache-control'\\nimport { getPreviouslyRevalidatedTags } from '../../server-utils'\\nimport { workAsyncStorage } from '../../app-render/work-async-storage.external'\\nimport { DetachedPromise } from '../../../lib/detached-promise'\\nimport { areTagsExpired, areTagsStale } from './tags-manifest.external'\\n\\nexport interface CacheHandlerContext {\\n fs?: CacheFs\\n dev?: boolean\\n flushToDisk?: boolean\\n serverDistDir?: string\\n maxMemoryCacheSize?: number\\n fetchCacheKeyPrefix?: string\\n prerenderManifest?: PrerenderManifest\\n revalidatedTags: string[]\\n _requestHeaders: IncrementalCache['requestHeaders']\\n}\\n\\nexport interface Cac...\n\n/workspace/node_modules/next/dist/esm/server/lib/incremental-cache/index.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../../../../src/server/lib/incremental-cache/index.ts\"],\"sourcesContent\":[\"import type { CacheFs } from '../../../shared/lib/utils'\\nimport type { PrerenderManifest } from '../../../build'\\nimport {\\n type IncrementalCacheValue,\\n type IncrementalCacheEntry,\\n type IncrementalCache as IncrementalCacheType,\\n IncrementalCacheKind,\\n CachedRouteKind,\\n type IncrementalResponseCacheEntry,\\n type IncrementalFetchCacheEntry,\\n type GetIncrementalFetchCacheContext,\\n type GetIncrementalResponseCacheContext,\\n type CachedFetchValue,\\n type SetIncrementalFetchCacheContext,\\n type SetIncrementalResponseCacheContext,\\n} from '../../response-cache'\\nimport type { DeepReadonly } from '../../../shared/lib/deep-readonly'\\nimport FileSystemCache from './file-system-cache'\\nimport { normalizePagePath } from '../../../shared/lib/page-path/normalize-page-path'\\n\\nimport {\\n CACHE_ONE_YEAR_SECONDS,\\n NEXT_CACHE_TAGS_HEADER,\\n PRERENDER_REVALIDATE_HEADER,\\n} from '../../../lib/constants'\\nimport { toRoute } from '../to-route'\\nimport { SharedCacheControls } from './shared-cache-controls.external'\\nimport {\\n getResumeDataCache,\\n workUnitAsyncStorage,\\n} from '../../app-render/work-unit-async-storage.external'\\nimport { InvariantError } from '../../../shared/lib/invariant-error'\\nimport type { Revalidate } from '../cache-control'\\nimport { getPreviouslyRevalidatedTags } from '../../server-utils'\\nimport { workAsyncStorage } from '../../app-render/work-async-storage.external'\\nimport { DetachedPromise } from '../../../lib/detached-promise'\\nimport { areTagsExpired, areTagsStale } from './tags-manifest.external'\\n\\nexport interface CacheHandlerContext {\\n fs?: CacheFs\\n dev?: boolean\\n flushToDisk?: boolean\\n serverDistDir?: string\\n maxMemoryCacheSize?: number\\n fetchCacheKeyPrefix?: string\\n prerenderManifest?: PrerenderManifest\\n revalidatedTags: string[]\\n _requestHeaders: IncrementalCache['requestHeaders']\\n}\\n\\nexport interface ...\n\n/workspace/node_modules/next/dist/server/lib/incremental-cache/file-system-cache.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../../../src/server/lib/incremental-cache/file-system-cache.ts\"],\"sourcesContent\":[\"import type { RouteMetadata } from '../../../export/routes/types'\\nimport type { CacheHandler, CacheHandlerContext, CacheHandlerValue } from '.'\\nimport type { CacheFs } from '../../../shared/lib/utils'\\nimport type { TagManifestEntry } from './tags-manifest.external'\\nimport {\\n CachedRouteKind,\\n IncrementalCacheKind,\\n type CachedFetchValue,\\n type IncrementalCacheValue,\\n type SetIncrementalFetchCacheContext,\\n type SetIncrementalResponseCacheContext,\\n} from '../../response-cache'\\n\\nimport type { LRUCache } from '../lru-cache'\\nimport path from '../../../shared/lib/isomorphic/path'\\nimport {\\n NEXT_CACHE_TAGS_HEADER,\\n NEXT_DATA_SUFFIX,\\n NEXT_META_SUFFIX,\\n RSC_SEGMENT_SUFFIX,\\n RSC_SEGMENTS_DIR_SUFFIX,\\n RSC_SUFFIX,\\n} from '../../../lib/constants'\\nimport { areTagsExpired, tagsManifest } from './tags-manifest.external'\\nimport { MultiFileWriter } from '../../../lib/multi-file-writer'\\nimport { getMemoryCache } from './memory-cache.external'\\n\\ntype FileSystemCacheContext = Omit<\\n CacheHandlerContext,\\n 'fs' | 'serverDistDir'\\n> & {\\n fs: CacheFs\\n serverDistDir: string\\n}\\n\\nexport default class FileSystemCache implements CacheHandler {\\n private fs: FileSystemCacheContext['fs']\\n private flushToDisk?: FileSystemCacheContext['flushToDisk']\\n private serverDistDir: FileSystemCacheContext['serverDistDir']\\n private revalidatedTags: string[]\\n private static debug: boolean = !!process.env.NEXT_PRIVATE_DEBUG_CACHE\\n private static memoryCache: LRUCache | undefined\\n\\n constructor(ctx: FileSystemCacheContext) {\\n this.fs = ctx.fs\\n this.flushToDisk = ctx.flushToDisk\\n this.serverDistDir = ctx.serverDistDir\\n this.revalidatedTags = ctx.revalidatedTags\\n\\n if (ctx.maxMemoryCacheSize) {\\n if (!FileSystemCache.memoryCache) {\\n if (FileSystemCache.debug) {\\n console.log('FileSyst...\n\n/workspace/node_modules/next/dist/esm/server/lib/incremental-cache/file-system-cache.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../../../../src/server/lib/incremental-cache/file-system-cache.ts\"],\"sourcesContent\":[\"import type { RouteMetadata } from '../../../export/routes/types'\\nimport type { CacheHandler, CacheHandlerContext, CacheHandlerValue } from '.'\\nimport type { CacheFs } from '../../../shared/lib/utils'\\nimport type { TagManifestEntry } from './tags-manifest.external'\\nimport {\\n CachedRouteKind,\\n IncrementalCacheKind,\\n type CachedFetchValue,\\n type IncrementalCacheValue,\\n type SetIncrementalFetchCacheContext,\\n type SetIncrementalResponseCacheContext,\\n} from '../../response-cache'\\n\\nimport type { LRUCache } from '../lru-cache'\\nimport path from '../../../shared/lib/isomorphic/path'\\nimport {\\n NEXT_CACHE_TAGS_HEADER,\\n NEXT_DATA_SUFFIX,\\n NEXT_META_SUFFIX,\\n RSC_SEGMENT_SUFFIX,\\n RSC_SEGMENTS_DIR_SUFFIX,\\n RSC_SUFFIX,\\n} from '../../../lib/constants'\\nimport { areTagsExpired, tagsManifest } from './tags-manifest.external'\\nimport { MultiFileWriter } from '../../../lib/multi-file-writer'\\nimport { getMemoryCache } from './memory-cache.external'\\n\\ntype FileSystemCacheContext = Omit<\\n CacheHandlerContext,\\n 'fs' | 'serverDistDir'\\n> & {\\n fs: CacheFs\\n serverDistDir: string\\n}\\n\\nexport default class FileSystemCache implements CacheHandler {\\n private fs: FileSystemCacheContext['fs']\\n private flushToDisk?: FileSystemCacheContext['flushToDisk']\\n private serverDistDir: FileSystemCacheContext['serverDistDir']\\n private revalidatedTags: string[]\\n private static debug: boolean = !!process.env.NEXT_PRIVATE_DEBUG_CACHE\\n private static memoryCache: LRUCache | undefined\\n\\n constructor(ctx: FileSystemCacheContext) {\\n this.fs = ctx.fs\\n this.flushToDisk = ctx.flushToDisk\\n this.serverDistDir = ctx.serverDistDir\\n this.revalidatedTags = ctx.revalidatedTags\\n\\n if (ctx.maxMemoryCacheSize) {\\n if (!FileSystemCache.memoryCache) {\\n if (FileSystemCache.debug) {\\n console.log('FileS...\n\n/workspace/node_modules/next/dist/server/lib/router-utils/cache-life-type-utils.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../../../src/server/lib/router-utils/cache-life-type-utils.ts\"],\"sourcesContent\":[\"import type { CacheLife } from '../../use-cache/cache-life'\\nimport fs from 'fs'\\nimport path from 'path'\\n\\nconst MINUTE_IN_SECONDS = 60\\nconst HOUR_IN_SECONDS = MINUTE_IN_SECONDS * 60 // nevermind leap seconds\\nconst DAY_IN_SECONDS = HOUR_IN_SECONDS * 24\\nconst WEEK_IN_SECONDS = DAY_IN_SECONDS * 7\\n// Nevermind leap years, or you know, July\\nconst MONTH_30_DAYS_IN_SECONDS = DAY_IN_SECONDS * 30\\n\\nfunction formatTimespan(seconds: number): string {\\n if (seconds > 0) {\\n if (seconds === MONTH_30_DAYS_IN_SECONDS) {\\n return '1 month'\\n }\\n if (seconds === WEEK_IN_SECONDS) {\\n return '1 week'\\n }\\n if (seconds === DAY_IN_SECONDS) {\\n return '1 day'\\n }\\n if (seconds === HOUR_IN_SECONDS) {\\n return '1 hour'\\n }\\n if (seconds === MINUTE_IN_SECONDS) {\\n return '1 minute'\\n }\\n if (seconds % MONTH_30_DAYS_IN_SECONDS === 0) {\\n return seconds / MONTH_30_DAYS_IN_SECONDS + ' months'\\n }\\n if (seconds % 18144000 === 0) {\\n return seconds / 18144000 + ' months'\\n }\\n if (seconds % WEEK_IN_SECONDS === 0) {\\n return seconds / WEEK_IN_SECONDS + ' weeks'\\n }\\n if (seconds % DAY_IN_SECONDS === 0) {\\n return seconds / DAY_IN_SECONDS + ' days'\\n }\\n if (seconds % HOUR_IN_SECONDS === 0) {\\n return seconds / HOUR_IN_SECONDS + ' hours'\\n }\\n if (seconds % MINUTE_IN_SECONDS === 0) {\\n return seconds / MINUTE_IN_SECONDS + ' minutes'\\n }\\n }\\n return seconds + ' seconds'\\n}\\n\\nfunction formatTimespanWithSeconds(seconds: undefined | number): string {\\n if (seconds === undefined) {\\n return 'default'\\n }\\n if (seconds >= 0xfffffffe) {\\n return 'never'\\n }\\n const text = seconds + ' seconds'\\n const descriptive = formatTimespan(seconds)\\n if (descriptive === text) {\\n return text\\n }\\n return text + ' (' + descriptive + ')'\\n}\\n\\n/**\\n * Genera...\n\n/workspace/node_modules/next/dist/esm/server/lib/router-utils/cache-life-type-utils.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../../../../src/server/lib/router-utils/cache-life-type-utils.ts\"],\"sourcesContent\":[\"import type { CacheLife } from '../../use-cache/cache-life'\\nimport fs from 'fs'\\nimport path from 'path'\\n\\nconst MINUTE_IN_SECONDS = 60\\nconst HOUR_IN_SECONDS = MINUTE_IN_SECONDS * 60 // nevermind leap seconds\\nconst DAY_IN_SECONDS = HOUR_IN_SECONDS * 24\\nconst WEEK_IN_SECONDS = DAY_IN_SECONDS * 7\\n// Nevermind leap years, or you know, July\\nconst MONTH_30_DAYS_IN_SECONDS = DAY_IN_SECONDS * 30\\n\\nfunction formatTimespan(seconds: number): string {\\n if (seconds > 0) {\\n if (seconds === MONTH_30_DAYS_IN_SECONDS) {\\n return '1 month'\\n }\\n if (seconds === WEEK_IN_SECONDS) {\\n return '1 week'\\n }\\n if (seconds === DAY_IN_SECONDS) {\\n return '1 day'\\n }\\n if (seconds === HOUR_IN_SECONDS) {\\n return '1 hour'\\n }\\n if (seconds === MINUTE_IN_SECONDS) {\\n return '1 minute'\\n }\\n if (seconds % MONTH_30_DAYS_IN_SECONDS === 0) {\\n return seconds / MONTH_30_DAYS_IN_SECONDS + ' months'\\n }\\n if (seconds % 18144000 === 0) {\\n return seconds / 18144000 + ' months'\\n }\\n if (seconds % WEEK_IN_SECONDS === 0) {\\n return seconds / WEEK_IN_SECONDS + ' weeks'\\n }\\n if (seconds % DAY_IN_SECONDS === 0) {\\n return seconds / DAY_IN_SECONDS + ' days'\\n }\\n if (seconds % HOUR_IN_SECONDS === 0) {\\n return seconds / HOUR_IN_SECONDS + ' hours'\\n }\\n if (seconds % MINUTE_IN_SECONDS === 0) {\\n return seconds / MINUTE_IN_SECONDS + ' minutes'\\n }\\n }\\n return seconds + ' seconds'\\n}\\n\\nfunction formatTimespanWithSeconds(seconds: undefined | number): string {\\n if (seconds === undefined) {\\n return 'default'\\n }\\n if (seconds >= 0xfffffffe) {\\n return 'never'\\n }\\n const text = seconds + ' seconds'\\n const descriptive = formatTimespan(seconds)\\n if (descriptive === text) {\\n return text\\n }\\n return text + ' (' + descriptive + ')'\\n}\\n\\n/**\\n * Gen...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-route.runtime.prod.js.map:\n Line 1: {\"version\":3,\"file\":\"app-route.runtime.prod.js\",\"sources\":[\"webpack://next/webpack/runtime/create_fake_namespace_object\",\"webpack://next/./dist/compiled/@edge-runtime/cookies/index.js\",\"webpack://next/./dist/compiled/cookie/index.js\",\"webpack://next/./dist/compiled/p-queue/index.js\",\"webpack://next/./dist/compiled/path-to-regexp/index.js\",\"webpack://next/./dist/compiled/react/cjs/react.production.js\",\"webpack://next/./dist/compiled/react/index.js\",\"webpack://next/./dist/compiled/string-hash/index.js\",\"webpack://next/./src/lib/constants.ts\",\"webpack://next/./src/lib/format-dynamic-import-path.ts\",\"webpack://next/./src/server/api-utils/index.ts\",\"webpack://next/./src/server/api-utils/node/try-get-preview-data.ts\",\"webpack://next/./src/server/app-render/instant-validation/instant-samples.ts\",\"webpack://next/./src/server/app-render/instant-validation/instant-validation-error.ts\",\"webpack://next/./src/server/crypto-utils.ts\",\"webpack://next/./src/server/lib/node-fs-methods.ts\",\"webpack://next/./src/server/lib/router-utils/is-postpone.ts\",\"webpack://next/./src/server/lib/trace/constants.ts\",\"webpack://next/./src/server/node-environment-extensions/process-error-handlers.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/headers.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/reflect.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/request-cookies.ts\",\"webpack://next/./src/shared/lib/action-revalidation-kind.ts\",\"webpack://next/./src/shared/lib/invariant-error.ts\",\"webpack://next/./src/shared/lib/isomorphic/path.js\",\"webpack://next/./src/shared/lib/modern-browserslist-target.js\",\"webpack://next/./src/shared/lib/page-path/ensure-leading-slash.ts\",\"webpack://next/./src/shared/lib/router/utils/app-paths.ts\",\"webpack://next/./src/shared/lib/router/utils/get-segment-param.tsx\",\"webpack://next/./src/shared/lib/router/utils/interception-routes.ts\",\"webpack://next/./src/shared/lib/router/utils/parse-relative-url.ts\",\"webpack://next/./src/shared/li...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-route.runtime.dev.js.map:\n Line 1: {\"version\":3,\"file\":\"app-route.runtime.dev.js\",\"sources\":[\"webpack://next/webpack/runtime/create_fake_namespace_object\",\"webpack://next/./dist/compiled/@edge-runtime/cookies/index.js\",\"webpack://next/./dist/compiled/cookie/index.js\",\"webpack://next/./dist/compiled/p-queue/index.js\",\"webpack://next/./dist/compiled/path-to-regexp/index.js\",\"webpack://next/./dist/compiled/react/cjs/react.development.js\",\"webpack://next/./dist/compiled/react/index.js\",\"webpack://next/./dist/compiled/string-hash/index.js\",\"webpack://next/./src/lib/constants.ts\",\"webpack://next/./src/lib/format-dynamic-import-path.ts\",\"webpack://next/./src/server/api-utils/index.ts\",\"webpack://next/./src/server/api-utils/node/try-get-preview-data.ts\",\"webpack://next/./src/server/app-render/instant-validation/instant-samples.ts\",\"webpack://next/./src/server/app-render/instant-validation/instant-validation-error.ts\",\"webpack://next/./src/server/crypto-utils.ts\",\"webpack://next/./src/server/lib/node-fs-methods.ts\",\"webpack://next/./src/server/lib/router-utils/is-postpone.ts\",\"webpack://next/./src/server/lib/trace/constants.ts\",\"webpack://next/./src/server/node-environment-extensions/process-error-handlers.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/headers.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/reflect.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/request-cookies.ts\",\"webpack://next/./src/shared/lib/action-revalidation-kind.ts\",\"webpack://next/./src/shared/lib/invariant-error.ts\",\"webpack://next/./src/shared/lib/isomorphic/path.js\",\"webpack://next/./src/shared/lib/modern-browserslist-target.js\",\"webpack://next/./src/shared/lib/page-path/ensure-leading-slash.ts\",\"webpack://next/./src/shared/lib/router/utils/app-paths.ts\",\"webpack://next/./src/shared/lib/router/utils/get-segment-param.tsx\",\"webpack://next/./src/shared/lib/router/utils/interception-routes.ts\",\"webpack://next/./src/shared/lib/router/utils/parse-relative-url.ts\",\"webpack://next/./src/shared/li...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-route-turbo.runtime.prod.js.map:\n Line 1: {\"version\":3,\"file\":\"app-route-turbo.runtime.prod.js\",\"sources\":[\"webpack://next/webpack/runtime/create_fake_namespace_object\",\"webpack://next/./dist/compiled/@edge-runtime/cookies/index.js\",\"webpack://next/./dist/compiled/cookie/index.js\",\"webpack://next/./dist/compiled/p-queue/index.js\",\"webpack://next/./dist/compiled/path-to-regexp/index.js\",\"webpack://next/./dist/compiled/react/cjs/react.production.js\",\"webpack://next/./dist/compiled/react/index.js\",\"webpack://next/./dist/compiled/string-hash/index.js\",\"webpack://next/./src/lib/constants.ts\",\"webpack://next/./src/lib/format-dynamic-import-path.ts\",\"webpack://next/./src/server/api-utils/index.ts\",\"webpack://next/./src/server/api-utils/node/try-get-preview-data.ts\",\"webpack://next/./src/server/app-render/instant-validation/instant-samples.ts\",\"webpack://next/./src/server/app-render/instant-validation/instant-validation-error.ts\",\"webpack://next/./src/server/crypto-utils.ts\",\"webpack://next/./src/server/lib/node-fs-methods.ts\",\"webpack://next/./src/server/lib/router-utils/is-postpone.ts\",\"webpack://next/./src/server/lib/trace/constants.ts\",\"webpack://next/./src/server/node-environment-extensions/process-error-handlers.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/headers.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/reflect.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/request-cookies.ts\",\"webpack://next/./src/shared/lib/action-revalidation-kind.ts\",\"webpack://next/./src/shared/lib/invariant-error.ts\",\"webpack://next/./src/shared/lib/isomorphic/path.js\",\"webpack://next/./src/shared/lib/modern-browserslist-target.js\",\"webpack://next/./src/shared/lib/page-path/ensure-leading-slash.ts\",\"webpack://next/./src/shared/lib/router/utils/app-paths.ts\",\"webpack://next/./src/shared/lib/router/utils/get-segment-param.tsx\",\"webpack://next/./src/shared/lib/router/utils/interception-routes.ts\",\"webpack://next/./src/shared/lib/router/utils/parse-relative-url.ts\",\"webpack://next/./src/sha...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-route-turbo.runtime.dev.js.map:\n Line 1: {\"version\":3,\"file\":\"app-route-turbo.runtime.dev.js\",\"sources\":[\"webpack://next/webpack/runtime/create_fake_namespace_object\",\"webpack://next/./dist/compiled/@edge-runtime/cookies/index.js\",\"webpack://next/./dist/compiled/cookie/index.js\",\"webpack://next/./dist/compiled/p-queue/index.js\",\"webpack://next/./dist/compiled/path-to-regexp/index.js\",\"webpack://next/./dist/compiled/react/cjs/react.development.js\",\"webpack://next/./dist/compiled/react/index.js\",\"webpack://next/./dist/compiled/string-hash/index.js\",\"webpack://next/./src/lib/constants.ts\",\"webpack://next/./src/lib/format-dynamic-import-path.ts\",\"webpack://next/./src/server/api-utils/index.ts\",\"webpack://next/./src/server/api-utils/node/try-get-preview-data.ts\",\"webpack://next/./src/server/app-render/instant-validation/instant-samples.ts\",\"webpack://next/./src/server/app-render/instant-validation/instant-validation-error.ts\",\"webpack://next/./src/server/crypto-utils.ts\",\"webpack://next/./src/server/lib/node-fs-methods.ts\",\"webpack://next/./src/server/lib/router-utils/is-postpone.ts\",\"webpack://next/./src/server/lib/trace/constants.ts\",\"webpack://next/./src/server/node-environment-extensions/process-error-handlers.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/headers.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/reflect.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/request-cookies.ts\",\"webpack://next/./src/shared/lib/action-revalidation-kind.ts\",\"webpack://next/./src/shared/lib/invariant-error.ts\",\"webpack://next/./src/shared/lib/isomorphic/path.js\",\"webpack://next/./src/shared/lib/modern-browserslist-target.js\",\"webpack://next/./src/shared/lib/page-path/ensure-leading-slash.ts\",\"webpack://next/./src/shared/lib/router/utils/app-paths.ts\",\"webpack://next/./src/shared/lib/router/utils/get-segment-param.tsx\",\"webpack://next/./src/shared/lib/router/utils/interception-routes.ts\",\"webpack://next/./src/shared/lib/router/utils/parse-relative-url.ts\",\"webpack://next/./src/sha...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-route-turbo-experimental.runtime.prod.js.map:\n Line 1: {\"version\":3,\"file\":\"app-route-turbo-experimental.runtime.prod.js\",\"sources\":[\"webpack://next/webpack/runtime/create_fake_namespace_object\",\"webpack://next/./dist/compiled/@edge-runtime/cookies/index.js\",\"webpack://next/./dist/compiled/cookie/index.js\",\"webpack://next/./dist/compiled/p-queue/index.js\",\"webpack://next/./dist/compiled/path-to-regexp/index.js\",\"webpack://next/./dist/compiled/react-experimental/cjs/react.production.js\",\"webpack://next/./dist/compiled/react-experimental/index.js\",\"webpack://next/./dist/compiled/string-hash/index.js\",\"webpack://next/./src/lib/constants.ts\",\"webpack://next/./src/lib/format-dynamic-import-path.ts\",\"webpack://next/./src/server/api-utils/index.ts\",\"webpack://next/./src/server/api-utils/node/try-get-preview-data.ts\",\"webpack://next/./src/server/app-render/instant-validation/instant-samples.ts\",\"webpack://next/./src/server/app-render/instant-validation/instant-validation-error.ts\",\"webpack://next/./src/server/crypto-utils.ts\",\"webpack://next/./src/server/lib/node-fs-methods.ts\",\"webpack://next/./src/server/lib/router-utils/is-postpone.ts\",\"webpack://next/./src/server/lib/trace/constants.ts\",\"webpack://next/./src/server/node-environment-extensions/process-error-handlers.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/headers.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/reflect.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/request-cookies.ts\",\"webpack://next/./src/shared/lib/action-revalidation-kind.ts\",\"webpack://next/./src/shared/lib/invariant-error.ts\",\"webpack://next/./src/shared/lib/isomorphic/path.js\",\"webpack://next/./src/shared/lib/modern-browserslist-target.js\",\"webpack://next/./src/shared/lib/page-path/ensure-leading-slash.ts\",\"webpack://next/./src/shared/lib/router/utils/app-paths.ts\",\"webpack://next/./src/shared/lib/router/utils/get-segment-param.tsx\",\"webpack://next/./src/shared/lib/router/utils/interception-routes.ts\",\"webpack://next/./src/shared/lib/router/utils/parse-rel...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-route-turbo-experimental.runtime.dev.js.map:\n Line 1: {\"version\":3,\"file\":\"app-route-turbo-experimental.runtime.dev.js\",\"sources\":[\"webpack://next/webpack/runtime/create_fake_namespace_object\",\"webpack://next/./dist/compiled/@edge-runtime/cookies/index.js\",\"webpack://next/./dist/compiled/cookie/index.js\",\"webpack://next/./dist/compiled/p-queue/index.js\",\"webpack://next/./dist/compiled/path-to-regexp/index.js\",\"webpack://next/./dist/compiled/react-experimental/cjs/react.development.js\",\"webpack://next/./dist/compiled/react-experimental/index.js\",\"webpack://next/./dist/compiled/string-hash/index.js\",\"webpack://next/./src/lib/constants.ts\",\"webpack://next/./src/lib/format-dynamic-import-path.ts\",\"webpack://next/./src/server/api-utils/index.ts\",\"webpack://next/./src/server/api-utils/node/try-get-preview-data.ts\",\"webpack://next/./src/server/app-render/instant-validation/instant-samples.ts\",\"webpack://next/./src/server/app-render/instant-validation/instant-validation-error.ts\",\"webpack://next/./src/server/crypto-utils.ts\",\"webpack://next/./src/server/lib/node-fs-methods.ts\",\"webpack://next/./src/server/lib/router-utils/is-postpone.ts\",\"webpack://next/./src/server/lib/trace/constants.ts\",\"webpack://next/./src/server/node-environment-extensions/process-error-handlers.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/headers.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/reflect.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/request-cookies.ts\",\"webpack://next/./src/shared/lib/action-revalidation-kind.ts\",\"webpack://next/./src/shared/lib/invariant-error.ts\",\"webpack://next/./src/shared/lib/isomorphic/path.js\",\"webpack://next/./src/shared/lib/modern-browserslist-target.js\",\"webpack://next/./src/shared/lib/page-path/ensure-leading-slash.ts\",\"webpack://next/./src/shared/lib/router/utils/app-paths.ts\",\"webpack://next/./src/shared/lib/router/utils/get-segment-param.tsx\",\"webpack://next/./src/shared/lib/router/utils/interception-routes.ts\",\"webpack://next/./src/shared/lib/router/utils/parse-rel...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-route-experimental.runtime.prod.js.map:\n Line 1: {\"version\":3,\"file\":\"app-route-experimental.runtime.prod.js\",\"sources\":[\"webpack://next/webpack/runtime/create_fake_namespace_object\",\"webpack://next/./dist/compiled/@edge-runtime/cookies/index.js\",\"webpack://next/./dist/compiled/cookie/index.js\",\"webpack://next/./dist/compiled/p-queue/index.js\",\"webpack://next/./dist/compiled/path-to-regexp/index.js\",\"webpack://next/./dist/compiled/react-experimental/cjs/react.production.js\",\"webpack://next/./dist/compiled/react-experimental/index.js\",\"webpack://next/./dist/compiled/string-hash/index.js\",\"webpack://next/./src/lib/constants.ts\",\"webpack://next/./src/lib/format-dynamic-import-path.ts\",\"webpack://next/./src/server/api-utils/index.ts\",\"webpack://next/./src/server/api-utils/node/try-get-preview-data.ts\",\"webpack://next/./src/server/app-render/instant-validation/instant-samples.ts\",\"webpack://next/./src/server/app-render/instant-validation/instant-validation-error.ts\",\"webpack://next/./src/server/crypto-utils.ts\",\"webpack://next/./src/server/lib/node-fs-methods.ts\",\"webpack://next/./src/server/lib/router-utils/is-postpone.ts\",\"webpack://next/./src/server/lib/trace/constants.ts\",\"webpack://next/./src/server/node-environment-extensions/process-error-handlers.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/headers.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/reflect.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/request-cookies.ts\",\"webpack://next/./src/shared/lib/action-revalidation-kind.ts\",\"webpack://next/./src/shared/lib/invariant-error.ts\",\"webpack://next/./src/shared/lib/isomorphic/path.js\",\"webpack://next/./src/shared/lib/modern-browserslist-target.js\",\"webpack://next/./src/shared/lib/page-path/ensure-leading-slash.ts\",\"webpack://next/./src/shared/lib/router/utils/app-paths.ts\",\"webpack://next/./src/shared/lib/router/utils/get-segment-param.tsx\",\"webpack://next/./src/shared/lib/router/utils/interception-routes.ts\",\"webpack://next/./src/shared/lib/router/utils/parse-relative-...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-route-experimental.runtime.dev.js.map:\n Line 1: {\"version\":3,\"file\":\"app-route-experimental.runtime.dev.js\",\"sources\":[\"webpack://next/webpack/runtime/create_fake_namespace_object\",\"webpack://next/./dist/compiled/@edge-runtime/cookies/index.js\",\"webpack://next/./dist/compiled/cookie/index.js\",\"webpack://next/./dist/compiled/p-queue/index.js\",\"webpack://next/./dist/compiled/path-to-regexp/index.js\",\"webpack://next/./dist/compiled/react-experimental/cjs/react.development.js\",\"webpack://next/./dist/compiled/react-experimental/index.js\",\"webpack://next/./dist/compiled/string-hash/index.js\",\"webpack://next/./src/lib/constants.ts\",\"webpack://next/./src/lib/format-dynamic-import-path.ts\",\"webpack://next/./src/server/api-utils/index.ts\",\"webpack://next/./src/server/api-utils/node/try-get-preview-data.ts\",\"webpack://next/./src/server/app-render/instant-validation/instant-samples.ts\",\"webpack://next/./src/server/app-render/instant-validation/instant-validation-error.ts\",\"webpack://next/./src/server/crypto-utils.ts\",\"webpack://next/./src/server/lib/node-fs-methods.ts\",\"webpack://next/./src/server/lib/router-utils/is-postpone.ts\",\"webpack://next/./src/server/lib/trace/constants.ts\",\"webpack://next/./src/server/node-environment-extensions/process-error-handlers.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/headers.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/reflect.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/request-cookies.ts\",\"webpack://next/./src/shared/lib/action-revalidation-kind.ts\",\"webpack://next/./src/shared/lib/invariant-error.ts\",\"webpack://next/./src/shared/lib/isomorphic/path.js\",\"webpack://next/./src/shared/lib/modern-browserslist-target.js\",\"webpack://next/./src/shared/lib/page-path/ensure-leading-slash.ts\",\"webpack://next/./src/shared/lib/router/utils/app-paths.ts\",\"webpack://next/./src/shared/lib/router/utils/get-segment-param.tsx\",\"webpack://next/./src/shared/lib/router/utils/interception-routes.ts\",\"webpack://next/./src/shared/lib/router/utils/parse-relative-...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js.map:\n Line 1: {\"version\":3,\"file\":\"app-page.runtime.prod.js\",\"sources\":[\"webpack://next/webpack/runtime/create_fake_namespace_object\",\"webpack://next/./src/build/webpack/alias/react-dom-server.js\",\"webpack://next/./dist/compiled/@edge-runtime/cookies/index.js\",\"webpack://next/./dist/compiled/busboy/index.js\",\"webpack://next/./dist/compiled/bytes/index.js\",\"webpack://next/./dist/compiled/cookie/index.js\",\"webpack://next/./dist/compiled/p-queue/index.js\",\"webpack://next/./dist/compiled/path-to-regexp/index.js\",\"webpack://next/./dist/compiled/react-dom/cjs/react-dom-server.node.production.js\",\"webpack://next/./dist/compiled/react-dom/cjs/react-dom.production.js\",\"webpack://next/./dist/compiled/react-dom/index.js\",\"webpack://next/./dist/compiled/react-dom/static.node.js\",\"webpack://next/./dist/compiled/react-is/cjs/react-is.production.js\",\"webpack://next/./dist/compiled/react-is/index.js\",\"webpack://next/./dist/compiled/react-server-dom-webpack/cjs/react-server-dom-webpack-client.node.production.js\",\"webpack://next/./dist/compiled/react-server-dom-webpack/client.node.js\",\"webpack://next/./dist/compiled/react/cjs/react-compiler-runtime.production.js\",\"webpack://next/./dist/compiled/react/cjs/react-jsx-dev-runtime.production.js\",\"webpack://next/./dist/compiled/react/cjs/react-jsx-runtime.production.js\",\"webpack://next/./dist/compiled/react/cjs/react.production.js\",\"webpack://next/./dist/compiled/react/compiler-runtime.js\",\"webpack://next/./dist/compiled/react/index.js\",\"webpack://next/./dist/compiled/react/jsx-dev-runtime.js\",\"webpack://next/./dist/compiled/react/jsx-runtime.js\",\"webpack://next/./dist/compiled/string-hash/index.js\",\"webpack://next/./src/client/app-call-server.ts\",\"webpack://next/./src/client/app-find-source-map-url.ts\",\"webpack://next/./src/client/components/app-router-headers.ts\",\"webpack://next/./src/client/components/hooks-server-context.ts\",\"webpack://next/./src/client/components/http-access-fallback/http-access-fallback.ts\",\"webpack://next/./src/client/components/...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js.map:\n Line 1: {\"version\":3,\"file\":\"app-page.runtime.dev.js\",\"sources\":[\"webpack://next/webpack/runtime/create_fake_namespace_object\",\"webpack://next/webpack/runtime/require_chunk_loading\",\"webpack://next/./src/build/webpack/alias/react-dom-server.js\",\"webpack://next/./dist/compiled/@edge-runtime/cookies/index.js\",\"webpack://next/./dist/compiled/busboy/index.js\",\"webpack://next/./dist/compiled/bytes/index.js\",\"webpack://next/./dist/compiled/cookie/index.js\",\"webpack://next/./dist/compiled/p-queue/index.js\",\"webpack://next/./dist/compiled/path-to-regexp/index.js\",\"webpack://next/./dist/compiled/react-dom/cjs/react-dom-server.node.development.js\",\"webpack://next/./dist/compiled/react-dom/cjs/react-dom.development.js\",\"webpack://next/./dist/compiled/react-dom/index.js\",\"webpack://next/./dist/compiled/react-dom/static.node.js\",\"webpack://next/./dist/compiled/react-is/cjs/react-is.development.js\",\"webpack://next/./dist/compiled/react-is/index.js\",\"webpack://next/./dist/compiled/react-server-dom-webpack/cjs/react-server-dom-webpack-client.node.development.js\",\"webpack://next/./dist/compiled/react-server-dom-webpack/client.node.js\",\"webpack://next/./dist/compiled/react/cjs/react-compiler-runtime.development.js\",\"webpack://next/./dist/compiled/react/cjs/react-jsx-dev-runtime.development.js\",\"webpack://next/./dist/compiled/react/cjs/react-jsx-runtime.development.js\",\"webpack://next/./dist/compiled/react/cjs/react.development.js\",\"webpack://next/./dist/compiled/react/compiler-runtime.js\",\"webpack://next/./dist/compiled/react/index.js\",\"webpack://next/./dist/compiled/react/jsx-dev-runtime.js\",\"webpack://next/./dist/compiled/react/jsx-runtime.js\",\"webpack://next/./dist/compiled/safe-stable-stringify/index.js\",\"webpack://next/./dist/compiled/string-hash/index.js\",\"webpack://next/./dist/compiled/strip-ansi/index.js\",\"webpack://next/./src/client/app-call-server.ts\",\"webpack://next/./src/client/app-find-source-map-url.ts\",\"webpack://next/./src/client/components/app-router-headers.ts\",\"webpack://n...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js.map:\n Line 1: {\"version\":3,\"file\":\"app-page-turbo.runtime.prod.js\",\"sources\":[\"webpack://next/webpack/runtime/create_fake_namespace_object\",\"webpack://next/./src/build/webpack/alias/react-dom-server.js\",\"webpack://next/./dist/compiled/@edge-runtime/cookies/index.js\",\"webpack://next/./dist/compiled/busboy/index.js\",\"webpack://next/./dist/compiled/bytes/index.js\",\"webpack://next/./dist/compiled/cookie/index.js\",\"webpack://next/./dist/compiled/p-queue/index.js\",\"webpack://next/./dist/compiled/path-to-regexp/index.js\",\"webpack://next/./dist/compiled/react-dom/cjs/react-dom-server.node.production.js\",\"webpack://next/./dist/compiled/react-dom/cjs/react-dom.production.js\",\"webpack://next/./dist/compiled/react-dom/index.js\",\"webpack://next/./dist/compiled/react-dom/static.node.js\",\"webpack://next/./dist/compiled/react-is/cjs/react-is.production.js\",\"webpack://next/./dist/compiled/react-is/index.js\",\"webpack://next/./dist/compiled/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.node.production.js\",\"webpack://next/./dist/compiled/react-server-dom-turbopack/client.node.js\",\"webpack://next/./dist/compiled/react/cjs/react-compiler-runtime.production.js\",\"webpack://next/./dist/compiled/react/cjs/react-jsx-dev-runtime.production.js\",\"webpack://next/./dist/compiled/react/cjs/react-jsx-runtime.production.js\",\"webpack://next/./dist/compiled/react/cjs/react.production.js\",\"webpack://next/./dist/compiled/react/compiler-runtime.js\",\"webpack://next/./dist/compiled/react/index.js\",\"webpack://next/./dist/compiled/react/jsx-dev-runtime.js\",\"webpack://next/./dist/compiled/react/jsx-runtime.js\",\"webpack://next/./dist/compiled/string-hash/index.js\",\"webpack://next/./src/client/app-call-server.ts\",\"webpack://next/./src/client/app-find-source-map-url.ts\",\"webpack://next/./src/client/components/app-router-headers.ts\",\"webpack://next/./src/client/components/hooks-server-context.ts\",\"webpack://next/./src/client/components/http-access-fallback/http-access-fallback.ts\",\"webpack://next/./src/client...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.dev.js.map:\n Line 1: {\"version\":3,\"file\":\"app-page-turbo.runtime.dev.js\",\"sources\":[\"webpack://next/webpack/runtime/create_fake_namespace_object\",\"webpack://next/webpack/runtime/require_chunk_loading\",\"webpack://next/./src/build/webpack/alias/react-dom-server.js\",\"webpack://next/./dist/compiled/@edge-runtime/cookies/index.js\",\"webpack://next/./dist/compiled/busboy/index.js\",\"webpack://next/./dist/compiled/bytes/index.js\",\"webpack://next/./dist/compiled/cookie/index.js\",\"webpack://next/./dist/compiled/p-queue/index.js\",\"webpack://next/./dist/compiled/path-to-regexp/index.js\",\"webpack://next/./dist/compiled/react-dom/cjs/react-dom-server.node.development.js\",\"webpack://next/./dist/compiled/react-dom/cjs/react-dom.development.js\",\"webpack://next/./dist/compiled/react-dom/index.js\",\"webpack://next/./dist/compiled/react-dom/static.node.js\",\"webpack://next/./dist/compiled/react-is/cjs/react-is.development.js\",\"webpack://next/./dist/compiled/react-is/index.js\",\"webpack://next/./dist/compiled/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.node.development.js\",\"webpack://next/./dist/compiled/react-server-dom-turbopack/client.node.js\",\"webpack://next/./dist/compiled/react/cjs/react-compiler-runtime.development.js\",\"webpack://next/./dist/compiled/react/cjs/react-jsx-dev-runtime.development.js\",\"webpack://next/./dist/compiled/react/cjs/react-jsx-runtime.development.js\",\"webpack://next/./dist/compiled/react/cjs/react.development.js\",\"webpack://next/./dist/compiled/react/compiler-runtime.js\",\"webpack://next/./dist/compiled/react/index.js\",\"webpack://next/./dist/compiled/react/jsx-dev-runtime.js\",\"webpack://next/./dist/compiled/react/jsx-runtime.js\",\"webpack://next/./dist/compiled/safe-stable-stringify/index.js\",\"webpack://next/./dist/compiled/string-hash/index.js\",\"webpack://next/./dist/compiled/strip-ansi/index.js\",\"webpack://next/./src/client/app-call-server.ts\",\"webpack://next/./src/client/app-find-source-map-url.ts\",\"webpack://next/./src/client/components/app-router-headers.ts\",...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-page-turbo-experimental.runtime.prod.js.map:\n Line 1: {\"version\":3,\"file\":\"app-page-turbo-experimental.runtime.prod.js\",\"sources\":[\"webpack://next/webpack/runtime/create_fake_namespace_object\",\"webpack://next/./src/build/webpack/alias/react-dom-server-experimental.js\",\"webpack://next/./dist/compiled/@edge-runtime/cookies/index.js\",\"webpack://next/./dist/compiled/busboy/index.js\",\"webpack://next/./dist/compiled/bytes/index.js\",\"webpack://next/./dist/compiled/cookie/index.js\",\"webpack://next/./dist/compiled/p-queue/index.js\",\"webpack://next/./dist/compiled/path-to-regexp/index.js\",\"webpack://next/./dist/compiled/react-dom-experimental/cjs/react-dom-server.node.production.js\",\"webpack://next/./dist/compiled/react-dom-experimental/cjs/react-dom.production.js\",\"webpack://next/./dist/compiled/react-dom-experimental/index.js\",\"webpack://next/./dist/compiled/react-dom-experimental/static.node.js\",\"webpack://next/./dist/compiled/react-experimental/cjs/react-compiler-runtime.production.js\",\"webpack://next/./dist/compiled/react-experimental/cjs/react-jsx-dev-runtime.production.js\",\"webpack://next/./dist/compiled/react-experimental/cjs/react-jsx-runtime.production.js\",\"webpack://next/./dist/compiled/react-experimental/cjs/react.production.js\",\"webpack://next/./dist/compiled/react-experimental/compiler-runtime.js\",\"webpack://next/./dist/compiled/react-experimental/index.js\",\"webpack://next/./dist/compiled/react-experimental/jsx-dev-runtime.js\",\"webpack://next/./dist/compiled/react-experimental/jsx-runtime.js\",\"webpack://next/./dist/compiled/react-is/cjs/react-is.production.js\",\"webpack://next/./dist/compiled/react-is/index.js\",\"webpack://next/./dist/compiled/react-server-dom-turbopack-experimental/cjs/react-server-dom-turbopack-client.node.production.js\",\"webpack://next/./dist/compiled/react-server-dom-turbopack-experimental/client.node.js\",\"webpack://next/./dist/compiled/string-hash/index.js\",\"webpack://next/./src/client/app-call-server.ts\",\"webpack://next/./src/client/app-find-source-map-url.ts\",\"webpack://next/./src/client/compo...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-page-turbo-experimental.runtime.dev.js.map:\n Line 1: {\"version\":3,\"file\":\"app-page-turbo-experimental.runtime.dev.js\",\"sources\":[\"webpack://next/webpack/runtime/create_fake_namespace_object\",\"webpack://next/webpack/runtime/require_chunk_loading\",\"webpack://next/./src/build/webpack/alias/react-dom-server-experimental.js\",\"webpack://next/./dist/compiled/@edge-runtime/cookies/index.js\",\"webpack://next/./dist/compiled/busboy/index.js\",\"webpack://next/./dist/compiled/bytes/index.js\",\"webpack://next/./dist/compiled/cookie/index.js\",\"webpack://next/./dist/compiled/p-queue/index.js\",\"webpack://next/./dist/compiled/path-to-regexp/index.js\",\"webpack://next/./dist/compiled/react-dom-experimental/cjs/react-dom-server.node.development.js\",\"webpack://next/./dist/compiled/react-dom-experimental/cjs/react-dom.development.js\",\"webpack://next/./dist/compiled/react-dom-experimental/index.js\",\"webpack://next/./dist/compiled/react-dom-experimental/static.node.js\",\"webpack://next/./dist/compiled/react-experimental/cjs/react-compiler-runtime.development.js\",\"webpack://next/./dist/compiled/react-experimental/cjs/react-jsx-dev-runtime.development.js\",\"webpack://next/./dist/compiled/react-experimental/cjs/react-jsx-runtime.development.js\",\"webpack://next/./dist/compiled/react-experimental/cjs/react.development.js\",\"webpack://next/./dist/compiled/react-experimental/compiler-runtime.js\",\"webpack://next/./dist/compiled/react-experimental/index.js\",\"webpack://next/./dist/compiled/react-experimental/jsx-dev-runtime.js\",\"webpack://next/./dist/compiled/react-experimental/jsx-runtime.js\",\"webpack://next/./dist/compiled/react-is/cjs/react-is.development.js\",\"webpack://next/./dist/compiled/react-is/index.js\",\"webpack://next/./dist/compiled/react-server-dom-turbopack-experimental/cjs/react-server-dom-turbopack-client.node.development.js\",\"webpack://next/./dist/compiled/react-server-dom-turbopack-experimental/client.node.js\",\"webpack://next/./dist/compiled/safe-stable-stringify/index.js\",\"webpack://next/./dist/compiled/string-hash/index.js\",\"webpack://nex...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-page-experimental.runtime.prod.js.map:\n Line 1: {\"version\":3,\"file\":\"app-page-experimental.runtime.prod.js\",\"sources\":[\"webpack://next/webpack/runtime/create_fake_namespace_object\",\"webpack://next/./src/build/webpack/alias/react-dom-server-experimental.js\",\"webpack://next/./dist/compiled/@edge-runtime/cookies/index.js\",\"webpack://next/./dist/compiled/busboy/index.js\",\"webpack://next/./dist/compiled/bytes/index.js\",\"webpack://next/./dist/compiled/cookie/index.js\",\"webpack://next/./dist/compiled/p-queue/index.js\",\"webpack://next/./dist/compiled/path-to-regexp/index.js\",\"webpack://next/./dist/compiled/react-dom-experimental/cjs/react-dom-server.node.production.js\",\"webpack://next/./dist/compiled/react-dom-experimental/cjs/react-dom.production.js\",\"webpack://next/./dist/compiled/react-dom-experimental/index.js\",\"webpack://next/./dist/compiled/react-dom-experimental/static.node.js\",\"webpack://next/./dist/compiled/react-experimental/cjs/react-compiler-runtime.production.js\",\"webpack://next/./dist/compiled/react-experimental/cjs/react-jsx-dev-runtime.production.js\",\"webpack://next/./dist/compiled/react-experimental/cjs/react-jsx-runtime.production.js\",\"webpack://next/./dist/compiled/react-experimental/cjs/react.production.js\",\"webpack://next/./dist/compiled/react-experimental/compiler-runtime.js\",\"webpack://next/./dist/compiled/react-experimental/index.js\",\"webpack://next/./dist/compiled/react-experimental/jsx-dev-runtime.js\",\"webpack://next/./dist/compiled/react-experimental/jsx-runtime.js\",\"webpack://next/./dist/compiled/react-is/cjs/react-is.production.js\",\"webpack://next/./dist/compiled/react-is/index.js\",\"webpack://next/./dist/compiled/react-server-dom-webpack-experimental/cjs/react-server-dom-webpack-client.node.production.js\",\"webpack://next/./dist/compiled/react-server-dom-webpack-experimental/client.node.js\",\"webpack://next/./dist/compiled/string-hash/index.js\",\"webpack://next/./src/client/app-call-server.ts\",\"webpack://next/./src/client/app-find-source-map-url.ts\",\"webpack://next/./src/client/components/app-ro...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-page-experimental.runtime.dev.js.map:\n Line 1: {\"version\":3,\"file\":\"app-page-experimental.runtime.dev.js\",\"sources\":[\"webpack://next/webpack/runtime/create_fake_namespace_object\",\"webpack://next/webpack/runtime/require_chunk_loading\",\"webpack://next/./src/build/webpack/alias/react-dom-server-experimental.js\",\"webpack://next/./dist/compiled/@edge-runtime/cookies/index.js\",\"webpack://next/./dist/compiled/busboy/index.js\",\"webpack://next/./dist/compiled/bytes/index.js\",\"webpack://next/./dist/compiled/cookie/index.js\",\"webpack://next/./dist/compiled/p-queue/index.js\",\"webpack://next/./dist/compiled/path-to-regexp/index.js\",\"webpack://next/./dist/compiled/react-dom-experimental/cjs/react-dom-server.node.development.js\",\"webpack://next/./dist/compiled/react-dom-experimental/cjs/react-dom.development.js\",\"webpack://next/./dist/compiled/react-dom-experimental/index.js\",\"webpack://next/./dist/compiled/react-dom-experimental/static.node.js\",\"webpack://next/./dist/compiled/react-experimental/cjs/react-compiler-runtime.development.js\",\"webpack://next/./dist/compiled/react-experimental/cjs/react-jsx-dev-runtime.development.js\",\"webpack://next/./dist/compiled/react-experimental/cjs/react-jsx-runtime.development.js\",\"webpack://next/./dist/compiled/react-experimental/cjs/react.development.js\",\"webpack://next/./dist/compiled/react-experimental/compiler-runtime.js\",\"webpack://next/./dist/compiled/react-experimental/index.js\",\"webpack://next/./dist/compiled/react-experimental/jsx-dev-runtime.js\",\"webpack://next/./dist/compiled/react-experimental/jsx-runtime.js\",\"webpack://next/./dist/compiled/react-is/cjs/react-is.development.js\",\"webpack://next/./dist/compiled/react-is/index.js\",\"webpack://next/./dist/compiled/react-server-dom-webpack-experimental/cjs/react-server-dom-webpack-client.node.development.js\",\"webpack://next/./dist/compiled/react-server-dom-webpack-experimental/client.node.js\",\"webpack://next/./dist/compiled/safe-stable-stringify/index.js\",\"webpack://next/./dist/compiled/string-hash/index.js\",\"webpack://next/./dist/com...\n\n/workspace/node_modules/next/dist/server/app-render/action-handler.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../../src/server/app-render/action-handler.ts\"],\"sourcesContent\":[\"import type { IncomingHttpHeaders, OutgoingHttpHeaders } from 'node:http'\\nimport type { SizeLimit } from '../../types'\\nimport type { RequestStore } from '../app-render/work-unit-async-storage.external'\\nimport type { AppRenderContext, GenerateFlight } from './app-render'\\nimport type { AppPageModule } from '../route-modules/app-page/module'\\nimport type { BaseNextRequest, BaseNextResponse } from '../base-http'\\n\\nimport {\\n RSC_HEADER,\\n RSC_CONTENT_TYPE_HEADER,\\n NEXT_ROUTER_STATE_TREE_HEADER,\\n ACTION_HEADER,\\n NEXT_ACTION_NOT_FOUND_HEADER,\\n NEXT_ROUTER_PREFETCH_HEADER,\\n NEXT_ROUTER_SEGMENT_PREFETCH_HEADER,\\n NEXT_URL,\\n NEXT_ACTION_REVALIDATED_HEADER,\\n} from '../../client/components/app-router-headers'\\nimport {\\n getAccessFallbackHTTPStatus,\\n isHTTPAccessFallbackError,\\n} from '../../client/components/http-access-fallback/http-access-fallback'\\nimport {\\n getRedirectTypeFromError,\\n getURLFromRedirectError,\\n} from '../../client/components/redirect'\\nimport {\\n isRedirectError,\\n type RedirectType,\\n} from '../../client/components/redirect-error'\\nimport RenderResult, {\\n type AppPageRenderResultMetadata,\\n} from '../render-result'\\nimport type { WorkStore } from '../app-render/work-async-storage.external'\\nimport { actionAsyncStorage } from '../app-render/action-async-storage.external'\\nimport { FlightRenderResult } from './flight-render-result'\\nimport {\\n filterReqHeaders,\\n actionsForbiddenHeaders,\\n} from '../lib/server-ipc/utils'\\nimport { getModifiedCookieValues } from '../web/spec-extension/adapters/request-cookies'\\n\\nimport {\\n JSON_CONTENT_TYPE_HEADER,\\n NEXT_CACHE_REVALIDATED_TAGS_HEADER,\\n NEXT_CACHE_REVALIDATE_TAG_TOKEN_HEADER,\\n} from '../../lib/constants'\\nimport { getServerActionRequestMetadata } from '../lib/server-action-request-meta'\\nimport { isCsrfOriginAllowed } from './csrf-protection'\\nimport { warn } from '../../buil...\n\n/workspace/node_modules/next/dist/esm/server/app-render/action-handler.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../../../src/server/app-render/action-handler.ts\"],\"sourcesContent\":[\"import type { IncomingHttpHeaders, OutgoingHttpHeaders } from 'node:http'\\nimport type { SizeLimit } from '../../types'\\nimport type { RequestStore } from '../app-render/work-unit-async-storage.external'\\nimport type { AppRenderContext, GenerateFlight } from './app-render'\\nimport type { AppPageModule } from '../route-modules/app-page/module'\\nimport type { BaseNextRequest, BaseNextResponse } from '../base-http'\\n\\nimport {\\n RSC_HEADER,\\n RSC_CONTENT_TYPE_HEADER,\\n NEXT_ROUTER_STATE_TREE_HEADER,\\n ACTION_HEADER,\\n NEXT_ACTION_NOT_FOUND_HEADER,\\n NEXT_ROUTER_PREFETCH_HEADER,\\n NEXT_ROUTER_SEGMENT_PREFETCH_HEADER,\\n NEXT_URL,\\n NEXT_ACTION_REVALIDATED_HEADER,\\n} from '../../client/components/app-router-headers'\\nimport {\\n getAccessFallbackHTTPStatus,\\n isHTTPAccessFallbackError,\\n} from '../../client/components/http-access-fallback/http-access-fallback'\\nimport {\\n getRedirectTypeFromError,\\n getURLFromRedirectError,\\n} from '../../client/components/redirect'\\nimport {\\n isRedirectError,\\n type RedirectType,\\n} from '../../client/components/redirect-error'\\nimport RenderResult, {\\n type AppPageRenderResultMetadata,\\n} from '../render-result'\\nimport type { WorkStore } from '../app-render/work-async-storage.external'\\nimport { actionAsyncStorage } from '../app-render/action-async-storage.external'\\nimport { FlightRenderResult } from './flight-render-result'\\nimport {\\n filterReqHeaders,\\n actionsForbiddenHeaders,\\n} from '../lib/server-ipc/utils'\\nimport { getModifiedCookieValues } from '../web/spec-extension/adapters/request-cookies'\\n\\nimport {\\n JSON_CONTENT_TYPE_HEADER,\\n NEXT_CACHE_REVALIDATED_TAGS_HEADER,\\n NEXT_CACHE_REVALIDATE_TAG_TOKEN_HEADER,\\n} from '../../lib/constants'\\nimport { getServerActionRequestMetadata } from '../lib/server-action-request-meta'\\nimport { isCsrfOriginAllowed } from './csrf-protection'\\nimport { warn } from '../../b...\n\n/workspace/node_modules/next/dist/esm/server/web/spec-extension/revalidate.js:\n Line 19: */ export function revalidateTag(tag, profile) {\n\n/workspace/node_modules/next/dist/compiled/next-server/pages.runtime.prod.js:\n Line 1: (()=>{var e,t,r={\"./dist/compiled/@edge-runtime/cookies/index.js\"(e){\"use strict\";var t=Object.defineProperty,r=Object.getOwnPropertyDescriptor,a=Object.getOwnPropertyNames,n=Object.prototype.hasOwnProperty,i={},s={RequestCookies:()=>p,ResponseCookies:()=>f,parseCookie:()=>c,parseSetCookie:()=>u,stringifyCookie:()=>l};for(var o in s)t(i,o,{get:s[o],enumerable:!0});function l(e){var t;let r=[\"path\"in e&&e.path&&`Path=${e.path}`,\"expires\"in e&&(e.expires||0===e.expires)&&`Expires=${(\"number\"==typeof e.expires?new Date(e.expires):e.expires).toUTCString()}`,\"maxAge\"in e&&\"number\"==typeof e.maxAge&&`Max-Age=${e.maxAge}`,\"domain\"in e&&e.domain&&`Domain=${e.domain}`,\"secure\"in e&&e.secure&&\"Secure\",\"httpOnly\"in e&&e.httpOnly&&\"HttpOnly\",\"sameSite\"in e&&e.sameSite&&`SameSite=${e.sameSite}`,\"partitioned\"in e&&e.partitioned&&\"Partitioned\",\"priority\"in e&&e.priority&&`Priority=${e.priority}`].filter(Boolean),a=`${e.name}=${encodeURIComponent(null!=(t=e.value)?t:\"\")}`;return 0===r.length?a:`${a}; ${r.join(\"; \")}`}function c(e){let t=new Map;for(let r of e.split(/; */)){if(!r)continue;let e=r.indexOf(\"=\");if(-1===e){t.set(r,\"true\");continue}let[a,n]=[r.slice(0,e),r.slice(e+1)];try{t.set(a,decodeURIComponent(null!=n?n:\"true\"))}catch{}}return t}function u(e){if(!e)return;let[[t,r],...a]=c(e),{domain:n,expires:i,httponly:s,maxage:o,path:l,samesite:u,secure:p,partitioned:f,priority:m}=Object.fromEntries(a.map(([e,t])=>[e.toLowerCase().replace(/-/g,\"\"),t]));{var g,v,y={name:t,value:decodeURIComponent(r),domain:n,...i&&{expires:new Date(i)},...s&&{httpOnly:!0},...\"string\"==typeof o&&{maxAge:Number(o)},path:l,...u&&{sameSite:d.includes(g=(g=u).toLowerCase())?g:void 0},...p&&{secure:!0},...m&&{priority:h.includes(v=(v=m).toLowerCase())?v:void 0},...f&&{partitioned:!0}};let e={};for(let t in y)y[t]&&(e[t]=y[t]);return e}}e.exports=((e,i,s,o)=>{if(i&&\"object\"==typeof i||\"function\"==typeof i)for(let s of a(i))n.call(e,s)||void 0===s||t(e,s,{get:()=>i[s],enumerable:!(o=r(i,s))||o.enumerable...\n\n/workspace/node_modules/next/dist/compiled/next-server/pages.runtime.dev.js:\n Line 1: (()=>{var leafPrototypes,getProto,__webpack_modules__={\"./dist/compiled/@edge-runtime/cookies/index.js\"(module1){\"use strict\";var __defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropNames=Object.getOwnPropertyNames,__hasOwnProp=Object.prototype.hasOwnProperty,src_exports={},all={RequestCookies:()=>RequestCookies,ResponseCookies:()=>ResponseCookies,parseCookie:()=>parseCookie,parseSetCookie:()=>parseSetCookie,stringifyCookie:()=>stringifyCookie};for(var name in all)__defProp(src_exports,name,{get:all[name],enumerable:!0});function stringifyCookie(c){var _a;let attrs=[\"path\"in c&&c.path&&`Path=${c.path}`,\"expires\"in c&&(c.expires||0===c.expires)&&`Expires=${(\"number\"==typeof c.expires?new Date(c.expires):c.expires).toUTCString()}`,\"maxAge\"in c&&\"number\"==typeof c.maxAge&&`Max-Age=${c.maxAge}`,\"domain\"in c&&c.domain&&`Domain=${c.domain}`,\"secure\"in c&&c.secure&&\"Secure\",\"httpOnly\"in c&&c.httpOnly&&\"HttpOnly\",\"sameSite\"in c&&c.sameSite&&`SameSite=${c.sameSite}`,\"partitioned\"in c&&c.partitioned&&\"Partitioned\",\"priority\"in c&&c.priority&&`Priority=${c.priority}`].filter(Boolean),stringified=`${c.name}=${encodeURIComponent(null!=(_a=c.value)?_a:\"\")}`;return 0===attrs.length?stringified:`${stringified}; ${attrs.join(\"; \")}`}function parseCookie(cookie){let map=new Map;for(let pair of cookie.split(/; */)){if(!pair)continue;let splitAt=pair.indexOf(\"=\");if(-1===splitAt){map.set(pair,\"true\");continue}let[key,value]=[pair.slice(0,splitAt),pair.slice(splitAt+1)];try{map.set(key,decodeURIComponent(null!=value?value:\"true\"))}catch{}}return map}function parseSetCookie(setCookie){if(!setCookie)return;let[[name,value],...attributes]=parseCookie(setCookie),{domain,expires,httponly,maxage,path,samesite,secure,partitioned,priority}=Object.fromEntries(attributes.map(([key,value2])=>[key.toLowerCase().replace(/-/g,\"\"),value2]));{var string,string1,t={name,value:decodeURIComponent(value),domain,...expires&&{expires:new Date(expires)},...httponly&&{h...\n\n/workspace/node_modules/next/dist/compiled/next-server/pages-turbo.runtime.prod.js:\n Line 1: (()=>{var e,t,r={\"./dist/compiled/@edge-runtime/cookies/index.js\"(e){\"use strict\";var t=Object.defineProperty,r=Object.getOwnPropertyDescriptor,a=Object.getOwnPropertyNames,n=Object.prototype.hasOwnProperty,i={},s={RequestCookies:()=>p,ResponseCookies:()=>f,parseCookie:()=>c,parseSetCookie:()=>u,stringifyCookie:()=>l};for(var o in s)t(i,o,{get:s[o],enumerable:!0});function l(e){var t;let r=[\"path\"in e&&e.path&&`Path=${e.path}`,\"expires\"in e&&(e.expires||0===e.expires)&&`Expires=${(\"number\"==typeof e.expires?new Date(e.expires):e.expires).toUTCString()}`,\"maxAge\"in e&&\"number\"==typeof e.maxAge&&`Max-Age=${e.maxAge}`,\"domain\"in e&&e.domain&&`Domain=${e.domain}`,\"secure\"in e&&e.secure&&\"Secure\",\"httpOnly\"in e&&e.httpOnly&&\"HttpOnly\",\"sameSite\"in e&&e.sameSite&&`SameSite=${e.sameSite}`,\"partitioned\"in e&&e.partitioned&&\"Partitioned\",\"priority\"in e&&e.priority&&`Priority=${e.priority}`].filter(Boolean),a=`${e.name}=${encodeURIComponent(null!=(t=e.value)?t:\"\")}`;return 0===r.length?a:`${a}; ${r.join(\"; \")}`}function c(e){let t=new Map;for(let r of e.split(/; */)){if(!r)continue;let e=r.indexOf(\"=\");if(-1===e){t.set(r,\"true\");continue}let[a,n]=[r.slice(0,e),r.slice(e+1)];try{t.set(a,decodeURIComponent(null!=n?n:\"true\"))}catch{}}return t}function u(e){if(!e)return;let[[t,r],...a]=c(e),{domain:n,expires:i,httponly:s,maxage:o,path:l,samesite:u,secure:p,partitioned:f,priority:m}=Object.fromEntries(a.map(([e,t])=>[e.toLowerCase().replace(/-/g,\"\"),t]));{var g,v,y={name:t,value:decodeURIComponent(r),domain:n,...i&&{expires:new Date(i)},...s&&{httpOnly:!0},...\"string\"==typeof o&&{maxAge:Number(o)},path:l,...u&&{sameSite:d.includes(g=(g=u).toLowerCase())?g:void 0},...p&&{secure:!0},...m&&{priority:h.includes(v=(v=m).toLowerCase())?v:void 0},...f&&{partitioned:!0}};let e={};for(let t in y)y[t]&&(e[t]=y[t]);return e}}e.exports=((e,i,s,o)=>{if(i&&\"object\"==typeof i||\"function\"==typeof i)for(let s of a(i))n.call(e,s)||void 0===s||t(e,s,{get:()=>i[s],enumerable:!(o=r(i,s))||o.enumerable...\n\n/workspace/node_modules/next/dist/compiled/next-server/pages-turbo.runtime.dev.js:\n Line 1: (()=>{var leafPrototypes,getProto,__webpack_modules__={\"./dist/compiled/@edge-runtime/cookies/index.js\"(module1){\"use strict\";var __defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropNames=Object.getOwnPropertyNames,__hasOwnProp=Object.prototype.hasOwnProperty,src_exports={},all={RequestCookies:()=>RequestCookies,ResponseCookies:()=>ResponseCookies,parseCookie:()=>parseCookie,parseSetCookie:()=>parseSetCookie,stringifyCookie:()=>stringifyCookie};for(var name in all)__defProp(src_exports,name,{get:all[name],enumerable:!0});function stringifyCookie(c){var _a;let attrs=[\"path\"in c&&c.path&&`Path=${c.path}`,\"expires\"in c&&(c.expires||0===c.expires)&&`Expires=${(\"number\"==typeof c.expires?new Date(c.expires):c.expires).toUTCString()}`,\"maxAge\"in c&&\"number\"==typeof c.maxAge&&`Max-Age=${c.maxAge}`,\"domain\"in c&&c.domain&&`Domain=${c.domain}`,\"secure\"in c&&c.secure&&\"Secure\",\"httpOnly\"in c&&c.httpOnly&&\"HttpOnly\",\"sameSite\"in c&&c.sameSite&&`SameSite=${c.sameSite}`,\"partitioned\"in c&&c.partitioned&&\"Partitioned\",\"priority\"in c&&c.priority&&`Priority=${c.priority}`].filter(Boolean),stringified=`${c.name}=${encodeURIComponent(null!=(_a=c.value)?_a:\"\")}`;return 0===attrs.length?stringified:`${stringified}; ${attrs.join(\"; \")}`}function parseCookie(cookie){let map=new Map;for(let pair of cookie.split(/; */)){if(!pair)continue;let splitAt=pair.indexOf(\"=\");if(-1===splitAt){map.set(pair,\"true\");continue}let[key,value]=[pair.slice(0,splitAt),pair.slice(splitAt+1)];try{map.set(key,decodeURIComponent(null!=value?value:\"true\"))}catch{}}return map}function parseSetCookie(setCookie){if(!setCookie)return;let[[name,value],...attributes]=parseCookie(setCookie),{domain,expires,httponly,maxage,path,samesite,secure,partitioned,priority}=Object.fromEntries(attributes.map(([key,value2])=>[key.toLowerCase().replace(/-/g,\"\"),value2]));{var string,string1,t={name,value:decodeURIComponent(value),domain,...expires&&{expires:new Date(expires)},...httponly&&{h...\n\n/workspace/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:\n Line 1: (()=>{var e,t,r={\"./dist/compiled/@edge-runtime/cookies/index.js\"(e){\"use strict\";var t=Object.defineProperty,r=Object.getOwnPropertyDescriptor,a=Object.getOwnPropertyNames,n=Object.prototype.hasOwnProperty,i={},s={RequestCookies:()=>p,ResponseCookies:()=>f,parseCookie:()=>c,parseSetCookie:()=>u,stringifyCookie:()=>l};for(var o in s)t(i,o,{get:s[o],enumerable:!0});function l(e){var t;let r=[\"path\"in e&&e.path&&`Path=${e.path}`,\"expires\"in e&&(e.expires||0===e.expires)&&`Expires=${(\"number\"==typeof e.expires?new Date(e.expires):e.expires).toUTCString()}`,\"maxAge\"in e&&\"number\"==typeof e.maxAge&&`Max-Age=${e.maxAge}`,\"domain\"in e&&e.domain&&`Domain=${e.domain}`,\"secure\"in e&&e.secure&&\"Secure\",\"httpOnly\"in e&&e.httpOnly&&\"HttpOnly\",\"sameSite\"in e&&e.sameSite&&`SameSite=${e.sameSite}`,\"partitioned\"in e&&e.partitioned&&\"Partitioned\",\"priority\"in e&&e.priority&&`Priority=${e.priority}`].filter(Boolean),a=`${e.name}=${encodeURIComponent(null!=(t=e.value)?t:\"\")}`;return 0===r.length?a:`${a}; ${r.join(\"; \")}`}function c(e){let t=new Map;for(let r of e.split(/; */)){if(!r)continue;let e=r.indexOf(\"=\");if(-1===e){t.set(r,\"true\");continue}let[a,n]=[r.slice(0,e),r.slice(e+1)];try{t.set(a,decodeURIComponent(null!=n?n:\"true\"))}catch{}}return t}function u(e){if(!e)return;let[[t,r],...a]=c(e),{domain:n,expires:i,httponly:s,maxage:o,path:l,samesite:u,secure:p,partitioned:f,priority:m}=Object.fromEntries(a.map(([e,t])=>[e.toLowerCase().replace(/-/g,\"\"),t]));{var g,v,y={name:t,value:decodeURIComponent(r),domain:n,...i&&{expires:new Date(i)},...s&&{httpOnly:!0},...\"string\"==typeof o&&{maxAge:Number(o)},path:l,...u&&{sameSite:d.includes(g=(g=u).toLowerCase())?g:void 0},...p&&{secure:!0},...m&&{priority:h.includes(v=(v=m).toLowerCase())?v:void 0},...f&&{partitioned:!0}};let e={};for(let t in y)y[t]&&(e[t]=y[t]);return e}}e.exports=((e,i,s,o)=>{if(i&&\"object\"==typeof i||\"function\"==typeof i)for(let s of a(i))n.call(e,s)||void 0===s||t(e,s,{get:()=>i[s],enumerable:!(o=r(i,s))||o.enumerable...\n\n/workspace/node_modules/next/dist/compiled/next-server/pages-api.runtime.dev.js:\n Line 1: (()=>{var leafPrototypes,getProto,__webpack_modules__={\"./dist/compiled/@edge-runtime/cookies/index.js\"(module1){\"use strict\";var __defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropNames=Object.getOwnPropertyNames,__hasOwnProp=Object.prototype.hasOwnProperty,src_exports={},all={RequestCookies:()=>RequestCookies,ResponseCookies:()=>ResponseCookies,parseCookie:()=>parseCookie,parseSetCookie:()=>parseSetCookie,stringifyCookie:()=>stringifyCookie};for(var name in all)__defProp(src_exports,name,{get:all[name],enumerable:!0});function stringifyCookie(c){var _a;let attrs=[\"path\"in c&&c.path&&`Path=${c.path}`,\"expires\"in c&&(c.expires||0===c.expires)&&`Expires=${(\"number\"==typeof c.expires?new Date(c.expires):c.expires).toUTCString()}`,\"maxAge\"in c&&\"number\"==typeof c.maxAge&&`Max-Age=${c.maxAge}`,\"domain\"in c&&c.domain&&`Domain=${c.domain}`,\"secure\"in c&&c.secure&&\"Secure\",\"httpOnly\"in c&&c.httpOnly&&\"HttpOnly\",\"sameSite\"in c&&c.sameSite&&`SameSite=${c.sameSite}`,\"partitioned\"in c&&c.partitioned&&\"Partitioned\",\"priority\"in c&&c.priority&&`Priority=${c.priority}`].filter(Boolean),stringified=`${c.name}=${encodeURIComponent(null!=(_a=c.value)?_a:\"\")}`;return 0===attrs.length?stringified:`${stringified}; ${attrs.join(\"; \")}`}function parseCookie(cookie){let map=new Map;for(let pair of cookie.split(/; */)){if(!pair)continue;let splitAt=pair.indexOf(\"=\");if(-1===splitAt){map.set(pair,\"true\");continue}let[key,value]=[pair.slice(0,splitAt),pair.slice(splitAt+1)];try{map.set(key,decodeURIComponent(null!=value?value:\"true\"))}catch{}}return map}function parseSetCookie(setCookie){if(!setCookie)return;let[[name,value],...attributes]=parseCookie(setCookie),{domain,expires,httponly,maxage,path,samesite,secure,partitioned,priority}=Object.fromEntries(attributes.map(([key,value2])=>[key.toLowerCase().replace(/-/g,\"\"),value2]));{var string,string1,t={name,value:decodeURIComponent(value),domain,...expires&&{expires:new Date(expires)},...httponly&&{h...\n\n/workspace/node_modules/next/dist/compiled/next-server/pages-api-turbo.runtime.prod.js:\n Line 1: (()=>{var e,t,r={\"./dist/compiled/@edge-runtime/cookies/index.js\"(e){\"use strict\";var t=Object.defineProperty,r=Object.getOwnPropertyDescriptor,a=Object.getOwnPropertyNames,n=Object.prototype.hasOwnProperty,i={},s={RequestCookies:()=>p,ResponseCookies:()=>f,parseCookie:()=>c,parseSetCookie:()=>u,stringifyCookie:()=>l};for(var o in s)t(i,o,{get:s[o],enumerable:!0});function l(e){var t;let r=[\"path\"in e&&e.path&&`Path=${e.path}`,\"expires\"in e&&(e.expires||0===e.expires)&&`Expires=${(\"number\"==typeof e.expires?new Date(e.expires):e.expires).toUTCString()}`,\"maxAge\"in e&&\"number\"==typeof e.maxAge&&`Max-Age=${e.maxAge}`,\"domain\"in e&&e.domain&&`Domain=${e.domain}`,\"secure\"in e&&e.secure&&\"Secure\",\"httpOnly\"in e&&e.httpOnly&&\"HttpOnly\",\"sameSite\"in e&&e.sameSite&&`SameSite=${e.sameSite}`,\"partitioned\"in e&&e.partitioned&&\"Partitioned\",\"priority\"in e&&e.priority&&`Priority=${e.priority}`].filter(Boolean),a=`${e.name}=${encodeURIComponent(null!=(t=e.value)?t:\"\")}`;return 0===r.length?a:`${a}; ${r.join(\"; \")}`}function c(e){let t=new Map;for(let r of e.split(/; */)){if(!r)continue;let e=r.indexOf(\"=\");if(-1===e){t.set(r,\"true\");continue}let[a,n]=[r.slice(0,e),r.slice(e+1)];try{t.set(a,decodeURIComponent(null!=n?n:\"true\"))}catch{}}return t}function u(e){if(!e)return;let[[t,r],...a]=c(e),{domain:n,expires:i,httponly:s,maxage:o,path:l,samesite:u,secure:p,partitioned:f,priority:m}=Object.fromEntries(a.map(([e,t])=>[e.toLowerCase().replace(/-/g,\"\"),t]));{var g,v,y={name:t,value:decodeURIComponent(r),domain:n,...i&&{expires:new Date(i)},...s&&{httpOnly:!0},...\"string\"==typeof o&&{maxAge:Number(o)},path:l,...u&&{sameSite:d.includes(g=(g=u).toLowerCase())?g:void 0},...p&&{secure:!0},...m&&{priority:h.includes(v=(v=m).toLowerCase())?v:void 0},...f&&{partitioned:!0}};let e={};for(let t in y)y[t]&&(e[t]=y[t]);return e}}e.exports=((e,i,s,o)=>{if(i&&\"object\"==typeof i||\"function\"==typeof i)for(let s of a(i))n.call(e,s)||void 0===s||t(e,s,{get:()=>i[s],enumerable:!(o=r(i,s))||o.enumerable...\n\n/workspace/node_modules/next/dist/compiled/next-server/pages-api-turbo.runtime.dev.js:\n Line 1: (()=>{var leafPrototypes,getProto,__webpack_modules__={\"./dist/compiled/@edge-runtime/cookies/index.js\"(module1){\"use strict\";var __defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropNames=Object.getOwnPropertyNames,__hasOwnProp=Object.prototype.hasOwnProperty,src_exports={},all={RequestCookies:()=>RequestCookies,ResponseCookies:()=>ResponseCookies,parseCookie:()=>parseCookie,parseSetCookie:()=>parseSetCookie,stringifyCookie:()=>stringifyCookie};for(var name in all)__defProp(src_exports,name,{get:all[name],enumerable:!0});function stringifyCookie(c){var _a;let attrs=[\"path\"in c&&c.path&&`Path=${c.path}`,\"expires\"in c&&(c.expires||0===c.expires)&&`Expires=${(\"number\"==typeof c.expires?new Date(c.expires):c.expires).toUTCString()}`,\"maxAge\"in c&&\"number\"==typeof c.maxAge&&`Max-Age=${c.maxAge}`,\"domain\"in c&&c.domain&&`Domain=${c.domain}`,\"secure\"in c&&c.secure&&\"Secure\",\"httpOnly\"in c&&c.httpOnly&&\"HttpOnly\",\"sameSite\"in c&&c.sameSite&&`SameSite=${c.sameSite}`,\"partitioned\"in c&&c.partitioned&&\"Partitioned\",\"priority\"in c&&c.priority&&`Priority=${c.priority}`].filter(Boolean),stringified=`${c.name}=${encodeURIComponent(null!=(_a=c.value)?_a:\"\")}`;return 0===attrs.length?stringified:`${stringified}; ${attrs.join(\"; \")}`}function parseCookie(cookie){let map=new Map;for(let pair of cookie.split(/; */)){if(!pair)continue;let splitAt=pair.indexOf(\"=\");if(-1===splitAt){map.set(pair,\"true\");continue}let[key,value]=[pair.slice(0,splitAt),pair.slice(splitAt+1)];try{map.set(key,decodeURIComponent(null!=value?value:\"true\"))}catch{}}return map}function parseSetCookie(setCookie){if(!setCookie)return;let[[name,value],...attributes]=parseCookie(setCookie),{domain,expires,httponly,maxage,path,samesite,secure,partitioned,priority}=Object.fromEntries(attributes.map(([key,value2])=>[key.toLowerCase().replace(/-/g,\"\"),value2]));{var string,string1,t={name,value:decodeURIComponent(value),domain,...expires&&{expires:new Date(expires)},...httponly&&{h...\n\n/workspace/node_modules/next/cache.js:\n Line 89: exports.revalidateTag = cacheExports.revalidateTag\n\n/workspace/node_modules/next/dist/compiled/next-server/app-route.runtime.prod.js:\n Line 1: (()=>{var e,t,r={\"./dist/compiled/@edge-runtime/cookies/index.js\"(e){\"use strict\";var t=Object.defineProperty,r=Object.getOwnPropertyDescriptor,n=Object.getOwnPropertyNames,a=Object.prototype.hasOwnProperty,i={},s={RequestCookies:()=>f,ResponseCookies:()=>p,parseCookie:()=>c,parseSetCookie:()=>u,stringifyCookie:()=>l};for(var o in s)t(i,o,{get:s[o],enumerable:!0});function l(e){var t;let r=[\"path\"in e&&e.path&&`Path=${e.path}`,\"expires\"in e&&(e.expires||0===e.expires)&&`Expires=${(\"number\"==typeof e.expires?new Date(e.expires):e.expires).toUTCString()}`,\"maxAge\"in e&&\"number\"==typeof e.maxAge&&`Max-Age=${e.maxAge}`,\"domain\"in e&&e.domain&&`Domain=${e.domain}`,\"secure\"in e&&e.secure&&\"Secure\",\"httpOnly\"in e&&e.httpOnly&&\"HttpOnly\",\"sameSite\"in e&&e.sameSite&&`SameSite=${e.sameSite}`,\"partitioned\"in e&&e.partitioned&&\"Partitioned\",\"priority\"in e&&e.priority&&`Priority=${e.priority}`].filter(Boolean),n=`${e.name}=${encodeURIComponent(null!=(t=e.value)?t:\"\")}`;return 0===r.length?n:`${n}; ${r.join(\"; \")}`}function c(e){let t=new Map;for(let r of e.split(/; */)){if(!r)continue;let e=r.indexOf(\"=\");if(-1===e){t.set(r,\"true\");continue}let[n,a]=[r.slice(0,e),r.slice(e+1)];try{t.set(n,decodeURIComponent(null!=a?a:\"true\"))}catch{}}return t}function u(e){if(!e)return;let[[t,r],...n]=c(e),{domain:a,expires:i,httponly:s,maxage:o,path:l,samesite:u,secure:f,partitioned:p,priority:m}=Object.fromEntries(n.map(([e,t])=>[e.toLowerCase().replace(/-/g,\"\"),t]));{var g,v,y={name:t,value:decodeURIComponent(r),domain:a,...i&&{expires:new Date(i)},...s&&{httpOnly:!0},...\"string\"==typeof o&&{maxAge:Number(o)},path:l,...u&&{sameSite:d.includes(g=(g=u).toLowerCase())?g:void 0},...f&&{secure:!0},...m&&{priority:h.includes(v=(v=m).toLowerCase())?v:void 0},...p&&{partitioned:!0}};let e={};for(let t in y)y[t]&&(e[t]=y[t]);return e}}e.exports=((e,i,s,o)=>{if(i&&\"object\"==typeof i||\"function\"==typeof i)for(let l of n(i))a.call(e,l)||l===s||t(e,l,{get:()=>i[l],enumerable:!(o=r(i,l))||o.enumerable});re...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-route.runtime.dev.js:\n Line 1: (()=>{var leafPrototypes,getProto,__webpack_modules__={\"./dist/compiled/@edge-runtime/cookies/index.js\"(module1){\"use strict\";var __defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropNames=Object.getOwnPropertyNames,__hasOwnProp=Object.prototype.hasOwnProperty,src_exports={},all={RequestCookies:()=>RequestCookies,ResponseCookies:()=>ResponseCookies,parseCookie:()=>parseCookie,parseSetCookie:()=>parseSetCookie,stringifyCookie:()=>stringifyCookie};for(var name in all)__defProp(src_exports,name,{get:all[name],enumerable:!0});function stringifyCookie(c){var _a;let attrs=[\"path\"in c&&c.path&&`Path=${c.path}`,\"expires\"in c&&(c.expires||0===c.expires)&&`Expires=${(\"number\"==typeof c.expires?new Date(c.expires):c.expires).toUTCString()}`,\"maxAge\"in c&&\"number\"==typeof c.maxAge&&`Max-Age=${c.maxAge}`,\"domain\"in c&&c.domain&&`Domain=${c.domain}`,\"secure\"in c&&c.secure&&\"Secure\",\"httpOnly\"in c&&c.httpOnly&&\"HttpOnly\",\"sameSite\"in c&&c.sameSite&&`SameSite=${c.sameSite}`,\"partitioned\"in c&&c.partitioned&&\"Partitioned\",\"priority\"in c&&c.priority&&`Priority=${c.priority}`].filter(Boolean),stringified=`${c.name}=${encodeURIComponent(null!=(_a=c.value)?_a:\"\")}`;return 0===attrs.length?stringified:`${stringified}; ${attrs.join(\"; \")}`}function parseCookie(cookie){let map=new Map;for(let pair of cookie.split(/; */)){if(!pair)continue;let splitAt=pair.indexOf(\"=\");if(-1===splitAt){map.set(pair,\"true\");continue}let[key,value1]=[pair.slice(0,splitAt),pair.slice(splitAt+1)];try{map.set(key,decodeURIComponent(null!=value1?value1:\"true\"))}catch{}}return map}function parseSetCookie(setCookie){if(!setCookie)return;let[[name,value1],...attributes]=parseCookie(setCookie),{domain,expires,httponly,maxage,path,samesite,secure,partitioned,priority}=Object.fromEntries(attributes.map(([key,value2])=>[key.toLowerCase().replace(/-/g,\"\"),value2]));{var string,string1,t={name,value:decodeURIComponent(value1),domain,...expires&&{expires:new Date(expires)},...httponl...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-route-turbo.runtime.prod.js:\n Line 1: (()=>{var e,t,r={\"./dist/compiled/@edge-runtime/cookies/index.js\"(e){\"use strict\";var t=Object.defineProperty,r=Object.getOwnPropertyDescriptor,n=Object.getOwnPropertyNames,a=Object.prototype.hasOwnProperty,i={},s={RequestCookies:()=>f,ResponseCookies:()=>p,parseCookie:()=>c,parseSetCookie:()=>u,stringifyCookie:()=>l};for(var o in s)t(i,o,{get:s[o],enumerable:!0});function l(e){var t;let r=[\"path\"in e&&e.path&&`Path=${e.path}`,\"expires\"in e&&(e.expires||0===e.expires)&&`Expires=${(\"number\"==typeof e.expires?new Date(e.expires):e.expires).toUTCString()}`,\"maxAge\"in e&&\"number\"==typeof e.maxAge&&`Max-Age=${e.maxAge}`,\"domain\"in e&&e.domain&&`Domain=${e.domain}`,\"secure\"in e&&e.secure&&\"Secure\",\"httpOnly\"in e&&e.httpOnly&&\"HttpOnly\",\"sameSite\"in e&&e.sameSite&&`SameSite=${e.sameSite}`,\"partitioned\"in e&&e.partitioned&&\"Partitioned\",\"priority\"in e&&e.priority&&`Priority=${e.priority}`].filter(Boolean),n=`${e.name}=${encodeURIComponent(null!=(t=e.value)?t:\"\")}`;return 0===r.length?n:`${n}; ${r.join(\"; \")}`}function c(e){let t=new Map;for(let r of e.split(/; */)){if(!r)continue;let e=r.indexOf(\"=\");if(-1===e){t.set(r,\"true\");continue}let[n,a]=[r.slice(0,e),r.slice(e+1)];try{t.set(n,decodeURIComponent(null!=a?a:\"true\"))}catch{}}return t}function u(e){if(!e)return;let[[t,r],...n]=c(e),{domain:a,expires:i,httponly:s,maxage:o,path:l,samesite:u,secure:f,partitioned:p,priority:m}=Object.fromEntries(n.map(([e,t])=>[e.toLowerCase().replace(/-/g,\"\"),t]));{var g,v,y={name:t,value:decodeURIComponent(r),domain:a,...i&&{expires:new Date(i)},...s&&{httpOnly:!0},...\"string\"==typeof o&&{maxAge:Number(o)},path:l,...u&&{sameSite:d.includes(g=(g=u).toLowerCase())?g:void 0},...f&&{secure:!0},...m&&{priority:h.includes(v=(v=m).toLowerCase())?v:void 0},...p&&{partitioned:!0}};let e={};for(let t in y)y[t]&&(e[t]=y[t]);return e}}e.exports=((e,i,s,o)=>{if(i&&\"object\"==typeof i||\"function\"==typeof i)for(let l of n(i))a.call(e,l)||l===s||t(e,l,{get:()=>i[l],enumerable:!(o=r(i,l))||o.enumerable});re...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-route-turbo.runtime.dev.js:\n Line 1: (()=>{var leafPrototypes,getProto,__webpack_modules__={\"./dist/compiled/@edge-runtime/cookies/index.js\"(module1){\"use strict\";var __defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropNames=Object.getOwnPropertyNames,__hasOwnProp=Object.prototype.hasOwnProperty,src_exports={},all={RequestCookies:()=>RequestCookies,ResponseCookies:()=>ResponseCookies,parseCookie:()=>parseCookie,parseSetCookie:()=>parseSetCookie,stringifyCookie:()=>stringifyCookie};for(var name in all)__defProp(src_exports,name,{get:all[name],enumerable:!0});function stringifyCookie(c){var _a;let attrs=[\"path\"in c&&c.path&&`Path=${c.path}`,\"expires\"in c&&(c.expires||0===c.expires)&&`Expires=${(\"number\"==typeof c.expires?new Date(c.expires):c.expires).toUTCString()}`,\"maxAge\"in c&&\"number\"==typeof c.maxAge&&`Max-Age=${c.maxAge}`,\"domain\"in c&&c.domain&&`Domain=${c.domain}`,\"secure\"in c&&c.secure&&\"Secure\",\"httpOnly\"in c&&c.httpOnly&&\"HttpOnly\",\"sameSite\"in c&&c.sameSite&&`SameSite=${c.sameSite}`,\"partitioned\"in c&&c.partitioned&&\"Partitioned\",\"priority\"in c&&c.priority&&`Priority=${c.priority}`].filter(Boolean),stringified=`${c.name}=${encodeURIComponent(null!=(_a=c.value)?_a:\"\")}`;return 0===attrs.length?stringified:`${stringified}; ${attrs.join(\"; \")}`}function parseCookie(cookie){let map=new Map;for(let pair of cookie.split(/; */)){if(!pair)continue;let splitAt=pair.indexOf(\"=\");if(-1===splitAt){map.set(pair,\"true\");continue}let[key,value1]=[pair.slice(0,splitAt),pair.slice(splitAt+1)];try{map.set(key,decodeURIComponent(null!=value1?value1:\"true\"))}catch{}}return map}function parseSetCookie(setCookie){if(!setCookie)return;let[[name,value1],...attributes]=parseCookie(setCookie),{domain,expires,httponly,maxage,path,samesite,secure,partitioned,priority}=Object.fromEntries(attributes.map(([key,value2])=>[key.toLowerCase().replace(/-/g,\"\"),value2]));{var string,string1,t={name,value:decodeURIComponent(value1),domain,...expires&&{expires:new Date(expires)},...httponl...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-route-turbo-experimental.runtime.prod.js:\n Line 1: (()=>{var e,t,r={\"./dist/compiled/@edge-runtime/cookies/index.js\"(e){\"use strict\";var t=Object.defineProperty,r=Object.getOwnPropertyDescriptor,n=Object.getOwnPropertyNames,a=Object.prototype.hasOwnProperty,i={},s={RequestCookies:()=>f,ResponseCookies:()=>p,parseCookie:()=>c,parseSetCookie:()=>u,stringifyCookie:()=>l};for(var o in s)t(i,o,{get:s[o],enumerable:!0});function l(e){var t;let r=[\"path\"in e&&e.path&&`Path=${e.path}`,\"expires\"in e&&(e.expires||0===e.expires)&&`Expires=${(\"number\"==typeof e.expires?new Date(e.expires):e.expires).toUTCString()}`,\"maxAge\"in e&&\"number\"==typeof e.maxAge&&`Max-Age=${e.maxAge}`,\"domain\"in e&&e.domain&&`Domain=${e.domain}`,\"secure\"in e&&e.secure&&\"Secure\",\"httpOnly\"in e&&e.httpOnly&&\"HttpOnly\",\"sameSite\"in e&&e.sameSite&&`SameSite=${e.sameSite}`,\"partitioned\"in e&&e.partitioned&&\"Partitioned\",\"priority\"in e&&e.priority&&`Priority=${e.priority}`].filter(Boolean),n=`${e.name}=${encodeURIComponent(null!=(t=e.value)?t:\"\")}`;return 0===r.length?n:`${n}; ${r.join(\"; \")}`}function c(e){let t=new Map;for(let r of e.split(/; */)){if(!r)continue;let e=r.indexOf(\"=\");if(-1===e){t.set(r,\"true\");continue}let[n,a]=[r.slice(0,e),r.slice(e+1)];try{t.set(n,decodeURIComponent(null!=a?a:\"true\"))}catch{}}return t}function u(e){if(!e)return;let[[t,r],...n]=c(e),{domain:a,expires:i,httponly:s,maxage:o,path:l,samesite:u,secure:f,partitioned:p,priority:m}=Object.fromEntries(n.map(([e,t])=>[e.toLowerCase().replace(/-/g,\"\"),t]));{var g,v,y={name:t,value:decodeURIComponent(r),domain:a,...i&&{expires:new Date(i)},...s&&{httpOnly:!0},...\"string\"==typeof o&&{maxAge:Number(o)},path:l,...u&&{sameSite:d.includes(g=(g=u).toLowerCase())?g:void 0},...f&&{secure:!0},...m&&{priority:h.includes(v=(v=m).toLowerCase())?v:void 0},...p&&{partitioned:!0}};let e={};for(let t in y)y[t]&&(e[t]=y[t]);return e}}e.exports=((e,i,s,o)=>{if(i&&\"object\"==typeof i||\"function\"==typeof i)for(let l of n(i))a.call(e,l)||l===s||t(e,l,{get:()=>i[l],enumerable:!(o=r(i,l))||o.enumerable});re...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-route-turbo-experimental.runtime.dev.js:\n Line 1: (()=>{var leafPrototypes,getProto,__webpack_modules__={\"./dist/compiled/@edge-runtime/cookies/index.js\"(module1){\"use strict\";var __defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropNames=Object.getOwnPropertyNames,__hasOwnProp=Object.prototype.hasOwnProperty,src_exports={},all={RequestCookies:()=>RequestCookies,ResponseCookies:()=>ResponseCookies,parseCookie:()=>parseCookie,parseSetCookie:()=>parseSetCookie,stringifyCookie:()=>stringifyCookie};for(var name in all)__defProp(src_exports,name,{get:all[name],enumerable:!0});function stringifyCookie(c){var _a;let attrs=[\"path\"in c&&c.path&&`Path=${c.path}`,\"expires\"in c&&(c.expires||0===c.expires)&&`Expires=${(\"number\"==typeof c.expires?new Date(c.expires):c.expires).toUTCString()}`,\"maxAge\"in c&&\"number\"==typeof c.maxAge&&`Max-Age=${c.maxAge}`,\"domain\"in c&&c.domain&&`Domain=${c.domain}`,\"secure\"in c&&c.secure&&\"Secure\",\"httpOnly\"in c&&c.httpOnly&&\"HttpOnly\",\"sameSite\"in c&&c.sameSite&&`SameSite=${c.sameSite}`,\"partitioned\"in c&&c.partitioned&&\"Partitioned\",\"priority\"in c&&c.priority&&`Priority=${c.priority}`].filter(Boolean),stringified=`${c.name}=${encodeURIComponent(null!=(_a=c.value)?_a:\"\")}`;return 0===attrs.length?stringified:`${stringified}; ${attrs.join(\"; \")}`}function parseCookie(cookie){let map=new Map;for(let pair of cookie.split(/; */)){if(!pair)continue;let splitAt=pair.indexOf(\"=\");if(-1===splitAt){map.set(pair,\"true\");continue}let[key,value1]=[pair.slice(0,splitAt),pair.slice(splitAt+1)];try{map.set(key,decodeURIComponent(null!=value1?value1:\"true\"))}catch{}}return map}function parseSetCookie(setCookie){if(!setCookie)return;let[[name,value1],...attributes]=parseCookie(setCookie),{domain,expires,httponly,maxage,path,samesite,secure,partitioned,priority}=Object.fromEntries(attributes.map(([key,value2])=>[key.toLowerCase().replace(/-/g,\"\"),value2]));{var string,string1,t={name,value:decodeURIComponent(value1),domain,...expires&&{expires:new Date(expires)},...httponl...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-route-experimental.runtime.prod.js:\n Line 1: (()=>{var e,t,r={\"./dist/compiled/@edge-runtime/cookies/index.js\"(e){\"use strict\";var t=Object.defineProperty,r=Object.getOwnPropertyDescriptor,n=Object.getOwnPropertyNames,a=Object.prototype.hasOwnProperty,i={},s={RequestCookies:()=>f,ResponseCookies:()=>p,parseCookie:()=>c,parseSetCookie:()=>u,stringifyCookie:()=>l};for(var o in s)t(i,o,{get:s[o],enumerable:!0});function l(e){var t;let r=[\"path\"in e&&e.path&&`Path=${e.path}`,\"expires\"in e&&(e.expires||0===e.expires)&&`Expires=${(\"number\"==typeof e.expires?new Date(e.expires):e.expires).toUTCString()}`,\"maxAge\"in e&&\"number\"==typeof e.maxAge&&`Max-Age=${e.maxAge}`,\"domain\"in e&&e.domain&&`Domain=${e.domain}`,\"secure\"in e&&e.secure&&\"Secure\",\"httpOnly\"in e&&e.httpOnly&&\"HttpOnly\",\"sameSite\"in e&&e.sameSite&&`SameSite=${e.sameSite}`,\"partitioned\"in e&&e.partitioned&&\"Partitioned\",\"priority\"in e&&e.priority&&`Priority=${e.priority}`].filter(Boolean),n=`${e.name}=${encodeURIComponent(null!=(t=e.value)?t:\"\")}`;return 0===r.length?n:`${n}; ${r.join(\"; \")}`}function c(e){let t=new Map;for(let r of e.split(/; */)){if(!r)continue;let e=r.indexOf(\"=\");if(-1===e){t.set(r,\"true\");continue}let[n,a]=[r.slice(0,e),r.slice(e+1)];try{t.set(n,decodeURIComponent(null!=a?a:\"true\"))}catch{}}return t}function u(e){if(!e)return;let[[t,r],...n]=c(e),{domain:a,expires:i,httponly:s,maxage:o,path:l,samesite:u,secure:f,partitioned:p,priority:m}=Object.fromEntries(n.map(([e,t])=>[e.toLowerCase().replace(/-/g,\"\"),t]));{var g,v,y={name:t,value:decodeURIComponent(r),domain:a,...i&&{expires:new Date(i)},...s&&{httpOnly:!0},...\"string\"==typeof o&&{maxAge:Number(o)},path:l,...u&&{sameSite:d.includes(g=(g=u).toLowerCase())?g:void 0},...f&&{secure:!0},...m&&{priority:h.includes(v=(v=m).toLowerCase())?v:void 0},...p&&{partitioned:!0}};let e={};for(let t in y)y[t]&&(e[t]=y[t]);return e}}e.exports=((e,i,s,o)=>{if(i&&\"object\"==typeof i||\"function\"==typeof i)for(let l of n(i))a.call(e,l)||l===s||t(e,l,{get:()=>i[l],enumerable:!(o=r(i,l))||o.enumerable});re...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-route-experimental.runtime.dev.js:\n Line 1: (()=>{var leafPrototypes,getProto,__webpack_modules__={\"./dist/compiled/@edge-runtime/cookies/index.js\"(module1){\"use strict\";var __defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropNames=Object.getOwnPropertyNames,__hasOwnProp=Object.prototype.hasOwnProperty,src_exports={},all={RequestCookies:()=>RequestCookies,ResponseCookies:()=>ResponseCookies,parseCookie:()=>parseCookie,parseSetCookie:()=>parseSetCookie,stringifyCookie:()=>stringifyCookie};for(var name in all)__defProp(src_exports,name,{get:all[name],enumerable:!0});function stringifyCookie(c){var _a;let attrs=[\"path\"in c&&c.path&&`Path=${c.path}`,\"expires\"in c&&(c.expires||0===c.expires)&&`Expires=${(\"number\"==typeof c.expires?new Date(c.expires):c.expires).toUTCString()}`,\"maxAge\"in c&&\"number\"==typeof c.maxAge&&`Max-Age=${c.maxAge}`,\"domain\"in c&&c.domain&&`Domain=${c.domain}`,\"secure\"in c&&c.secure&&\"Secure\",\"httpOnly\"in c&&c.httpOnly&&\"HttpOnly\",\"sameSite\"in c&&c.sameSite&&`SameSite=${c.sameSite}`,\"partitioned\"in c&&c.partitioned&&\"Partitioned\",\"priority\"in c&&c.priority&&`Priority=${c.priority}`].filter(Boolean),stringified=`${c.name}=${encodeURIComponent(null!=(_a=c.value)?_a:\"\")}`;return 0===attrs.length?stringified:`${stringified}; ${attrs.join(\"; \")}`}function parseCookie(cookie){let map=new Map;for(let pair of cookie.split(/; */)){if(!pair)continue;let splitAt=pair.indexOf(\"=\");if(-1===splitAt){map.set(pair,\"true\");continue}let[key,value1]=[pair.slice(0,splitAt),pair.slice(splitAt+1)];try{map.set(key,decodeURIComponent(null!=value1?value1:\"true\"))}catch{}}return map}function parseSetCookie(setCookie){if(!setCookie)return;let[[name,value1],...attributes]=parseCookie(setCookie),{domain,expires,httponly,maxage,path,samesite,secure,partitioned,priority}=Object.fromEntries(attributes.map(([key,value2])=>[key.toLowerCase().replace(/-/g,\"\"),value2]));{var string,string1,t={name,value:decodeURIComponent(value1),domain,...expires&&{expires:new Date(expires)},...httponl...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js:\n Line 122: `+(\"useParams()\"===t?\" - [cache] For known params, prerender them with `generateStaticParams`\\n https://nextjs.org/docs/messages/blocking-prerender-client-hook#for-known-params-prerender\\n\":\"\")+\" - [block] Set `export const instant = false` to silence this warning and allow a blocking route\\n https://nextjs.org/docs/messages/blocking-prerender-client-hook#allow-blocking-route\"),this.digest=s,Object.defineProperty(this,\"__NEXT_ERROR_CODE\",{value:\"E1315\",enumerable:!1,configurable:!0})}}function u(e){return\"object\"==typeof e&&null!==e&&\"digest\"in e&&e.digest===s}let c=new WeakMap;function d(e,t){var r=e,n=t;if(r.aborted)return Promise.reject(n);{let e=new Promise((e,t)=>{let a=t.bind(null,n),i=c.get(r);if(i)i.push(a);else{let e=[a];c.set(r,e),r.addEventListener(\"abort\",()=>{for(let t=0;ti});var n=r(\"./dist/esm/server/lib/lru-cache.js\"),a=r(\"./tags-manifest.external\");function i(e){if(0===e)return{get:()=>Promise.resolve(void 0),set:()=>Promise.resolve(),refreshTags:()=>Promise.resolve(),getExpiration:()=>Promise.resolve(0),updateTags:()=>Promise.resolve()};let t=new n.q(e,e=>e.size),r=new Map,i=process.env.NEXT_PRIVATE_DEBUG_CACHE?console.debug.bind(console,\"DefaultCacheHandler:\"):void 0;return{async get(e){let n=r.get(e);n&&(null==i||i(\"get\",e,\"pending\"),await n);let s=t.get(e);if(!s){null==i||i(\"get\",e,\"not found\");return}let o=s.entry,l=o.revalidate;if(performance.timeOrigin+performance.now()>o.timestamp+1e3*l){null==i||i(\"get\",e,\"expired\");return}let u=o.revalidate;if((0,a.areTagsExpired)(o.tags,o.timestamp)){null==i||i(\"get\",e,\"had expired tag\");return}(0,a.areTagsStale)(o.tags,o.timestamp)&&(null==i||i(\"get\",e,\"had...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:\n Line 190: `+(\"useParams()\"===expression?\" - [cache] For known params, prerender them with `generateStaticParams`\\n https://nextjs.org/docs/messages/blocking-prerender-client-hook#for-known-params-prerender\\n\":\"\")+\" - [block] Set `export const instant = false` to silence this warning and allow a blocking route\\n https://nextjs.org/docs/messages/blocking-prerender-client-hook#allow-blocking-route\"),this.digest=CLIENT_HOOK_DYNAMIC,Object.defineProperty(this,\"__NEXT_ERROR_CODE\",{value:\"E1315\",enumerable:!1,configurable:!0})}}function isClientHookDynamicError(err){return\"object\"==typeof err&&null!==err&&\"digest\"in err&&err.digest===CLIENT_HOOK_DYNAMIC}let abortListenersBySignal=new WeakMap;function makeHangingPromise(signal,route,expression){return makeHangingPromiseWithError(signal,new HangingPromiseRejectionError(route,expression))}function makeClientHookHangingPromise(signal,error){return makeHangingPromiseWithError(signal,error)}function makeHangingPromiseWithError(signal,error){if(signal.aborted)return Promise.reject(error);{let hangingPromise=new Promise((_,reject)=>{let boundRejection=reject.bind(null,error),currentListeners=abortListenersBySignal.get(signal);if(currentListeners)currentListeners.push(boundRejection);else{let listeners=[boundRejection];abortListenersBySignal.set(signal,listeners),signal.addEventListener(\"abort\",()=>{for(let i=0;ivalue1);return promise.catch(ignoreReject),promise}function makeDevtoolsIOAwarePromise(underlying,requestStore,stage){return requestStore.stagedRendering?requestStore.stagedRendering.delayUntilStage(stage,void 0,underlying):new Promise(resolve=>{setTimeout(()=>{resolve(underlying)},0)})}let RENDER_STAGES_BY_DATA_KIND={sessionData:{early:_app_render_staged_rendering__rspack_import_1.RenderStage.ShellEarlyRuntime,late:_...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js:\n Line 122: `+(\"useParams()\"===t?\" - [cache] For known params, prerender them with `generateStaticParams`\\n https://nextjs.org/docs/messages/blocking-prerender-client-hook#for-known-params-prerender\\n\":\"\")+\" - [block] Set `export const instant = false` to silence this warning and allow a blocking route\\n https://nextjs.org/docs/messages/blocking-prerender-client-hook#allow-blocking-route\"),this.digest=s,Object.defineProperty(this,\"__NEXT_ERROR_CODE\",{value:\"E1315\",enumerable:!1,configurable:!0})}}function u(e){return\"object\"==typeof e&&null!==e&&\"digest\"in e&&e.digest===s}let c=new WeakMap;function d(e,t){var r=e,n=t;if(r.aborted)return Promise.reject(n);{let e=new Promise((e,t)=>{let a=t.bind(null,n),i=c.get(r);if(i)i.push(a);else{let e=[a];c.set(r,e),r.addEventListener(\"abort\",()=>{for(let t=0;ti});var n=r(\"./dist/esm/server/lib/lru-cache.js\"),a=r(\"./tags-manifest.external\");function i(e){if(0===e)return{get:()=>Promise.resolve(void 0),set:()=>Promise.resolve(),refreshTags:()=>Promise.resolve(),getExpiration:()=>Promise.resolve(0),updateTags:()=>Promise.resolve()};let t=new n.q(e,e=>e.size),r=new Map,i=process.env.NEXT_PRIVATE_DEBUG_CACHE?console.debug.bind(console,\"DefaultCacheHandler:\"):void 0;return{async get(e){let n=r.get(e);n&&(null==i||i(\"get\",e,\"pending\"),await n);let s=t.get(e);if(!s){null==i||i(\"get\",e,\"not found\");return}let o=s.entry,l=o.revalidate;if(performance.timeOrigin+performance.now()>o.timestamp+1e3*l){null==i||i(\"get\",e,\"expired\");return}let u=o.revalidate;if((0,a.areTagsExpired)(o.tags,o.timestamp)){null==i||i(\"get\",e,\"had expired tag\");return}(0,a.areTagsStale)(o.tags,o.timestamp)&&(null==i||i(\"get\",e,\"had...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.dev.js:\n Line 190: `+(\"useParams()\"===expression?\" - [cache] For known params, prerender them with `generateStaticParams`\\n https://nextjs.org/docs/messages/blocking-prerender-client-hook#for-known-params-prerender\\n\":\"\")+\" - [block] Set `export const instant = false` to silence this warning and allow a blocking route\\n https://nextjs.org/docs/messages/blocking-prerender-client-hook#allow-blocking-route\"),this.digest=CLIENT_HOOK_DYNAMIC,Object.defineProperty(this,\"__NEXT_ERROR_CODE\",{value:\"E1315\",enumerable:!1,configurable:!0})}}function isClientHookDynamicError(err){return\"object\"==typeof err&&null!==err&&\"digest\"in err&&err.digest===CLIENT_HOOK_DYNAMIC}let abortListenersBySignal=new WeakMap;function makeHangingPromise(signal,route,expression){return makeHangingPromiseWithError(signal,new HangingPromiseRejectionError(route,expression))}function makeClientHookHangingPromise(signal,error){return makeHangingPromiseWithError(signal,error)}function makeHangingPromiseWithError(signal,error){if(signal.aborted)return Promise.reject(error);{let hangingPromise=new Promise((_,reject)=>{let boundRejection=reject.bind(null,error),currentListeners=abortListenersBySignal.get(signal);if(currentListeners)currentListeners.push(boundRejection);else{let listeners=[boundRejection];abortListenersBySignal.set(signal,listeners),signal.addEventListener(\"abort\",()=>{for(let i=0;ivalue1);return promise.catch(ignoreReject),promise}function makeDevtoolsIOAwarePromise(underlying,requestStore,stage){return requestStore.stagedRendering?requestStore.stagedRendering.delayUntilStage(stage,void 0,underlying):new Promise(resolve=>{setTimeout(()=>{resolve(underlying)},0)})}let RENDER_STAGES_BY_DATA_KIND={sessionData:{early:_app_render_staged_rendering__rspack_import_1.RenderStage.ShellEarlyRuntime,late:_...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-page-turbo-experimental.runtime.prod.js:\n Line 122: `+(\"useParams()\"===t?\" - [cache] For known params, prerender them with `generateStaticParams`\\n https://nextjs.org/docs/messages/blocking-prerender-client-hook#for-known-params-prerender\\n\":\"\")+\" - [block] Set `export const instant = false` to silence this warning and allow a blocking route\\n https://nextjs.org/docs/messages/blocking-prerender-client-hook#allow-blocking-route\"),this.digest=s,Object.defineProperty(this,\"__NEXT_ERROR_CODE\",{value:\"E1315\",enumerable:!1,configurable:!0})}}function u(e){return\"object\"==typeof e&&null!==e&&\"digest\"in e&&e.digest===s}let c=new WeakMap;function d(e,t){var r=e,n=t;if(r.aborted)return Promise.reject(n);{let e=new Promise((e,t)=>{let a=t.bind(null,n),i=c.get(r);if(i)i.push(a);else{let e=[a];c.set(r,e),r.addEventListener(\"abort\",()=>{for(let t=0;ti});var n=r(\"./dist/esm/server/lib/lru-cache.js\"),a=r(\"./tags-manifest.external\");function i(e){if(0===e)return{get:()=>Promise.resolve(void 0),set:()=>Promise.resolve(),refreshTags:()=>Promise.resolve(),getExpiration:()=>Promise.resolve(0),updateTags:()=>Promise.resolve()};let t=new n.q(e,e=>e.size),r=new Map,i=process.env.NEXT_PRIVATE_DEBUG_CACHE?console.debug.bind(console,\"DefaultCacheHandler:\"):void 0;return{async get(e){let n=r.get(e);n&&(null==i||i(\"get\",e,\"pending\"),await n);let s=t.get(e);if(!s){null==i||i(\"get\",e,\"not found\");return}let o=s.entry,l=o.revalidate;if(performance.timeOrigin+performance.now()>o.timestamp+1e3*l){null==i||i(\"get\",e,\"expired\");return}let u=o.revalidate;if((0,a.areTagsExpired)(o.tags,o.timestamp)){null==i||i(\"get\",e,\"had expired tag\");return}(0,a.areTagsStale)(o.tags,o.timestamp)&&(null==i||i(\"get\",e,\"had...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-page-turbo-experimental.runtime.dev.js:\n Line 190: `+(\"useParams()\"===expression?\" - [cache] For known params, prerender them with `generateStaticParams`\\n https://nextjs.org/docs/messages/blocking-prerender-client-hook#for-known-params-prerender\\n\":\"\")+\" - [block] Set `export const instant = false` to silence this warning and allow a blocking route\\n https://nextjs.org/docs/messages/blocking-prerender-client-hook#allow-blocking-route\"),this.digest=CLIENT_HOOK_DYNAMIC,Object.defineProperty(this,\"__NEXT_ERROR_CODE\",{value:\"E1315\",enumerable:!1,configurable:!0})}}function isClientHookDynamicError(err){return\"object\"==typeof err&&null!==err&&\"digest\"in err&&err.digest===CLIENT_HOOK_DYNAMIC}let abortListenersBySignal=new WeakMap;function makeHangingPromise(signal,route,expression){return makeHangingPromiseWithError(signal,new HangingPromiseRejectionError(route,expression))}function makeClientHookHangingPromise(signal,error){return makeHangingPromiseWithError(signal,error)}function makeHangingPromiseWithError(signal,error){if(signal.aborted)return Promise.reject(error);{let hangingPromise=new Promise((_,reject)=>{let boundRejection=reject.bind(null,error),currentListeners=abortListenersBySignal.get(signal);if(currentListeners)currentListeners.push(boundRejection);else{let listeners=[boundRejection];abortListenersBySignal.set(signal,listeners),signal.addEventListener(\"abort\",()=>{for(let i=0;ivalue1);return promise.catch(ignoreReject),promise}function makeDevtoolsIOAwarePromise(underlying,requestStore,stage){return requestStore.stagedRendering?requestStore.stagedRendering.delayUntilStage(stage,void 0,underlying):new Promise(resolve=>{setTimeout(()=>{resolve(underlying)},0)})}let RENDER_STAGES_BY_DATA_KIND={sessionData:{early:_app_render_staged_rendering__rspack_import_1.RenderStage.ShellEarlyRuntime,late:_...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-page-experimental.runtime.prod.js:\n Line 122: `+(\"useParams()\"===t?\" - [cache] For known params, prerender them with `generateStaticParams`\\n https://nextjs.org/docs/messages/blocking-prerender-client-hook#for-known-params-prerender\\n\":\"\")+\" - [block] Set `export const instant = false` to silence this warning and allow a blocking route\\n https://nextjs.org/docs/messages/blocking-prerender-client-hook#allow-blocking-route\"),this.digest=s,Object.defineProperty(this,\"__NEXT_ERROR_CODE\",{value:\"E1315\",enumerable:!1,configurable:!0})}}function u(e){return\"object\"==typeof e&&null!==e&&\"digest\"in e&&e.digest===s}let c=new WeakMap;function d(e,t){var r=e,n=t;if(r.aborted)return Promise.reject(n);{let e=new Promise((e,t)=>{let a=t.bind(null,n),i=c.get(r);if(i)i.push(a);else{let e=[a];c.set(r,e),r.addEventListener(\"abort\",()=>{for(let t=0;ti});var n=r(\"./dist/esm/server/lib/lru-cache.js\"),a=r(\"./tags-manifest.external\");function i(e){if(0===e)return{get:()=>Promise.resolve(void 0),set:()=>Promise.resolve(),refreshTags:()=>Promise.resolve(),getExpiration:()=>Promise.resolve(0),updateTags:()=>Promise.resolve()};let t=new n.q(e,e=>e.size),r=new Map,i=process.env.NEXT_PRIVATE_DEBUG_CACHE?console.debug.bind(console,\"DefaultCacheHandler:\"):void 0;return{async get(e){let n=r.get(e);n&&(null==i||i(\"get\",e,\"pending\"),await n);let s=t.get(e);if(!s){null==i||i(\"get\",e,\"not found\");return}let o=s.entry,l=o.revalidate;if(performance.timeOrigin+performance.now()>o.timestamp+1e3*l){null==i||i(\"get\",e,\"expired\");return}let u=o.revalidate;if((0,a.areTagsExpired)(o.tags,o.timestamp)){null==i||i(\"get\",e,\"had expired tag\");return}(0,a.areTagsStale)(o.tags,o.timestamp)&&(null==i||i(\"get\",e,\"had...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-page-experimental.runtime.dev.js:\n Line 190: `+(\"useParams()\"===expression?\" - [cache] For known params, prerender them with `generateStaticParams`\\n https://nextjs.org/docs/messages/blocking-prerender-client-hook#for-known-params-prerender\\n\":\"\")+\" - [block] Set `export const instant = false` to silence this warning and allow a blocking route\\n https://nextjs.org/docs/messages/blocking-prerender-client-hook#allow-blocking-route\"),this.digest=CLIENT_HOOK_DYNAMIC,Object.defineProperty(this,\"__NEXT_ERROR_CODE\",{value:\"E1315\",enumerable:!1,configurable:!0})}}function isClientHookDynamicError(err){return\"object\"==typeof err&&null!==err&&\"digest\"in err&&err.digest===CLIENT_HOOK_DYNAMIC}let abortListenersBySignal=new WeakMap;function makeHangingPromise(signal,route,expression){return makeHangingPromiseWithError(signal,new HangingPromiseRejectionError(route,expression))}function makeClientHookHangingPromise(signal,error){return makeHangingPromiseWithError(signal,error)}function makeHangingPromiseWithError(signal,error){if(signal.aborted)return Promise.reject(error);{let hangingPromise=new Promise((_,reject)=>{let boundRejection=reject.bind(null,error),currentListeners=abortListenersBySignal.get(signal);if(currentListeners)currentListeners.push(boundRejection);else{let listeners=[boundRejection];abortListenersBySignal.set(signal,listeners),signal.addEventListener(\"abort\",()=>{for(let i=0;ivalue1);return promise.catch(ignoreReject),promise}function makeDevtoolsIOAwarePromise(underlying,requestStore,stage){return requestStore.stagedRendering?requestStore.stagedRendering.delayUntilStage(stage,void 0,underlying):new Promise(resolve=>{setTimeout(()=>{resolve(underlying)},0)})}let RENDER_STAGES_BY_DATA_KIND={sessionData:{early:_app_render_staged_rendering__rspack_import_1.RenderStage.ShellEarlyRuntime,late:_...","title":"export.*revalidateTag","metadata":{"matches":70,"truncated":false},"time":{"start":1781390535727,"end":1781390536734}}}}
+{"type":"step_finish","timestamp":1781390536750,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec3267022001rOgdc5mhImlFzT","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec3265c1b0011MQIUmxcjVa1Tw","type":"step-finish","reason":"tool-calls","snapshot":"a73cc177aa6be3b38387792c45a1506702be7a41","cost":0.00332009,"tokens":{"input":615,"output":131,"reasoning":0,"cache":{"read":13824,"write":0}}}}
+{"type":"step_start","timestamp":1781390544382,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec3268df8001scSLseGaIX1L72","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec326703e00110ZOyI8EvjOjCA","type":"step-start","snapshot":"a73cc177aa6be3b38387792c45a1506702be7a41"}}
+{"type":"tool_use","timestamp":1781390546043,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec326936f001z71jvWBhO6F24T","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec326703e00110ZOyI8EvjOjCA","type":"tool","callID":"grep_13","tool":"grep","state":{"status":"completed","input":{"path":"/workspace/node_modules/next","pattern":"export declare function updateTag"},"output":"Found 1 matches\n/workspace/node_modules/next/dist/server/web/spec-extension/revalidate.d.ts:\n Line 20: export declare function updateTag(tag: string): undefined;","title":"export declare function updateTag","metadata":{"matches":1,"truncated":false},"time":{"start":1781390545931,"end":1781390546040}}}}
+{"type":"step_finish","timestamp":1781390546046,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec326947a001UtTTonsP7JRbHR","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec326703e00110ZOyI8EvjOjCA","type":"step-finish","reason":"tool-calls","snapshot":"a73cc177aa6be3b38387792c45a1506702be7a41","cost":0.03718086,"tokens":{"input":36298,"output":101,"reasoning":0,"cache":{"read":14336,"write":0}}}}
+{"type":"step_start","timestamp":1781390548063,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec3269c58001vhzv5IWscrJ62O","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec326948d001jvPtrpJk4oCP4D","type":"step-start","snapshot":"a73cc177aa6be3b38387792c45a1506702be7a41"}}
+{"type":"tool_use","timestamp":1781390551957,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec326ab25001g7sgwHGKnnZM6p","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec326948d001jvPtrpJk4oCP4D","type":"tool","callID":"read_14","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/node_modules/next/dist/server/web/spec-extension/revalidate.js","limit":120},"output":"\n00001| \"use strict\";\n00002| Object.defineProperty(exports, \"__esModule\", {\n00003| value: true\n00004| });\n00005| 0 && (module.exports = {\n00006| refresh: null,\n00007| revalidatePath: null,\n00008| revalidateTag: null,\n00009| updateTag: null\n00010| });\n00011| function _export(target, all) {\n00012| for(var name in all)Object.defineProperty(target, name, {\n00013| enumerable: true,\n00014| get: all[name]\n00015| });\n00016| }\n00017| _export(exports, {\n00018| refresh: function() {\n00019| return refresh;\n00020| },\n00021| revalidatePath: function() {\n00022| return revalidatePath;\n00023| },\n00024| revalidateTag: function() {\n00025| return revalidateTag;\n00026| },\n00027| updateTag: function() {\n00028| return updateTag;\n00029| }\n00030| });\n00031| const _dynamicrendering = require(\"../../app-render/dynamic-rendering\");\n00032| const _utils = require(\"../../../shared/lib/router/utils\");\n00033| const _constants = require(\"../../../lib/constants\");\n00034| const _workasyncstorageexternal = require(\"../../app-render/work-async-storage.external\");\n00035| const _workunitasyncstorageexternal = require(\"../../app-render/work-unit-async-storage.external\");\n00036| const _hooksservercontext = require(\"../../../client/components/hooks-server-context\");\n00037| const _invarianterror = require(\"../../../shared/lib/invariant-error\");\n00038| const _actionrevalidationkind = require(\"../../../shared/lib/action-revalidation-kind\");\n00039| const _removetrailingslash = require(\"../../../shared/lib/router/utils/remove-trailing-slash\");\n00040| const _encodecachetag = require(\"../../lib/encode-cache-tag\");\n00041| function revalidateTag(tag, profile) {\n00042| if (!profile) {\n00043| console.warn('\"revalidateTag\" without the second argument is now deprecated, add second argument of \"max\" or use \"updateTag\". See more info here: https://nextjs.org/docs/messages/revalidate-tag-single-arg');\n00044| }\n00045| return revalidate([\n00046| (0, _encodecachetag.encodeCacheTag)(tag)\n00047| ], `revalidateTag ${tag}`, profile);\n00048| }\n00049| function updateTag(tag) {\n00050| const workStore = _workasyncstorageexternal.workAsyncStorage.getStore();\n00051| // TODO: change this after investigating why phase: 'action' is\n00052| // set for route handlers\n00053| if (!workStore || workStore.page.endsWith('/route')) {\n00054| throw Object.defineProperty(new Error('updateTag can only be called from within a Server Action. ' + 'To invalidate cache tags in Route Handlers or other contexts, use revalidateTag instead. ' + 'See more info here: https://nextjs.org/docs/app/api-reference/functions/updateTag'), \"__NEXT_ERROR_CODE\", {\n00055| value: \"E872\",\n00056| enumerable: false,\n00057| configurable: true\n00058| });\n00059| }\n00060| // updateTag uses immediate expiration (no profile) without deprecation warning\n00061| return revalidate([\n00062| (0, _encodecachetag.encodeCacheTag)(tag)\n00063| ], `updateTag ${tag}`, undefined);\n00064| }\n00065| function refresh() {\n00066| const workStore = _workasyncstorageexternal.workAsyncStorage.getStore();\n00067| const workUnitStore = _workunitasyncstorageexternal.workUnitAsyncStorage.getStore();\n00068| if (!workStore || workStore.page.endsWith('/route') || (workUnitStore == null ? void 0 : workUnitStore.phase) !== 'action') {\n00069| throw Object.defineProperty(new Error('refresh can only be called from within a Server Action. ' + 'See more info here: https://nextjs.org/docs/app/api-reference/functions/refresh'), \"__NEXT_ERROR_CODE\", {\n00070| value: \"E870\",\n00071| enumerable: false,\n00072| configurable: true\n00073| });\n00074| }\n00075| if (workStore) {\n00076| // The Server Action version of refresh() only revalidates the dynamic data\n00077| // on the client. It doesn't affect cached data.\n00078| workStore.pathWasRevalidated = _actionrevalidationkind.ActionDidRevalidateDynamicOnly;\n00079| }\n00080| }\n00081| function revalidatePath(originalPath, type) {\n00082| if (originalPath.length > _constants.NEXT_CACHE_SOFT_TAG_MAX_LENGTH) {\n00083| console.warn(`Warning: revalidatePath received \"${originalPath}\" which exceeded max length of ${_constants.NEXT_CACHE_SOFT_TAG_MAX_LENGTH}. See more info here https://nextjs.org/docs/app/api-reference/functions/revalidatePath`);\n00084| return;\n00085| }\n00086| let normalizedPath = `${_constants.NEXT_CACHE_IMPLICIT_TAG_ID}${(0, _encodecachetag.encodeCacheTag)((0, _removetrailingslash.removeTrailingSlash)(originalPath))}`;\n00087| if (type) {\n00088| normalizedPath += `${normalizedPath.endsWith('/') ? '' : '/'}${type}`;\n00089| } else if ((0, _utils.isDynamicRoute)(originalPath)) {\n00090| console.warn(`Warning: a dynamic page path \"${originalPath}\" was passed to \"revalidatePath\", but the \"type\" parameter is missing. This has no effect by default, see more info here https://nextjs.org/docs/app/api-reference/functions/revalidatePath`);\n00091| }\n00092| const tags = [\n00093| normalizedPath\n00094| ];\n00095| if (normalizedPath === `${_constants.NEXT_CACHE_IMPLICIT_TAG_ID}/`) {\n00096| tags.push(`${_constants.NEXT_CACHE_IMPLICIT_TAG_ID}/index`);\n00097| } else if (normalizedPath === `${_constants.NEXT_CACHE_IMPLICIT_TAG_ID}/index`) {\n00098| tags.push(`${_constants.NEXT_CACHE_IMPLICIT_TAG_ID}/`);\n00099| }\n00100| return revalidate(tags, `revalidatePath ${originalPath}`);\n00101| }\n00102| function revalidate(tags, expression, profile) {\n00103| var _store_cacheLifeProfiles;\n00104| const store = _workasyncstorageexternal.workAsyncStorage.getStore();\n00105| if (!store || !store.incrementalCache) {\n00106| throw Object.defineProperty(new Error(`Invariant: static generation store missing in ${expression}`), \"__NEXT_ERROR_CODE\", {\n00107| value: \"E263\",\n00108| enumerable: false,\n00109| configurable: true\n00110| });\n00111| }\n00112| const workUnitStore = _workunitasyncstorageexternal.workUnitAsyncStorage.getStore();\n00113| if (workUnitStore) {\n00114| if (workUnitStore.phase === 'render') {\n00115| throw Object.defineProperty(new Error(`Route ${store.route} used \"${expression}\" during render which is unsupported. To ensure revalidation is performed consistently it must always happen outside of renders and cached functions. See more info here: https://nextjs.org/docs/app/building-your-application/rendering/static-and-dynamic#dynamic-rendering`), \"__NEXT_ERROR_CODE\", {\n00116| value: \"E7\",\n00117| enumerable: false,\n00118| configurable: true\n00119| });\n00120| }\n\n(File has more lines. Use 'offset' parameter to read beyond line 120)\n","title":"node_modules/next/dist/server/web/spec-extension/revalidate.js","metadata":{"preview":"\"use strict\";\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n0 && (module.exports = {\n refresh: null,\n revalidatePath: null,\n revalidateTag: null,\n updateTag: null\n});\nfunction _export(target, all) {\n for(var name in all)Object.defineProperty(target, name, {\n enumerable: true,\n get: all[name]\n });\n}\n_export(exports, {\n refresh: function() {\n return refresh;\n },"},"time":{"start":1781390551951,"end":1781390551954}}}}
+{"type":"step_finish","timestamp":1781390551960,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec326ab93001MPBU8EKwltrgkd","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec326948d001jvPtrpJk4oCP4D","type":"step-finish","reason":"tool-calls","snapshot":"a73cc177aa6be3b38387792c45a1506702be7a41","cost":0.00934637,"tokens":{"input":355,"output":235,"reasoning":0,"cache":{"read":50432,"write":0}}}}
+{"type":"step_start","timestamp":1781390554204,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec326b4580012fLopsxgI8lyJT","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec326abac0015qiFUFnel7eD6N","type":"step-start","snapshot":"a73cc177aa6be3b38387792c45a1506702be7a41"}}
+{"type":"tool_use","timestamp":1781390563391,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec326d5fb0016xR6ISs2CGvVqQ","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec326abac0015qiFUFnel7eD6N","type":"tool","callID":"read_15","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/node_modules/next/dist/server/web/spec-extension/revalidate.js","offset":120,"limit":200},"output":"\n00121| switch(workUnitStore.type){\n00122| case 'cache':\n00123| case 'private-cache':\n00124| throw Object.defineProperty(new Error(`Route ${store.route} used \"${expression}\" inside a \"use cache\" which is unsupported. To ensure revalidation is performed consistently it must always happen outside of renders and cached functions. See more info here: https://nextjs.org/docs/app/building-your-application/rendering/static-and-dynamic#dynamic-rendering`), \"__NEXT_ERROR_CODE\", {\n00125| value: \"E181\",\n00126| enumerable: false,\n00127| configurable: true\n00128| });\n00129| case 'unstable-cache':\n00130| throw Object.defineProperty(new Error(`Route ${store.route} used \"${expression}\" inside a function cached with \"unstable_cache(...)\" which is unsupported. To ensure revalidation is performed consistently it must always happen outside of renders and cached functions. See more info here: https://nextjs.org/docs/app/building-your-application/rendering/static-and-dynamic#dynamic-rendering`), \"__NEXT_ERROR_CODE\", {\n00131| value: \"E306\",\n00132| enumerable: false,\n00133| configurable: true\n00134| });\n00135| case 'generate-static-params':\n00136| throw Object.defineProperty(new Error(`Route ${store.route} used \"${expression}\" inside \\`generateStaticParams\\` which is unsupported. To ensure revalidation is performed consistently it must always happen outside of renders and cached functions. See more info here: https://nextjs.org/docs/app/building-your-application/rendering/static-and-dynamic#dynamic-rendering`), \"__NEXT_ERROR_CODE\", {\n00137| value: \"E1127\",\n00138| enumerable: false,\n00139| configurable: true\n00140| });\n00141| case 'prerender':\n00142| case 'prerender-runtime':\n00143| // cacheComponents Prerender\n00144| const error = Object.defineProperty(new Error(`Route ${store.route} used ${expression} without first calling \\`await connection()\\`.`), \"__NEXT_ERROR_CODE\", {\n00145| value: \"E406\",\n00146| enumerable: false,\n00147| configurable: true\n00148| });\n00149| return (0, _dynamicrendering.abortAndThrowOnSynchronousRequestDataAccess)(store.route, expression, error, workUnitStore);\n00150| case 'prerender-client':\n00151| case 'validation-client':\n00152| throw Object.defineProperty(new _invarianterror.InvariantError(`${expression} must not be used within a client component. Next.js should be preventing ${expression} from being included in client components statically, but did not in this case.`), \"__NEXT_ERROR_CODE\", {\n00153| value: \"E693\",\n00154| enumerable: false,\n00155| configurable: true\n00156| });\n00157| case 'prerender-ppr':\n00158| return (0, _dynamicrendering.postponeWithTracking)(store.route, expression, workUnitStore.dynamicTracking);\n00159| case 'prerender-legacy':\n00160| workUnitStore.revalidate = 0;\n00161| const err = Object.defineProperty(new _hooksservercontext.DynamicServerError(`Route ${store.route} couldn't be rendered statically because it used \\`${expression}\\`. See more info here: https://nextjs.org/docs/messages/dynamic-server-error`), \"__NEXT_ERROR_CODE\", {\n00162| value: \"E558\",\n00163| enumerable: false,\n00164| configurable: true\n00165| });\n00166| store.dynamicUsageDescription = expression;\n00167| store.dynamicUsageStack = err.stack;\n00168| throw err;\n00169| case 'request':\n00170| if (process.env.NODE_ENV !== 'production') {\n00171| // TODO: This is most likely incorrect. It would lead to the ISR\n00172| // status being flipped when revalidating a static page with a server\n00173| // action.\n00174| workUnitStore.usedDynamic = true;\n00175| // TODO(restart-on-cache-miss): we should do a sync IO error here in dev\n00176| // to match prerender behavior\n00177| }\n00178| break;\n00179| default:\n00180| workUnitStore;\n00181| }\n00182| }\n00183| if (!store.pendingRevalidatedTags) {\n00184| store.pendingRevalidatedTags = [];\n00185| }\n00186| for (const tag of tags){\n00187| const existingIndex = store.pendingRevalidatedTags.findIndex((item)=>{\n00188| if (item.tag !== tag) return false;\n00189| // Compare profiles: both strings, both objects, or both undefined\n00190| if (typeof item.profile === 'string' && typeof profile === 'string') {\n00191| return item.profile === profile;\n00192| }\n00193| if (typeof item.profile === 'object' && typeof profile === 'object') {\n00194| return JSON.stringify(item.profile) === JSON.stringify(profile);\n00195| }\n00196| return item.profile === profile;\n00197| });\n00198| if (existingIndex === -1) {\n00199| store.pendingRevalidatedTags.push({\n00200| tag,\n00201| profile\n00202| });\n00203| }\n00204| }\n00205| // if profile is provided and this is a stale-while-revalidate\n00206| // update we do not mark the path as revalidated so that server\n00207| // actions don't pull their own writes\n00208| const cacheLife = profile && typeof profile === 'object' ? profile : profile && typeof profile === 'string' && (store == null ? void 0 : (_store_cacheLifeProfiles = store.cacheLifeProfiles) == null ? void 0 : _store_cacheLifeProfiles[profile]) ? store.cacheLifeProfiles[profile] : undefined;\n00209| if (!profile || (cacheLife == null ? void 0 : cacheLife.expire) === 0) {\n00210| // TODO: only revalidate if the path matches\n00211| store.pathWasRevalidated = _actionrevalidationkind.ActionDidRevalidateStaticAndDynamic;\n00212| }\n00213| }\n00214| \n00215| //# sourceMappingURL=revalidate.js.map\n\n(End of file - total 215 lines)\n","title":"node_modules/next/dist/server/web/spec-extension/revalidate.js","metadata":{"preview":" switch(workUnitStore.type){\n case 'cache':\n case 'private-cache':\n throw Object.defineProperty(new Error(`Route ${store.route} used \"${expression}\" inside a \"use cache\" which is unsupported. To ensure revalidation is performed consistently it must always happen outside of renders and cached functions. See more info here: https://nextjs.org/docs/app/building-your-application/rendering/static-and-dynamic#dynamic-rendering`), \"__NEXT_ERROR_CODE\", {\n value: \"E181\",\n enumerable: false,\n configurable: true\n });\n case 'unstable-cache':\n throw Object.defineProperty(new Error(`Route ${store.route} used \"${expression}\" inside a function cached with \"unstable_cache(...)\" which is unsupported. To ensure revalidation is performed consistently it must always happen outside of renders and cached functions. See more info here: https://nextjs.org/docs/app/building-your-application/rendering/static-and-dynamic#dynamic-rendering`), \"__NEXT_ERROR_CODE\", {\n value: \"E306\",\n enumerable: false,\n configurable: true\n });\n case 'generate-static-params':\n throw Object.defineProperty(new Error(`Route ${store.route} used \"${expression}\" inside \\`generateStaticParams\\` which is unsupported. To ensure revalidation is performed consistently it must always happen outside of renders and cached functions. See more info here: https://nextjs.org/docs/app/building-your-application/rendering/static-and-dynamic#dynamic-rendering`), \"__NEXT_ERROR_CODE\", {\n value: \"E1127\",\n enumerable: false,\n configurable: true\n });"},"time":{"start":1781390563384,"end":1781390563388}}}}
+{"type":"step_finish","timestamp":1781390563398,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec326d83d0012bWK7n5f4dMmxt","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec326abac0015qiFUFnel7eD6N","type":"step-finish","reason":"tool-calls","snapshot":"a73cc177aa6be3b38387792c45a1506702be7a41","cost":0.01238018,"tokens":{"input":2078,"output":574,"reasoning":0,"cache":{"read":50688,"write":0}}}}
+{"type":"step_start","timestamp":1781390565929,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec326e2250018rO59Wo73JKQVp","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec326d872001cmywiKAvuKVi17","type":"step-start","snapshot":"a73cc177aa6be3b38387792c45a1506702be7a41"}}
+{"type":"tool_use","timestamp":1781390578553,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec3270f85001z6upZz22ppVjnq","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec326d872001cmywiKAvuKVi17","type":"tool","callID":"grep_16","tool":"grep","state":{"status":"completed","input":{"path":"/workspace/node_modules/next","pattern":"unstable_cache"},"output":"Found 100 matches\n/workspace/node_modules/next/dist/server/app-render/work-unit-async-storage.external.d.ts:\n Line 247: * `unstable_cache`, which doesn't carry root params. Currently, `\"use cache\"`\n Line 248: * inside `unstable_cache` is allowed, so this case must be handled. The error\n Line 282: * Always `undefined` for `unstable_cache` — root params are not available in\n Line 283: * this context. If a `\"use cache\"` function nested inside `unstable_cache`\n Line 290: * unstable_cache context. A cache store shadows an outer request store (if\n\n/workspace/node_modules/next/dist/server/web/spec-extension/unstable-cache.d.ts:\n Line 5: * Read more: [Next.js Docs: `unstable_cache`](https://nextjs.org/docs/app/api-reference/functions/unstable_cache)\n Line 7: export declare function unstable_cache(cb: T, keyParts?: string[], options?: {\n\n/workspace/node_modules/next/dist/build/index.d.ts:\n Line 30: * - unstable_cache\n\n/workspace/node_modules/next/dist/server/app-render/dynamic-rendering.d.ts:\n Line 13: * inside unstable_cache it can still be cached. This type of indication can be removed if we ever\n Line 19: * unstable_cache should error. If you want to use some dynamic data inside unstable_cache you should\n\n/workspace/node_modules/next/cache.d.ts:\n Line 1: export { unstable_cache } from 'next/dist/server/web/spec-extension/unstable-cache'\n Line 155: export const unstable_cacheLife: typeof cacheLife\n Line 156: export const unstable_cacheTag: typeof cacheTag\n\n/workspace/node_modules/next/dist/docs/01-app/02-guides/upgrading/version-16.md:\n Line 571: unstable_cacheLife as cacheLife,\n Line 572: unstable_cacheTag as cacheTag,\n\n/workspace/node_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache.md:\n Line 216: > For data that needs to persist across deploys, use [`unstable_cache`](/docs/app/api-reference/functions/unstable_cache) for non-`fetch` functions or the [`fetch`](/docs/app/api-reference/functions/fetch) cache.\n\n/workspace/node_modules/next/dist/docs/01-app/03-api-reference/01-directives/use-cache-remote.md:\n Line 98: If you need entries that persist across deploys, use [`unstable_cache`](/docs/app/api-reference/functions/unstable_cache) for non-`fetch` functions, or rely on the [`fetch`](/docs/app/api-reference/functions/fetch) cache.\n\n/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/unstable_noStore.md:\n Line 26: - Using `unstable_noStore` inside [`unstable_cache`](/docs/app/api-reference/functions/unstable_cache) will not opt out of static generation. Instead, it will defer to the cache configuration to determine whether to cache the result or not.\n\n/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/unstable_cache.md:\n Line 2: title: unstable_cache\n Line 3: description: API Reference for the unstable_cache function.\n Line 8: > We recommend opting into [Cache Components](/docs/app/getting-started/caching) and replacing `unstable_cache` with the `use cache` directive.\n Line 10: `unstable_cache` allows you to cache the results of expensive operations, like database queries, and reuse them across multiple requests.\n Line 14: import { unstable_cache } from 'next/cache';\n Line 16: const getCachedUser = unstable_cache(\n Line 35: const data = unstable_cache(fetchData, keyParts, options)()\n Line 39: - `keyParts`: This is an extra array of keys that further adds identification to the cache. By default, `unstable_cache` already uses the arguments and the stringified version of your function as the cache key. It is optional in most cases; the only time you need to use it is when you use external variables without passing them as parameters. However, it is important to add closures used within the function if you do not pass them as parameters.\n Line 46: `unstable_cache` returns a function that when invoked, returns a Promise that resolves to the cached data. If the data is not in the cache, the provided function will be invoked, and its result will be cached and returned.\n Line 51: import { unstable_cache } from 'next/cache'\n Line 59: const getCachedUser = unstable_cache(\n Line 75: import { unstable_cache } from 'next/cache';\n Line 79: const getCachedUser = unstable_cache(\n Line 98: | `v14.0.0` | `unstable_cache` introduced. |\n\n/workspace/node_modules/next/dist/docs/01-app/02-guides/production-checklist.md:\n Line 68: - **[Data Caching](/docs/app/getting-started/caching):** Verify whether your data requests are being cached or not, and opt into caching, where appropriate. Ensure requests that don't use `fetch` are [cached](/docs/app/api-reference/functions/unstable_cache).\n\n/workspace/node_modules/next/dist/docs/01-app/03-api-reference/04-functions/next-root-params.md:\n Line 326: ### Not available in `unstable_cache`\n Line 328: Calling a root parameter getter inside `unstable_cache` will throw a runtime error. Use [`\"use cache\"`](/docs/app/api-reference/directives/use-cache) instead.\n Line 332: import { unstable_cache } from 'next/cache'\n Line 334: const getCachedData = unstable_cache(async () => {\n Line 335: const language = await lang() // Error: Not supported inside unstable_cache\n\n/workspace/node_modules/next/dist/docs/01-app/02-guides/migrating-to-cache-components.md:\n Line 23: Your existing `fetch` and `unstable_cache` caching keeps working as a separate layer, so let the insights and errors guide what to change.\n Line 324: ## `unstable_cache`\n Line 328: `unstable_cache` is replaced by the [`use cache`](/docs/app/api-reference/directives/use-cache) directive.\n Line 334: import { unstable_cache } from 'next/cache'\n Line 337: export const getUser = unstable_cache(\n Line 348: import { unstable_cache } from 'next/cache'\n Line 351: export const getUser = unstable_cache(\n Line 386: Like the `fetch` Data Cache, `unstable_cache` persists cached values across deployments and serverless instances, while `use cache` does not. See [`fetch` cache options](#fetch-cache-options) above for the storage details.\n\n/workspace/node_modules/next/dist/docs/01-app/02-guides/incremental-static-regeneration.md:\n Line 340: If you are using an ORM or connecting to a database, you can use `unstable_cache`:\n Line 343: import { unstable_cache } from 'next/cache'\n Line 346: const getCachedPosts = unstable_cache(\n Line 361: import { unstable_cache } from 'next/cache'\n Line 364: const getCachedPosts = unstable_cache(\n\n/workspace/node_modules/next/dist/docs/01-app/02-guides/draft-mode.md:\n Line 22: - [`unstable_cache`](/docs/app/api-reference/functions/unstable_cache) reads and writes are bypassed in the same way.\n\n/workspace/node_modules/next/dist/docs/01-app/02-guides/deploying-to-platforms.md:\n Line 72: The adapter API plus Next.js caching interfaces form the complete platform integration surface. The adapter handles build-time output, while `cacheHandler` and `cacheHandlers` cover different runtime caching paths. `cacheHandler` (singular) covers server cache paths like ISR, route handlers, patched `fetch`/`unstable_cache`, and image optimization. `cacheHandlers` (plural) configures `'use cache'` directive backends.\n\n/workspace/node_modules/next/dist/docs/01-app/02-guides/upgrading/codemods.md:\n Line 93: import { unstable_cacheTag as cacheTag } from 'next/cache'\n\n/workspace/node_modules/next/dist/docs/01-app/02-guides/caching-without-cache-components.md:\n Line 4: description: Learn how to cache and revalidate data using fetch options, unstable_cache, and route segment configs for projects not using Cache Components.\n Line 27: ### `unstable_cache` for non-`fetch` functions\n Line 29: `unstable_cache` allows you to cache the result of database queries and other async functions that don't use `fetch`. Wrap `unstable_cache` around the function:\n Line 32: import { unstable_cache } from 'next/cache'\n Line 35: export const getCachedUser = unstable_cache(\n Line 52: import { unstable_cache } from 'next/cache'\n Line 55: export const getCachedUser = unstable_cache(\n Line 76: See the [`unstable_cache` API reference](/docs/app/api-reference/functions/unstable_cache) to learn more.\n Line 163: For non-`fetch` functions, `unstable_cache` accepts a `revalidate` option in its configuration (see [example above](#unstable_cache-for-non-fetch-functions)).\n Line 218: For non-`fetch` functions, `unstable_cache` also accepts a `tags` option (see [example above](#unstable_cache-for-non-fetch-functions)).\n\n/workspace/node_modules/next/dist/server/app-render/work-unit-async-storage.external.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../../src/server/app-render/work-unit-async-storage.external.ts\"],\"sourcesContent\":[\"import type { AsyncLocalStorage } from 'async_hooks'\\nimport type { DraftModeProvider } from '../async-storage/draft-mode-provider'\\nimport type { ResponseCookies } from '../web/spec-extension/cookies'\\nimport type { ReadonlyHeaders } from '../web/spec-extension/adapters/headers'\\nimport type { ReadonlyRequestCookies } from '../web/spec-extension/adapters/request-cookies'\\nimport type { CacheSignal } from './cache-signal'\\nimport type { ResponseVaryParamsAccumulator } from './vary-params'\\nimport type { DynamicTrackingState } from './dynamic-rendering'\\nimport type { OpaqueFallbackRouteParams } from '../request/fallback-params'\\n\\n// Share the instance module in the next-shared layer\\nimport { workUnitAsyncStorageInstance } from './work-unit-async-storage-instance' with { 'turbopack-transition': 'next-shared' }\\nimport type { ServerComponentsHmrCache } from '../response-cache'\\nimport type {\\n PrerenderResumeDataCache,\\n ResumeDataCache,\\n} from '../resume-data-cache/resume-data-cache'\\nimport type { Params } from '../request/params'\\nimport type { ImplicitTags } from '../lib/implicit-tags'\\nimport type { WorkStore } from './work-async-storage.external'\\nimport { NEXT_HMR_REFRESH_HASH_COOKIE } from '../../client/components/app-router-headers'\\nimport { InvariantError } from '../../shared/lib/invariant-error'\\nimport type { StagedRenderingController } from './staged-rendering'\\nimport { isEarlyRenderStage, RenderStage } from './staged-rendering'\\nimport type { ValidationBoundaryTracking } from './instant-validation/boundary-tracking'\\nimport type { InstantValidationSampleTracking } from './instant-validation/instant-samples'\\n\\nexport type WorkUnitPhase = 'action' | 'render' | 'after'\\n\\nexport interface CommonWorkUnitStore {\\n /** NOTE: Will be mutated as phases change */\\n phase: WorkUnitPhase\\n readonly implicitTags: ImplicitTags\\n}\\n\\nexport inter...\n\n/workspace/node_modules/next/dist/esm/server/app-render/work-unit-async-storage.external.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../../../src/server/app-render/work-unit-async-storage.external.ts\"],\"sourcesContent\":[\"import type { AsyncLocalStorage } from 'async_hooks'\\nimport type { DraftModeProvider } from '../async-storage/draft-mode-provider'\\nimport type { ResponseCookies } from '../web/spec-extension/cookies'\\nimport type { ReadonlyHeaders } from '../web/spec-extension/adapters/headers'\\nimport type { ReadonlyRequestCookies } from '../web/spec-extension/adapters/request-cookies'\\nimport type { CacheSignal } from './cache-signal'\\nimport type { ResponseVaryParamsAccumulator } from './vary-params'\\nimport type { DynamicTrackingState } from './dynamic-rendering'\\nimport type { OpaqueFallbackRouteParams } from '../request/fallback-params'\\n\\n// Share the instance module in the next-shared layer\\nimport { workUnitAsyncStorageInstance } from './work-unit-async-storage-instance' with { 'turbopack-transition': 'next-shared' }\\nimport type { ServerComponentsHmrCache } from '../response-cache'\\nimport type {\\n PrerenderResumeDataCache,\\n ResumeDataCache,\\n} from '../resume-data-cache/resume-data-cache'\\nimport type { Params } from '../request/params'\\nimport type { ImplicitTags } from '../lib/implicit-tags'\\nimport type { WorkStore } from './work-async-storage.external'\\nimport { NEXT_HMR_REFRESH_HASH_COOKIE } from '../../client/components/app-router-headers'\\nimport { InvariantError } from '../../shared/lib/invariant-error'\\nimport type { StagedRenderingController } from './staged-rendering'\\nimport { isEarlyRenderStage, RenderStage } from './staged-rendering'\\nimport type { ValidationBoundaryTracking } from './instant-validation/boundary-tracking'\\nimport type { InstantValidationSampleTracking } from './instant-validation/instant-samples'\\n\\nexport type WorkUnitPhase = 'action' | 'render' | 'after'\\n\\nexport interface CommonWorkUnitStore {\\n /** NOTE: Will be mutated as phases change */\\n phase: WorkUnitPhase\\n readonly implicitTags: ImplicitTags\\n}\\n\\nexport in...\n\n/workspace/node_modules/next/dist/server/use-cache/use-cache-wrapper.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../../src/server/use-cache/use-cache-wrapper.ts\"],\"sourcesContent\":[\"import type { DeepReadonly } from '../../shared/lib/deep-readonly'\\n/* eslint-disable import/no-extraneous-dependencies */\\nimport {\\n renderToReadableStream,\\n decodeReply,\\n decodeReplyFromAsyncIterable,\\n createTemporaryReferenceSet as createServerTemporaryReferenceSet,\\n} from 'react-server-dom-webpack/server'\\nimport {\\n createFromReadableStream,\\n encodeReply,\\n createTemporaryReferenceSet as createClientTemporaryReferenceSet,\\n} from 'react-server-dom-webpack/client'\\nimport { prerender } from 'react-server-dom-webpack/static'\\n/* eslint-enable import/no-extraneous-dependencies */\\n\\nimport type { WorkStore } from '../app-render/work-async-storage.external'\\nimport { workAsyncStorage } from '../app-render/work-async-storage.external'\\nimport type {\\n PrerenderStoreModernClient,\\n PrerenderStoreModernRuntime,\\n PrivateUseCacheStore,\\n RequestStore,\\n RevalidateStore,\\n UseCacheStore,\\n ValidationStoreClient,\\n WorkUnitStore,\\n} from '../app-render/work-unit-async-storage.external'\\nimport {\\n getHmrRefreshHash,\\n getResumeDataCache,\\n workUnitAsyncStorage,\\n getDraftModeProviderForCacheScope,\\n getCacheSignal,\\n isHmrRefresh,\\n getServerComponentsHmrCache,\\n getStagedRenderingController,\\n} from '../app-render/work-unit-async-storage.external'\\n\\nimport {\\n applyOwnerStack,\\n makeDevtoolsIOAwarePromise,\\n makeHangingPromise,\\n getSessionDataStage,\\n getRuntimeLinkDataStage,\\n getStaticLinkDataStage,\\n} from '../dynamic-rendering-utils'\\n\\nimport type { ClientReferenceManifest } from '../../build/webpack/plugins/flight-manifest-plugin'\\n\\nimport {\\n getClientReferenceManifest,\\n getServerModuleMap,\\n} from '../app-render/manifests-singleton'\\nimport type { CacheEntry } from '../lib/cache-handlers/types'\\nimport type { CacheSignal } from '../app-render/cache-signal'\\nimport { decryptActionBoundArgs } from '../app-render/encryption'\\nimp...\n\n/workspace/node_modules/next/dist/esm/server/use-cache/use-cache-wrapper.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../../../src/server/use-cache/use-cache-wrapper.ts\"],\"sourcesContent\":[\"import type { DeepReadonly } from '../../shared/lib/deep-readonly'\\n/* eslint-disable import/no-extraneous-dependencies */\\nimport {\\n renderToReadableStream,\\n decodeReply,\\n decodeReplyFromAsyncIterable,\\n createTemporaryReferenceSet as createServerTemporaryReferenceSet,\\n} from 'react-server-dom-webpack/server'\\nimport {\\n createFromReadableStream,\\n encodeReply,\\n createTemporaryReferenceSet as createClientTemporaryReferenceSet,\\n} from 'react-server-dom-webpack/client'\\nimport { prerender } from 'react-server-dom-webpack/static'\\n/* eslint-enable import/no-extraneous-dependencies */\\n\\nimport type { WorkStore } from '../app-render/work-async-storage.external'\\nimport { workAsyncStorage } from '../app-render/work-async-storage.external'\\nimport type {\\n PrerenderStoreModernClient,\\n PrerenderStoreModernRuntime,\\n PrivateUseCacheStore,\\n RequestStore,\\n RevalidateStore,\\n UseCacheStore,\\n ValidationStoreClient,\\n WorkUnitStore,\\n} from '../app-render/work-unit-async-storage.external'\\nimport {\\n getHmrRefreshHash,\\n getResumeDataCache,\\n workUnitAsyncStorage,\\n getDraftModeProviderForCacheScope,\\n getCacheSignal,\\n isHmrRefresh,\\n getServerComponentsHmrCache,\\n getStagedRenderingController,\\n} from '../app-render/work-unit-async-storage.external'\\n\\nimport {\\n applyOwnerStack,\\n makeDevtoolsIOAwarePromise,\\n makeHangingPromise,\\n getSessionDataStage,\\n getRuntimeLinkDataStage,\\n getStaticLinkDataStage,\\n} from '../dynamic-rendering-utils'\\n\\nimport type { ClientReferenceManifest } from '../../build/webpack/plugins/flight-manifest-plugin'\\n\\nimport {\\n getClientReferenceManifest,\\n getServerModuleMap,\\n} from '../app-render/manifests-singleton'\\nimport type { CacheEntry } from '../lib/cache-handlers/types'\\nimport type { CacheSignal } from '../app-render/cache-signal'\\nimport { decryptActionBoundArgs } from '../app-render/encryption'\\n...\n\n/workspace/node_modules/next/dist/compiled/next-server/use-cache-probe-worker.runtime.dev.js.map:\n Line 1: {\"version\":3,\"file\":\"use-cache-probe-worker.runtime.dev.js\",\"sources\":[\"webpack://next/./dist/compiled/@edge-runtime/cookies/index.js\",\"webpack://next/./dist/compiled/cookie/index.js\",\"webpack://next/./dist/compiled/p-queue/index.js\",\"webpack://next/./dist/compiled/react-dom/cjs/react-dom.react-server.development.js\",\"webpack://next/./dist/compiled/react-dom/react-dom.react-server.js\",\"webpack://next/./dist/compiled/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.development.js\",\"webpack://next/./dist/compiled/react-server-dom-webpack/server.node.js\",\"webpack://next/./dist/compiled/react/cjs/react.react-server.development.js\",\"webpack://next/./dist/compiled/react/react.react-server.js\",\"webpack://next/./src/server/node-environment-baseline.ts\",\"webpack://next/./src/shared/lib/modern-browserslist-target.js\",\"webpack://next/webpack/runtime/compat_get_default_export\",\"webpack://next/webpack/runtime/define_property_getters\",\"webpack://next/webpack/runtime/ensure_chunk\",\"webpack://next/webpack/runtime/has_own_property\",\"webpack://next/webpack/runtime/make_namespace_object\",\"webpack://next/./src/server/patch-error-inspect.ts\",\"webpack://next/./src/server/node-environment-extensions/web-crypto.tsx\",\"webpack://next/./src/server/require-hook.ts\",\"webpack://next/./src/server/app-render/staged-rendering.ts\",\"webpack://next/./src/server/node-environment-extensions/date.tsx\",\"webpack://next/./src/server/lib/trace/constants.ts\",\"webpack://next/./src/lib/picocolors.ts\",\"webpack://next/./src/server/lib/lru-cache.ts\",\"webpack://next/./src/server/lib/source-maps.ts\",\"webpack://next/./src/server/lib/parse-stack.ts\",\"webpack://next/./src/server/node-environment-extensions/error-inspect.tsx\",\"webpack://next/./src/server/dev/browser-logs/file-logger.ts\",\"webpack://next/./src/client/lib/console.ts\",\"webpack://next/./src/server/node-environment-extensions/console-file.tsx\",\"webpack://next/./src/server/node-environment-extensions/console-exit.tsx\",\"webpack://next/./src/sha...\n\n/workspace/node_modules/next/dist/compiled/next-server/use-cache-probe-worker-turbo.runtime.dev.js.map:\n Line 1: {\"version\":3,\"file\":\"use-cache-probe-worker-turbo.runtime.dev.js\",\"sources\":[\"webpack://next/./dist/compiled/@edge-runtime/cookies/index.js\",\"webpack://next/./dist/compiled/cookie/index.js\",\"webpack://next/./dist/compiled/p-queue/index.js\",\"webpack://next/./dist/compiled/react-dom/cjs/react-dom.react-server.development.js\",\"webpack://next/./dist/compiled/react-dom/react-dom.react-server.js\",\"webpack://next/./dist/compiled/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.node.development.js\",\"webpack://next/./dist/compiled/react-server-dom-turbopack/server.node.js\",\"webpack://next/./dist/compiled/react/cjs/react.react-server.development.js\",\"webpack://next/./dist/compiled/react/react.react-server.js\",\"webpack://next/./src/server/node-environment-baseline.ts\",\"webpack://next/./src/shared/lib/modern-browserslist-target.js\",\"webpack://next/webpack/runtime/compat_get_default_export\",\"webpack://next/webpack/runtime/define_property_getters\",\"webpack://next/webpack/runtime/has_own_property\",\"webpack://next/webpack/runtime/make_namespace_object\",\"webpack://next/./src/server/patch-error-inspect.ts\",\"webpack://next/./src/server/node-environment-extensions/web-crypto.tsx\",\"webpack://next/./src/server/require-hook.ts\",\"webpack://next/./src/server/app-render/staged-rendering.ts\",\"webpack://next/./src/server/node-environment-extensions/date.tsx\",\"webpack://next/./src/server/lib/trace/constants.ts\",\"webpack://next/./src/lib/picocolors.ts\",\"webpack://next/./src/server/lib/lru-cache.ts\",\"webpack://next/./src/server/lib/source-maps.ts\",\"webpack://next/./src/server/lib/parse-stack.ts\",\"webpack://next/./src/server/node-environment-extensions/error-inspect.tsx\",\"webpack://next/./src/server/dev/browser-logs/file-logger.ts\",\"webpack://next/./src/client/lib/console.ts\",\"webpack://next/./src/server/node-environment-extensions/console-file.tsx\",\"webpack://next/./src/server/node-environment-extensions/console-exit.tsx\",\"webpack://next/./src/shared/lib/invariant-error.ts\",\"webpa...\n\n/workspace/node_modules/next/dist/compiled/next-server/use-cache-probe-worker-turbo-experimental.runtime.dev.js.map:\n Line 1: {\"version\":3,\"file\":\"use-cache-probe-worker-turbo-experimental.runtime.dev.js\",\"sources\":[\"webpack://next/./dist/compiled/@edge-runtime/cookies/index.js\",\"webpack://next/./dist/compiled/cookie/index.js\",\"webpack://next/./dist/compiled/p-queue/index.js\",\"webpack://next/./dist/compiled/react-dom-experimental/cjs/react-dom.react-server.development.js\",\"webpack://next/./dist/compiled/react-dom-experimental/react-dom.react-server.js\",\"webpack://next/./dist/compiled/react-experimental/cjs/react.react-server.development.js\",\"webpack://next/./dist/compiled/react-experimental/react.react-server.js\",\"webpack://next/./dist/compiled/react-server-dom-turbopack-experimental/cjs/react-server-dom-turbopack-server.node.development.js\",\"webpack://next/./dist/compiled/react-server-dom-turbopack-experimental/server.node.js\",\"webpack://next/./src/server/node-environment-baseline.ts\",\"webpack://next/./src/shared/lib/modern-browserslist-target.js\",\"webpack://next/webpack/runtime/compat_get_default_export\",\"webpack://next/webpack/runtime/define_property_getters\",\"webpack://next/webpack/runtime/has_own_property\",\"webpack://next/webpack/runtime/make_namespace_object\",\"webpack://next/./src/server/patch-error-inspect.ts\",\"webpack://next/./src/server/node-environment-extensions/web-crypto.tsx\",\"webpack://next/./src/server/require-hook.ts\",\"webpack://next/./src/server/app-render/staged-rendering.ts\",\"webpack://next/./src/server/node-environment-extensions/date.tsx\",\"webpack://next/./src/server/lib/trace/constants.ts\",\"webpack://next/./src/lib/picocolors.ts\",\"webpack://next/./src/server/lib/lru-cache.ts\",\"webpack://next/./src/server/lib/source-maps.ts\",\"webpack://next/./src/server/lib/parse-stack.ts\",\"webpack://next/./src/server/node-environment-extensions/error-inspect.tsx\",\"webpack://next/./src/server/dev/browser-logs/file-logger.ts\",\"webpack://next/./src/client/lib/console.ts\",\"webpack://next/./src/server/node-environment-extensions/console-file.tsx\",\"webpack://next/./src/server/node-environme...\n\n/workspace/node_modules/next/dist/compiled/next-server/use-cache-probe-worker-experimental.runtime.dev.js.map:\n Line 1: {\"version\":3,\"file\":\"use-cache-probe-worker-experimental.runtime.dev.js\",\"sources\":[\"webpack://next/./dist/compiled/@edge-runtime/cookies/index.js\",\"webpack://next/./dist/compiled/cookie/index.js\",\"webpack://next/./dist/compiled/p-queue/index.js\",\"webpack://next/./dist/compiled/react-dom-experimental/cjs/react-dom.react-server.development.js\",\"webpack://next/./dist/compiled/react-dom-experimental/react-dom.react-server.js\",\"webpack://next/./dist/compiled/react-experimental/cjs/react.react-server.development.js\",\"webpack://next/./dist/compiled/react-experimental/react.react-server.js\",\"webpack://next/./dist/compiled/react-server-dom-webpack-experimental/cjs/react-server-dom-webpack-server.node.development.js\",\"webpack://next/./dist/compiled/react-server-dom-webpack-experimental/server.node.js\",\"webpack://next/./src/server/node-environment-baseline.ts\",\"webpack://next/./src/shared/lib/modern-browserslist-target.js\",\"webpack://next/webpack/runtime/compat_get_default_export\",\"webpack://next/webpack/runtime/define_property_getters\",\"webpack://next/webpack/runtime/ensure_chunk\",\"webpack://next/webpack/runtime/has_own_property\",\"webpack://next/webpack/runtime/make_namespace_object\",\"webpack://next/./src/server/patch-error-inspect.ts\",\"webpack://next/./src/server/node-environment-extensions/web-crypto.tsx\",\"webpack://next/./src/server/require-hook.ts\",\"webpack://next/./src/server/app-render/staged-rendering.ts\",\"webpack://next/./src/server/node-environment-extensions/date.tsx\",\"webpack://next/./src/server/lib/trace/constants.ts\",\"webpack://next/./src/lib/picocolors.ts\",\"webpack://next/./src/server/lib/lru-cache.ts\",\"webpack://next/./src/server/lib/source-maps.ts\",\"webpack://next/./src/server/lib/parse-stack.ts\",\"webpack://next/./src/server/node-environment-extensions/error-inspect.tsx\",\"webpack://next/./src/server/dev/browser-logs/file-logger.ts\",\"webpack://next/./src/client/lib/console.ts\",\"webpack://next/./src/server/node-environment-extensions/console-file.tsx\",\"webpack:...\n\n/workspace/node_modules/next/dist/server/web/spec-extension/unstable-cache.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../../../src/server/web/spec-extension/unstable-cache.ts\"],\"sourcesContent\":[\"import type { IncrementalCache } from '../../lib/incremental-cache'\\n\\nimport { CACHE_ONE_YEAR_SECONDS } from '../../../lib/constants'\\nimport { validateRevalidate, validateTags } from '../../lib/patch-fetch'\\nimport {\\n workAsyncStorage,\\n type WorkStore,\\n} from '../../app-render/work-async-storage.external'\\nimport {\\n getCacheSignal,\\n getDraftModeProviderForCacheScope,\\n workUnitAsyncStorage,\\n} from '../../app-render/work-unit-async-storage.external'\\nimport {\\n CachedRouteKind,\\n IncrementalCacheKind,\\n type CachedFetchData,\\n} from '../../response-cache'\\nimport type {\\n UnstableCacheStore,\\n WorkUnitStore,\\n} from '../../app-render/work-unit-async-storage.external'\\n\\ntype Callback = (...args: any[]) => Promise\\n\\nlet noStoreFetchIdx = 0\\n\\nasync function cacheNewResult(\\n result: T,\\n incrementalCache: IncrementalCache,\\n cacheKey: string,\\n tags: string[],\\n revalidate: number | false | undefined,\\n fetchIdx: number,\\n fetchUrl: string\\n): Promise {\\n await incrementalCache.set(\\n cacheKey,\\n {\\n kind: CachedRouteKind.FETCH,\\n data: {\\n headers: {},\\n // TODO: handle non-JSON values?\\n body: JSON.stringify(result),\\n status: 200,\\n url: '',\\n } satisfies CachedFetchData,\\n revalidate:\\n typeof revalidate !== 'number' ? CACHE_ONE_YEAR_SECONDS : revalidate,\\n },\\n { fetchCache: true, tags, fetchIdx, fetchUrl }\\n )\\n return\\n}\\n\\n/**\\n * This function allows you to cache the results of expensive operations, like database queries, and reuse them across multiple requests.\\n *\\n * Read more: [Next.js Docs: `unstable_cache`](https://nextjs.org/docs/app/api-reference/functions/unstable_cache)\\n */\\nexport function unstable_cache(\\n cb: T,\\n keyParts?: string[],\\n options: {\\n /**\\n * The revalidation interval in seconds....\n\n/workspace/node_modules/next/dist/esm/server/web/spec-extension/unstable-cache.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../../../../src/server/web/spec-extension/unstable-cache.ts\"],\"sourcesContent\":[\"import type { IncrementalCache } from '../../lib/incremental-cache'\\n\\nimport { CACHE_ONE_YEAR_SECONDS } from '../../../lib/constants'\\nimport { validateRevalidate, validateTags } from '../../lib/patch-fetch'\\nimport {\\n workAsyncStorage,\\n type WorkStore,\\n} from '../../app-render/work-async-storage.external'\\nimport {\\n getCacheSignal,\\n getDraftModeProviderForCacheScope,\\n workUnitAsyncStorage,\\n} from '../../app-render/work-unit-async-storage.external'\\nimport {\\n CachedRouteKind,\\n IncrementalCacheKind,\\n type CachedFetchData,\\n} from '../../response-cache'\\nimport type {\\n UnstableCacheStore,\\n WorkUnitStore,\\n} from '../../app-render/work-unit-async-storage.external'\\n\\ntype Callback = (...args: any[]) => Promise\\n\\nlet noStoreFetchIdx = 0\\n\\nasync function cacheNewResult(\\n result: T,\\n incrementalCache: IncrementalCache,\\n cacheKey: string,\\n tags: string[],\\n revalidate: number | false | undefined,\\n fetchIdx: number,\\n fetchUrl: string\\n): Promise {\\n await incrementalCache.set(\\n cacheKey,\\n {\\n kind: CachedRouteKind.FETCH,\\n data: {\\n headers: {},\\n // TODO: handle non-JSON values?\\n body: JSON.stringify(result),\\n status: 200,\\n url: '',\\n } satisfies CachedFetchData,\\n revalidate:\\n typeof revalidate !== 'number' ? CACHE_ONE_YEAR_SECONDS : revalidate,\\n },\\n { fetchCache: true, tags, fetchIdx, fetchUrl }\\n )\\n return\\n}\\n\\n/**\\n * This function allows you to cache the results of expensive operations, like database queries, and reuse them across multiple requests.\\n *\\n * Read more: [Next.js Docs: `unstable_cache`](https://nextjs.org/docs/app/api-reference/functions/unstable_cache)\\n */\\nexport function unstable_cache(\\n cb: T,\\n keyParts?: string[],\\n options: {\\n /**\\n * The revalidation interval in secon...\n\n/workspace/node_modules/next/dist/compiled/next-server/server.runtime.prod.js.map:\n Line 1: {\"version\":3,\"file\":\"server.runtime.prod.js\",\"sources\":[\"webpack://next/../../node_modules/.pnpm/react@19.3.0-canary-43bcbf80-20260603/node_modules/react/cjs/react.production.js\",\"webpack://next/../../node_modules/.pnpm/react@19.3.0-canary-43bcbf80-20260603/node_modules/react/index.js\",\"webpack://next/../next-env/dist/index.js\",\"webpack://next/./dist/compiled/@edge-runtime/cookies/index.js\",\"webpack://next/./dist/compiled/bytes/index.js\",\"webpack://next/./dist/compiled/ci-info/index.js\",\"webpack://next/./dist/compiled/cookie/index.js\",\"webpack://next/./dist/compiled/fresh/index.js\",\"webpack://next/./dist/compiled/p-queue/index.js\",\"webpack://next/./dist/compiled/path-to-regexp/index.js\",\"webpack://next/./src/lib/format-server-error.ts\",\"webpack://next/./src/server/node-environment-baseline.ts\",\"webpack://next/./src/server/node-polyfill-crypto.ts\",\"webpack://next/./src/shared/lib/isomorphic/path.js\",\"webpack://next/./src/shared/lib/modern-browserslist-target.js\",\"webpack://next/webpack/runtime/compat_get_default_export\",\"webpack://next/webpack/runtime/define_property_getters\",\"webpack://next/webpack/runtime/has_own_property\",\"webpack://next/webpack/runtime/make_namespace_object\",\"webpack://next/./src/server/patch-error-inspect.ts\",\"webpack://next/./src/server/node-environment-extensions/web-crypto.tsx\",\"webpack://next/./src/server/lib/streaming-metadata.ts\",\"webpack://next/./src/server/app-render/staged-rendering.ts\",\"webpack://next/./src/server/node-environment-extensions/date.tsx\",\"webpack://next/./src/server/lib/trace/constants.ts\",\"webpack://next/./src/client/components/redirect-status-code.ts\",\"webpack://next/./src/server/route-kind.ts\",\"webpack://next/./src/server/response-cache/types.ts\",\"webpack://next/./src/lib/picocolors.ts\",\"webpack://next/./src/server/lib/lru-cache.ts\",\"webpack://next/./src/server/lib/source-maps.ts\",\"webpack://next/./src/server/lib/parse-stack.ts\",\"webpack://next/./src/server/node-environment-extensions/error-inspect.tsx\",\"webpack://next...\n\n/workspace/node_modules/next/dist/server/web/spec-extension/revalidate.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../../../src/server/web/spec-extension/revalidate.ts\"],\"sourcesContent\":[\"import {\\n abortAndThrowOnSynchronousRequestDataAccess,\\n postponeWithTracking,\\n} from '../../app-render/dynamic-rendering'\\nimport { isDynamicRoute } from '../../../shared/lib/router/utils'\\nimport {\\n NEXT_CACHE_IMPLICIT_TAG_ID,\\n NEXT_CACHE_SOFT_TAG_MAX_LENGTH,\\n} from '../../../lib/constants'\\nimport { workAsyncStorage } from '../../app-render/work-async-storage.external'\\nimport { workUnitAsyncStorage } from '../../app-render/work-unit-async-storage.external'\\nimport { DynamicServerError } from '../../../client/components/hooks-server-context'\\nimport { InvariantError } from '../../../shared/lib/invariant-error'\\nimport {\\n ActionDidRevalidateDynamicOnly,\\n ActionDidRevalidateStaticAndDynamic as ActionDidRevalidate,\\n} from '../../../shared/lib/action-revalidation-kind'\\nimport { removeTrailingSlash } from '../../../shared/lib/router/utils/remove-trailing-slash'\\nimport { encodeCacheTag } from '../../lib/encode-cache-tag'\\n\\ntype CacheLifeConfig = {\\n expire?: number\\n}\\n\\n/**\\n * This function allows you to purge [cached data](https://nextjs.org/docs/app/building-your-application/caching) on-demand for a specific cache tag.\\n *\\n * The second argument specifies a [`cacheLife`](https://nextjs.org/docs/app/api-reference/functions/cacheLife#reference) profile\\n * (e.g. `\\\"max\\\"`), or a `{ expire }` object. For immediate expiration in Server Actions, use\\n * [`updateTag`](https://nextjs.org/docs/app/api-reference/functions/updateTag) instead.\\n *\\n * Read more: [Next.js Docs: `revalidateTag`](https://nextjs.org/docs/app/api-reference/functions/revalidateTag)\\n */\\nexport function revalidateTag(tag: string, profile: string | CacheLifeConfig) {\\n if (!profile) {\\n console.warn(\\n '\\\"revalidateTag\\\" without the second argument is now deprecated, add second argument of \\\"max\\\" or use \\\"updateTag\\\". See more info here: https://nextjs.org/docs/messages/...\n\n/workspace/node_modules/next/dist/server/request/root-params.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../../src/server/request/root-params.ts\"],\"sourcesContent\":[\"import { InvariantError } from '../../shared/lib/invariant-error'\\nimport {\\n postponeWithTracking,\\n throwToInterruptStaticGeneration,\\n} from '../app-render/dynamic-rendering'\\nimport {\\n workAsyncStorage,\\n type WorkStore,\\n} from '../app-render/work-async-storage.external'\\nimport {\\n workUnitAsyncStorage,\\n type PrerenderStoreLegacy,\\n type PrerenderStoreModernServer,\\n type PrerenderStorePPR,\\n} from '../app-render/work-unit-async-storage.external'\\nimport {\\n getRuntimeLinkDataStage,\\n getStaticLinkDataStage,\\n makeHangingPromise,\\n} from '../dynamic-rendering-utils'\\nimport type { ParamValue } from './params'\\nimport { describeStringPropertyAccess } from '../../shared/lib/utils/reflect-utils'\\nimport { actionAsyncStorage } from '../app-render/action-async-storage.external'\\nimport { accumulateRootVaryParam } from '../app-render/vary-params'\\nimport type {\\n RenderStage,\\n StagedRenderingController,\\n} from '../app-render/staged-rendering'\\n\\n/**\\n * Used for the compiler-generated `next/root-params` module.\\n * @internal\\n */\\nexport function getRootParam(paramName: string): Promise {\\n const apiName = `\\\\`import('next/root-params').${paramName}()\\\\``\\n\\n const workStore = workAsyncStorage.getStore()\\n if (!workStore) {\\n throw new InvariantError(`Missing workStore in ${apiName}`)\\n }\\n\\n const workUnitStore = workUnitAsyncStorage.getStore()\\n if (!workUnitStore) {\\n throw new Error(\\n `Route ${workStore.route} used ${apiName} outside of a Server Component. This is not allowed.`\\n )\\n }\\n\\n const actionStore = actionAsyncStorage.getStore()\\n if (actionStore) {\\n if (actionStore.isAppRoute) {\\n // TODO(root-params): add support for route handlers\\n throw new Error(\\n `Route ${workStore.route} used ${apiName} inside a Route Handler. Support for this API in Route Handlers is planned for a future version of ...\n\n/workspace/node_modules/next/dist/esm/server/request/root-params.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../../../src/server/request/root-params.ts\"],\"sourcesContent\":[\"import { InvariantError } from '../../shared/lib/invariant-error'\\nimport {\\n postponeWithTracking,\\n throwToInterruptStaticGeneration,\\n} from '../app-render/dynamic-rendering'\\nimport {\\n workAsyncStorage,\\n type WorkStore,\\n} from '../app-render/work-async-storage.external'\\nimport {\\n workUnitAsyncStorage,\\n type PrerenderStoreLegacy,\\n type PrerenderStoreModernServer,\\n type PrerenderStorePPR,\\n} from '../app-render/work-unit-async-storage.external'\\nimport {\\n getRuntimeLinkDataStage,\\n getStaticLinkDataStage,\\n makeHangingPromise,\\n} from '../dynamic-rendering-utils'\\nimport type { ParamValue } from './params'\\nimport { describeStringPropertyAccess } from '../../shared/lib/utils/reflect-utils'\\nimport { actionAsyncStorage } from '../app-render/action-async-storage.external'\\nimport { accumulateRootVaryParam } from '../app-render/vary-params'\\nimport type {\\n RenderStage,\\n StagedRenderingController,\\n} from '../app-render/staged-rendering'\\n\\n/**\\n * Used for the compiler-generated `next/root-params` module.\\n * @internal\\n */\\nexport function getRootParam(paramName: string): Promise {\\n const apiName = `\\\\`import('next/root-params').${paramName}()\\\\``\\n\\n const workStore = workAsyncStorage.getStore()\\n if (!workStore) {\\n throw new InvariantError(`Missing workStore in ${apiName}`)\\n }\\n\\n const workUnitStore = workUnitAsyncStorage.getStore()\\n if (!workUnitStore) {\\n throw new Error(\\n `Route ${workStore.route} used ${apiName} outside of a Server Component. This is not allowed.`\\n )\\n }\\n\\n const actionStore = actionAsyncStorage.getStore()\\n if (actionStore) {\\n if (actionStore.isAppRoute) {\\n // TODO(root-params): add support for route handlers\\n throw new Error(\\n `Route ${workStore.route} used ${apiName} inside a Route Handler. Support for this API in Route Handlers is planned for a future version ...\n\n/workspace/node_modules/next/dist/esm/server/web/spec-extension/revalidate.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../../../../src/server/web/spec-extension/revalidate.ts\"],\"sourcesContent\":[\"import {\\n abortAndThrowOnSynchronousRequestDataAccess,\\n postponeWithTracking,\\n} from '../../app-render/dynamic-rendering'\\nimport { isDynamicRoute } from '../../../shared/lib/router/utils'\\nimport {\\n NEXT_CACHE_IMPLICIT_TAG_ID,\\n NEXT_CACHE_SOFT_TAG_MAX_LENGTH,\\n} from '../../../lib/constants'\\nimport { workAsyncStorage } from '../../app-render/work-async-storage.external'\\nimport { workUnitAsyncStorage } from '../../app-render/work-unit-async-storage.external'\\nimport { DynamicServerError } from '../../../client/components/hooks-server-context'\\nimport { InvariantError } from '../../../shared/lib/invariant-error'\\nimport {\\n ActionDidRevalidateDynamicOnly,\\n ActionDidRevalidateStaticAndDynamic as ActionDidRevalidate,\\n} from '../../../shared/lib/action-revalidation-kind'\\nimport { removeTrailingSlash } from '../../../shared/lib/router/utils/remove-trailing-slash'\\nimport { encodeCacheTag } from '../../lib/encode-cache-tag'\\n\\ntype CacheLifeConfig = {\\n expire?: number\\n}\\n\\n/**\\n * This function allows you to purge [cached data](https://nextjs.org/docs/app/building-your-application/caching) on-demand for a specific cache tag.\\n *\\n * The second argument specifies a [`cacheLife`](https://nextjs.org/docs/app/api-reference/functions/cacheLife#reference) profile\\n * (e.g. `\\\"max\\\"`), or a `{ expire }` object. For immediate expiration in Server Actions, use\\n * [`updateTag`](https://nextjs.org/docs/app/api-reference/functions/updateTag) instead.\\n *\\n * Read more: [Next.js Docs: `revalidateTag`](https://nextjs.org/docs/app/api-reference/functions/revalidateTag)\\n */\\nexport function revalidateTag(tag: string, profile: string | CacheLifeConfig) {\\n if (!profile) {\\n console.warn(\\n '\\\"revalidateTag\\\" without the second argument is now deprecated, add second argument of \\\"max\\\" or use \\\"updateTag\\\". See more info here: https://nextjs.org/docs/messag...\n\n/workspace/node_modules/next/dist/server/lib/patch-fetch.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../../src/server/lib/patch-fetch.ts\"],\"sourcesContent\":[\"import type {\\n WorkAsyncStorage,\\n WorkStore,\\n} from '../app-render/work-async-storage.external'\\n\\nimport { AppRenderSpan, NextNodeServerSpan } from './trace/constants'\\nimport { getTracer, SpanKind } from './trace/tracer'\\nimport {\\n CACHE_ONE_YEAR_SECONDS,\\n INFINITE_CACHE,\\n NEXT_CACHE_TAG_MAX_ITEMS,\\n NEXT_CACHE_TAG_MAX_LENGTH,\\n} from '../../lib/constants'\\nimport { markCurrentScopeAsDynamic } from '../app-render/dynamic-rendering'\\nimport { makeHangingPromise } from '../dynamic-rendering-utils'\\nimport type { FetchMetric } from '../base-http'\\nimport { createDedupeFetch } from './dedupe-fetch'\\nimport {\\n getCacheSignal,\\n type RevalidateStore,\\n type WorkUnitAsyncStorage,\\n} from '../app-render/work-unit-async-storage.external'\\nimport {\\n CachedRouteKind,\\n IncrementalCacheKind,\\n type CachedFetchData,\\n type ServerComponentsHmrCache,\\n type SetIncrementalFetchCacheContext,\\n} from '../response-cache'\\nimport { cloneResponse } from './clone-response'\\nimport type { IncrementalCache } from './incremental-cache'\\nimport { RenderStage } from '../app-render/staged-rendering'\\nimport { encodeCacheTag } from './encode-cache-tag'\\n\\nconst isEdgeRuntime = process.env.NEXT_RUNTIME === 'edge'\\n\\ntype Fetcher = typeof fetch\\n\\ntype PatchedFetcher = Fetcher & {\\n readonly __nextPatched: true\\n readonly __nextGetStaticStore: () => WorkAsyncStorage\\n readonly _nextOriginalFetch: Fetcher\\n}\\n\\nexport const NEXT_PATCH_SYMBOL = Symbol.for('next-patch')\\n\\nfunction isFetchPatched() {\\n return (globalThis as Record)[NEXT_PATCH_SYMBOL] === true\\n}\\n\\nexport function validateRevalidate(\\n revalidateVal: unknown,\\n route: string\\n): undefined | number {\\n try {\\n let normalizedRevalidate: number | undefined = undefined\\n\\n if (revalidateVal === false) {\\n normalizedRevalidate = INFINITE_CACHE\\n } else if (\\n typeof revalidateVal === 'num...\n\n/workspace/node_modules/next/dist/esm/server/lib/patch-fetch.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../../../src/server/lib/patch-fetch.ts\"],\"sourcesContent\":[\"import type {\\n WorkAsyncStorage,\\n WorkStore,\\n} from '../app-render/work-async-storage.external'\\n\\nimport { AppRenderSpan, NextNodeServerSpan } from './trace/constants'\\nimport { getTracer, SpanKind } from './trace/tracer'\\nimport {\\n CACHE_ONE_YEAR_SECONDS,\\n INFINITE_CACHE,\\n NEXT_CACHE_TAG_MAX_ITEMS,\\n NEXT_CACHE_TAG_MAX_LENGTH,\\n} from '../../lib/constants'\\nimport { markCurrentScopeAsDynamic } from '../app-render/dynamic-rendering'\\nimport { makeHangingPromise } from '../dynamic-rendering-utils'\\nimport type { FetchMetric } from '../base-http'\\nimport { createDedupeFetch } from './dedupe-fetch'\\nimport {\\n getCacheSignal,\\n type RevalidateStore,\\n type WorkUnitAsyncStorage,\\n} from '../app-render/work-unit-async-storage.external'\\nimport {\\n CachedRouteKind,\\n IncrementalCacheKind,\\n type CachedFetchData,\\n type ServerComponentsHmrCache,\\n type SetIncrementalFetchCacheContext,\\n} from '../response-cache'\\nimport { cloneResponse } from './clone-response'\\nimport type { IncrementalCache } from './incremental-cache'\\nimport { RenderStage } from '../app-render/staged-rendering'\\nimport { encodeCacheTag } from './encode-cache-tag'\\n\\nconst isEdgeRuntime = process.env.NEXT_RUNTIME === 'edge'\\n\\ntype Fetcher = typeof fetch\\n\\ntype PatchedFetcher = Fetcher & {\\n readonly __nextPatched: true\\n readonly __nextGetStaticStore: () => WorkAsyncStorage\\n readonly _nextOriginalFetch: Fetcher\\n}\\n\\nexport const NEXT_PATCH_SYMBOL = Symbol.for('next-patch')\\n\\nfunction isFetchPatched() {\\n return (globalThis as Record)[NEXT_PATCH_SYMBOL] === true\\n}\\n\\nexport function validateRevalidate(\\n revalidateVal: unknown,\\n route: string\\n): undefined | number {\\n try {\\n let normalizedRevalidate: number | undefined = undefined\\n\\n if (revalidateVal === false) {\\n normalizedRevalidate = INFINITE_CACHE\\n } else if (\\n typeof revalidateVal === '...\n\n/workspace/node_modules/next/dist/server/route-modules/app-route/module.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../../../src/server/route-modules/app-route/module.ts\"],\"sourcesContent\":[\"import type { NextConfig } from '../../config-shared'\\nimport type { AppRouteRouteDefinition } from '../../route-definitions/app-route-route-definition'\\nimport type { AppSegmentConfig } from '../../../build/segment-config/app/app-segment-config'\\nimport type { NextRequest } from '../../web/spec-extension/request'\\nimport type { NextURL } from '../../web/next-url'\\nimport type { DeepReadonly } from '../../../shared/lib/deep-readonly'\\nimport type { WorkUnitStore } from '../../app-render/work-unit-async-storage.external'\\nimport type { __ApiPreviewProps } from '../../api-utils'\\n\\nimport {\\n RouteModule,\\n type RouteModuleHandleContext,\\n type RouteModuleOptions,\\n} from '../route-module'\\nimport { createRequestStoreForAPI } from '../../async-storage/request-store'\\nimport {\\n createWorkStore,\\n type WorkStoreContext,\\n} from '../../async-storage/work-store'\\nimport { type HTTP_METHOD, HTTP_METHODS, isHTTPMethod } from '../../web/http'\\nimport { getImplicitTags, type ImplicitTags } from '../../lib/implicit-tags'\\nimport { patchFetch } from '../../lib/patch-fetch'\\nimport { getTracer } from '../../lib/trace/tracer'\\nimport { AppRouteRouteHandlersSpan } from '../../lib/trace/constants'\\nimport * as Log from '../../../build/output/log'\\nimport { autoImplementMethods } from './helpers/auto-implement-methods'\\nimport {\\n appendMutableCookies,\\n type ReadonlyRequestCookies,\\n} from '../../web/spec-extension/adapters/request-cookies'\\nimport { HeadersAdapter } from '../../web/spec-extension/adapters/headers'\\nimport { RequestCookiesAdapter } from '../../web/spec-extension/adapters/request-cookies'\\nimport { parsedUrlQueryToParams } from './helpers/parsed-url-query-to-params'\\nimport {\\n Phase,\\n printDebugThrownValueForProspectiveRender,\\n} from '../../app-render/prospective-render-utils'\\n\\nimport * as serverHooks from '../../../client/components/hooks-server-con...\n\n/workspace/node_modules/next/dist/esm/server/route-modules/app-route/module.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../../../../src/server/route-modules/app-route/module.ts\"],\"sourcesContent\":[\"import type { NextConfig } from '../../config-shared'\\nimport type { AppRouteRouteDefinition } from '../../route-definitions/app-route-route-definition'\\nimport type { AppSegmentConfig } from '../../../build/segment-config/app/app-segment-config'\\nimport type { NextRequest } from '../../web/spec-extension/request'\\nimport type { NextURL } from '../../web/next-url'\\nimport type { DeepReadonly } from '../../../shared/lib/deep-readonly'\\nimport type { WorkUnitStore } from '../../app-render/work-unit-async-storage.external'\\nimport type { __ApiPreviewProps } from '../../api-utils'\\n\\nimport {\\n RouteModule,\\n type RouteModuleHandleContext,\\n type RouteModuleOptions,\\n} from '../route-module'\\nimport { createRequestStoreForAPI } from '../../async-storage/request-store'\\nimport {\\n createWorkStore,\\n type WorkStoreContext,\\n} from '../../async-storage/work-store'\\nimport { type HTTP_METHOD, HTTP_METHODS, isHTTPMethod } from '../../web/http'\\nimport { getImplicitTags, type ImplicitTags } from '../../lib/implicit-tags'\\nimport { patchFetch } from '../../lib/patch-fetch'\\nimport { getTracer } from '../../lib/trace/tracer'\\nimport { AppRouteRouteHandlersSpan } from '../../lib/trace/constants'\\nimport * as Log from '../../../build/output/log'\\nimport { autoImplementMethods } from './helpers/auto-implement-methods'\\nimport {\\n appendMutableCookies,\\n type ReadonlyRequestCookies,\\n} from '../../web/spec-extension/adapters/request-cookies'\\nimport { HeadersAdapter } from '../../web/spec-extension/adapters/headers'\\nimport { RequestCookiesAdapter } from '../../web/spec-extension/adapters/request-cookies'\\nimport { parsedUrlQueryToParams } from './helpers/parsed-url-query-to-params'\\nimport {\\n Phase,\\n printDebugThrownValueForProspectiveRender,\\n} from '../../app-render/prospective-render-utils'\\n\\nimport * as serverHooks from '../../../client/components/hooks-server-...\n\n/workspace/node_modules/next/dist/esm/build/index.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../../src/build/index.ts\"],\"sourcesContent\":[\"import type { PagesManifest } from './webpack/plugins/pages-manifest-plugin'\\nimport type {\\n ExportPathMap,\\n NextConfigComplete,\\n NextConfigRuntime,\\n} from '../server/config-shared'\\nimport type { MiddlewareManifest } from './webpack/plugins/middleware-plugin'\\nimport type { ActionManifest } from './webpack/plugins/flight-client-entry-plugin'\\nimport type { CacheControl, Revalidate } from '../server/lib/cache-control'\\nimport type { PrefetchHints } from '../shared/lib/app-router-types'\\n\\nimport '../lib/setup-exception-listeners'\\n\\nimport { loadEnvConfig, type LoadedEnvFiles } from '@next/env'\\nimport { bold, yellow } from '../lib/picocolors'\\nimport { makeRe } from 'next/dist/compiled/picomatch'\\nimport { existsSync, promises as fs } from 'fs'\\nimport os from 'os'\\nimport { getNextBuildDebuggerPortOffset, Worker } from '../lib/worker'\\nimport { defaultConfig, getNextConfigRuntime } from '../server/config-shared'\\nimport devalue from 'next/dist/compiled/devalue'\\nimport findUp from 'next/dist/compiled/find-up'\\nimport { nanoid } from 'next/dist/compiled/nanoid/index.cjs'\\nimport path from 'path'\\nimport { resolveCacheHandlerPathToFilesystem } from '../lib/format-dynamic-import-path'\\nimport {\\n STATIC_STATUS_PAGE_GET_INITIAL_PROPS_ERROR,\\n PUBLIC_DIR_MIDDLEWARE_CONFLICT,\\n MIDDLEWARE_FILENAME,\\n PROXY_FILENAME,\\n PAGES_DIR_ALIAS,\\n INSTRUMENTATION_HOOK_FILENAME,\\n RSC_SUFFIX,\\n PRERENDER_REVALIDATE_HEADER,\\n PRERENDER_REVALIDATE_ONLY_GENERATED_HEADER,\\n NEXT_CACHE_REVALIDATE_TAG_TOKEN_HEADER,\\n NEXT_CACHE_REVALIDATED_TAGS_HEADER,\\n MATCHED_PATH_HEADER,\\n type RSC_SEGMENTS_DIR_SUFFIX,\\n type RSC_SEGMENT_SUFFIX,\\n} from '../lib/constants'\\nimport { FileType, fileExists } from '../lib/file-exists'\\nimport { findPagesDir } from '../lib/find-pages-dir'\\nimport loadCustomRoutes, {\\n normalizeRouteRegex,\\n} from '../lib/load-custom-routes'\\nimport type {\\n CustomRoutes,\\n Hea...\n\n/workspace/node_modules/next/dist/build/index.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../src/build/index.ts\"],\"sourcesContent\":[\"import type { PagesManifest } from './webpack/plugins/pages-manifest-plugin'\\nimport type {\\n ExportPathMap,\\n NextConfigComplete,\\n NextConfigRuntime,\\n} from '../server/config-shared'\\nimport type { MiddlewareManifest } from './webpack/plugins/middleware-plugin'\\nimport type { ActionManifest } from './webpack/plugins/flight-client-entry-plugin'\\nimport type { CacheControl, Revalidate } from '../server/lib/cache-control'\\nimport type { PrefetchHints } from '../shared/lib/app-router-types'\\n\\nimport '../lib/setup-exception-listeners'\\n\\nimport { loadEnvConfig, type LoadedEnvFiles } from '@next/env'\\nimport { bold, yellow } from '../lib/picocolors'\\nimport { makeRe } from 'next/dist/compiled/picomatch'\\nimport { existsSync, promises as fs } from 'fs'\\nimport os from 'os'\\nimport { getNextBuildDebuggerPortOffset, Worker } from '../lib/worker'\\nimport { defaultConfig, getNextConfigRuntime } from '../server/config-shared'\\nimport devalue from 'next/dist/compiled/devalue'\\nimport findUp from 'next/dist/compiled/find-up'\\nimport { nanoid } from 'next/dist/compiled/nanoid/index.cjs'\\nimport path from 'path'\\nimport { resolveCacheHandlerPathToFilesystem } from '../lib/format-dynamic-import-path'\\nimport {\\n STATIC_STATUS_PAGE_GET_INITIAL_PROPS_ERROR,\\n PUBLIC_DIR_MIDDLEWARE_CONFLICT,\\n MIDDLEWARE_FILENAME,\\n PROXY_FILENAME,\\n PAGES_DIR_ALIAS,\\n INSTRUMENTATION_HOOK_FILENAME,\\n RSC_SUFFIX,\\n PRERENDER_REVALIDATE_HEADER,\\n PRERENDER_REVALIDATE_ONLY_GENERATED_HEADER,\\n NEXT_CACHE_REVALIDATE_TAG_TOKEN_HEADER,\\n NEXT_CACHE_REVALIDATED_TAGS_HEADER,\\n MATCHED_PATH_HEADER,\\n type RSC_SEGMENTS_DIR_SUFFIX,\\n type RSC_SEGMENT_SUFFIX,\\n} from '../lib/constants'\\nimport { FileType, fileExists } from '../lib/file-exists'\\nimport { findPagesDir } from '../lib/find-pages-dir'\\nimport loadCustomRoutes, {\\n normalizeRouteRegex,\\n} from '../lib/load-custom-routes'\\nimport type {\\n CustomRoutes,\\n Header...\n\n/workspace/node_modules/next/dist/server/request/headers.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../../src/server/request/headers.ts\"],\"sourcesContent\":[\"import {\\n HeadersAdapter,\\n type ReadonlyHeaders,\\n} from '../web/spec-extension/adapters/headers'\\nimport {\\n workAsyncStorage,\\n type WorkStore,\\n} from '../app-render/work-async-storage.external'\\nimport {\\n throwForMissingRequestStore,\\n workUnitAsyncStorage,\\n type PrerenderStoreModern,\\n type RequestStore,\\n isInEarlyRenderStage,\\n} from '../app-render/work-unit-async-storage.external'\\nimport {\\n postponeWithTracking,\\n throwToInterruptStaticGeneration,\\n trackDynamicDataInDynamicRender,\\n} from '../app-render/dynamic-rendering'\\nimport { StaticGenBailoutError } from '../../client/components/static-generation-bailout'\\nimport {\\n makeDevtoolsIOAwarePromise,\\n makeHangingPromise,\\n getSessionDataStage,\\n} from '../dynamic-rendering-utils'\\nimport { createDedupedByCallsiteServerErrorLoggerDev } from '../create-deduped-by-callsite-server-error-logger'\\nimport { isRequestAPICallableInsideAfter } from './utils'\\nimport { applyOwnerStack } from '../dynamic-rendering-utils'\\nimport { InvariantError } from '../../shared/lib/invariant-error'\\nimport { RenderStage } from '../app-render/staged-rendering'\\n\\n/**\\n * This function allows you to read the HTTP incoming request headers in\\n * [Server Components](https://nextjs.org/docs/app/building-your-application/rendering/server-components),\\n * [Server Actions](https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations),\\n * [Route Handlers](https://nextjs.org/docs/app/building-your-application/routing/route-handlers) and\\n * [Middleware](https://nextjs.org/docs/app/building-your-application/routing/middleware).\\n *\\n * Read more: [Next.js Docs: `headers`](https://nextjs.org/docs/app/api-reference/functions/headers)\\n */\\nexport function headers(): Promise {\\n const callingExpression = 'headers'\\n const workStore = workAsyncStorage.getStore()\\n const workUnitStore ...\n\n/workspace/node_modules/next/dist/esm/server/request/headers.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../../../src/server/request/headers.ts\"],\"sourcesContent\":[\"import {\\n HeadersAdapter,\\n type ReadonlyHeaders,\\n} from '../web/spec-extension/adapters/headers'\\nimport {\\n workAsyncStorage,\\n type WorkStore,\\n} from '../app-render/work-async-storage.external'\\nimport {\\n throwForMissingRequestStore,\\n workUnitAsyncStorage,\\n type PrerenderStoreModern,\\n type RequestStore,\\n isInEarlyRenderStage,\\n} from '../app-render/work-unit-async-storage.external'\\nimport {\\n postponeWithTracking,\\n throwToInterruptStaticGeneration,\\n trackDynamicDataInDynamicRender,\\n} from '../app-render/dynamic-rendering'\\nimport { StaticGenBailoutError } from '../../client/components/static-generation-bailout'\\nimport {\\n makeDevtoolsIOAwarePromise,\\n makeHangingPromise,\\n getSessionDataStage,\\n} from '../dynamic-rendering-utils'\\nimport { createDedupedByCallsiteServerErrorLoggerDev } from '../create-deduped-by-callsite-server-error-logger'\\nimport { isRequestAPICallableInsideAfter } from './utils'\\nimport { applyOwnerStack } from '../dynamic-rendering-utils'\\nimport { InvariantError } from '../../shared/lib/invariant-error'\\nimport { RenderStage } from '../app-render/staged-rendering'\\n\\n/**\\n * This function allows you to read the HTTP incoming request headers in\\n * [Server Components](https://nextjs.org/docs/app/building-your-application/rendering/server-components),\\n * [Server Actions](https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations),\\n * [Route Handlers](https://nextjs.org/docs/app/building-your-application/routing/route-handlers) and\\n * [Middleware](https://nextjs.org/docs/app/building-your-application/routing/middleware).\\n *\\n * Read more: [Next.js Docs: `headers`](https://nextjs.org/docs/app/api-reference/functions/headers)\\n */\\nexport function headers(): Promise {\\n const callingExpression = 'headers'\\n const workStore = workAsyncStorage.getStore()\\n const workUnitSto...\n\n/workspace/node_modules/next/dist/server/app-render/dynamic-rendering.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../../src/server/app-render/dynamic-rendering.ts\"],\"sourcesContent\":[\"/**\\n * The functions provided by this module are used to communicate certain properties\\n * about the currently running code so that Next.js can make decisions on how to handle\\n * the current execution in different rendering modes such as pre-rendering, resuming, and SSR.\\n *\\n * Today Next.js treats all code as potentially static. Certain APIs may only make sense when dynamically rendering.\\n * Traditionally this meant deopting the entire render to dynamic however with PPR we can now deopt parts\\n * of a React tree as dynamic while still keeping other parts static. There are really two different kinds of\\n * Dynamic indications.\\n *\\n * The first is simply an intention to be dynamic. unstable_noStore is an example of this where\\n * the currently executing code simply declares that the current scope is dynamic but if you use it\\n * inside unstable_cache it can still be cached. This type of indication can be removed if we ever\\n * make the default dynamic to begin with because the only way you would ever be static is inside\\n * a cache scope which this indication does not affect.\\n *\\n * The second is an indication that a dynamic data source was read. This is a stronger form of dynamic\\n * because it means that it is inappropriate to cache this at all. using a dynamic data source inside\\n * unstable_cache should error. If you want to use some dynamic data inside unstable_cache you should\\n * read that data outside the cache and pass it in as an argument to the cached function.\\n */\\n\\nimport type { WorkStore } from '../app-render/work-async-storage.external'\\nimport type {\\n WorkUnitStore,\\n PrerenderStoreLegacy,\\n PrerenderStoreModern,\\n ValidationStoreClient,\\n} from '../app-render/work-unit-async-storage.external'\\n\\n// Once postpone is in stable we should switch to importing the postpone export directly\\nimport React from 'react'\\n\\nimport { DynamicServerError ...\n\n/workspace/node_modules/next/dist/esm/server/app-render/dynamic-rendering.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../../../src/server/app-render/dynamic-rendering.ts\"],\"sourcesContent\":[\"/**\\n * The functions provided by this module are used to communicate certain properties\\n * about the currently running code so that Next.js can make decisions on how to handle\\n * the current execution in different rendering modes such as pre-rendering, resuming, and SSR.\\n *\\n * Today Next.js treats all code as potentially static. Certain APIs may only make sense when dynamically rendering.\\n * Traditionally this meant deopting the entire render to dynamic however with PPR we can now deopt parts\\n * of a React tree as dynamic while still keeping other parts static. There are really two different kinds of\\n * Dynamic indications.\\n *\\n * The first is simply an intention to be dynamic. unstable_noStore is an example of this where\\n * the currently executing code simply declares that the current scope is dynamic but if you use it\\n * inside unstable_cache it can still be cached. This type of indication can be removed if we ever\\n * make the default dynamic to begin with because the only way you would ever be static is inside\\n * a cache scope which this indication does not affect.\\n *\\n * The second is an indication that a dynamic data source was read. This is a stronger form of dynamic\\n * because it means that it is inappropriate to cache this at all. using a dynamic data source inside\\n * unstable_cache should error. If you want to use some dynamic data inside unstable_cache you should\\n * read that data outside the cache and pass it in as an argument to the cached function.\\n */\\n\\nimport type { WorkStore } from '../app-render/work-async-storage.external'\\nimport type {\\n WorkUnitStore,\\n PrerenderStoreLegacy,\\n PrerenderStoreModern,\\n ValidationStoreClient,\\n} from '../app-render/work-unit-async-storage.external'\\n\\n// Once postpone is in stable we should switch to importing the postpone export directly\\nimport React from 'react'\\n\\nimport { DynamicServerErr...\n\n/workspace/node_modules/next/dist/server/request/draft-mode.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../../src/server/request/draft-mode.ts\"],\"sourcesContent\":[\"import {\\n getDraftModeProviderForCacheScope,\\n throwForMissingRequestStore,\\n} from '../app-render/work-unit-async-storage.external'\\n\\nimport type { DraftModeProvider } from '../async-storage/draft-mode-provider'\\n\\nimport {\\n workAsyncStorage,\\n type WorkStore,\\n} from '../app-render/work-async-storage.external'\\nimport { workUnitAsyncStorage } from '../app-render/work-unit-async-storage.external'\\nimport {\\n abortAndThrowOnSynchronousRequestDataAccess,\\n postponeWithTracking,\\n trackDynamicDataInDynamicRender,\\n} from '../app-render/dynamic-rendering'\\nimport { createDedupedByCallsiteServerErrorLoggerDev } from '../create-deduped-by-callsite-server-error-logger'\\nimport { StaticGenBailoutError } from '../../client/components/static-generation-bailout'\\nimport { DynamicServerError } from '../../client/components/hooks-server-context'\\nimport { InvariantError } from '../../shared/lib/invariant-error'\\nimport { ReflectAdapter } from '../web/spec-extension/adapters/reflect'\\nimport {\\n applyOwnerStack,\\n getSessionDataStage,\\n} from '../dynamic-rendering-utils'\\n\\nexport function draftMode(): Promise {\\n const callingExpression = 'draftMode'\\n const workStore = workAsyncStorage.getStore()\\n const workUnitStore = workUnitAsyncStorage.getStore()\\n\\n if (!workStore || !workUnitStore) {\\n throwForMissingRequestStore(callingExpression)\\n }\\n\\n switch (workUnitStore.type) {\\n case 'prerender-runtime': {\\n // TODO(runtime-ppr): does it make sense to delay this? normally it's always microtasky\\n const { stagedRendering } = workUnitStore\\n if (stagedRendering) {\\n return stagedRendering.delayUntilStage(\\n getSessionDataStage(stagedRendering),\\n 'draftMode',\\n new DraftMode(workUnitStore.draftMode)\\n )\\n } else {\\n return createOrGetCachedDraftMode(workUnitStore.draftMode, workStore)\\n ...\n\n/workspace/node_modules/next/dist/esm/server/request/draft-mode.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../../../src/server/request/draft-mode.ts\"],\"sourcesContent\":[\"import {\\n getDraftModeProviderForCacheScope,\\n throwForMissingRequestStore,\\n} from '../app-render/work-unit-async-storage.external'\\n\\nimport type { DraftModeProvider } from '../async-storage/draft-mode-provider'\\n\\nimport {\\n workAsyncStorage,\\n type WorkStore,\\n} from '../app-render/work-async-storage.external'\\nimport { workUnitAsyncStorage } from '../app-render/work-unit-async-storage.external'\\nimport {\\n abortAndThrowOnSynchronousRequestDataAccess,\\n postponeWithTracking,\\n trackDynamicDataInDynamicRender,\\n} from '../app-render/dynamic-rendering'\\nimport { createDedupedByCallsiteServerErrorLoggerDev } from '../create-deduped-by-callsite-server-error-logger'\\nimport { StaticGenBailoutError } from '../../client/components/static-generation-bailout'\\nimport { DynamicServerError } from '../../client/components/hooks-server-context'\\nimport { InvariantError } from '../../shared/lib/invariant-error'\\nimport { ReflectAdapter } from '../web/spec-extension/adapters/reflect'\\nimport {\\n applyOwnerStack,\\n getSessionDataStage,\\n} from '../dynamic-rendering-utils'\\n\\nexport function draftMode(): Promise {\\n const callingExpression = 'draftMode'\\n const workStore = workAsyncStorage.getStore()\\n const workUnitStore = workUnitAsyncStorage.getStore()\\n\\n if (!workStore || !workUnitStore) {\\n throwForMissingRequestStore(callingExpression)\\n }\\n\\n switch (workUnitStore.type) {\\n case 'prerender-runtime': {\\n // TODO(runtime-ppr): does it make sense to delay this? normally it's always microtasky\\n const { stagedRendering } = workUnitStore\\n if (stagedRendering) {\\n return stagedRendering.delayUntilStage(\\n getSessionDataStage(stagedRendering),\\n 'draftMode',\\n new DraftMode(workUnitStore.draftMode)\\n )\\n } else {\\n return createOrGetCachedDraftMode(workUnitStore.draftMode, workStore)\\n ...\n\n/workspace/node_modules/next/dist/server/request/cookies.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../../src/server/request/cookies.ts\"],\"sourcesContent\":[\"import {\\n type ReadonlyRequestCookies,\\n areCookiesMutableInCurrentPhase,\\n RequestCookiesAdapter,\\n} from '../web/spec-extension/adapters/request-cookies'\\nimport { RequestCookies } from '../web/spec-extension/cookies'\\nimport {\\n workAsyncStorage,\\n type WorkStore,\\n} from '../app-render/work-async-storage.external'\\nimport {\\n throwForMissingRequestStore,\\n workUnitAsyncStorage,\\n type PrerenderStoreModern,\\n type RequestStore,\\n isInEarlyRenderStage,\\n} from '../app-render/work-unit-async-storage.external'\\nimport {\\n postponeWithTracking,\\n throwToInterruptStaticGeneration,\\n trackDynamicDataInDynamicRender,\\n} from '../app-render/dynamic-rendering'\\nimport { StaticGenBailoutError } from '../../client/components/static-generation-bailout'\\nimport {\\n makeDevtoolsIOAwarePromise,\\n makeHangingPromise,\\n getSessionDataStage,\\n} from '../dynamic-rendering-utils'\\nimport { createDedupedByCallsiteServerErrorLoggerDev } from '../create-deduped-by-callsite-server-error-logger'\\nimport { isRequestAPICallableInsideAfter } from './utils'\\nimport { applyOwnerStack } from '../dynamic-rendering-utils'\\nimport { InvariantError } from '../../shared/lib/invariant-error'\\nimport { RenderStage } from '../app-render/staged-rendering'\\n\\nexport function cookies(): Promise {\\n const callingExpression = 'cookies'\\n const workStore = workAsyncStorage.getStore()\\n const workUnitStore = workUnitAsyncStorage.getStore()\\n\\n if (workStore) {\\n if (\\n workUnitStore &&\\n workUnitStore.phase === 'after' &&\\n !isRequestAPICallableInsideAfter()\\n ) {\\n throw new Error(\\n // TODO(after): clarify that this only applies to pages?\\n `Route ${workStore.route} used \\\\`cookies()\\\\` inside \\\\`after()\\\\`. This is not supported. If you need this data inside an \\\\`after()\\\\` callback, use \\\\`cookies()\\\\` outside of the callback. See more ...\n\n/workspace/node_modules/next/dist/esm/server/request/cookies.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../../../src/server/request/cookies.ts\"],\"sourcesContent\":[\"import {\\n type ReadonlyRequestCookies,\\n areCookiesMutableInCurrentPhase,\\n RequestCookiesAdapter,\\n} from '../web/spec-extension/adapters/request-cookies'\\nimport { RequestCookies } from '../web/spec-extension/cookies'\\nimport {\\n workAsyncStorage,\\n type WorkStore,\\n} from '../app-render/work-async-storage.external'\\nimport {\\n throwForMissingRequestStore,\\n workUnitAsyncStorage,\\n type PrerenderStoreModern,\\n type RequestStore,\\n isInEarlyRenderStage,\\n} from '../app-render/work-unit-async-storage.external'\\nimport {\\n postponeWithTracking,\\n throwToInterruptStaticGeneration,\\n trackDynamicDataInDynamicRender,\\n} from '../app-render/dynamic-rendering'\\nimport { StaticGenBailoutError } from '../../client/components/static-generation-bailout'\\nimport {\\n makeDevtoolsIOAwarePromise,\\n makeHangingPromise,\\n getSessionDataStage,\\n} from '../dynamic-rendering-utils'\\nimport { createDedupedByCallsiteServerErrorLoggerDev } from '../create-deduped-by-callsite-server-error-logger'\\nimport { isRequestAPICallableInsideAfter } from './utils'\\nimport { applyOwnerStack } from '../dynamic-rendering-utils'\\nimport { InvariantError } from '../../shared/lib/invariant-error'\\nimport { RenderStage } from '../app-render/staged-rendering'\\n\\nexport function cookies(): Promise {\\n const callingExpression = 'cookies'\\n const workStore = workAsyncStorage.getStore()\\n const workUnitStore = workUnitAsyncStorage.getStore()\\n\\n if (workStore) {\\n if (\\n workUnitStore &&\\n workUnitStore.phase === 'after' &&\\n !isRequestAPICallableInsideAfter()\\n ) {\\n throw new Error(\\n // TODO(after): clarify that this only applies to pages?\\n `Route ${workStore.route} used \\\\`cookies()\\\\` inside \\\\`after()\\\\`. This is not supported. If you need this data inside an \\\\`after()\\\\` callback, use \\\\`cookies()\\\\` outside of the callback. See mo...\n\n/workspace/node_modules/next/dist/server/request/connection.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../../src/server/request/connection.ts\"],\"sourcesContent\":[\"import { workAsyncStorage } from '../app-render/work-async-storage.external'\\nimport {\\n throwForMissingRequestStore,\\n workUnitAsyncStorage,\\n} from '../app-render/work-unit-async-storage.external'\\nimport {\\n postponeWithTracking,\\n throwToInterruptStaticGeneration,\\n trackDynamicDataInDynamicRender,\\n} from '../app-render/dynamic-rendering'\\nimport { StaticGenBailoutError } from '../../client/components/static-generation-bailout'\\nimport {\\n makeHangingPromise,\\n makeDevtoolsIOAwarePromise,\\n} from '../dynamic-rendering-utils'\\nimport { isRequestAPICallableInsideAfter } from './utils'\\nimport { applyOwnerStack } from '../dynamic-rendering-utils'\\nimport { RenderStage } from '../app-render/staged-rendering'\\nimport { InvariantError } from '../../shared/lib/invariant-error'\\n\\n/**\\n * This function allows you to indicate that you require an actual user Request before continuing.\\n *\\n * During prerendering it will never resolve and during rendering it resolves immediately.\\n */\\nexport function connection(): Promise {\\n const callingExpression = 'connection'\\n const workStore = workAsyncStorage.getStore()\\n const workUnitStore = workUnitAsyncStorage.getStore()\\n\\n if (workStore) {\\n if (\\n workUnitStore &&\\n workUnitStore.phase === 'after' &&\\n !isRequestAPICallableInsideAfter()\\n ) {\\n throw new Error(\\n `Route ${workStore.route} used \\\\`connection()\\\\` inside \\\\`after()\\\\`. The \\\\`connection()\\\\` function is used to indicate the subsequent code must only run when there is an actual Request, but \\\\`after()\\\\` executes after the request, so this function is not allowed in this scope. See more info here: https://nextjs.org/docs/app/api-reference/functions/after`\\n )\\n }\\n\\n if (workStore.forceStatic) {\\n // When using forceStatic, we override all other logic and always just\\n // return a resolving promise with...\n\n/workspace/node_modules/next/dist/esm/server/request/connection.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../../../src/server/request/connection.ts\"],\"sourcesContent\":[\"import { workAsyncStorage } from '../app-render/work-async-storage.external'\\nimport {\\n throwForMissingRequestStore,\\n workUnitAsyncStorage,\\n} from '../app-render/work-unit-async-storage.external'\\nimport {\\n postponeWithTracking,\\n throwToInterruptStaticGeneration,\\n trackDynamicDataInDynamicRender,\\n} from '../app-render/dynamic-rendering'\\nimport { StaticGenBailoutError } from '../../client/components/static-generation-bailout'\\nimport {\\n makeHangingPromise,\\n makeDevtoolsIOAwarePromise,\\n} from '../dynamic-rendering-utils'\\nimport { isRequestAPICallableInsideAfter } from './utils'\\nimport { applyOwnerStack } from '../dynamic-rendering-utils'\\nimport { RenderStage } from '../app-render/staged-rendering'\\nimport { InvariantError } from '../../shared/lib/invariant-error'\\n\\n/**\\n * This function allows you to indicate that you require an actual user Request before continuing.\\n *\\n * During prerendering it will never resolve and during rendering it resolves immediately.\\n */\\nexport function connection(): Promise {\\n const callingExpression = 'connection'\\n const workStore = workAsyncStorage.getStore()\\n const workUnitStore = workUnitAsyncStorage.getStore()\\n\\n if (workStore) {\\n if (\\n workUnitStore &&\\n workUnitStore.phase === 'after' &&\\n !isRequestAPICallableInsideAfter()\\n ) {\\n throw new Error(\\n `Route ${workStore.route} used \\\\`connection()\\\\` inside \\\\`after()\\\\`. The \\\\`connection()\\\\` function is used to indicate the subsequent code must only run when there is an actual Request, but \\\\`after()\\\\` executes after the request, so this function is not allowed in this scope. See more info here: https://nextjs.org/docs/app/api-reference/functions/after`\\n )\\n }\\n\\n if (workStore.forceStatic) {\\n // When using forceStatic, we override all other logic and always just\\n // return a resolving promise w...\n\n/workspace/node_modules/next/dist/server/lib/router-utils/cache-life-type-utils.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../../../src/server/lib/router-utils/cache-life-type-utils.ts\"],\"sourcesContent\":[\"import type { CacheLife } from '../../use-cache/cache-life'\\nimport fs from 'fs'\\nimport path from 'path'\\n\\nconst MINUTE_IN_SECONDS = 60\\nconst HOUR_IN_SECONDS = MINUTE_IN_SECONDS * 60 // nevermind leap seconds\\nconst DAY_IN_SECONDS = HOUR_IN_SECONDS * 24\\nconst WEEK_IN_SECONDS = DAY_IN_SECONDS * 7\\n// Nevermind leap years, or you know, July\\nconst MONTH_30_DAYS_IN_SECONDS = DAY_IN_SECONDS * 30\\n\\nfunction formatTimespan(seconds: number): string {\\n if (seconds > 0) {\\n if (seconds === MONTH_30_DAYS_IN_SECONDS) {\\n return '1 month'\\n }\\n if (seconds === WEEK_IN_SECONDS) {\\n return '1 week'\\n }\\n if (seconds === DAY_IN_SECONDS) {\\n return '1 day'\\n }\\n if (seconds === HOUR_IN_SECONDS) {\\n return '1 hour'\\n }\\n if (seconds === MINUTE_IN_SECONDS) {\\n return '1 minute'\\n }\\n if (seconds % MONTH_30_DAYS_IN_SECONDS === 0) {\\n return seconds / MONTH_30_DAYS_IN_SECONDS + ' months'\\n }\\n if (seconds % 18144000 === 0) {\\n return seconds / 18144000 + ' months'\\n }\\n if (seconds % WEEK_IN_SECONDS === 0) {\\n return seconds / WEEK_IN_SECONDS + ' weeks'\\n }\\n if (seconds % DAY_IN_SECONDS === 0) {\\n return seconds / DAY_IN_SECONDS + ' days'\\n }\\n if (seconds % HOUR_IN_SECONDS === 0) {\\n return seconds / HOUR_IN_SECONDS + ' hours'\\n }\\n if (seconds % MINUTE_IN_SECONDS === 0) {\\n return seconds / MINUTE_IN_SECONDS + ' minutes'\\n }\\n }\\n return seconds + ' seconds'\\n}\\n\\nfunction formatTimespanWithSeconds(seconds: undefined | number): string {\\n if (seconds === undefined) {\\n return 'default'\\n }\\n if (seconds >= 0xfffffffe) {\\n return 'never'\\n }\\n const text = seconds + ' seconds'\\n const descriptive = formatTimespan(seconds)\\n if (descriptive === text) {\\n return text\\n }\\n return text + ' (' + descriptive + ')'\\n}\\n\\n/**\\n * Genera...\n\n/workspace/node_modules/next/dist/esm/server/lib/router-utils/cache-life-type-utils.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../../../../src/server/lib/router-utils/cache-life-type-utils.ts\"],\"sourcesContent\":[\"import type { CacheLife } from '../../use-cache/cache-life'\\nimport fs from 'fs'\\nimport path from 'path'\\n\\nconst MINUTE_IN_SECONDS = 60\\nconst HOUR_IN_SECONDS = MINUTE_IN_SECONDS * 60 // nevermind leap seconds\\nconst DAY_IN_SECONDS = HOUR_IN_SECONDS * 24\\nconst WEEK_IN_SECONDS = DAY_IN_SECONDS * 7\\n// Nevermind leap years, or you know, July\\nconst MONTH_30_DAYS_IN_SECONDS = DAY_IN_SECONDS * 30\\n\\nfunction formatTimespan(seconds: number): string {\\n if (seconds > 0) {\\n if (seconds === MONTH_30_DAYS_IN_SECONDS) {\\n return '1 month'\\n }\\n if (seconds === WEEK_IN_SECONDS) {\\n return '1 week'\\n }\\n if (seconds === DAY_IN_SECONDS) {\\n return '1 day'\\n }\\n if (seconds === HOUR_IN_SECONDS) {\\n return '1 hour'\\n }\\n if (seconds === MINUTE_IN_SECONDS) {\\n return '1 minute'\\n }\\n if (seconds % MONTH_30_DAYS_IN_SECONDS === 0) {\\n return seconds / MONTH_30_DAYS_IN_SECONDS + ' months'\\n }\\n if (seconds % 18144000 === 0) {\\n return seconds / 18144000 + ' months'\\n }\\n if (seconds % WEEK_IN_SECONDS === 0) {\\n return seconds / WEEK_IN_SECONDS + ' weeks'\\n }\\n if (seconds % DAY_IN_SECONDS === 0) {\\n return seconds / DAY_IN_SECONDS + ' days'\\n }\\n if (seconds % HOUR_IN_SECONDS === 0) {\\n return seconds / HOUR_IN_SECONDS + ' hours'\\n }\\n if (seconds % MINUTE_IN_SECONDS === 0) {\\n return seconds / MINUTE_IN_SECONDS + ' minutes'\\n }\\n }\\n return seconds + ' seconds'\\n}\\n\\nfunction formatTimespanWithSeconds(seconds: undefined | number): string {\\n if (seconds === undefined) {\\n return 'default'\\n }\\n if (seconds >= 0xfffffffe) {\\n return 'never'\\n }\\n const text = seconds + ' seconds'\\n const descriptive = formatTimespan(seconds)\\n if (descriptive === text) {\\n return text\\n }\\n return text + ' (' + descriptive + ')'\\n}\\n\\n/**\\n * Gen...\n\n/workspace/node_modules/next/dist/server/base-server.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../src/server/base-server.ts\"],\"sourcesContent\":[\"import type { __ApiPreviewProps } from './api-utils'\\nimport type {\\n GenericComponentMod,\\n LoadComponentsReturnType,\\n} from './load-components'\\nimport type { MiddlewareRouteMatch } from '../shared/lib/router/utils/middleware-route-matcher'\\nimport type { Params } from './request/params'\\nimport type { NextConfig, NextConfigRuntime } from './config-shared'\\nimport { parseMaxPostponedStateSize } from './config-shared'\\nimport type {\\n NextParsedUrlQuery,\\n NextUrlWithParsedQuery,\\n RequestMeta,\\n} from './request-meta'\\nimport type { ParsedUrlQuery } from 'querystring'\\nimport type { RenderOptsPartial as PagesRenderOptsPartial } from './render'\\nimport type {\\n RenderOptsPartial as AppRenderOptsPartial,\\n ServerOnInstrumentationRequestError,\\n} from './app-render/types'\\nimport type { ServerComponentsHmrCache } from './response-cache'\\nimport {\\n NormalizeError,\\n DecodeError,\\n normalizeRepeatedSlashes,\\n MissingStaticPage,\\n} from '../shared/lib/utils'\\nimport type { PagesManifest } from '../build/webpack/plugins/pages-manifest-plugin'\\nimport type { BaseNextRequest, BaseNextResponse } from './base-http'\\nimport type {\\n ManifestRewriteRoute,\\n ManifestRoute,\\n PrerenderManifest,\\n} from '../build'\\nimport type { ClientReferenceManifest } from '../build/webpack/plugins/flight-manifest-plugin'\\nimport type { NextFontManifest } from '../build/webpack/plugins/next-font-manifest-plugin'\\nimport type { PagesAPIRouteMatch } from './route-matches/pages-api-route-match'\\nimport type {\\n Server as HTTPServer,\\n IncomingMessage,\\n ServerResponse as HTTPServerResponse,\\n} from 'http'\\nimport type { ProxyMatcher } from '../build/analysis/get-page-static-info'\\nimport type { TLSSocket } from 'tls'\\nimport type { PathnameNormalizer } from './normalizers/request/pathname-normalizer'\\nimport type { InstrumentationModule } from './instrumentation/types'\\n\\nimport * as path from 'path'\\...\n\n/workspace/node_modules/next/dist/esm/server/base-server.js.map:\n Line 1: {\"version\":3,\"sources\":[\"../../../src/server/base-server.ts\"],\"sourcesContent\":[\"import type { __ApiPreviewProps } from './api-utils'\\nimport type {\\n GenericComponentMod,\\n LoadComponentsReturnType,\\n} from './load-components'\\nimport type { MiddlewareRouteMatch } from '../shared/lib/router/utils/middleware-route-matcher'\\nimport type { Params } from './request/params'\\nimport type { NextConfig, NextConfigRuntime } from './config-shared'\\nimport { parseMaxPostponedStateSize } from './config-shared'\\nimport type {\\n NextParsedUrlQuery,\\n NextUrlWithParsedQuery,\\n RequestMeta,\\n} from './request-meta'\\nimport type { ParsedUrlQuery } from 'querystring'\\nimport type { RenderOptsPartial as PagesRenderOptsPartial } from './render'\\nimport type {\\n RenderOptsPartial as AppRenderOptsPartial,\\n ServerOnInstrumentationRequestError,\\n} from './app-render/types'\\nimport type { ServerComponentsHmrCache } from './response-cache'\\nimport {\\n NormalizeError,\\n DecodeError,\\n normalizeRepeatedSlashes,\\n MissingStaticPage,\\n} from '../shared/lib/utils'\\nimport type { PagesManifest } from '../build/webpack/plugins/pages-manifest-plugin'\\nimport type { BaseNextRequest, BaseNextResponse } from './base-http'\\nimport type {\\n ManifestRewriteRoute,\\n ManifestRoute,\\n PrerenderManifest,\\n} from '../build'\\nimport type { ClientReferenceManifest } from '../build/webpack/plugins/flight-manifest-plugin'\\nimport type { NextFontManifest } from '../build/webpack/plugins/next-font-manifest-plugin'\\nimport type { PagesAPIRouteMatch } from './route-matches/pages-api-route-match'\\nimport type {\\n Server as HTTPServer,\\n IncomingMessage,\\n ServerResponse as HTTPServerResponse,\\n} from 'http'\\nimport type { ProxyMatcher } from '../build/analysis/get-page-static-info'\\nimport type { TLSSocket } from 'tls'\\nimport type { PathnameNormalizer } from './normalizers/request/pathname-normalizer'\\nimport type { InstrumentationModule } from './instrumentation/types'\\n\\nimport * as path from 'pat...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-route.runtime.prod.js.map:\n Line 1: {\"version\":3,\"file\":\"app-route.runtime.prod.js\",\"sources\":[\"webpack://next/webpack/runtime/create_fake_namespace_object\",\"webpack://next/./dist/compiled/@edge-runtime/cookies/index.js\",\"webpack://next/./dist/compiled/cookie/index.js\",\"webpack://next/./dist/compiled/p-queue/index.js\",\"webpack://next/./dist/compiled/path-to-regexp/index.js\",\"webpack://next/./dist/compiled/react/cjs/react.production.js\",\"webpack://next/./dist/compiled/react/index.js\",\"webpack://next/./dist/compiled/string-hash/index.js\",\"webpack://next/./src/lib/constants.ts\",\"webpack://next/./src/lib/format-dynamic-import-path.ts\",\"webpack://next/./src/server/api-utils/index.ts\",\"webpack://next/./src/server/api-utils/node/try-get-preview-data.ts\",\"webpack://next/./src/server/app-render/instant-validation/instant-samples.ts\",\"webpack://next/./src/server/app-render/instant-validation/instant-validation-error.ts\",\"webpack://next/./src/server/crypto-utils.ts\",\"webpack://next/./src/server/lib/node-fs-methods.ts\",\"webpack://next/./src/server/lib/router-utils/is-postpone.ts\",\"webpack://next/./src/server/lib/trace/constants.ts\",\"webpack://next/./src/server/node-environment-extensions/process-error-handlers.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/headers.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/reflect.ts\",\"webpack://next/./src/server/web/spec-extension/adapters/request-cookies.ts\",\"webpack://next/./src/shared/lib/action-revalidation-kind.ts\",\"webpack://next/./src/shared/lib/invariant-error.ts\",\"webpack://next/./src/shared/lib/isomorphic/path.js\",\"webpack://next/./src/shared/lib/modern-browserslist-target.js\",\"webpack://next/./src/shared/lib/page-path/ensure-leading-slash.ts\",\"webpack://next/./src/shared/lib/router/utils/app-paths.ts\",\"webpack://next/./src/shared/lib/router/utils/get-segment-param.tsx\",\"webpack://next/./src/shared/lib/router/utils/interception-routes.ts\",\"webpack://next/./src/shared/lib/router/utils/parse-relative-url.ts\",\"webpack://next/./src/shared/li...\n\n(Results are truncated. Consider using a more specific path or pattern.)","title":"unstable_cache","metadata":{"matches":100,"truncated":true},"time":{"start":1781390577937,"end":1781390578545}}}}
+{"type":"step_finish","timestamp":1781390578563,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec3271374001ahN3oIPfyAhuAr","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec326d872001cmywiKAvuKVi17","type":"step-finish","reason":"tool-calls","snapshot":"a73cc177aa6be3b38387792c45a1506702be7a41","cost":0.01321271,"tokens":{"input":2041,"output":709,"reasoning":0,"cache":{"read":52736,"write":0}}}}
+{"type":"step_start","timestamp":1781390585894,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec327301d001AGs5C7AwqiWrmI","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec327139b0013rIYYGNanGiVB8","type":"step-start","snapshot":"a73cc177aa6be3b38387792c45a1506702be7a41"}}
+{"type":"tool_use","timestamp":1781390597658,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec3275d9e001AEVaxkoKrIyous","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec327139b0013rIYYGNanGiVB8","type":"tool","callID":"grep_17","tool":"grep","state":{"status":"completed","input":{"path":"/workspace/node_modules/next/dist/server/lib","pattern":"cacheLifeProfiles"},"output":"No files found","title":"cacheLifeProfiles","metadata":{"matches":0,"truncated":false},"time":{"start":1781390597651,"end":1781390597656}}}}
+{"type":"step_finish","timestamp":1781390597662,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec3275e19001HgvdvqE1G987jn","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec327139b0013rIYYGNanGiVB8","type":"step-finish","reason":"tool-calls","snapshot":"a73cc177aa6be3b38387792c45a1506702be7a41","cost":0.03117248,"tokens":{"input":21040,"output":615,"reasoning":0,"cache":{"read":54528,"write":0}}}}
+{"type":"step_start","timestamp":1781390600436,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec32768ee0014GLYsHGel7immh","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec3275e3c001uuR7Vr8VIrdOeX","type":"step-start","snapshot":"a73cc177aa6be3b38387792c45a1506702be7a41"}}
+{"type":"tool_use","timestamp":1781390601279,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec3276a56001k2VjwnpKVs4lKF","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec3275e3c001uuR7Vr8VIrdOeX","type":"tool","callID":"grep_18","tool":"grep","state":{"status":"completed","input":{"path":"/workspace/node_modules/next/dist","pattern":"max.*expire|cacheLife.*max","include":"*.js"},"output":"Found 100 matches\n/workspace/node_modules/next/dist/compiled/next-server/use-cache-probe-worker.runtime.dev.js:\n Line 1: (()=>{var __webpack_modules__={\"next/dist/compiled/ws\"(module1){\"use strict\";module1.exports=require(\"next/dist/compiled/ws\")},async_hooks(module1){\"use strict\";module1.exports=require(\"async_hooks\")},crypto(module1){\"use strict\";module1.exports=require(\"crypto\")},module(module1){\"use strict\";module1.exports=require(\"module\")},\"node:crypto\"(module1){\"use strict\";module1.exports=require(\"node:crypto\")},path(module1){\"use strict\";module1.exports=require(\"path\")},stream(module1){\"use strict\";module1.exports=require(\"stream\")},util(module1){\"use strict\";module1.exports=require(\"util\")},\"(react-server)/./dist/compiled/@edge-runtime/cookies/index.js\"(module1){\"use strict\";var __defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropNames=Object.getOwnPropertyNames,__hasOwnProp=Object.prototype.hasOwnProperty,src_exports={},all={RequestCookies:()=>RequestCookies,ResponseCookies:()=>ResponseCookies,parseCookie:()=>parseCookie,parseSetCookie:()=>parseSetCookie,stringifyCookie:()=>stringifyCookie};for(var name in all)__defProp(src_exports,name,{get:all[name],enumerable:!0});function stringifyCookie(c){var _a;let attrs=[\"path\"in c&&c.path&&`Path=${c.path}`,\"expires\"in c&&(c.expires||0===c.expires)&&`Expires=${(\"number\"==typeof c.expires?new Date(c.expires):c.expires).toUTCString()}`,\"maxAge\"in c&&\"number\"==typeof c.maxAge&&`Max-Age=${c.maxAge}`,\"domain\"in c&&c.domain&&`Domain=${c.domain}`,\"secure\"in c&&c.secure&&\"Secure\",\"httpOnly\"in c&&c.httpOnly&&\"HttpOnly\",\"sameSite\"in c&&c.sameSite&&`SameSite=${c.sameSite}`,\"partitioned\"in c&&c.partitioned&&\"Partitioned\",\"priority\"in c&&c.priority&&`Priority=${c.priority}`].filter(Boolean),stringified=`${c.name}=${encodeURIComponent(null!=(_a=c.value)?_a:\"\")}`;return 0===attrs.length?stringified:`${stringified}; ${attrs.join(\"; \")}`}function parseCookie(cookie){let map=new Map;for(let pair of cookie.split(/; */)){if(!pair)continue;let splitAt=pair.indexOf(\"=\");if(-1===splitAt){map.set(pair,\"true\");contin...\n Line 21: ${docsUrl}#move-into-effect-or-event-handler`+elapsedTimeBullet(type,docsUrl)),\"__NEXT_ERROR_CODE\",{value:\"E1287\",enumerable:!1,configurable:!0}))),workUnitStore);break}case\"request\":{let stageController=workUnitStore.stagedRendering;if(stageController&&stageController.shouldTrackSyncInterrupt()){let syncIOError;syncIOError=applyOwnerStack(syncIOError=stageController.currentStage===staged_rendering_RenderStage.Static||stageController.currentStage===staged_rendering_RenderStage.EarlyStatic?createSyncIOErrorImpl(workStore.route,expression,type,SYNC_IO_DOCS[type]):createSyncIOErrorImpl(workStore.route,expression,type,SYNC_IO_RUNTIME_DOCS[type])),stageController.syncInterruptCurrentStageWithReason(syncIOError),workUnitStore.controller&&!workUnitStore.controller.signal.aborted&&workUnitStore.controller.abort(syncIOError)}}}}let random_expression=\"`Math.random()`\";try{let _random=Math.random;Math.random=(function(){return io(random_expression,\"random\"),_random.apply(null,arguments)}).bind(null),Object.defineProperty(Math.random,\"name\",{value:\"random\"})}catch{console.error(`Failed to install ${random_expression} extension. When using \\`cacheComponents\\` calling this function will not correctly trigger dynamic behavior.`)}try{let properties,apply,construct,newConstructor;Date=(originalConstructor=Date,(properties=Object.getOwnPropertyDescriptors(originalConstructor)).now.value=(originalNow=originalConstructor.now,({now:function(){return io(\"`Date.now()`\",\"time\"),originalNow()}})[\"now\".slice()].bind(null)),apply=Reflect.apply,construct=Reflect.construct,newConstructor=Object.defineProperties(function(){return new.target===void 0?(io(\"`Date()`\",\"time\"),apply(originalConstructor,void 0,arguments)):(0==arguments.length&&io(\"`new Date()`\",\"time\"),construct(originalConstructor,arguments,new.target))},properties),Object.defineProperty(originalConstructor.prototype,\"constructor\",{value:newConstructor}),newConstructor)}catch{console.error(\"Failed to install `Date` class extensio...\n\n/workspace/node_modules/next/dist/compiled/next-server/use-cache-probe-worker-turbo.runtime.dev.js:\n Line 1: (()=>{var __webpack_modules__={\"next/dist/compiled/ws\"(module1){\"use strict\";module1.exports=require(\"next/dist/compiled/ws\")},async_hooks(module1){\"use strict\";module1.exports=require(\"async_hooks\")},crypto(module1){\"use strict\";module1.exports=require(\"crypto\")},module(module1){\"use strict\";module1.exports=require(\"module\")},\"node:crypto\"(module1){\"use strict\";module1.exports=require(\"node:crypto\")},path(module1){\"use strict\";module1.exports=require(\"path\")},stream(module1){\"use strict\";module1.exports=require(\"stream\")},util(module1){\"use strict\";module1.exports=require(\"util\")},\"(react-server)/./dist/compiled/@edge-runtime/cookies/index.js\"(module1){\"use strict\";var __defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropNames=Object.getOwnPropertyNames,__hasOwnProp=Object.prototype.hasOwnProperty,src_exports={},all={RequestCookies:()=>RequestCookies,ResponseCookies:()=>ResponseCookies,parseCookie:()=>parseCookie,parseSetCookie:()=>parseSetCookie,stringifyCookie:()=>stringifyCookie};for(var name in all)__defProp(src_exports,name,{get:all[name],enumerable:!0});function stringifyCookie(c){var _a;let attrs=[\"path\"in c&&c.path&&`Path=${c.path}`,\"expires\"in c&&(c.expires||0===c.expires)&&`Expires=${(\"number\"==typeof c.expires?new Date(c.expires):c.expires).toUTCString()}`,\"maxAge\"in c&&\"number\"==typeof c.maxAge&&`Max-Age=${c.maxAge}`,\"domain\"in c&&c.domain&&`Domain=${c.domain}`,\"secure\"in c&&c.secure&&\"Secure\",\"httpOnly\"in c&&c.httpOnly&&\"HttpOnly\",\"sameSite\"in c&&c.sameSite&&`SameSite=${c.sameSite}`,\"partitioned\"in c&&c.partitioned&&\"Partitioned\",\"priority\"in c&&c.priority&&`Priority=${c.priority}`].filter(Boolean),stringified=`${c.name}=${encodeURIComponent(null!=(_a=c.value)?_a:\"\")}`;return 0===attrs.length?stringified:`${stringified}; ${attrs.join(\"; \")}`}function parseCookie(cookie){let map=new Map;for(let pair of cookie.split(/; */)){if(!pair)continue;let splitAt=pair.indexOf(\"=\");if(-1===splitAt){map.set(pair,\"true\");contin...\n Line 21: ${docsUrl}#move-into-effect-or-event-handler`+elapsedTimeBullet(type,docsUrl)),\"__NEXT_ERROR_CODE\",{value:\"E1287\",enumerable:!1,configurable:!0}))),workUnitStore);break}case\"request\":{let stageController=workUnitStore.stagedRendering;if(stageController&&stageController.shouldTrackSyncInterrupt()){let syncIOError;syncIOError=applyOwnerStack(syncIOError=stageController.currentStage===staged_rendering_RenderStage.Static||stageController.currentStage===staged_rendering_RenderStage.EarlyStatic?createSyncIOErrorImpl(workStore.route,expression,type,SYNC_IO_DOCS[type]):createSyncIOErrorImpl(workStore.route,expression,type,SYNC_IO_RUNTIME_DOCS[type])),stageController.syncInterruptCurrentStageWithReason(syncIOError),workUnitStore.controller&&!workUnitStore.controller.signal.aborted&&workUnitStore.controller.abort(syncIOError)}}}}let random_expression=\"`Math.random()`\";try{let _random=Math.random;Math.random=(function(){return io(random_expression,\"random\"),_random.apply(null,arguments)}).bind(null),Object.defineProperty(Math.random,\"name\",{value:\"random\"})}catch{console.error(`Failed to install ${random_expression} extension. When using \\`cacheComponents\\` calling this function will not correctly trigger dynamic behavior.`)}try{let properties,apply,construct,newConstructor;Date=(originalConstructor=Date,(properties=Object.getOwnPropertyDescriptors(originalConstructor)).now.value=(originalNow=originalConstructor.now,({now:function(){return io(\"`Date.now()`\",\"time\"),originalNow()}})[\"now\".slice()].bind(null)),apply=Reflect.apply,construct=Reflect.construct,newConstructor=Object.defineProperties(function(){return new.target===void 0?(io(\"`Date()`\",\"time\"),apply(originalConstructor,void 0,arguments)):(0==arguments.length&&io(\"`new Date()`\",\"time\"),construct(originalConstructor,arguments,new.target))},properties),Object.defineProperty(originalConstructor.prototype,\"constructor\",{value:newConstructor}),newConstructor)}catch{console.error(\"Failed to install `Date` class extensio...\n\n/workspace/node_modules/next/dist/compiled/next-server/use-cache-probe-worker-turbo-experimental.runtime.dev.js:\n Line 1: (()=>{var __webpack_modules__={\"next/dist/compiled/ws\"(module1){\"use strict\";module1.exports=require(\"next/dist/compiled/ws\")},async_hooks(module1){\"use strict\";module1.exports=require(\"async_hooks\")},crypto(module1){\"use strict\";module1.exports=require(\"crypto\")},module(module1){\"use strict\";module1.exports=require(\"module\")},\"node:crypto\"(module1){\"use strict\";module1.exports=require(\"node:crypto\")},path(module1){\"use strict\";module1.exports=require(\"path\")},stream(module1){\"use strict\";module1.exports=require(\"stream\")},util(module1){\"use strict\";module1.exports=require(\"util\")},\"(react-server)/./dist/compiled/@edge-runtime/cookies/index.js\"(module1){\"use strict\";var __defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropNames=Object.getOwnPropertyNames,__hasOwnProp=Object.prototype.hasOwnProperty,src_exports={},all={RequestCookies:()=>RequestCookies,ResponseCookies:()=>ResponseCookies,parseCookie:()=>parseCookie,parseSetCookie:()=>parseSetCookie,stringifyCookie:()=>stringifyCookie};for(var name in all)__defProp(src_exports,name,{get:all[name],enumerable:!0});function stringifyCookie(c){var _a;let attrs=[\"path\"in c&&c.path&&`Path=${c.path}`,\"expires\"in c&&(c.expires||0===c.expires)&&`Expires=${(\"number\"==typeof c.expires?new Date(c.expires):c.expires).toUTCString()}`,\"maxAge\"in c&&\"number\"==typeof c.maxAge&&`Max-Age=${c.maxAge}`,\"domain\"in c&&c.domain&&`Domain=${c.domain}`,\"secure\"in c&&c.secure&&\"Secure\",\"httpOnly\"in c&&c.httpOnly&&\"HttpOnly\",\"sameSite\"in c&&c.sameSite&&`SameSite=${c.sameSite}`,\"partitioned\"in c&&c.partitioned&&\"Partitioned\",\"priority\"in c&&c.priority&&`Priority=${c.priority}`].filter(Boolean),stringified=`${c.name}=${encodeURIComponent(null!=(_a=c.value)?_a:\"\")}`;return 0===attrs.length?stringified:`${stringified}; ${attrs.join(\"; \")}`}function parseCookie(cookie){let map=new Map;for(let pair of cookie.split(/; */)){if(!pair)continue;let splitAt=pair.indexOf(\"=\");if(-1===splitAt){map.set(pair,\"true\");contin...\n Line 21: ${docsUrl}#move-into-effect-or-event-handler`+elapsedTimeBullet(type,docsUrl)),\"__NEXT_ERROR_CODE\",{value:\"E1287\",enumerable:!1,configurable:!0}))),workUnitStore);break}case\"request\":{let stageController=workUnitStore.stagedRendering;if(stageController&&stageController.shouldTrackSyncInterrupt()){let syncIOError;syncIOError=applyOwnerStack(syncIOError=stageController.currentStage===staged_rendering_RenderStage.Static||stageController.currentStage===staged_rendering_RenderStage.EarlyStatic?createSyncIOErrorImpl(workStore.route,expression,type,SYNC_IO_DOCS[type]):createSyncIOErrorImpl(workStore.route,expression,type,SYNC_IO_RUNTIME_DOCS[type])),stageController.syncInterruptCurrentStageWithReason(syncIOError),workUnitStore.controller&&!workUnitStore.controller.signal.aborted&&workUnitStore.controller.abort(syncIOError)}}}}let random_expression=\"`Math.random()`\";try{let _random=Math.random;Math.random=(function(){return io(random_expression,\"random\"),_random.apply(null,arguments)}).bind(null),Object.defineProperty(Math.random,\"name\",{value:\"random\"})}catch{console.error(`Failed to install ${random_expression} extension. When using \\`cacheComponents\\` calling this function will not correctly trigger dynamic behavior.`)}try{let properties,apply,construct,newConstructor;Date=(originalConstructor=Date,(properties=Object.getOwnPropertyDescriptors(originalConstructor)).now.value=(originalNow=originalConstructor.now,({now:function(){return io(\"`Date.now()`\",\"time\"),originalNow()}})[\"now\".slice()].bind(null)),apply=Reflect.apply,construct=Reflect.construct,newConstructor=Object.defineProperties(function(){return new.target===void 0?(io(\"`Date()`\",\"time\"),apply(originalConstructor,void 0,arguments)):(0==arguments.length&&io(\"`new Date()`\",\"time\"),construct(originalConstructor,arguments,new.target))},properties),Object.defineProperty(originalConstructor.prototype,\"constructor\",{value:newConstructor}),newConstructor)}catch{console.error(\"Failed to install `Date` class extensio...\n\n/workspace/node_modules/next/dist/compiled/next-server/use-cache-probe-worker-experimental.runtime.dev.js:\n Line 1: (()=>{var __webpack_modules__={\"next/dist/compiled/ws\"(module1){\"use strict\";module1.exports=require(\"next/dist/compiled/ws\")},async_hooks(module1){\"use strict\";module1.exports=require(\"async_hooks\")},crypto(module1){\"use strict\";module1.exports=require(\"crypto\")},module(module1){\"use strict\";module1.exports=require(\"module\")},\"node:crypto\"(module1){\"use strict\";module1.exports=require(\"node:crypto\")},path(module1){\"use strict\";module1.exports=require(\"path\")},stream(module1){\"use strict\";module1.exports=require(\"stream\")},util(module1){\"use strict\";module1.exports=require(\"util\")},\"(react-server)/./dist/compiled/@edge-runtime/cookies/index.js\"(module1){\"use strict\";var __defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropNames=Object.getOwnPropertyNames,__hasOwnProp=Object.prototype.hasOwnProperty,src_exports={},all={RequestCookies:()=>RequestCookies,ResponseCookies:()=>ResponseCookies,parseCookie:()=>parseCookie,parseSetCookie:()=>parseSetCookie,stringifyCookie:()=>stringifyCookie};for(var name in all)__defProp(src_exports,name,{get:all[name],enumerable:!0});function stringifyCookie(c){var _a;let attrs=[\"path\"in c&&c.path&&`Path=${c.path}`,\"expires\"in c&&(c.expires||0===c.expires)&&`Expires=${(\"number\"==typeof c.expires?new Date(c.expires):c.expires).toUTCString()}`,\"maxAge\"in c&&\"number\"==typeof c.maxAge&&`Max-Age=${c.maxAge}`,\"domain\"in c&&c.domain&&`Domain=${c.domain}`,\"secure\"in c&&c.secure&&\"Secure\",\"httpOnly\"in c&&c.httpOnly&&\"HttpOnly\",\"sameSite\"in c&&c.sameSite&&`SameSite=${c.sameSite}`,\"partitioned\"in c&&c.partitioned&&\"Partitioned\",\"priority\"in c&&c.priority&&`Priority=${c.priority}`].filter(Boolean),stringified=`${c.name}=${encodeURIComponent(null!=(_a=c.value)?_a:\"\")}`;return 0===attrs.length?stringified:`${stringified}; ${attrs.join(\"; \")}`}function parseCookie(cookie){let map=new Map;for(let pair of cookie.split(/; */)){if(!pair)continue;let splitAt=pair.indexOf(\"=\");if(-1===splitAt){map.set(pair,\"true\");contin...\n Line 21: ${docsUrl}#move-into-effect-or-event-handler`+elapsedTimeBullet(type,docsUrl)),\"__NEXT_ERROR_CODE\",{value:\"E1287\",enumerable:!1,configurable:!0}))),workUnitStore);break}case\"request\":{let stageController=workUnitStore.stagedRendering;if(stageController&&stageController.shouldTrackSyncInterrupt()){let syncIOError;syncIOError=applyOwnerStack(syncIOError=stageController.currentStage===staged_rendering_RenderStage.Static||stageController.currentStage===staged_rendering_RenderStage.EarlyStatic?createSyncIOErrorImpl(workStore.route,expression,type,SYNC_IO_DOCS[type]):createSyncIOErrorImpl(workStore.route,expression,type,SYNC_IO_RUNTIME_DOCS[type])),stageController.syncInterruptCurrentStageWithReason(syncIOError),workUnitStore.controller&&!workUnitStore.controller.signal.aborted&&workUnitStore.controller.abort(syncIOError)}}}}let random_expression=\"`Math.random()`\";try{let _random=Math.random;Math.random=(function(){return io(random_expression,\"random\"),_random.apply(null,arguments)}).bind(null),Object.defineProperty(Math.random,\"name\",{value:\"random\"})}catch{console.error(`Failed to install ${random_expression} extension. When using \\`cacheComponents\\` calling this function will not correctly trigger dynamic behavior.`)}try{let properties,apply,construct,newConstructor;Date=(originalConstructor=Date,(properties=Object.getOwnPropertyDescriptors(originalConstructor)).now.value=(originalNow=originalConstructor.now,({now:function(){return io(\"`Date.now()`\",\"time\"),originalNow()}})[\"now\".slice()].bind(null)),apply=Reflect.apply,construct=Reflect.construct,newConstructor=Object.defineProperties(function(){return new.target===void 0?(io(\"`Date()`\",\"time\"),apply(originalConstructor,void 0,arguments)):(0==arguments.length&&io(\"`new Date()`\",\"time\"),construct(originalConstructor,arguments,new.target))},properties),Object.defineProperty(originalConstructor.prototype,\"constructor\",{value:newConstructor}),newConstructor)}catch{console.error(\"Failed to install `Date` class extensio...\n\n/workspace/node_modules/next/dist/compiled/next-server/server.runtime.prod.js:\n Line 1: (()=>{var e={\"../../node_modules/.pnpm/react@19.3.0-canary-43bcbf80-20260603/node_modules/react/cjs/react.production.js\"(e,t){\"use strict\";var r=Symbol.for(\"react.transitional.element\"),n=Symbol.for(\"react.portal\"),i=(Symbol.for(\"react.fragment\"),Symbol.for(\"react.strict_mode\"),Symbol.for(\"react.profiler\"),Symbol.for(\"react.consumer\"),Symbol.for(\"react.context\"),Symbol.for(\"react.forward_ref\"),Symbol.for(\"react.suspense\"),Symbol.for(\"react.memo\"),Symbol.for(\"react.lazy\")),s=(Symbol.for(\"react.activity\"),Symbol.for(\"react.view_transition\"),Symbol.iterator),a={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},o=Object.assign,l={};function c(e,t,r){this.props=e,this.context=t,this.refs=l,this.updater=r||a}function u(){}function d(e,t,r){this.props=e,this.context=t,this.refs=l,this.updater=r||a}c.prototype.isReactComponent={},c.prototype.setState=function(e,t){if(\"object\"!=typeof e&&\"function\"!=typeof e&&null!=e)throw Error(\"takes an object of state variables to update or a function which returns an object of state variables.\");this.updater.enqueueSetState(this,e,t,\"setState\")},c.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,\"forceUpdate\")},u.prototype=c.prototype;var h=d.prototype=new u;h.constructor=d,o(h,c.prototype),h.isPureReactComponent=!0;Object.prototype.hasOwnProperty;\"function\"==typeof reportError&&reportError},\"../../node_modules/.pnpm/react@19.3.0-canary-43bcbf80-20260603/node_modules/react/index.js\"(e,t,r){\"use strict\";e.exports=r(\"../../node_modules/.pnpm/react@19.3.0-canary-43bcbf80-20260603/node_modules/react/cjs/react.production.js\")},\"../next-env/dist/index.js\"(e,t,r){var n={505:e=>{\"use strict\";e.exports.f=function(e){let t=e.ignoreProcessEnv?{}:process.env;for(let r in e.parsed){let n=Object.prototype.hasOwnProperty.call(t,r)?t[r]:e.parsed[r];e.parsed[r]=(function e(t,r,n){var i;let s,a=(i=/(?!(?<=\\\\))\\$/g,(s=Array.from(t.matchAll(i))).length>0?s.sl...\n Line 23: ${s}#move-into-effect-or-event-handler`+ec(t,s)),\"__NEXT_ERROR_CODE\",{value:\"E1287\",enumerable:!1,configurable:!0})),n);break}case\"request\":{let r=n.stagedRendering;if(r&&r.shouldTrackSyncInterrupt()){let s;s=r.currentStage===ei.Static||r.currentStage===ei.EarlyStatic?ed(i.route,e,t,ea[t]):ed(i.route,e,t,el[t]),r.syncInterruptCurrentStageWithReason(s),n.controller&&!n.controller.signal.aborted&&n.controller.abort(s)}}}}let ep=\"`Math.random()`\";try{let e=Math.random;Math.random=(function(){return eh(ep,\"random\"),e.apply(null,arguments)}).bind(null),Object.defineProperty(Math.random,\"name\",{value:\"random\"})}catch{console.error(`Failed to install ${ep} extension. When using \\`cacheComponents\\` calling this function will not correctly trigger dynamic behavior.`)}try{let e,t,r,n;Date=(c=Date,(e=Object.getOwnPropertyDescriptors(c)).now.value=(u=c.now,({now:function(){return eh(\"`Date.now()`\",\"time\"),u()}})[\"now\".slice()].bind(null)),t=Reflect.apply,r=Reflect.construct,n=Object.defineProperties(function(){return new.target===void 0?(eh(\"`Date()`\",\"time\"),t(c,void 0,arguments)):(0==arguments.length&&eh(\"`new Date()`\",\"time\"),r(c,arguments,new.target))},e),Object.defineProperty(c.prototype,\"constructor\",{value:n}),n)}catch{console.error(\"Failed to install `Date` class extension. When using `cacheComponents`, APIs that read the current time will not correctly trigger dynamic behavior.\")}t=\"undefined\"==typeof crypto?r(\"node:crypto\").webcrypto:crypto;let ef=\"`crypto.getRandomValues()`\";try{let e=t.getRandomValues;t.getRandomValues=function(){return eh(ef,\"crypto\"),e.apply(t,arguments)}}catch{console.error(`Failed to install ${ef} extension. When using \\`cacheComponents\\` calling this function will not correctly trigger dynamic behavior.`)}try{let e=t.randomUUID;t.randomUUID=function(){return eh(\"`crypto.randomUUID()`\",\"crypto\"),e.apply(t,arguments)}}catch{console.error(`Failed to install ${ef} extension. When using \\`cacheComponents\\` calling this function will not correctl...\n Line 34: `),Object.defineProperty(this,\"__NEXT_ERROR_CODE\",{value:\"E1172\",enumerable:!1,configurable:!0})}}var rg=r(\"./dist/compiled/@edge-runtime/cookies/index.js\");let ry=Symbol(\"internal request\");class rv extends Request{constructor(e,t={}){const r=\"string\"!=typeof e&&\"url\"in e?e.url:String(e);t6(r),t.body&&\"half\"!==t.duplex&&(t.duplex=\"half\"),e instanceof Request?super(e,t):super(r,t);const n=new rh(r,{headers:t9(this.headers),nextConfig:t.nextConfig});this[ry]={cookies:new rg.RequestCookies(this.headers),nextUrl:n,url:process.env.__NEXT_NO_MIDDLEWARE_URL_NORMALIZE?r:n.toString()}}[Symbol.for(\"edge-runtime.inspect.custom\")](){return{cookies:this.cookies,nextUrl:this.nextUrl,url:this.url,bodyUsed:this.bodyUsed,cache:this.cache,credentials:this.credentials,destination:this.destination,headers:Object.fromEntries(this.headers),integrity:this.integrity,keepalive:this.keepalive,method:this.method,mode:this.mode,redirect:this.redirect,referrer:this.referrer,referrerPolicy:this.referrerPolicy,signal:this.signal}}get cookies(){return this[ry].cookies}get nextUrl(){return this[ry].nextUrl}get page(){throw new rf}get ua(){throw new rm}get url(){return this[ry].url}}let rE=\"ResponseAborted\";class rb extends Error{constructor(...e){super(...e),this.name=rE}}class r_{constructor(){let e,t;this.promise=new Promise((r,n)=>{e=r,t=n}),this.resolve=e,this.reject=t}}let rR=0,rx=0,rw=0;function rC(e={}){let t=0===rR?void 0:{clientComponentLoadStart:rR,clientComponentLoadTimes:rx,clientComponentLoadCount:rw};return e.reset&&(rR=0,rx=0,rw=0),t}function rP(e){return(null==e?void 0:e.name)===\"AbortError\"||(null==e?void 0:e.name)===rE}let rO=\"performance\"in globalThis&&process.env.NEXT_OTEL_PERFORMANCE_PREFIX;async function rT(e,t,r){try{var n;let i,{errored:s,destroyed:a}=t;if(s||a)return;let o=(n=t,i=new AbortController,n.once(\"close\",()=>{n.writableFinished||i.abort(new rb)}),i),l=function(e,t){let r=!1,n=new r_;function i(){n.resolve()}e.on(\"drain\",i),e.once(\"close\",()=>{e.off(\"drain\",i),n...\n Line 35: See here for info: https://nextjs.org/docs/messages/custom-error-no-custom-404`)});const{dir:n=\".\",quiet:i=!1,conf:s,dev:a=!1,minimalMode:o=!1,hostname:l,port:c,experimentalTestProxy:u}=e;if(this.dev=a,this.experimentalTestProxy=u,this.serverOptions=e,this.dir=R.resolve(n),this.quiet=i,this.loadEnvConfig({dev:a,forceReload:!1}),this.nextConfig=s,this.nextConfig.experimental.runtimeServerDeploymentId){if(!process.env.NEXT_DEPLOYMENT_ID)throw Object.defineProperty(Error(\"process.env.NEXT_DEPLOYMENT_ID is missing but runtimeServerDeploymentId is enabled\"),\"__NEXT_ERROR_CODE\",{value:\"E970\",enumerable:!1,configurable:!0});this.deploymentId=process.env.NEXT_DEPLOYMENT_ID}else{let e=this.nextConfig.experimental.useSkewCookie?\"\":this.nextConfig.deploymentId||\"\";this.deploymentId=e,process.env.NEXT_DEPLOYMENT_ID=e}globalThis.NEXT_CLIENT_ASSET_SUFFIX=this.nextConfig.experimental.supportsImmutableAssets||!this.deploymentId?\"\":`?dpl=${this.deploymentId}`,this.hostname=l,this.hostname&&(this.fetchHostname=function(e){return tF.test(e)?`[${e}]`:e}(this.hostname)),this.port=c,this.distDir=R.join(this.dir,this.nextConfig.distDir),this.publicDir=this.getPublicDir(),this.hasStaticDir=!o&&this.getHasStaticDir(),this.i18nProvider=(null==(t=this.nextConfig.i18n)?void 0:t.locales)?new nq(this.nextConfig.i18n):void 0,this.localeNormalizer=this.i18nProvider?new r2(this.i18nProvider):void 0;const{assetPrefix:d,generateEtags:h}=this.nextConfig;this.buildId=this.getBuildId(),this.minimalMode=o||!!process.env.NEXT_PRIVATE_MINIMAL_MODE,this.enabledDirectories=this.getEnabledDirectories(a),this.isAppPPREnabled=this.enabledDirectories.app&&function(e){return void 0!==e&&(\"boolean\"==typeof e?e:\"incremental\"===e)}(this.nextConfig.experimental.ppr),this.normalizers={rsc:this.enabledDirectories.app&&1?new nz:void 0,segmentPrefetchRSC:new n5,data:this.enabledDirectories.pages?new nX(this.buildId):void 0},this.nextFontManifest=this.getNextFontManifest(),this.renderOpts={dir:this.dir,supportsDynamicResp...\n Line 48: `,eK)};throw new ir(Object.defineProperty(Error(\"missing required error components\"),\"__NEXT_ERROR_CODE\",{value:\"E60\",enumerable:!1,configurable:!0}))}i.components.routeModule?e$(e.req,\"match\",{definition:i.components.routeModule.definition,params:void 0}):eM(e.req,\"match\");try{return await this.renderToResponseWithComponents({...e,pathname:o,renderOpts:{...e.renderOpts,err:t}},i)}catch(e){if(e instanceof n7.NoFallbackError)throw Object.defineProperty(Error(\"invariant: failed to render error page\"),\"__NEXT_ERROR_CODE\",{value:\"E55\",enumerable:!1,configurable:!0});throw e}}catch(a){let t=rK(a),i=t instanceof ir;i||this.logError(t),r.statusCode=500;let s=await this.getFallbackErrorComponents(e.req.url);if(s)return e$(e.req,\"match\",{definition:s.routeModule.definition,params:void 0}),this.renderToResponseWithComponents({...e,pathname:\"/_error\",renderOpts:{...e.renderOpts,err:i?t.innerError:t}},{query:n,components:s});return{body:rD.fromStatic(\"Internal Server Error\",\"text/plain\")}}}async renderErrorToHTML(e,t,r,n,i={}){return this.getStaticHTML(t=>this.renderErrorToResponse(t,e),{req:t,res:r,pathname:n,query:i})}async render404(e,t,r,n=!0){let{pathname:i,query:s}=r||tp(e.url);return this.nextConfig.i18n&&(ek(e,\"locale\")||e$(e,\"locale\",this.nextConfig.i18n.defaultLocale),e$(e,\"defaultLocale\",this.nextConfig.i18n.defaultLocale)),t.statusCode=404,this.renderError(null,e,t,i,s,n)}}let is=require(\"next/dist/server/load-manifest.external.js\"),ia=new T(1e3);function io(e,t,r,n){let i,s=`${e}:${t}:${r}:${n}`,a=null==ia?void 0:ia.get(s);if(a)return a;let o=x().join(t,eF);n&&(i=(0,is.loadManifest)(x().join(o,eU),!0));let l=(0,is.loadManifest)(x().join(o,eH),!0);try{e=rI(nr(e))}catch(t){throw console.error(t),new ew(e)}let c=t=>{let n=t[e];if(!t[n]&&r){let i={};for(let e of Object.keys(t))i[ra(e,r).pathname]=l[e];n=i[e]}return n};return(i&&(a=c(i)),a||(a=c(l)),a)?(x().isAbsolute(a)||(a=x().join(o,a)),null==ia||ia.set(s,a),a):(null==ia||ia.set(s,null),null)}f...\n\n/workspace/node_modules/next/dist/esm/server/revalidation-utils.js:\n Line 91: throw Object.defineProperty(new Error(`Invalid profile provided \"${profile}\" must be configured under cacheLife in next.config or be \"max\"`), \"__NEXT_ERROR_CODE\", {\n\n/workspace/node_modules/next/dist/server/revalidation-utils.js:\n Line 113: throw Object.defineProperty(new Error(`Invalid profile provided \"${profile}\" must be configured under cacheLife in next.config or be \"max\"`), \"__NEXT_ERROR_CODE\", {\n\n/workspace/node_modules/next/dist/esm/server/web/spec-extension/revalidate.js:\n Line 15: * (e.g. `\"max\"`), or a `{ expire }` object. For immediate expiration in Server Actions, use\n\n/workspace/node_modules/next/dist/compiled/next-server/pages.runtime.prod.js:\n Line 1: (()=>{var e,t,r={\"./dist/compiled/@edge-runtime/cookies/index.js\"(e){\"use strict\";var t=Object.defineProperty,r=Object.getOwnPropertyDescriptor,a=Object.getOwnPropertyNames,n=Object.prototype.hasOwnProperty,i={},s={RequestCookies:()=>p,ResponseCookies:()=>f,parseCookie:()=>c,parseSetCookie:()=>u,stringifyCookie:()=>l};for(var o in s)t(i,o,{get:s[o],enumerable:!0});function l(e){var t;let r=[\"path\"in e&&e.path&&`Path=${e.path}`,\"expires\"in e&&(e.expires||0===e.expires)&&`Expires=${(\"number\"==typeof e.expires?new Date(e.expires):e.expires).toUTCString()}`,\"maxAge\"in e&&\"number\"==typeof e.maxAge&&`Max-Age=${e.maxAge}`,\"domain\"in e&&e.domain&&`Domain=${e.domain}`,\"secure\"in e&&e.secure&&\"Secure\",\"httpOnly\"in e&&e.httpOnly&&\"HttpOnly\",\"sameSite\"in e&&e.sameSite&&`SameSite=${e.sameSite}`,\"partitioned\"in e&&e.partitioned&&\"Partitioned\",\"priority\"in e&&e.priority&&`Priority=${e.priority}`].filter(Boolean),a=`${e.name}=${encodeURIComponent(null!=(t=e.value)?t:\"\")}`;return 0===r.length?a:`${a}; ${r.join(\"; \")}`}function c(e){let t=new Map;for(let r of e.split(/; */)){if(!r)continue;let e=r.indexOf(\"=\");if(-1===e){t.set(r,\"true\");continue}let[a,n]=[r.slice(0,e),r.slice(e+1)];try{t.set(a,decodeURIComponent(null!=n?n:\"true\"))}catch{}}return t}function u(e){if(!e)return;let[[t,r],...a]=c(e),{domain:n,expires:i,httponly:s,maxage:o,path:l,samesite:u,secure:p,partitioned:f,priority:m}=Object.fromEntries(a.map(([e,t])=>[e.toLowerCase().replace(/-/g,\"\"),t]));{var g,v,y={name:t,value:decodeURIComponent(r),domain:n,...i&&{expires:new Date(i)},...s&&{httpOnly:!0},...\"string\"==typeof o&&{maxAge:Number(o)},path:l,...u&&{sameSite:d.includes(g=(g=u).toLowerCase())?g:void 0},...p&&{secure:!0},...m&&{priority:h.includes(v=(v=m).toLowerCase())?v:void 0},...f&&{partitioned:!0}};let e={};for(let t in y)y[t]&&(e[t]=y[t]);return e}}e.exports=((e,i,s,o)=>{if(i&&\"object\"==typeof i||\"function\"==typeof i)for(let s of a(i))n.call(e,s)||void 0===s||t(e,s,{get:()=>i[s],enumerable:!(o=r(i,s))||o.enumerable...\n Line 11: Read more: https://nextjs.org/docs/messages/get-initial-props-export`);let Q=!J&&V&&!X&&!C;if(Q&&N&&(n.setHeader(\"Cache-Control\",function({revalidate:e,expire:t}){let r=\"number\"==typeof e&&void 0!==t&&e{var leafPrototypes,getProto,__webpack_modules__={\"./dist/compiled/@edge-runtime/cookies/index.js\"(module1){\"use strict\";var __defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropNames=Object.getOwnPropertyNames,__hasOwnProp=Object.prototype.hasOwnProperty,src_exports={},all={RequestCookies:()=>RequestCookies,ResponseCookies:()=>ResponseCookies,parseCookie:()=>parseCookie,parseSetCookie:()=>parseSetCookie,stringifyCookie:()=>stringifyCookie};for(var name in all)__defProp(src_exports,name,{get:all[name],enumerable:!0});function stringifyCookie(c){var _a;let attrs=[\"path\"in c&&c.path&&`Path=${c.path}`,\"expires\"in c&&(c.expires||0===c.expires)&&`Expires=${(\"number\"==typeof c.expires?new Date(c.expires):c.expires).toUTCString()}`,\"maxAge\"in c&&\"number\"==typeof c.maxAge&&`Max-Age=${c.maxAge}`,\"domain\"in c&&c.domain&&`Domain=${c.domain}`,\"secure\"in c&&c.secure&&\"Secure\",\"httpOnly\"in c&&c.httpOnly&&\"HttpOnly\",\"sameSite\"in c&&c.sameSite&&`SameSite=${c.sameSite}`,\"partitioned\"in c&&c.partitioned&&\"Partitioned\",\"priority\"in c&&c.priority&&`Priority=${c.priority}`].filter(Boolean),stringified=`${c.name}=${encodeURIComponent(null!=(_a=c.value)?_a:\"\")}`;return 0===attrs.length?stringified:`${stringified}; ${attrs.join(\"; \")}`}function parseCookie(cookie){let map=new Map;for(let pair of cookie.split(/; */)){if(!pair)continue;let splitAt=pair.indexOf(\"=\");if(-1===splitAt){map.set(pair,\"true\");continue}let[key,value]=[pair.slice(0,splitAt),pair.slice(splitAt+1)];try{map.set(key,decodeURIComponent(null!=value?value:\"true\"))}catch{}}return map}function parseSetCookie(setCookie){if(!setCookie)return;let[[name,value],...attributes]=parseCookie(setCookie),{domain,expires,httponly,maxage,path,samesite,secure,partitioned,priority}=Object.fromEntries(attributes.map(([key,value2])=>[key.toLowerCase().replace(/-/g,\"\"),value2]));{var string,string1,t={name,value:decodeURIComponent(value),domain,...expires&&{expires:new Date(expires)},...httponly&&{h...\n Line 11: Read more: https://nextjs.org/docs/messages/get-initial-props-export`);let isAutoExport=!hasPageGetInitialProps&&defaultAppGetInitialProps&&!isSSG&&!getServerSideProps;if(isAutoExport&&!process.env.__NEXT_DEV_SERVER&&isExperimentalCompile&&(res.setHeader(\"Cache-Control\",function({revalidate,expire}){let swrHeader=\"number\"==typeof revalidate&&void 0!==expire&&revalidate{var e,t,r={\"./dist/compiled/@edge-runtime/cookies/index.js\"(e){\"use strict\";var t=Object.defineProperty,r=Object.getOwnPropertyDescriptor,a=Object.getOwnPropertyNames,n=Object.prototype.hasOwnProperty,i={},s={RequestCookies:()=>p,ResponseCookies:()=>f,parseCookie:()=>c,parseSetCookie:()=>u,stringifyCookie:()=>l};for(var o in s)t(i,o,{get:s[o],enumerable:!0});function l(e){var t;let r=[\"path\"in e&&e.path&&`Path=${e.path}`,\"expires\"in e&&(e.expires||0===e.expires)&&`Expires=${(\"number\"==typeof e.expires?new Date(e.expires):e.expires).toUTCString()}`,\"maxAge\"in e&&\"number\"==typeof e.maxAge&&`Max-Age=${e.maxAge}`,\"domain\"in e&&e.domain&&`Domain=${e.domain}`,\"secure\"in e&&e.secure&&\"Secure\",\"httpOnly\"in e&&e.httpOnly&&\"HttpOnly\",\"sameSite\"in e&&e.sameSite&&`SameSite=${e.sameSite}`,\"partitioned\"in e&&e.partitioned&&\"Partitioned\",\"priority\"in e&&e.priority&&`Priority=${e.priority}`].filter(Boolean),a=`${e.name}=${encodeURIComponent(null!=(t=e.value)?t:\"\")}`;return 0===r.length?a:`${a}; ${r.join(\"; \")}`}function c(e){let t=new Map;for(let r of e.split(/; */)){if(!r)continue;let e=r.indexOf(\"=\");if(-1===e){t.set(r,\"true\");continue}let[a,n]=[r.slice(0,e),r.slice(e+1)];try{t.set(a,decodeURIComponent(null!=n?n:\"true\"))}catch{}}return t}function u(e){if(!e)return;let[[t,r],...a]=c(e),{domain:n,expires:i,httponly:s,maxage:o,path:l,samesite:u,secure:p,partitioned:f,priority:m}=Object.fromEntries(a.map(([e,t])=>[e.toLowerCase().replace(/-/g,\"\"),t]));{var g,v,y={name:t,value:decodeURIComponent(r),domain:n,...i&&{expires:new Date(i)},...s&&{httpOnly:!0},...\"string\"==typeof o&&{maxAge:Number(o)},path:l,...u&&{sameSite:d.includes(g=(g=u).toLowerCase())?g:void 0},...p&&{secure:!0},...m&&{priority:h.includes(v=(v=m).toLowerCase())?v:void 0},...f&&{partitioned:!0}};let e={};for(let t in y)y[t]&&(e[t]=y[t]);return e}}e.exports=((e,i,s,o)=>{if(i&&\"object\"==typeof i||\"function\"==typeof i)for(let s of a(i))n.call(e,s)||void 0===s||t(e,s,{get:()=>i[s],enumerable:!(o=r(i,s))||o.enumerable...\n Line 11: Read more: https://nextjs.org/docs/messages/get-initial-props-export`);let Q=!J&&V&&!X&&!C;if(Q&&N&&(n.setHeader(\"Cache-Control\",function({revalidate:e,expire:t}){let r=\"number\"==typeof e&&void 0!==t&&e{var leafPrototypes,getProto,__webpack_modules__={\"./dist/compiled/@edge-runtime/cookies/index.js\"(module1){\"use strict\";var __defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropNames=Object.getOwnPropertyNames,__hasOwnProp=Object.prototype.hasOwnProperty,src_exports={},all={RequestCookies:()=>RequestCookies,ResponseCookies:()=>ResponseCookies,parseCookie:()=>parseCookie,parseSetCookie:()=>parseSetCookie,stringifyCookie:()=>stringifyCookie};for(var name in all)__defProp(src_exports,name,{get:all[name],enumerable:!0});function stringifyCookie(c){var _a;let attrs=[\"path\"in c&&c.path&&`Path=${c.path}`,\"expires\"in c&&(c.expires||0===c.expires)&&`Expires=${(\"number\"==typeof c.expires?new Date(c.expires):c.expires).toUTCString()}`,\"maxAge\"in c&&\"number\"==typeof c.maxAge&&`Max-Age=${c.maxAge}`,\"domain\"in c&&c.domain&&`Domain=${c.domain}`,\"secure\"in c&&c.secure&&\"Secure\",\"httpOnly\"in c&&c.httpOnly&&\"HttpOnly\",\"sameSite\"in c&&c.sameSite&&`SameSite=${c.sameSite}`,\"partitioned\"in c&&c.partitioned&&\"Partitioned\",\"priority\"in c&&c.priority&&`Priority=${c.priority}`].filter(Boolean),stringified=`${c.name}=${encodeURIComponent(null!=(_a=c.value)?_a:\"\")}`;return 0===attrs.length?stringified:`${stringified}; ${attrs.join(\"; \")}`}function parseCookie(cookie){let map=new Map;for(let pair of cookie.split(/; */)){if(!pair)continue;let splitAt=pair.indexOf(\"=\");if(-1===splitAt){map.set(pair,\"true\");continue}let[key,value]=[pair.slice(0,splitAt),pair.slice(splitAt+1)];try{map.set(key,decodeURIComponent(null!=value?value:\"true\"))}catch{}}return map}function parseSetCookie(setCookie){if(!setCookie)return;let[[name,value],...attributes]=parseCookie(setCookie),{domain,expires,httponly,maxage,path,samesite,secure,partitioned,priority}=Object.fromEntries(attributes.map(([key,value2])=>[key.toLowerCase().replace(/-/g,\"\"),value2]));{var string,string1,t={name,value:decodeURIComponent(value),domain,...expires&&{expires:new Date(expires)},...httponly&&{h...\n Line 11: Read more: https://nextjs.org/docs/messages/get-initial-props-export`);let isAutoExport=!hasPageGetInitialProps&&defaultAppGetInitialProps&&!isSSG&&!getServerSideProps;if(isAutoExport&&!process.env.__NEXT_DEV_SERVER&&isExperimentalCompile&&(res.setHeader(\"Cache-Control\",function({revalidate,expire}){let swrHeader=\"number\"==typeof revalidate&&void 0!==expire&&revalidate{var e,t,r={\"./dist/compiled/@edge-runtime/cookies/index.js\"(e){\"use strict\";var t=Object.defineProperty,r=Object.getOwnPropertyDescriptor,a=Object.getOwnPropertyNames,n=Object.prototype.hasOwnProperty,i={},s={RequestCookies:()=>p,ResponseCookies:()=>f,parseCookie:()=>c,parseSetCookie:()=>u,stringifyCookie:()=>l};for(var o in s)t(i,o,{get:s[o],enumerable:!0});function l(e){var t;let r=[\"path\"in e&&e.path&&`Path=${e.path}`,\"expires\"in e&&(e.expires||0===e.expires)&&`Expires=${(\"number\"==typeof e.expires?new Date(e.expires):e.expires).toUTCString()}`,\"maxAge\"in e&&\"number\"==typeof e.maxAge&&`Max-Age=${e.maxAge}`,\"domain\"in e&&e.domain&&`Domain=${e.domain}`,\"secure\"in e&&e.secure&&\"Secure\",\"httpOnly\"in e&&e.httpOnly&&\"HttpOnly\",\"sameSite\"in e&&e.sameSite&&`SameSite=${e.sameSite}`,\"partitioned\"in e&&e.partitioned&&\"Partitioned\",\"priority\"in e&&e.priority&&`Priority=${e.priority}`].filter(Boolean),a=`${e.name}=${encodeURIComponent(null!=(t=e.value)?t:\"\")}`;return 0===r.length?a:`${a}; ${r.join(\"; \")}`}function c(e){let t=new Map;for(let r of e.split(/; */)){if(!r)continue;let e=r.indexOf(\"=\");if(-1===e){t.set(r,\"true\");continue}let[a,n]=[r.slice(0,e),r.slice(e+1)];try{t.set(a,decodeURIComponent(null!=n?n:\"true\"))}catch{}}return t}function u(e){if(!e)return;let[[t,r],...a]=c(e),{domain:n,expires:i,httponly:s,maxage:o,path:l,samesite:u,secure:p,partitioned:f,priority:m}=Object.fromEntries(a.map(([e,t])=>[e.toLowerCase().replace(/-/g,\"\"),t]));{var g,v,y={name:t,value:decodeURIComponent(r),domain:n,...i&&{expires:new Date(i)},...s&&{httpOnly:!0},...\"string\"==typeof o&&{maxAge:Number(o)},path:l,...u&&{sameSite:d.includes(g=(g=u).toLowerCase())?g:void 0},...p&&{secure:!0},...m&&{priority:h.includes(v=(v=m).toLowerCase())?v:void 0},...f&&{partitioned:!0}};let e={};for(let t in y)y[t]&&(e[t]=y[t]);return e}}e.exports=((e,i,s,o)=>{if(i&&\"object\"==typeof i||\"function\"==typeof i)for(let s of a(i))n.call(e,s)||void 0===s||t(e,s,{get:()=>i[s],enumerable:!(o=r(i,s))||o.enumerable...\n\n/workspace/node_modules/next/dist/compiled/next-server/pages-api.runtime.dev.js:\n Line 1: (()=>{var leafPrototypes,getProto,__webpack_modules__={\"./dist/compiled/@edge-runtime/cookies/index.js\"(module1){\"use strict\";var __defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropNames=Object.getOwnPropertyNames,__hasOwnProp=Object.prototype.hasOwnProperty,src_exports={},all={RequestCookies:()=>RequestCookies,ResponseCookies:()=>ResponseCookies,parseCookie:()=>parseCookie,parseSetCookie:()=>parseSetCookie,stringifyCookie:()=>stringifyCookie};for(var name in all)__defProp(src_exports,name,{get:all[name],enumerable:!0});function stringifyCookie(c){var _a;let attrs=[\"path\"in c&&c.path&&`Path=${c.path}`,\"expires\"in c&&(c.expires||0===c.expires)&&`Expires=${(\"number\"==typeof c.expires?new Date(c.expires):c.expires).toUTCString()}`,\"maxAge\"in c&&\"number\"==typeof c.maxAge&&`Max-Age=${c.maxAge}`,\"domain\"in c&&c.domain&&`Domain=${c.domain}`,\"secure\"in c&&c.secure&&\"Secure\",\"httpOnly\"in c&&c.httpOnly&&\"HttpOnly\",\"sameSite\"in c&&c.sameSite&&`SameSite=${c.sameSite}`,\"partitioned\"in c&&c.partitioned&&\"Partitioned\",\"priority\"in c&&c.priority&&`Priority=${c.priority}`].filter(Boolean),stringified=`${c.name}=${encodeURIComponent(null!=(_a=c.value)?_a:\"\")}`;return 0===attrs.length?stringified:`${stringified}; ${attrs.join(\"; \")}`}function parseCookie(cookie){let map=new Map;for(let pair of cookie.split(/; */)){if(!pair)continue;let splitAt=pair.indexOf(\"=\");if(-1===splitAt){map.set(pair,\"true\");continue}let[key,value]=[pair.slice(0,splitAt),pair.slice(splitAt+1)];try{map.set(key,decodeURIComponent(null!=value?value:\"true\"))}catch{}}return map}function parseSetCookie(setCookie){if(!setCookie)return;let[[name,value],...attributes]=parseCookie(setCookie),{domain,expires,httponly,maxage,path,samesite,secure,partitioned,priority}=Object.fromEntries(attributes.map(([key,value2])=>[key.toLowerCase().replace(/-/g,\"\"),value2]));{var string,string1,t={name,value:decodeURIComponent(value),domain,...expires&&{expires:new Date(expires)},...httponly&&{h...\n Line 2: See more info here https://nextjs.org/docs/messages/invalid-api-status-body`),res.end();return}let contentType=res.getHeader(\"Content-Type\");if(body instanceof external_stream_namespaceObject.Stream){contentType||res.setHeader(\"Content-Type\",\"application/octet-stream\"),body.pipe(res);return}let isJSONLike=[\"object\",\"number\",\"boolean\"].includes(typeof body),stringifiedBody=isJSONLike?JSON.stringify(body):body,etag=((payload,weak=!1)=>(weak?'W/\"':'\"')+(str=>{let len=str.length,i=0,t0=0,v0=8997,t1=0,v1=33826,t2=0,v2=40164,t3=0,v3=52210;for(;i>>16,v0=65535&t0,t2+=t1>>>16,v1=65535&t1,v3=t3+(t2>>>16)&65535,v2=65535&t2;return(15&v3)*0x1000000000000+0x100000000*v2+65536*v1+(v0^v3>>4)})(payload).toString(36)+payload.length.toString(36)+'\"')(stringifiedBody);if(etag&&res.setHeader(\"ETag\",etag),!fresh_default()(req.headers,{etag:etag})||(res.statusCode=304,res.end(),0)){if(Buffer.isBuffer(body)){contentType||res.setHeader(\"Content-Type\",\"application/octet-stream\"),res.setHeader(\"Content-Length\",body.length),res.end(body);return}isJSONLike&&res.setHeader(\"Content-Type\",constants.JSON_CONTENT_TYPE_HEADER),res.setHeader(\"Content-Length\",Buffer.byteLength(stringifiedBody)),res.end(stringifiedBody)}})(req,res,data),res.json=data=>{res.setHeader(\"Content-Type\",constants.JSON_CONTENT_TYPE_HEADER),res.send(JSON.stringify(data))},res.redirect=(statusOrUrl,url)=>(0,api_utils.redirect)(res,statusOrUrl,url),res.setDraftMode=(options={enable:!0})=>(function(res,options){if(!isValidData(options.previewModeId))throw Object.defineProperty(Error(\"invariant: invalid previewModeId\"),\"__NEXT_ERROR_CODE\",{value:\"E169\",enumerable:!1,configurable:!0});let expires=options.enable?void 0:new Date(0),{serialize}=__webpack_require__(\"./dist/compiled/cookie/index.js\"),previous=res.getHeader(\"Set-Cookie\");return res.setHeader(\"Set-Cookie\",[...\"string\"==typeof previous?[previous]:Array.isArray(previous)?previous...\n\n/workspace/node_modules/next/dist/compiled/next-server/pages-api-turbo.runtime.prod.js:\n Line 1: (()=>{var e,t,r={\"./dist/compiled/@edge-runtime/cookies/index.js\"(e){\"use strict\";var t=Object.defineProperty,r=Object.getOwnPropertyDescriptor,a=Object.getOwnPropertyNames,n=Object.prototype.hasOwnProperty,i={},s={RequestCookies:()=>p,ResponseCookies:()=>f,parseCookie:()=>c,parseSetCookie:()=>u,stringifyCookie:()=>l};for(var o in s)t(i,o,{get:s[o],enumerable:!0});function l(e){var t;let r=[\"path\"in e&&e.path&&`Path=${e.path}`,\"expires\"in e&&(e.expires||0===e.expires)&&`Expires=${(\"number\"==typeof e.expires?new Date(e.expires):e.expires).toUTCString()}`,\"maxAge\"in e&&\"number\"==typeof e.maxAge&&`Max-Age=${e.maxAge}`,\"domain\"in e&&e.domain&&`Domain=${e.domain}`,\"secure\"in e&&e.secure&&\"Secure\",\"httpOnly\"in e&&e.httpOnly&&\"HttpOnly\",\"sameSite\"in e&&e.sameSite&&`SameSite=${e.sameSite}`,\"partitioned\"in e&&e.partitioned&&\"Partitioned\",\"priority\"in e&&e.priority&&`Priority=${e.priority}`].filter(Boolean),a=`${e.name}=${encodeURIComponent(null!=(t=e.value)?t:\"\")}`;return 0===r.length?a:`${a}; ${r.join(\"; \")}`}function c(e){let t=new Map;for(let r of e.split(/; */)){if(!r)continue;let e=r.indexOf(\"=\");if(-1===e){t.set(r,\"true\");continue}let[a,n]=[r.slice(0,e),r.slice(e+1)];try{t.set(a,decodeURIComponent(null!=n?n:\"true\"))}catch{}}return t}function u(e){if(!e)return;let[[t,r],...a]=c(e),{domain:n,expires:i,httponly:s,maxage:o,path:l,samesite:u,secure:p,partitioned:f,priority:m}=Object.fromEntries(a.map(([e,t])=>[e.toLowerCase().replace(/-/g,\"\"),t]));{var g,v,y={name:t,value:decodeURIComponent(r),domain:n,...i&&{expires:new Date(i)},...s&&{httpOnly:!0},...\"string\"==typeof o&&{maxAge:Number(o)},path:l,...u&&{sameSite:d.includes(g=(g=u).toLowerCase())?g:void 0},...p&&{secure:!0},...m&&{priority:h.includes(v=(v=m).toLowerCase())?v:void 0},...f&&{partitioned:!0}};let e={};for(let t in y)y[t]&&(e[t]=y[t]);return e}}e.exports=((e,i,s,o)=>{if(i&&\"object\"==typeof i||\"function\"==typeof i)for(let s of a(i))n.call(e,s)||void 0===s||t(e,s,{get:()=>i[s],enumerable:!(o=r(i,s))||o.enumerable...\n\n/workspace/node_modules/next/dist/compiled/next-server/pages-api-turbo.runtime.dev.js:\n Line 1: (()=>{var leafPrototypes,getProto,__webpack_modules__={\"./dist/compiled/@edge-runtime/cookies/index.js\"(module1){\"use strict\";var __defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropNames=Object.getOwnPropertyNames,__hasOwnProp=Object.prototype.hasOwnProperty,src_exports={},all={RequestCookies:()=>RequestCookies,ResponseCookies:()=>ResponseCookies,parseCookie:()=>parseCookie,parseSetCookie:()=>parseSetCookie,stringifyCookie:()=>stringifyCookie};for(var name in all)__defProp(src_exports,name,{get:all[name],enumerable:!0});function stringifyCookie(c){var _a;let attrs=[\"path\"in c&&c.path&&`Path=${c.path}`,\"expires\"in c&&(c.expires||0===c.expires)&&`Expires=${(\"number\"==typeof c.expires?new Date(c.expires):c.expires).toUTCString()}`,\"maxAge\"in c&&\"number\"==typeof c.maxAge&&`Max-Age=${c.maxAge}`,\"domain\"in c&&c.domain&&`Domain=${c.domain}`,\"secure\"in c&&c.secure&&\"Secure\",\"httpOnly\"in c&&c.httpOnly&&\"HttpOnly\",\"sameSite\"in c&&c.sameSite&&`SameSite=${c.sameSite}`,\"partitioned\"in c&&c.partitioned&&\"Partitioned\",\"priority\"in c&&c.priority&&`Priority=${c.priority}`].filter(Boolean),stringified=`${c.name}=${encodeURIComponent(null!=(_a=c.value)?_a:\"\")}`;return 0===attrs.length?stringified:`${stringified}; ${attrs.join(\"; \")}`}function parseCookie(cookie){let map=new Map;for(let pair of cookie.split(/; */)){if(!pair)continue;let splitAt=pair.indexOf(\"=\");if(-1===splitAt){map.set(pair,\"true\");continue}let[key,value]=[pair.slice(0,splitAt),pair.slice(splitAt+1)];try{map.set(key,decodeURIComponent(null!=value?value:\"true\"))}catch{}}return map}function parseSetCookie(setCookie){if(!setCookie)return;let[[name,value],...attributes]=parseCookie(setCookie),{domain,expires,httponly,maxage,path,samesite,secure,partitioned,priority}=Object.fromEntries(attributes.map(([key,value2])=>[key.toLowerCase().replace(/-/g,\"\"),value2]));{var string,string1,t={name,value:decodeURIComponent(value),domain,...expires&&{expires:new Date(expires)},...httponly&&{h...\n Line 2: See more info here https://nextjs.org/docs/messages/invalid-api-status-body`),res.end();return}let contentType=res.getHeader(\"Content-Type\");if(body instanceof external_stream_namespaceObject.Stream){contentType||res.setHeader(\"Content-Type\",\"application/octet-stream\"),body.pipe(res);return}let isJSONLike=[\"object\",\"number\",\"boolean\"].includes(typeof body),stringifiedBody=isJSONLike?JSON.stringify(body):body,etag=((payload,weak=!1)=>(weak?'W/\"':'\"')+(str=>{let len=str.length,i=0,t0=0,v0=8997,t1=0,v1=33826,t2=0,v2=40164,t3=0,v3=52210;for(;i>>16,v0=65535&t0,t2+=t1>>>16,v1=65535&t1,v3=t3+(t2>>>16)&65535,v2=65535&t2;return(15&v3)*0x1000000000000+0x100000000*v2+65536*v1+(v0^v3>>4)})(payload).toString(36)+payload.length.toString(36)+'\"')(stringifiedBody);if(etag&&res.setHeader(\"ETag\",etag),!fresh_default()(req.headers,{etag:etag})||(res.statusCode=304,res.end(),0)){if(Buffer.isBuffer(body)){contentType||res.setHeader(\"Content-Type\",\"application/octet-stream\"),res.setHeader(\"Content-Length\",body.length),res.end(body);return}isJSONLike&&res.setHeader(\"Content-Type\",constants.JSON_CONTENT_TYPE_HEADER),res.setHeader(\"Content-Length\",Buffer.byteLength(stringifiedBody)),res.end(stringifiedBody)}})(req,res,data),res.json=data=>{res.setHeader(\"Content-Type\",constants.JSON_CONTENT_TYPE_HEADER),res.send(JSON.stringify(data))},res.redirect=(statusOrUrl,url)=>(0,api_utils.redirect)(res,statusOrUrl,url),res.setDraftMode=(options={enable:!0})=>(function(res,options){if(!isValidData(options.previewModeId))throw Object.defineProperty(Error(\"invariant: invalid previewModeId\"),\"__NEXT_ERROR_CODE\",{value:\"E169\",enumerable:!1,configurable:!0});let expires=options.enable?void 0:new Date(0),{serialize}=__webpack_require__(\"./dist/compiled/cookie/index.js\"),previous=res.getHeader(\"Set-Cookie\");return res.setHeader(\"Set-Cookie\",[...\"string\"==typeof previous?[previous]:Array.isArray(previous)?previous...\n\n/workspace/node_modules/next/dist/server/response-cache/index.js:\n Line 297: const expire = previousIncrementalCacheEntry.cacheControl.expire === undefined ? undefined : Math.max(revalidate + 3, previousIncrementalCacheEntry.cacheControl.expire);\n\n/workspace/node_modules/next/dist/esm/server/response-cache/index.js:\n Line 273: const expire = previousIncrementalCacheEntry.cacheControl.expire === undefined ? undefined : Math.max(revalidate + 3, previousIncrementalCacheEntry.cacheControl.expire);\n\n/workspace/node_modules/next/dist/compiled/jsonwebtoken/index.js:\n Line 1: (()=>{var e={775:(e,r,t)=>{\"use strict\";var n=t(181).Buffer;var a=t(181).SlowBuffer;e.exports=bufferEq;function bufferEq(e,r){if(!n.isBuffer(e)||!n.isBuffer(r)){return false}if(e.length!==r.length){return false}var t=0;for(var a=0;a{\"use strict\";var n=t(725).Buffer;var a=t(335);var i=128,s=0,o=32,u=16,l=2,c=u|o|s<<6,f=l|s<<6;function base64Url(e){return e.replace(/=/g,\"\").replace(/\\+/g,\"-\").replace(/\\//g,\"_\")}function signatureAsBuffer(e){if(n.isBuffer(e)){return e}else if(\"string\"===typeof e){return n.from(e,\"base64\")}throw new TypeError(\"ECDSA signature must be a Base64 string or a Buffer\")}function derToJose(e,r){e=signatureAsBuffer(e);var t=a(r);var s=t+1;var o=e.length;var u=0;if(e[u++]!==c){throw new Error('Could not find expected \"seq\"')}var l=e[u++];if(l===(i|1)){l=e[u++]}if(o-u{var __webpack_modules__={687:e=>{e.exports='\"use strict\";var c=Object.defineProperty,f=Object.getOwnPropertyDescriptor,y=Object.getOwnPropertyNames,S=Object.prototype.hasOwnProperty,a=(r,t)=>c(r,\"name\",{value:t,configurable:!0}),m=(r,t)=>{for(var e in t)c(r,e,{get:t[e],enumerable:!0})},w=(r,t,e,p)=>{if(t&&typeof t==\"object\"||typeof t==\"function\")for(let n of y(t))!S.call(r,n)&&n!==e&&c(r,n,{get:()=>t[n],enumerable:!(p=f(t,n))||p.enumerable});return r},E=r=>w(c({},\"__esModule\",{value:!0}),r),_={};m(_,{AbortController:()=>x,AbortSignal:()=>O,DOMException:()=>u});module.exports=E(_);var v=Symbol(\"kSignal\"),i=Symbol(\"kAborted\"),s=Symbol(\"kReason\"),g=Symbol(\"kName\"),o=Symbol(\"kOnabort\"),h=class extends Error{constructor(t,e){super(t),this[g]=e}get name(){return this[g]}};a(h,\"DOMException\");var u=h;function b(){let r=new EventTarget;return Object.setPrototypeOf(r,O.prototype),r[i]=!1,r[s]=void 0,r[o]=void 0,r}a(b,\"createAbortSignal\");function l(r,t){typeof t>\"u\"&&(t=new u(\"This operation was aborted\",\"AbortError\")),!r.aborted&&(r[s]=t,r[i]=!0,r.dispatchEvent(new Event(\"abort\")))}a(l,\"abortSignalAbort\");var d=class{constructor(){this[v]=b()}get signal(){return this[v]}abort(t){l(this.signal,t)}};a(d,\"AbortController\");var x=d,A=class extends EventTarget{constructor(){throw new TypeError(\"Illegal constructor\")}get aborted(){return this[i]}get reason(){return this[s]}get onabort(){return this[o]}set onabort(t){this[o]&&this.removeEventListener(\"abort\",this[o]),t&&(this[o]=t,this.addEventListener(\"abort\",this[o]))}throwIfAborted(){if(this[i])throw this[s]}static abort(t){let e=b();return l(e,t),e}static timeout(t){let e=b();return setTimeout(()=>{l(e,new u(\"The operation was aborted due to timeout\",\"TimeoutError\"))},t),e}};a(A,\"AbortSignal\");var O=A;\\n'},157:e=>{e.exports='\"use strict\";var Gr=Object.create,E=Object.defineProperty,Rr=Object.getOwnPropertyDescriptor,T=Object.getOwnPropertyNames,kr=Object.getPrototypeOf,Mr=Object.prototype.hasOwnProperty,a=(f,y)=>E(f,\"nam...\n\n/workspace/node_modules/next/dist/compiled/cookie/index.js:\n Line 7: */r.parse=parse;r.serialize=serialize;var i=decodeURIComponent;var t=encodeURIComponent;var a=/; */;var n=/^[\\u0009\\u0020-\\u007e\\u0080-\\u00ff]+$/;function parse(e,r){if(typeof e!==\"string\"){throw new TypeError(\"argument str must be a string\")}var t={};var n=r||{};var o=e.split(a);var s=n.decode||i;for(var p=0;p{var __webpack_modules__={4816:(e,t,s)=>{\"use strict\";e.exports=t;const r=s(9896);const o=s(6928);const a=s(1825);const c=s(1916);const u=s(7650);const d=s(4434).EventEmitter;const h=s(9023).inherits;const f=[\"clean\",\"install\",\"reinstall\",\"build\",\"rebuild\",\"package\",\"testpackage\",\"publish\",\"unpublish\",\"info\",\"testbinary\",\"reveal\",\"configure\"];const p={};Object.defineProperty(t,\"find\",{get:function(){return s(2520).find},enumerable:true});function Run({package_json_path:e=\"./package.json\",argv:t}){this.package_json_path=e;this.commands={};const s=this;f.forEach((e=>{s.commands[e]=function(t,r){c.verbose(\"command\",e,t);return require(\"./\"+e)(s,t,r)}}));this.parseArgv(t);this.binaryHostSet=false}h(Run,d);t.Run=Run;const y=Run.prototype;y.package=s(9355);y.configDefs={help:Boolean,arch:String,debug:Boolean,directory:String,proxy:String,loglevel:String,acl:String};y.shorthands={release:\"--no-debug\",C:\"--directory\",debug:\"--debug\",j:\"--jobs\",silent:\"--loglevel=silent\",silly:\"--loglevel=silly\",verbose:\"--loglevel=verbose\"};y.aliases=p;y.parseArgv=function parseOpts(e){this.opts=a(this.configDefs,this.shorthands,e);this.argv=this.opts.argv.remain.slice();const t=this.todo=[];e=this.argv.map((e=>{if(e in this.aliases){e=this.aliases[e]}return e}));e.slice().forEach((s=>{if(s in this.commands){const r=e.splice(0,e.indexOf(s));e.shift();if(t.length>0){t[t.length-1].args=r}t.push({name:s,args:[]})}}));if(t.length>0){t[t.length-1].args=e.splice(0)}let s=this.package_json_path;if(this.opts.directory){s=o.join(this.opts.directory,s)}this.package_json=JSON.parse(r.readFileSync(s));this.todo=u.expand_commands(this.package_json,this.opts,t);const d=\"npm_config_\";Object.keys(process.env).forEach((e=>{if(e.indexOf(d)!==0)return;const t=process.env[e];if(e===d+\"loglevel\"){c.level=t}else{e=e.substring(d.length);if(e===\"argv\"){if(this.opts.argv&&this.opts.argv.remain&&this.opts.argv.remain.length){}else{this.opts[e]=t}}else{this.opts[e]=t}}}));if(this.opts.loglevel){c.level=this.opts...\n\n/workspace/node_modules/next/dist/esm/server/image-optimizer.js:\n Line 132: async function writeToCacheDir(cacheDir, cacheKey, extension, maxAge, expireAt, buffer, etag, upstreamEtag) {\n Line 134: const filename = join(/* turbopackIgnore: true */ dir, `${maxAge}.${expireAt}.${etag}.${upstreamEtag}.${extension}`);\n Line 155: const [maxAgeSt, expireAtSt, etag, upstreamEtag, extension] = file.split('.', 5);\n Line 622: const { maxAge, expireAt, etag, upstreamEtag, buffer, extension } = await readFromCacheDir(this.cacheDir, cacheKey);\n\n/workspace/node_modules/next/dist/server/image-optimizer.js:\n Line 252: async function writeToCacheDir(cacheDir, cacheKey, extension, maxAge, expireAt, buffer, etag, upstreamEtag) {\n Line 254: const filename = (0, _path.join)(/* turbopackIgnore: true */ dir, `${maxAge}.${expireAt}.${etag}.${upstreamEtag}.${extension}`);\n Line 275: const [maxAgeSt, expireAtSt, etag, upstreamEtag, extension] = file.split('.', 5);\n Line 738: const { maxAge, expireAt, etag, upstreamEtag, buffer, extension } = await readFromCacheDir(this.cacheDir, cacheKey);\n\n/workspace/node_modules/next/dist/server/lib/cache-handlers/default.js:\n Line 56: const maxAgeSeconds = process.env.__NEXT_DEV_SERVER ? entry.expire : entry.revalidate;\n\n/workspace/node_modules/next/dist/esm/server/lib/cache-handlers/default.js:\n Line 46: const maxAgeSeconds = process.env.__NEXT_DEV_SERVER ? entry.expire : entry.revalidate;\n\n/workspace/node_modules/next/dist/server/lib/router-utils/cache-life-type-utils.js:\n Line 155: * This is similar to Cache-Control: max-age=\\`stale\\`,s-max-age=\\`revalidate\\`,stale-while-revalidate=\\`expire-revalidate\\`\n\n/workspace/node_modules/next/dist/esm/server/lib/router-utils/cache-life-type-utils.js:\n Line 132: * This is similar to Cache-Control: max-age=\\`stale\\`,s-max-age=\\`revalidate\\`,stale-while-revalidate=\\`expire-revalidate\\`\n\n/workspace/node_modules/next/dist/compiled/webpack/bundle5.js:\n Line 29: var I;var P;var R;var $;var L;var q;var K;var ae;var ge;var be;var xe;var ve;var Ce;var Ne;var He;var Qe;var Je;var Ve;var Ke;var Ye;var Xe;var Ze;var et;(function(I){var P=typeof global===\"object\"?global:typeof self===\"object\"?self:typeof this===\"object\"?this:{};if(typeof define===\"function\"&&define.amd){define(\"tslib\",[\"exports\"],(function(v){I(createExporter(P,createExporter(v)))}))}else if(true&&typeof v.exports===\"object\"){I(createExporter(P,createExporter(v.exports)))}else{I(createExporter(P))}function createExporter(v,I){if(v!==P){if(typeof Object.create===\"function\"){Object.defineProperty(v,\"__esModule\",{value:true})}else{v.__esModule=true}}return function(P,R){return v[P]=I?I(P,R):R}}})((function(v){var tt=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(v,I){v.__proto__=I}||function(v,I){for(var P in I)if(I.hasOwnProperty(P))v[P]=I[P]};I=function(v,I){tt(v,I);function __(){this.constructor=v}v.prototype=I===null?Object.create(I):(__.prototype=I.prototype,new __)};P=Object.assign||function(v){for(var I,P=1,R=arguments.length;P=0;K--)if(q=v[K])L=($<3?q(L):$>3?q(I,P,L):q(I,P))||L;return $>3&&L&&Object.defineProperty(I,P,L),L};L=function(v,I){return function(P,R){I(P,R,v)}};q=function(v,I){if(typeof Reflect===\"object\"&&typeof Reflect.metadata===\"function\")return Reflect.metadata(v,I)};K=function(...\n\n/workspace/node_modules/next/dist/compiled/terser/bundle.min.js:\n Line 1: (()=>{var e={108:function(e,t){(function(e,n){true?n(t):0})(this,(function(e){\"use strict\";const t=\",\".charCodeAt(0);const n=\";\".charCodeAt(0);const i=\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";const r=new Uint8Array(64);const o=new Uint8Array(128);for(let e=0;e>>=1;if(u){r=-2147483648|-r}n[i]+=r;return t}function hasMoreSegments(e,i){if(i>=e.length)return false;const r=e.charCodeAt(i);if(r===t||r===n)return false;return true}function sort(e){e.sort(sortComparator$1)}function sortComparator$1(e,t){return e[0]-t[0]}function encode(e){const i=new Int32Array(5);let r=new Uint8Array(1024);let o=0;for(let a=0;a0){r=reserve(r,o,1);r[o++]=n}if(s.length===0)continue;i[0]=0;for(let e=0;e0)r[o++]=t;o=encodeInteger(r,o,i,n,0);if(n.length===1)continue;o=encodeInteger(r,o,i,n,1);o=encodeInteger(r,o,i,n,2);o=encodeInteger(r,o,i,n,3);if(n.length===4)continue;o=encodeInteger(r,o,i,n,4)}}return a....\n\n/workspace/node_modules/next/dist/compiled/next-server/app-route.runtime.prod.js:\n Line 1: (()=>{var e,t,r={\"./dist/compiled/@edge-runtime/cookies/index.js\"(e){\"use strict\";var t=Object.defineProperty,r=Object.getOwnPropertyDescriptor,n=Object.getOwnPropertyNames,a=Object.prototype.hasOwnProperty,i={},s={RequestCookies:()=>f,ResponseCookies:()=>p,parseCookie:()=>c,parseSetCookie:()=>u,stringifyCookie:()=>l};for(var o in s)t(i,o,{get:s[o],enumerable:!0});function l(e){var t;let r=[\"path\"in e&&e.path&&`Path=${e.path}`,\"expires\"in e&&(e.expires||0===e.expires)&&`Expires=${(\"number\"==typeof e.expires?new Date(e.expires):e.expires).toUTCString()}`,\"maxAge\"in e&&\"number\"==typeof e.maxAge&&`Max-Age=${e.maxAge}`,\"domain\"in e&&e.domain&&`Domain=${e.domain}`,\"secure\"in e&&e.secure&&\"Secure\",\"httpOnly\"in e&&e.httpOnly&&\"HttpOnly\",\"sameSite\"in e&&e.sameSite&&`SameSite=${e.sameSite}`,\"partitioned\"in e&&e.partitioned&&\"Partitioned\",\"priority\"in e&&e.priority&&`Priority=${e.priority}`].filter(Boolean),n=`${e.name}=${encodeURIComponent(null!=(t=e.value)?t:\"\")}`;return 0===r.length?n:`${n}; ${r.join(\"; \")}`}function c(e){let t=new Map;for(let r of e.split(/; */)){if(!r)continue;let e=r.indexOf(\"=\");if(-1===e){t.set(r,\"true\");continue}let[n,a]=[r.slice(0,e),r.slice(e+1)];try{t.set(n,decodeURIComponent(null!=a?a:\"true\"))}catch{}}return t}function u(e){if(!e)return;let[[t,r],...n]=c(e),{domain:a,expires:i,httponly:s,maxage:o,path:l,samesite:u,secure:f,partitioned:p,priority:m}=Object.fromEntries(n.map(([e,t])=>[e.toLowerCase().replace(/-/g,\"\"),t]));{var g,v,y={name:t,value:decodeURIComponent(r),domain:a,...i&&{expires:new Date(i)},...s&&{httpOnly:!0},...\"string\"==typeof o&&{maxAge:Number(o)},path:l,...u&&{sameSite:d.includes(g=(g=u).toLowerCase())?g:void 0},...f&&{secure:!0},...m&&{priority:h.includes(v=(v=m).toLowerCase())?v:void 0},...p&&{partitioned:!0}};let e={};for(let t in y)y[t]&&(e[t]=y[t]);return e}}e.exports=((e,i,s,o)=>{if(i&&\"object\"==typeof i||\"function\"==typeof i)for(let l of n(i))a.call(e,l)||l===s||t(e,l,{get:()=>i[l],enumerable:!(o=r(i,l))||o.enumerable});re...\n Line 5: Original Message: ${n}`);console.error(`Route ${t} errored during ${r}. These errors are normally ignored and may not prevent the route from prerendering but are logged here because build debugging is enabled. The thrown value is logged just following this message`),console.error(e)}}var r$=a(\"../../app-render/action-async-storage.external\");let rN=t7.createContext(null),rI=t7.createContext(null),rM=t7.createContext(null),rU=t7.createContext(null),rL=t7.createContext(new Set);var rF=a(\"./dist/compiled/@edge-runtime/cookies/index.js\"),rH=a(\"./dist/esm/server/web/spec-extension/adapters/reflect.js\");class rq{constructor(){this.count=0,this.earlyListeners=[],this.listeners=[],this.tickPending=!1,this.pendingTimeoutCleanup=null,this.subscribedSignals=null,this.invokeListenersIfNoPendingReads=()=>{if(this.pendingTimeoutCleanup=null,0===this.count){for(let e=0;eprocess.nextTick(()=>{if(this.tickPending=!1,0===this.count){for(let e=0;e{t=clearTimeout.bind(null,setTimeout(e,0))}),t=clearImmediate.bind(null,r),()=>t())}inputReady(){return new Promise(e=>{this.earlyListeners.push(e),0===this.count&&this.noMorePendingCaches()})}cacheReady(){return new Promise(e=>{this.listeners.push(e),0===this.count&&this.noMorePendingCaches()})}beginRead(){if(this.count++,this.pendingTimeoutCleanup&&(this.pendingTimeoutCleanup(),this.pendingTimeoutCleanup=null),null!==this.subscribedSignals)for(let e of this.subscribedSignals)e.beginRead()}endRead(){if(0===this.count)throw Object.defineProperty(new j.z(\"CacheSignal got more endRead() calls than beginRead() calls\"),\"__NEXT_ERROR_CODE\",{value:\"E678\",...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-route.runtime.dev.js:\n Line 1: (()=>{var leafPrototypes,getProto,__webpack_modules__={\"./dist/compiled/@edge-runtime/cookies/index.js\"(module1){\"use strict\";var __defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropNames=Object.getOwnPropertyNames,__hasOwnProp=Object.prototype.hasOwnProperty,src_exports={},all={RequestCookies:()=>RequestCookies,ResponseCookies:()=>ResponseCookies,parseCookie:()=>parseCookie,parseSetCookie:()=>parseSetCookie,stringifyCookie:()=>stringifyCookie};for(var name in all)__defProp(src_exports,name,{get:all[name],enumerable:!0});function stringifyCookie(c){var _a;let attrs=[\"path\"in c&&c.path&&`Path=${c.path}`,\"expires\"in c&&(c.expires||0===c.expires)&&`Expires=${(\"number\"==typeof c.expires?new Date(c.expires):c.expires).toUTCString()}`,\"maxAge\"in c&&\"number\"==typeof c.maxAge&&`Max-Age=${c.maxAge}`,\"domain\"in c&&c.domain&&`Domain=${c.domain}`,\"secure\"in c&&c.secure&&\"Secure\",\"httpOnly\"in c&&c.httpOnly&&\"HttpOnly\",\"sameSite\"in c&&c.sameSite&&`SameSite=${c.sameSite}`,\"partitioned\"in c&&c.partitioned&&\"Partitioned\",\"priority\"in c&&c.priority&&`Priority=${c.priority}`].filter(Boolean),stringified=`${c.name}=${encodeURIComponent(null!=(_a=c.value)?_a:\"\")}`;return 0===attrs.length?stringified:`${stringified}; ${attrs.join(\"; \")}`}function parseCookie(cookie){let map=new Map;for(let pair of cookie.split(/; */)){if(!pair)continue;let splitAt=pair.indexOf(\"=\");if(-1===splitAt){map.set(pair,\"true\");continue}let[key,value1]=[pair.slice(0,splitAt),pair.slice(splitAt+1)];try{map.set(key,decodeURIComponent(null!=value1?value1:\"true\"))}catch{}}return map}function parseSetCookie(setCookie){if(!setCookie)return;let[[name,value1],...attributes]=parseCookie(setCookie),{domain,expires,httponly,maxage,path,samesite,secure,partitioned,priority}=Object.fromEntries(attributes.map(([key,value2])=>[key.toLowerCase().replace(/-/g,\"\"),value2]));{var string,string1,t={name,value:decodeURIComponent(value1),domain,...expires&&{expires:new Date(expires)},...httponl...\n Line 5: Original Message: ${message}`);console.error(`Route ${route} errored during ${phase}. These errors are normally ignored and may not prevent the route from prerendering but are logged here because build debugging is enabled. The thrown value is logged just following this message`),console.error(thrownValue)}}var action_async_storage_external_js_=__webpack_require__(\"../../app-render/action-async-storage.external\");let AppRouterContext=react_default().createContext(null),LayoutRouterContext=react_default().createContext(null),GlobalLayoutRouterContext=react_default().createContext(null),TemplateContext=react_default().createContext(null);AppRouterContext.displayName=\"AppRouterContext\",LayoutRouterContext.displayName=\"LayoutRouterContext\",GlobalLayoutRouterContext.displayName=\"GlobalLayoutRouterContext\",TemplateContext.displayName=\"TemplateContext\";let MissingSlotContext=react_default().createContext(new Set);var _edge_runtime_cookies=__webpack_require__(\"./dist/compiled/@edge-runtime/cookies/index.js\"),reflect=__webpack_require__(\"./dist/esm/server/web/spec-extension/adapters/reflect.js\");class CacheSignal{constructor(){this.count=0,this.earlyListeners=[],this.listeners=[],this.tickPending=!1,this.pendingTimeoutCleanup=null,this.subscribedSignals=null,this.invokeListenersIfNoPendingReads=()=>{if(this.pendingTimeoutCleanup=null,0===this.count){for(let i=0;iprocess.nextTick(()=>{if(this.tickPending=!1,0===this.count){for(let i=0;i{clearPending=clearTimeout.bind(null,setTimeout(cb,0))}),clearPending=clearImmediate.bind(null,immediate),()=>clearPendi...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-route-turbo.runtime.prod.js:\n Line 1: (()=>{var e,t,r={\"./dist/compiled/@edge-runtime/cookies/index.js\"(e){\"use strict\";var t=Object.defineProperty,r=Object.getOwnPropertyDescriptor,n=Object.getOwnPropertyNames,a=Object.prototype.hasOwnProperty,i={},s={RequestCookies:()=>f,ResponseCookies:()=>p,parseCookie:()=>c,parseSetCookie:()=>u,stringifyCookie:()=>l};for(var o in s)t(i,o,{get:s[o],enumerable:!0});function l(e){var t;let r=[\"path\"in e&&e.path&&`Path=${e.path}`,\"expires\"in e&&(e.expires||0===e.expires)&&`Expires=${(\"number\"==typeof e.expires?new Date(e.expires):e.expires).toUTCString()}`,\"maxAge\"in e&&\"number\"==typeof e.maxAge&&`Max-Age=${e.maxAge}`,\"domain\"in e&&e.domain&&`Domain=${e.domain}`,\"secure\"in e&&e.secure&&\"Secure\",\"httpOnly\"in e&&e.httpOnly&&\"HttpOnly\",\"sameSite\"in e&&e.sameSite&&`SameSite=${e.sameSite}`,\"partitioned\"in e&&e.partitioned&&\"Partitioned\",\"priority\"in e&&e.priority&&`Priority=${e.priority}`].filter(Boolean),n=`${e.name}=${encodeURIComponent(null!=(t=e.value)?t:\"\")}`;return 0===r.length?n:`${n}; ${r.join(\"; \")}`}function c(e){let t=new Map;for(let r of e.split(/; */)){if(!r)continue;let e=r.indexOf(\"=\");if(-1===e){t.set(r,\"true\");continue}let[n,a]=[r.slice(0,e),r.slice(e+1)];try{t.set(n,decodeURIComponent(null!=a?a:\"true\"))}catch{}}return t}function u(e){if(!e)return;let[[t,r],...n]=c(e),{domain:a,expires:i,httponly:s,maxage:o,path:l,samesite:u,secure:f,partitioned:p,priority:m}=Object.fromEntries(n.map(([e,t])=>[e.toLowerCase().replace(/-/g,\"\"),t]));{var g,v,y={name:t,value:decodeURIComponent(r),domain:a,...i&&{expires:new Date(i)},...s&&{httpOnly:!0},...\"string\"==typeof o&&{maxAge:Number(o)},path:l,...u&&{sameSite:d.includes(g=(g=u).toLowerCase())?g:void 0},...f&&{secure:!0},...m&&{priority:h.includes(v=(v=m).toLowerCase())?v:void 0},...p&&{partitioned:!0}};let e={};for(let t in y)y[t]&&(e[t]=y[t]);return e}}e.exports=((e,i,s,o)=>{if(i&&\"object\"==typeof i||\"function\"==typeof i)for(let l of n(i))a.call(e,l)||l===s||t(e,l,{get:()=>i[l],enumerable:!(o=r(i,l))||o.enumerable});re...\n Line 5: Original Message: ${n}`);console.error(`Route ${t} errored during ${r}. These errors are normally ignored and may not prevent the route from prerendering but are logged here because build debugging is enabled. The thrown value is logged just following this message`),console.error(e)}}var r$=a(\"../../app-render/action-async-storage.external\");let rN=t7.createContext(null),rI=t7.createContext(null),rM=t7.createContext(null),rU=t7.createContext(null),rL=t7.createContext(new Set);var rF=a(\"./dist/compiled/@edge-runtime/cookies/index.js\"),rH=a(\"./dist/esm/server/web/spec-extension/adapters/reflect.js\");class rq{constructor(){this.count=0,this.earlyListeners=[],this.listeners=[],this.tickPending=!1,this.pendingTimeoutCleanup=null,this.subscribedSignals=null,this.invokeListenersIfNoPendingReads=()=>{if(this.pendingTimeoutCleanup=null,0===this.count){for(let e=0;eprocess.nextTick(()=>{if(this.tickPending=!1,0===this.count){for(let e=0;e{t=clearTimeout.bind(null,setTimeout(e,0))}),t=clearImmediate.bind(null,r),()=>t())}inputReady(){return new Promise(e=>{this.earlyListeners.push(e),0===this.count&&this.noMorePendingCaches()})}cacheReady(){return new Promise(e=>{this.listeners.push(e),0===this.count&&this.noMorePendingCaches()})}beginRead(){if(this.count++,this.pendingTimeoutCleanup&&(this.pendingTimeoutCleanup(),this.pendingTimeoutCleanup=null),null!==this.subscribedSignals)for(let e of this.subscribedSignals)e.beginRead()}endRead(){if(0===this.count)throw Object.defineProperty(new j.z(\"CacheSignal got more endRead() calls than beginRead() calls\"),\"__NEXT_ERROR_CODE\",{value:\"E678\",...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-route-turbo.runtime.dev.js:\n Line 1: (()=>{var leafPrototypes,getProto,__webpack_modules__={\"./dist/compiled/@edge-runtime/cookies/index.js\"(module1){\"use strict\";var __defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropNames=Object.getOwnPropertyNames,__hasOwnProp=Object.prototype.hasOwnProperty,src_exports={},all={RequestCookies:()=>RequestCookies,ResponseCookies:()=>ResponseCookies,parseCookie:()=>parseCookie,parseSetCookie:()=>parseSetCookie,stringifyCookie:()=>stringifyCookie};for(var name in all)__defProp(src_exports,name,{get:all[name],enumerable:!0});function stringifyCookie(c){var _a;let attrs=[\"path\"in c&&c.path&&`Path=${c.path}`,\"expires\"in c&&(c.expires||0===c.expires)&&`Expires=${(\"number\"==typeof c.expires?new Date(c.expires):c.expires).toUTCString()}`,\"maxAge\"in c&&\"number\"==typeof c.maxAge&&`Max-Age=${c.maxAge}`,\"domain\"in c&&c.domain&&`Domain=${c.domain}`,\"secure\"in c&&c.secure&&\"Secure\",\"httpOnly\"in c&&c.httpOnly&&\"HttpOnly\",\"sameSite\"in c&&c.sameSite&&`SameSite=${c.sameSite}`,\"partitioned\"in c&&c.partitioned&&\"Partitioned\",\"priority\"in c&&c.priority&&`Priority=${c.priority}`].filter(Boolean),stringified=`${c.name}=${encodeURIComponent(null!=(_a=c.value)?_a:\"\")}`;return 0===attrs.length?stringified:`${stringified}; ${attrs.join(\"; \")}`}function parseCookie(cookie){let map=new Map;for(let pair of cookie.split(/; */)){if(!pair)continue;let splitAt=pair.indexOf(\"=\");if(-1===splitAt){map.set(pair,\"true\");continue}let[key,value1]=[pair.slice(0,splitAt),pair.slice(splitAt+1)];try{map.set(key,decodeURIComponent(null!=value1?value1:\"true\"))}catch{}}return map}function parseSetCookie(setCookie){if(!setCookie)return;let[[name,value1],...attributes]=parseCookie(setCookie),{domain,expires,httponly,maxage,path,samesite,secure,partitioned,priority}=Object.fromEntries(attributes.map(([key,value2])=>[key.toLowerCase().replace(/-/g,\"\"),value2]));{var string,string1,t={name,value:decodeURIComponent(value1),domain,...expires&&{expires:new Date(expires)},...httponl...\n Line 5: Original Message: ${message}`);console.error(`Route ${route} errored during ${phase}. These errors are normally ignored and may not prevent the route from prerendering but are logged here because build debugging is enabled. The thrown value is logged just following this message`),console.error(thrownValue)}}var action_async_storage_external_js_=__webpack_require__(\"../../app-render/action-async-storage.external\");let AppRouterContext=react_default().createContext(null),LayoutRouterContext=react_default().createContext(null),GlobalLayoutRouterContext=react_default().createContext(null),TemplateContext=react_default().createContext(null);AppRouterContext.displayName=\"AppRouterContext\",LayoutRouterContext.displayName=\"LayoutRouterContext\",GlobalLayoutRouterContext.displayName=\"GlobalLayoutRouterContext\",TemplateContext.displayName=\"TemplateContext\";let MissingSlotContext=react_default().createContext(new Set);var _edge_runtime_cookies=__webpack_require__(\"./dist/compiled/@edge-runtime/cookies/index.js\"),reflect=__webpack_require__(\"./dist/esm/server/web/spec-extension/adapters/reflect.js\");class CacheSignal{constructor(){this.count=0,this.earlyListeners=[],this.listeners=[],this.tickPending=!1,this.pendingTimeoutCleanup=null,this.subscribedSignals=null,this.invokeListenersIfNoPendingReads=()=>{if(this.pendingTimeoutCleanup=null,0===this.count){for(let i=0;iprocess.nextTick(()=>{if(this.tickPending=!1,0===this.count){for(let i=0;i{clearPending=clearTimeout.bind(null,setTimeout(cb,0))}),clearPending=clearImmediate.bind(null,immediate),()=>clearPendi...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-route-turbo-experimental.runtime.prod.js:\n Line 1: (()=>{var e,t,r={\"./dist/compiled/@edge-runtime/cookies/index.js\"(e){\"use strict\";var t=Object.defineProperty,r=Object.getOwnPropertyDescriptor,n=Object.getOwnPropertyNames,a=Object.prototype.hasOwnProperty,i={},s={RequestCookies:()=>f,ResponseCookies:()=>p,parseCookie:()=>c,parseSetCookie:()=>u,stringifyCookie:()=>l};for(var o in s)t(i,o,{get:s[o],enumerable:!0});function l(e){var t;let r=[\"path\"in e&&e.path&&`Path=${e.path}`,\"expires\"in e&&(e.expires||0===e.expires)&&`Expires=${(\"number\"==typeof e.expires?new Date(e.expires):e.expires).toUTCString()}`,\"maxAge\"in e&&\"number\"==typeof e.maxAge&&`Max-Age=${e.maxAge}`,\"domain\"in e&&e.domain&&`Domain=${e.domain}`,\"secure\"in e&&e.secure&&\"Secure\",\"httpOnly\"in e&&e.httpOnly&&\"HttpOnly\",\"sameSite\"in e&&e.sameSite&&`SameSite=${e.sameSite}`,\"partitioned\"in e&&e.partitioned&&\"Partitioned\",\"priority\"in e&&e.priority&&`Priority=${e.priority}`].filter(Boolean),n=`${e.name}=${encodeURIComponent(null!=(t=e.value)?t:\"\")}`;return 0===r.length?n:`${n}; ${r.join(\"; \")}`}function c(e){let t=new Map;for(let r of e.split(/; */)){if(!r)continue;let e=r.indexOf(\"=\");if(-1===e){t.set(r,\"true\");continue}let[n,a]=[r.slice(0,e),r.slice(e+1)];try{t.set(n,decodeURIComponent(null!=a?a:\"true\"))}catch{}}return t}function u(e){if(!e)return;let[[t,r],...n]=c(e),{domain:a,expires:i,httponly:s,maxage:o,path:l,samesite:u,secure:f,partitioned:p,priority:m}=Object.fromEntries(n.map(([e,t])=>[e.toLowerCase().replace(/-/g,\"\"),t]));{var g,v,y={name:t,value:decodeURIComponent(r),domain:a,...i&&{expires:new Date(i)},...s&&{httpOnly:!0},...\"string\"==typeof o&&{maxAge:Number(o)},path:l,...u&&{sameSite:d.includes(g=(g=u).toLowerCase())?g:void 0},...f&&{secure:!0},...m&&{priority:h.includes(v=(v=m).toLowerCase())?v:void 0},...p&&{partitioned:!0}};let e={};for(let t in y)y[t]&&(e[t]=y[t]);return e}}e.exports=((e,i,s,o)=>{if(i&&\"object\"==typeof i||\"function\"==typeof i)for(let l of n(i))a.call(e,l)||l===s||t(e,l,{get:()=>i[l],enumerable:!(o=r(i,l))||o.enumerable});re...\n Line 5: Original Message: ${n}`);console.error(`Route ${t} errored during ${r}. These errors are normally ignored and may not prevent the route from prerendering but are logged here because build debugging is enabled. The thrown value is logged just following this message`),console.error(e)}}var r$=a(\"../../app-render/action-async-storage.external\");let rN=t7.createContext(null),rI=t7.createContext(null),rM=t7.createContext(null),rU=t7.createContext(null),rL=t7.createContext(new Set);var rF=a(\"./dist/compiled/@edge-runtime/cookies/index.js\"),rH=a(\"./dist/esm/server/web/spec-extension/adapters/reflect.js\");class rq{constructor(){this.count=0,this.earlyListeners=[],this.listeners=[],this.tickPending=!1,this.pendingTimeoutCleanup=null,this.subscribedSignals=null,this.invokeListenersIfNoPendingReads=()=>{if(this.pendingTimeoutCleanup=null,0===this.count){for(let e=0;eprocess.nextTick(()=>{if(this.tickPending=!1,0===this.count){for(let e=0;e{t=clearTimeout.bind(null,setTimeout(e,0))}),t=clearImmediate.bind(null,r),()=>t())}inputReady(){return new Promise(e=>{this.earlyListeners.push(e),0===this.count&&this.noMorePendingCaches()})}cacheReady(){return new Promise(e=>{this.listeners.push(e),0===this.count&&this.noMorePendingCaches()})}beginRead(){if(this.count++,this.pendingTimeoutCleanup&&(this.pendingTimeoutCleanup(),this.pendingTimeoutCleanup=null),null!==this.subscribedSignals)for(let e of this.subscribedSignals)e.beginRead()}endRead(){if(0===this.count)throw Object.defineProperty(new j.z(\"CacheSignal got more endRead() calls than beginRead() calls\"),\"__NEXT_ERROR_CODE\",{value:\"E678\",...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-route-turbo-experimental.runtime.dev.js:\n Line 1: (()=>{var leafPrototypes,getProto,__webpack_modules__={\"./dist/compiled/@edge-runtime/cookies/index.js\"(module1){\"use strict\";var __defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropNames=Object.getOwnPropertyNames,__hasOwnProp=Object.prototype.hasOwnProperty,src_exports={},all={RequestCookies:()=>RequestCookies,ResponseCookies:()=>ResponseCookies,parseCookie:()=>parseCookie,parseSetCookie:()=>parseSetCookie,stringifyCookie:()=>stringifyCookie};for(var name in all)__defProp(src_exports,name,{get:all[name],enumerable:!0});function stringifyCookie(c){var _a;let attrs=[\"path\"in c&&c.path&&`Path=${c.path}`,\"expires\"in c&&(c.expires||0===c.expires)&&`Expires=${(\"number\"==typeof c.expires?new Date(c.expires):c.expires).toUTCString()}`,\"maxAge\"in c&&\"number\"==typeof c.maxAge&&`Max-Age=${c.maxAge}`,\"domain\"in c&&c.domain&&`Domain=${c.domain}`,\"secure\"in c&&c.secure&&\"Secure\",\"httpOnly\"in c&&c.httpOnly&&\"HttpOnly\",\"sameSite\"in c&&c.sameSite&&`SameSite=${c.sameSite}`,\"partitioned\"in c&&c.partitioned&&\"Partitioned\",\"priority\"in c&&c.priority&&`Priority=${c.priority}`].filter(Boolean),stringified=`${c.name}=${encodeURIComponent(null!=(_a=c.value)?_a:\"\")}`;return 0===attrs.length?stringified:`${stringified}; ${attrs.join(\"; \")}`}function parseCookie(cookie){let map=new Map;for(let pair of cookie.split(/; */)){if(!pair)continue;let splitAt=pair.indexOf(\"=\");if(-1===splitAt){map.set(pair,\"true\");continue}let[key,value1]=[pair.slice(0,splitAt),pair.slice(splitAt+1)];try{map.set(key,decodeURIComponent(null!=value1?value1:\"true\"))}catch{}}return map}function parseSetCookie(setCookie){if(!setCookie)return;let[[name,value1],...attributes]=parseCookie(setCookie),{domain,expires,httponly,maxage,path,samesite,secure,partitioned,priority}=Object.fromEntries(attributes.map(([key,value2])=>[key.toLowerCase().replace(/-/g,\"\"),value2]));{var string,string1,t={name,value:decodeURIComponent(value1),domain,...expires&&{expires:new Date(expires)},...httponl...\n Line 5: Original Message: ${message}`);console.error(`Route ${route} errored during ${phase}. These errors are normally ignored and may not prevent the route from prerendering but are logged here because build debugging is enabled. The thrown value is logged just following this message`),console.error(thrownValue)}}var action_async_storage_external_js_=__webpack_require__(\"../../app-render/action-async-storage.external\");let AppRouterContext=react_experimental_default().createContext(null),LayoutRouterContext=react_experimental_default().createContext(null),GlobalLayoutRouterContext=react_experimental_default().createContext(null),TemplateContext=react_experimental_default().createContext(null);AppRouterContext.displayName=\"AppRouterContext\",LayoutRouterContext.displayName=\"LayoutRouterContext\",GlobalLayoutRouterContext.displayName=\"GlobalLayoutRouterContext\",TemplateContext.displayName=\"TemplateContext\";let MissingSlotContext=react_experimental_default().createContext(new Set);var _edge_runtime_cookies=__webpack_require__(\"./dist/compiled/@edge-runtime/cookies/index.js\"),reflect=__webpack_require__(\"./dist/esm/server/web/spec-extension/adapters/reflect.js\");class CacheSignal{constructor(){this.count=0,this.earlyListeners=[],this.listeners=[],this.tickPending=!1,this.pendingTimeoutCleanup=null,this.subscribedSignals=null,this.invokeListenersIfNoPendingReads=()=>{if(this.pendingTimeoutCleanup=null,0===this.count){for(let i=0;iprocess.nextTick(()=>{if(this.tickPending=!1,0===this.count){for(let i=0;i{clearPending=clearTimeout.bind(null,setTimeout(cb,0))}...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-route-experimental.runtime.prod.js:\n Line 1: (()=>{var e,t,r={\"./dist/compiled/@edge-runtime/cookies/index.js\"(e){\"use strict\";var t=Object.defineProperty,r=Object.getOwnPropertyDescriptor,n=Object.getOwnPropertyNames,a=Object.prototype.hasOwnProperty,i={},s={RequestCookies:()=>f,ResponseCookies:()=>p,parseCookie:()=>c,parseSetCookie:()=>u,stringifyCookie:()=>l};for(var o in s)t(i,o,{get:s[o],enumerable:!0});function l(e){var t;let r=[\"path\"in e&&e.path&&`Path=${e.path}`,\"expires\"in e&&(e.expires||0===e.expires)&&`Expires=${(\"number\"==typeof e.expires?new Date(e.expires):e.expires).toUTCString()}`,\"maxAge\"in e&&\"number\"==typeof e.maxAge&&`Max-Age=${e.maxAge}`,\"domain\"in e&&e.domain&&`Domain=${e.domain}`,\"secure\"in e&&e.secure&&\"Secure\",\"httpOnly\"in e&&e.httpOnly&&\"HttpOnly\",\"sameSite\"in e&&e.sameSite&&`SameSite=${e.sameSite}`,\"partitioned\"in e&&e.partitioned&&\"Partitioned\",\"priority\"in e&&e.priority&&`Priority=${e.priority}`].filter(Boolean),n=`${e.name}=${encodeURIComponent(null!=(t=e.value)?t:\"\")}`;return 0===r.length?n:`${n}; ${r.join(\"; \")}`}function c(e){let t=new Map;for(let r of e.split(/; */)){if(!r)continue;let e=r.indexOf(\"=\");if(-1===e){t.set(r,\"true\");continue}let[n,a]=[r.slice(0,e),r.slice(e+1)];try{t.set(n,decodeURIComponent(null!=a?a:\"true\"))}catch{}}return t}function u(e){if(!e)return;let[[t,r],...n]=c(e),{domain:a,expires:i,httponly:s,maxage:o,path:l,samesite:u,secure:f,partitioned:p,priority:m}=Object.fromEntries(n.map(([e,t])=>[e.toLowerCase().replace(/-/g,\"\"),t]));{var g,v,y={name:t,value:decodeURIComponent(r),domain:a,...i&&{expires:new Date(i)},...s&&{httpOnly:!0},...\"string\"==typeof o&&{maxAge:Number(o)},path:l,...u&&{sameSite:d.includes(g=(g=u).toLowerCase())?g:void 0},...f&&{secure:!0},...m&&{priority:h.includes(v=(v=m).toLowerCase())?v:void 0},...p&&{partitioned:!0}};let e={};for(let t in y)y[t]&&(e[t]=y[t]);return e}}e.exports=((e,i,s,o)=>{if(i&&\"object\"==typeof i||\"function\"==typeof i)for(let l of n(i))a.call(e,l)||l===s||t(e,l,{get:()=>i[l],enumerable:!(o=r(i,l))||o.enumerable});re...\n Line 5: Original Message: ${n}`);console.error(`Route ${t} errored during ${r}. These errors are normally ignored and may not prevent the route from prerendering but are logged here because build debugging is enabled. The thrown value is logged just following this message`),console.error(e)}}var r$=a(\"../../app-render/action-async-storage.external\");let rN=t7.createContext(null),rI=t7.createContext(null),rM=t7.createContext(null),rU=t7.createContext(null),rL=t7.createContext(new Set);var rF=a(\"./dist/compiled/@edge-runtime/cookies/index.js\"),rH=a(\"./dist/esm/server/web/spec-extension/adapters/reflect.js\");class rq{constructor(){this.count=0,this.earlyListeners=[],this.listeners=[],this.tickPending=!1,this.pendingTimeoutCleanup=null,this.subscribedSignals=null,this.invokeListenersIfNoPendingReads=()=>{if(this.pendingTimeoutCleanup=null,0===this.count){for(let e=0;eprocess.nextTick(()=>{if(this.tickPending=!1,0===this.count){for(let e=0;e{t=clearTimeout.bind(null,setTimeout(e,0))}),t=clearImmediate.bind(null,r),()=>t())}inputReady(){return new Promise(e=>{this.earlyListeners.push(e),0===this.count&&this.noMorePendingCaches()})}cacheReady(){return new Promise(e=>{this.listeners.push(e),0===this.count&&this.noMorePendingCaches()})}beginRead(){if(this.count++,this.pendingTimeoutCleanup&&(this.pendingTimeoutCleanup(),this.pendingTimeoutCleanup=null),null!==this.subscribedSignals)for(let e of this.subscribedSignals)e.beginRead()}endRead(){if(0===this.count)throw Object.defineProperty(new j.z(\"CacheSignal got more endRead() calls than beginRead() calls\"),\"__NEXT_ERROR_CODE\",{value:\"E678\",...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-route-experimental.runtime.dev.js:\n Line 1: (()=>{var leafPrototypes,getProto,__webpack_modules__={\"./dist/compiled/@edge-runtime/cookies/index.js\"(module1){\"use strict\";var __defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropNames=Object.getOwnPropertyNames,__hasOwnProp=Object.prototype.hasOwnProperty,src_exports={},all={RequestCookies:()=>RequestCookies,ResponseCookies:()=>ResponseCookies,parseCookie:()=>parseCookie,parseSetCookie:()=>parseSetCookie,stringifyCookie:()=>stringifyCookie};for(var name in all)__defProp(src_exports,name,{get:all[name],enumerable:!0});function stringifyCookie(c){var _a;let attrs=[\"path\"in c&&c.path&&`Path=${c.path}`,\"expires\"in c&&(c.expires||0===c.expires)&&`Expires=${(\"number\"==typeof c.expires?new Date(c.expires):c.expires).toUTCString()}`,\"maxAge\"in c&&\"number\"==typeof c.maxAge&&`Max-Age=${c.maxAge}`,\"domain\"in c&&c.domain&&`Domain=${c.domain}`,\"secure\"in c&&c.secure&&\"Secure\",\"httpOnly\"in c&&c.httpOnly&&\"HttpOnly\",\"sameSite\"in c&&c.sameSite&&`SameSite=${c.sameSite}`,\"partitioned\"in c&&c.partitioned&&\"Partitioned\",\"priority\"in c&&c.priority&&`Priority=${c.priority}`].filter(Boolean),stringified=`${c.name}=${encodeURIComponent(null!=(_a=c.value)?_a:\"\")}`;return 0===attrs.length?stringified:`${stringified}; ${attrs.join(\"; \")}`}function parseCookie(cookie){let map=new Map;for(let pair of cookie.split(/; */)){if(!pair)continue;let splitAt=pair.indexOf(\"=\");if(-1===splitAt){map.set(pair,\"true\");continue}let[key,value1]=[pair.slice(0,splitAt),pair.slice(splitAt+1)];try{map.set(key,decodeURIComponent(null!=value1?value1:\"true\"))}catch{}}return map}function parseSetCookie(setCookie){if(!setCookie)return;let[[name,value1],...attributes]=parseCookie(setCookie),{domain,expires,httponly,maxage,path,samesite,secure,partitioned,priority}=Object.fromEntries(attributes.map(([key,value2])=>[key.toLowerCase().replace(/-/g,\"\"),value2]));{var string,string1,t={name,value:decodeURIComponent(value1),domain,...expires&&{expires:new Date(expires)},...httponl...\n Line 5: Original Message: ${message}`);console.error(`Route ${route} errored during ${phase}. These errors are normally ignored and may not prevent the route from prerendering but are logged here because build debugging is enabled. The thrown value is logged just following this message`),console.error(thrownValue)}}var action_async_storage_external_js_=__webpack_require__(\"../../app-render/action-async-storage.external\");let AppRouterContext=react_experimental_default().createContext(null),LayoutRouterContext=react_experimental_default().createContext(null),GlobalLayoutRouterContext=react_experimental_default().createContext(null),TemplateContext=react_experimental_default().createContext(null);AppRouterContext.displayName=\"AppRouterContext\",LayoutRouterContext.displayName=\"LayoutRouterContext\",GlobalLayoutRouterContext.displayName=\"GlobalLayoutRouterContext\",TemplateContext.displayName=\"TemplateContext\";let MissingSlotContext=react_experimental_default().createContext(new Set);var _edge_runtime_cookies=__webpack_require__(\"./dist/compiled/@edge-runtime/cookies/index.js\"),reflect=__webpack_require__(\"./dist/esm/server/web/spec-extension/adapters/reflect.js\");class CacheSignal{constructor(){this.count=0,this.earlyListeners=[],this.listeners=[],this.tickPending=!1,this.pendingTimeoutCleanup=null,this.subscribedSignals=null,this.invokeListenersIfNoPendingReads=()=>{if(this.pendingTimeoutCleanup=null,0===this.count){for(let i=0;iprocess.nextTick(()=>{if(this.tickPending=!1,0===this.count){for(let i=0;i{clearPending=clearTimeout.bind(null,setTimeout(cb,0))}...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js:\n Line 1: (()=>{var e,t,r={\"./dist/build/webpack/alias/react-dom-server.js\"(e,t,r){\"use strict\";var n;function a(){throw Object.defineProperty(Error(\"Internal Error: do not use legacy react-dom/server APIs. If you encountered this error, please open an issue on the Next.js repo.\"),\"__NEXT_ERROR_CODE\",{value:\"E1021\",enumerable:!1,configurable:!0})}t.version=(n=r(\"./dist/compiled/react-dom/cjs/react-dom-server.node.production.js\")).version,t.renderToReadableStream=n.renderToReadableStream,t.renderToString=a,t.renderToStaticMarkup=a,n.resume&&(t.resume=n.resume),n.renderToPipeableStream&&(t.renderToPipeableStream=n.renderToPipeableStream),n.resumeToPipeableStream&&(t.resumeToPipeableStream=n.resumeToPipeableStream)},\"./dist/compiled/@edge-runtime/cookies/index.js\"(e){\"use strict\";var t=Object.defineProperty,r=Object.getOwnPropertyDescriptor,n=Object.getOwnPropertyNames,a=Object.prototype.hasOwnProperty,i={},s={RequestCookies:()=>h,ResponseCookies:()=>p,parseCookie:()=>u,parseSetCookie:()=>c,stringifyCookie:()=>l};for(var o in s)t(i,o,{get:s[o],enumerable:!0});function l(e){var t;let r=[\"path\"in e&&e.path&&`Path=${e.path}`,\"expires\"in e&&(e.expires||0===e.expires)&&`Expires=${(\"number\"==typeof e.expires?new Date(e.expires):e.expires).toUTCString()}`,\"maxAge\"in e&&\"number\"==typeof e.maxAge&&`Max-Age=${e.maxAge}`,\"domain\"in e&&e.domain&&`Domain=${e.domain}`,\"secure\"in e&&e.secure&&\"Secure\",\"httpOnly\"in e&&e.httpOnly&&\"HttpOnly\",\"sameSite\"in e&&e.sameSite&&`SameSite=${e.sameSite}`,\"partitioned\"in e&&e.partitioned&&\"Partitioned\",\"priority\"in e&&e.priority&&`Priority=${e.priority}`].filter(Boolean),n=`${e.name}=${encodeURIComponent(null!=(t=e.value)?t:\"\")}`;return 0===r.length?n:`${n}; ${r.join(\"; \")}`}function u(e){let t=new Map;for(let r of e.split(/; */)){if(!r)continue;let e=r.indexOf(\"=\");if(-1===e){t.set(r,\"true\");continue}let[n,a]=[r.slice(0,e),r.slice(e+1)];try{t.set(n,decodeURIComponent(null!=a?a:\"true\"))}catch{}}return t}function c(e){if(!e)return;let[[t,r],...n]=u(e),{domai...\n Line 2: --${w}`,B),this._writecb=null,this._finalcb=null,this.write(d)}static detect(e){return\"multipart\"===e.type&&\"form-data\"===e.subtype}_write(e,t,r){let n;this._writecb=r,this._bparser.push(e,0),this._writecb&&(n=this._writecb,this._writecb=null,n&&n())}_destroy(e,t){this._hparser=null,this._bparser=y,e||(e=w(this));let r=this._fileStream;r&&(this._fileStream=null,r.destroy(e)),t(e)}_final(e){if(this._bparser.destroy(),!this._complete)return e(Error(\"Unexpected end of form\"));this._fileEndsLeft?this._finalcb=b.bind(null,this,e):b(this,e)}}},183:function(e,t,r){let{Writable:n}=r(203),{getDecoder:a}=r(827);function i(e,t,r,n){if(r>=n)return n;if(-1===e._byte){let a=l[t[r++]];if(-1===a)return -1;if(a>=8&&(e._encode=2),re.fieldNameSizeLimit){for(!e._keyTrunc&&e._lastPose.fieldSizeLimit){for(!e._valTrunc&&e._lastPos{let a=t.bind(null,n),i=c.get(r);if(i)i.push(a);else{let e=[a];c.set(r,e),r.addEventListener(\"abort\",()=>{for(let t=0;ti});var n=r(\"./dist/esm/server/lib/lru-cache.js\"),a=r(\"./tags-manifest.external\");function i(e){if(0===e)return{get:()=>Promise.resolve(void 0),set:()=>Promise.resolve(),refreshTags:()=>Promise.resolve(),getExpiration:()=>Promise.resolve(0),updateTags:()=>Promise.resolve()};let t=new n.q(e,e=>e.size),r=new Map,i=process.env.NEXT_PRIVATE_DEBUG_CACHE?console.debug.bind(console,\"DefaultCacheHandler:\"):void 0;return{async get(e){let n=r.get(e);n&&(null==i||i(\"get\",e,\"pending\"),await n);let s=t.get(e);if(!s){null==i||i(\"get\",e,\"not found\");return}let o=s.entry,l=o.revalidate;if(performance.timeOrigin+performance.now()>o.timestamp+1e3*l){null==i||i(\"get\",e,\"expired\");return}let u=o.revalidate;if((0,a.areTagsExpired)(o.tags,o.timestamp)){null==i||i(\"get\",e,\"had expired tag\");return}(0,a.areTagsStale)(o.tags,o.timestamp)&&(null==i||i(\"get\",e,\"had...\n Line 127: Read more: https://nextjs.org/docs/messages/failed-to-find-server-action`),\"__NEXT_ERROR_CODE\",{value:\"E974\",enumerable:!1,configurable:!0})}let t2=\"$ACTION_\",t3=\"$ACTION_REF_\",t4=\"$ACTION_ID_\",t8='{\"id\":\"',t6=P.createContext(null);function t9(e){let t=(0,P.useContext)(t6);t&&t(e)}function t7(){let e=[],t=t=>{e.push(t)};return{ServerInsertedHTMLProvider:({children:e})=>(0,R.jsx)(t6.Provider,{value:t,children:e}),renderServerInsertedHTML:()=>e.map((e,t)=>(0,R.jsx)(P.Fragment,{children:e()},\"__next_server_inserted__\"+t))}}function t5(e){return e.split(\"/\").map(e=>encodeURIComponent(e)).join(\"/\")}var re=a(\"./dist/compiled/react-dom/index.js\");function rt(e,t,r,n,a,i,s){var o;let l,u=[],c={src:\"\",crossOrigin:r},d=((null==(o=e.rootMainFilesTree)?void 0:o[s])||e.rootMainFiles).map(t5);if(0===d.length)throw Object.defineProperty(Error(\"Invariant: missing bootstrap script. This is a bug in Next.js\"),\"__NEXT_ERROR_CODE\",{value:\"E459\",enumerable:!1,configurable:!0});if(n){c.src=`${t}/_next/`+d[0]+a,c.integrity=n[d[0]];for(let e=1;e{for(let e=0;e{for(let e=0;e(0,R.jsx)(\"script\",{...e},e.src)),o=(n||[]).map(({key:e,value:t},r)=>(0,R.jsx)(\"meta\",{name:e,content:t},`next-trace-data-${r}`));return async function(){let e=[];for(;i{let a,i=function(e=0){{let n=!0,a=null,i=!1,s=!1;function t(e){return i=!0,aT&&(0,aC.unpatchedSetImmediate)(()=>{s=!0}),e()}function r(e){return aT&&s&&(aT=!1,aA()),e()}return function(s){if(i)throw Object.defineProperty(new ei.z(\"Cannot schedule more timers into a group that already executed\"),\"__NEXT_ERROR_CODE\",{value:\"E935\",enumerable:!1,configurable:!0});let o=setTimeout(n?t:r,e,s);if(n=!1,!aT)return o;try{\"_idleStart\"in o&&\"number\"==typeof o._idleStart?null===a?a=o._idleStart:o._idleStart=a:(aT=!1,aA())}catch(e){console.error(Object.defineProperty(new ei.z(\"An unexpected error occurred while adjusting `_idleStart` on an atomic timer\",{cause:e}),\"__NEXT_ERROR_CODE\",{value:\"E933\",enumerable:!1,configurable:!0})),aT=!1,aA()}return o}}}(),s=[];s.push(i(()=>{try{(0,aC.DANGEROUSLY_runPendingImmediatesAfterCurrentTask)(),a=e(),(0,nJ.Q)(a)&&a.then(aO,aO)}catch(e){for(let e=1;e{try{(0,aC.DANGEROUSLY_runPendingImmediatesAfterCurrentTask)(),r()}catch(e){for(;++a{try{(0,aC.expectNoPendingImmediates)(),r(a)}catch(e){n(e)}}))})}let aD=require(\"next/dist/server/app-render/console-async-storage.external.js\");class aI{constructor(){this.count=0,t...\n Line 162: ${e}`),V(m),m}if((0,eB.RM)(m))r.statusCode=(0,eB.jT)(m),l.statusCode=r.statusCode,t=(0,eB.qe)(r.statusCode);else if((0,ez.n)(m)){t=\"redirect\",r.statusCode=eV(m),l.statusCode=r.statusCode;let n=I(eq(m),v),a=new Headers;(0,ej.IN)(a,e.mutableCookies)&&J(\"set-cookie\",Array.from(a.values())),J(\"location\",n)}else s||(r.statusCode=500,l.statusCode=r.statusCode);let[u,f]=rt(b,d,S,O,rd(n,!1),h,\"/_not-found/page\");{let r,s;try{if(r=await tB.workUnitAsyncStorage.run(e,iO,a,n,c.has(m.digest)?null:m,t,!0),s=tB.workUnitAsyncStorage.run(e,eS,n.componentMod,r,Y,{filterStackFrame:o,onError:w}),null===G)throw V(m),m}catch(e){throw V(e),e}try{let t=!0!==j||!!A,{stream:r,allReady:a}=await tB.workUnitAsyncStorage.run(e,eE,(0,R.jsx)(iD,{reactServerStream:s,ServerInsertedHTMLProvider:M,preinitScripts:u,nonce:h,images:n.renderOpts.images}),{nonce:h,bootstrapScriptContent:q,bootstrapScripts:[f],formState:i},{waitForAllReady:t});return a.finally(()=>{X.isRecording()&&X.end()}),await el(r,{inlinedDataStream:ey(G.consume(),h,i),isStaticGeneration:t,deploymentId:n.sharedContext.deploymentId,getServerInsertedHTML:rr({polyfills:H,renderServerInsertedHTML:L,serverCapturedErrors:[],basePath:v,tracingMetadata:F}),getServerInsertedMetadata:U,validateRootLayout:!1})}catch(e){throw V(e),e}}}})}function iL(){return{shellStaticChunks:[],staticChunks:[],shellRuntimeChunks:[],runtimeChunks:[],dynamicChunks:[]}}async function iU(e,t,r){let n=iL();return await iF(n,e,t,r),n}async function iF(e,t,r,n){if(t instanceof ReadableStream){let i=t.getReader(),s=!1;function a(){s||(s=!0,i.cancel())}n&&n.addEventListener(\"abort\",a,{once:!0});try{for(;!s;){let{done:t,value:n}=await i.read();if(t||s){a();break}iH(e,r.currentStage,n)}}catch(e){if(!s)throw e}}else{let a=!1;n&&n.addEventListener(\"abort\",function(){a||(a=!0,t.destroy())},{once:!0});try{for await(let n of t){if(a)break;iH(e,r.currentStage,n)}}catch(e){if(!a)throw e}}}function iH(e,t,r){switch(t){case rA.D7.Before:throw Object.defineProperty(new ei.z(\"Unexpec...\n Line 163: ${e}`),C}if(null===X)throw C;let l=(0,eB.RM)(C),v=(0,ez.n)(C);if(l)t.statusCode=(0,eB.jT)(C),n.statusCode=t.statusCode,e=(0,eB.qe)(t.statusCode);else if(v){var et;e=\"redirect\",t.statusCode=eV(C),n.statusCode=t.statusCode,et=I(eq(C),p),t.setHeader(\"location\",et),K(\"location\")}else t.statusCode=500,n.statusCode=t.statusCode;if(x&&!l&&!v)throw F.get(C.digest)??C;let[w,S]=rt(m,s,y,k,rd(r,!1),c,\"/_not-found/page\");if(x){let t=X,s=V,l=W,d=G;if(null===t)throw Object.defineProperty(new ei.z(\"Cache Components error recovery expected an original Flight prerender result\"),\"__NEXT_ERROR_CODE\",{value:\"E1283\",enumerable:!1,configurable:!0});if(null===s)throw Object.defineProperty(new ei.z(\"Cache Components error recovery expected to know whether the original Flight prerender result was dynamic\"),\"__NEXT_ERROR_CODE\",{value:\"E1282\",enumerable:!1,configurable:!0});if(null===l)throw Object.defineProperty(new ei.z(\"Cache Components error recovery expected an original resume data cache\"),\"__NEXT_ERROR_CODE\",{value:\"E1285\",enumerable:!1,configurable:!0});if(null===d)throw Object.defineProperty(new ei.z(\"Cache Components error recovery expected an original prerender store\"),\"__NEXT_ERROR_CODE\",{value:\"E1284\",enumerable:!1,configurable:!0});let f=Q(d.stale),m=new AbortController,y=new AbortController,v=(0,e9.uO)(b),_={type:\"prerender\",phase:\"render\",rootParams:O,fallbackRouteParams:i,implicitTags:u,renderSignal:y.signal,controller:m,stagedRendering:null,cacheSignal:null,dynamicTracking:v,revalidate:void 0!==(null==ee?void 0:ee.revalidate)?ee.revalidate:T.AR,expire:void 0!==(null==ee?void 0:ee.expire)?ee.expire:T.AR,stale:void 0!==(null==ee?void 0:ee.stale)?ee.stale:T.AR,tags:[...(null==ee?void 0:ee.tags)||u.tags],resumeDataCache:l,hmrRefreshHash:void 0,varyParamsAccumulator:null},E=await tB.workUnitAsyncStorage.run(_,iO,a,r,F.has(C.digest)?void 0:C,e,!1),k=await (0,ak.PR)(aj(async()=>{let e=tB.workUnitAsyncStorage.run(_,ek(g),E,Z,{filterStackFrame:o,signal:m.signal,onError:e=>B(e)});retur...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:\n Line 1: (()=>{var leafPrototypes,getProto,installedChunks,__webpack_modules__={\"./dist/build/webpack/alias/react-dom-server.js\"(__unused_rspack_module,exports,__webpack_require__){\"use strict\";var b;function error(){throw Object.defineProperty(Error(\"Internal Error: do not use legacy react-dom/server APIs. If you encountered this error, please open an issue on the Next.js repo.\"),\"__NEXT_ERROR_CODE\",{value:\"E1021\",enumerable:!1,configurable:!0})}exports.version=(b=__webpack_require__(\"./dist/compiled/react-dom/cjs/react-dom-server.node.development.js\")).version,exports.renderToReadableStream=b.renderToReadableStream,exports.renderToString=error,exports.renderToStaticMarkup=error,b.resume&&(exports.resume=b.resume),b.renderToPipeableStream&&(exports.renderToPipeableStream=b.renderToPipeableStream),b.resumeToPipeableStream&&(exports.resumeToPipeableStream=b.resumeToPipeableStream)},\"./dist/compiled/@edge-runtime/cookies/index.js\"(module1){\"use strict\";var __defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropNames=Object.getOwnPropertyNames,__hasOwnProp=Object.prototype.hasOwnProperty,src_exports={},all={RequestCookies:()=>RequestCookies,ResponseCookies:()=>ResponseCookies,parseCookie:()=>parseCookie,parseSetCookie:()=>parseSetCookie,stringifyCookie:()=>stringifyCookie};for(var name in all)__defProp(src_exports,name,{get:all[name],enumerable:!0});function stringifyCookie(c){var _a;let attrs=[\"path\"in c&&c.path&&`Path=${c.path}`,\"expires\"in c&&(c.expires||0===c.expires)&&`Expires=${(\"number\"==typeof c.expires?new Date(c.expires):c.expires).toUTCString()}`,\"maxAge\"in c&&\"number\"==typeof c.maxAge&&`Max-Age=${c.maxAge}`,\"domain\"in c&&c.domain&&`Domain=${c.domain}`,\"secure\"in c&&c.secure&&\"Secure\",\"httpOnly\"in c&&c.httpOnly&&\"HttpOnly\",\"sameSite\"in c&&c.sameSite&&`SameSite=${c.sameSite}`,\"partitioned\"in c&&c.partitioned&&\"Partitioned\",\"priority\"in c&&c.priority&&`Priority=${c.priority}`].filter(Boolean),stringified=`${c.name}=${encodeURICompo...\n Line 2: --${i}`,ssCb),this._writecb=null,this._finalcb=null,this.write(h)}static detect(e){return\"multipart\"===e.type&&\"form-data\"===e.subtype}_write(e,t,i){let i1;this._writecb=i,this._bparser.push(e,0),this._writecb&&(i1=this._writecb,this._writecb=null,i1&&i1())}_destroy(e,t){this._hparser=null,this._bparser=k,e||(e=checkEndState(this));let i=this._fileStream;i&&(this._fileStream=null,i.destroy(e)),t(e)}_final(e){if(this._bparser.destroy(),!this._complete)return e(Error(\"Unexpected end of form\"));this._fileEndsLeft?this._finalcb=finalcb.bind(null,this,e):finalcb(this,e)}}},183:function(e,t,i){let{Writable:s}=i(203),{getDecoder:r}=i(827);function readPctEnc(e,t,i,s){if(i>=s)return s;if(-1===e._byte){let r=n[t[i++]];if(-1===r)return -1;if(r>=8&&(e._encode=2),ie.fieldNameSizeLimit){for(!e._keyTrunc&&e._lastPose.fieldSizeLimit){for(!e._valTrunc&&e._lastPos2&&\"\"===lines[1].trim()&&lines.splice(1,1),lines[1]&&lines[1].startsWith(\"Module not found: \")&&(lines=[lines[0],lines[1].replace(\"Error: \",\"\").replace(\"Module not found: Cannot find file:\",\"Cannot find file:\"),...lines.slice(2)]),lines[1]&&lines[1].match(/Cannot find module.+sass/)){let firstLine=lines[0].split(\"!\");lines[0]=firstLine[firstLine.length-1],lines[1]=\"To use Next.js' built-in Sass support, you first need to install `sass`.\\n\",lines[1]+=\"Run `npm i sass` or `yarn add sass` inside your workspace.\\n\",lines[1]+=\"\\nLearn more: https://nextjs.org/docs/messages/install-sass\",lines=lines.slice(0,2),hadMissingSassError=!0}else hadMissingSassError&&message.match(/(sass-loader|resolve-url-loader: CSS error)/)&&(lines=[]);if(verbose||(lines=(message=(message=(message=(message=lines.join(\"\\n\")).replace(/^\\s*at\\s((?!webpack:).)*:\\d+:\\d+[\\s)]*(\\n|$)/gm,\"\")).replace(/^\\s*at\\s(\\n|$)/gm,\"\")).replace(/File was processed with these loaders:\\n(.+[\\\\/](next[\\\\/]dist[\\\\/].+|@next[\\\\/]react-refresh-utils[\\\\/]loader)\\.js\\n)*You may need an additional loader to handle the result of these loaders.\\n/g,\"\")).split(\"\\n\")),loaderPaths.length>0)for(let loaderPath of loaderPaths)/[/\\\\]next[/\\\\]dist[/\\\\]/.test(loaderPath)||lines.push(` (from ${loaderPath})`);return(message=(lines=lines.filter((line,index,arr)=>0===index||\"\"!==line.trim()||line.trim()!==arr[index-1].trim())).join(\"\\n\")).trim()}function formatWebpackMessages(json,verbose){let formattedErrors=json.errors.map(message=>{let isUnknownNextFontError=...\n Line 190: `+(\"useParams()\"===expression?\" - [cache] For known params, prerender them with `generateStaticParams`\\n https://nextjs.org/docs/messages/blocking-prerender-client-hook#for-known-params-prerender\\n\":\"\")+\" - [block] Set `export const instant = false` to silence this warning and allow a blocking route\\n https://nextjs.org/docs/messages/blocking-prerender-client-hook#allow-blocking-route\"),this.digest=CLIENT_HOOK_DYNAMIC,Object.defineProperty(this,\"__NEXT_ERROR_CODE\",{value:\"E1315\",enumerable:!1,configurable:!0})}}function isClientHookDynamicError(err){return\"object\"==typeof err&&null!==err&&\"digest\"in err&&err.digest===CLIENT_HOOK_DYNAMIC}let abortListenersBySignal=new WeakMap;function makeHangingPromise(signal,route,expression){return makeHangingPromiseWithError(signal,new HangingPromiseRejectionError(route,expression))}function makeClientHookHangingPromise(signal,error){return makeHangingPromiseWithError(signal,error)}function makeHangingPromiseWithError(signal,error){if(signal.aborted)return Promise.reject(error);{let hangingPromise=new Promise((_,reject)=>{let boundRejection=reject.bind(null,error),currentListeners=abortListenersBySignal.get(signal);if(currentListeners)currentListeners.push(boundRejection);else{let listeners=[boundRejection];abortListenersBySignal.set(signal,listeners),signal.addEventListener(\"abort\",()=>{for(let i=0;ivalue1);return promise.catch(ignoreReject),promise}function makeDevtoolsIOAwarePromise(underlying,requestStore,stage){return requestStore.stagedRendering?requestStore.stagedRendering.delayUntilStage(stage,void 0,underlying):new Promise(resolve=>{setTimeout(()=>{resolve(underlying)},0)})}let RENDER_STAGES_BY_DATA_KIND={sessionData:{early:_app_render_staged_rendering__rspack_import_1.RenderStage.ShellEarlyRuntime,late:_...\n Line 197: `))}})}function chainTransformers(readable,transformers){let stream=readable;for(let transformer of transformers)transformer&&(stream=stream.pipeThrough(transformer));return stream}async function continueFizzStream(renderStream,{suffix,inlinedDataStream,isStaticGeneration,deploymentId,getServerInsertedHTML,getServerInsertedMetadata,validateRootLayout}){let suffixUnclosed=suffix?suffix.split(CLOSE_TAG,1)[0]:null;return isStaticGeneration?await renderStream.allReady:await (0,_lib_scheduler__rspack_import_3.waitAtLeastOneReactRenderTask)(),chainTransformers(renderStream,[createBufferedTransformStream(),deploymentId?createHtmlDataDplIdTransformStream(deploymentId):null,createMetadataTransformStream(getServerInsertedMetadata),null!=suffixUnclosed&&suffixUnclosed.length>0?createDeferredSuffixStream(suffixUnclosed):null,inlinedDataStream?createFlightDataInjectionTransformStream(inlinedDataStream,!0):null,validateRootLayout?createRootLayoutValidatorStream():null,createMoveSuffixStream(),createHeadInsertionTransformStream(getServerInsertedHTML)])}async function continueDynamicPrerender(prerenderStream,{getServerInsertedHTML,getServerInsertedMetadata,deploymentId}){return chainTransformers(prerenderStream,[createBufferedTransformStream(),new TransformStream({transform(chunk,controller){(0,_uint8array_helpers__rspack_import_5.isEquivalentUint8Arrays)(chunk,_encoded_tags__rspack_import_4.ENCODED_TAGS.CLOSED.BODY_AND_HTML)||(0,_uint8array_helpers__rspack_import_5.isEquivalentUint8Arrays)(chunk,_encoded_tags__rspack_import_4.ENCODED_TAGS.CLOSED.BODY)||(0,_uint8array_helpers__rspack_import_5.isEquivalentUint8Arrays)(chunk,_encoded_tags__rspack_import_4.ENCODED_TAGS.CLOSED.HTML)||(chunk=(0,_uint8array_helpers__rspack_import_5.removeFromUint8Array)(chunk,_encoded_tags__rspack_import_4.ENCODED_TAGS.CLOSED.BODY),chunk=(0,_uint8array_helpers__rspack_import_5.removeFromUint8Array)(chunk,_encoded_tags__rspack_import_4.ENCODED_TAGS.CLOSED.HTML),controller.enqueue(chunk))}}),depl...\n Line 202: Read more: https://nextjs.org/docs/messages/failed-to-find-server-action`),\"__NEXT_ERROR_CODE\",{value:\"E974\",enumerable:!1,configurable:!0})}let $ACTION_=\"$ACTION_\",$ACTION_REF_=\"$ACTION_REF_\",$ACTION_ID_=\"$ACTION_ID_\",ACTION_DESCRIPTOR_ID_PREFIX='{\"id\":\"',ServerInsertedHTMLContext=react_default().createContext(null);function useServerInsertedHTML(callback){let addInsertedServerHTMLCallback=(0,react.useContext)(ServerInsertedHTMLContext);addInsertedServerHTMLCallback&&addInsertedServerHTMLCallback(callback)}function createServerInsertedHTML(){let serverInsertedHTMLCallbacks=[],addInsertedHtml=handler=>{serverInsertedHTMLCallbacks.push(handler)};return{ServerInsertedHTMLProvider:({children})=>(0,jsx_runtime.jsx)(ServerInsertedHTMLContext.Provider,{value:addInsertedHtml,children:children}),renderServerInsertedHTML:()=>serverInsertedHTMLCallbacks.map((callback,index)=>(0,jsx_runtime.jsx)(react.Fragment,{children:callback()},\"__next_server_inserted__\"+index))}}function encodeURIPath(file){return file.split(\"/\").map(p=>encodeURIComponent(p)).join(\"/\")}var react_dom=__webpack_require__(\"./dist/compiled/react-dom/index.js\");function getRequiredScripts(buildManifest,assetPrefix,crossOrigin,SRIManifest,qs,nonce,pagePath){var _buildManifest_rootMainFilesTree;let preinitScripts,preinitScriptCommands=[],bootstrapScript={src:\"\",crossOrigin},files=((null==(_buildManifest_rootMainFilesTree=buildManifest.rootMainFilesTree)?void 0:_buildManifest_rootMainFilesTree[pagePath])||buildManifest.rootMainFiles).map(encodeURIPath);if(0===files.length)throw Object.defineProperty(Error(\"Invariant: missing bootstrap script. This is a bug in Next.js\"),\"__NEXT_ERROR_CODE\",{value:\"E459\",enumerable:!1,configurable:!0});if(SRIManifest){bootstrapScript.src=`${assetPrefix}/_next/`+files[0]+qs,bootstrapScript.integrity=SRIManifest[files[0]];for(let i=1;i{let result,scheduleTimeout=function(delayMs=0){{let isFirstCallback=!0,firstTimerIdleStart=null,didFirstTimerRun=!1,didImmediateRun=!1;function runFirstCallback(callback){return didFirstTimerRun=!0,shouldAttemptPatching&&(0,fast_set_immediate_external_js_namespaceObject.unpatchedSetImmediate)(()=>{didImmediateRun=!0}),callback()}function runSubsequentCallback(callback){return shouldAttemptPatching&&didImmediateRun&&(shouldAttemptPatching=!1,warnAboutTimers()),callback()}return function(callback){if(didFirstTimerRun)throw Object.defineProperty(new invariant_error.InvariantError(\"Cannot schedule more timers into a group that already executed\"),\"__NEXT_ERROR_CODE\",{value:\"E935\",enumerable:!1,configurable:!0});let timer=setTimeout(isFirstCallback?runFirstCallback:runSubsequentCallback,delayMs,callback);if(isFirstCallback=!1,!shouldAttemptPatching)return timer;try{\"_idleStart\"in timer&&\"number\"==typeof timer._idleStart?null===firstTimerIdleStart?firstTimerIdleStart=timer._idleStart:timer._idleStart=firstTimerIdleStart:(shouldAttemptPatching=!1,warnAboutTimers()...\n Line 207: ${stack}`),endSpanWithError(err),err}if((0,http_access_fallback.isHTTPAccessFallbackError)(err))res.statusCode=(0,http_access_fallback.getAccessFallbackHTTPStatus)(err),metadata.statusCode=res.statusCode,errorType=(0,http_access_fallback.getAccessFallbackErrorTypeByStatus)(res.statusCode);else if((0,redirect_error.isRedirectError)(err)){errorType=\"redirect\",res.statusCode=(0,components_redirect.getRedirectStatusCodeFromError)(err),metadata.statusCode=res.statusCode;let redirectUrl=(0,add_path_prefix.addPathPrefix)((0,components_redirect.getURLFromRedirectError)(err),basePath),headers=new Headers;(0,request_cookies.appendMutableCookies)(headers,requestStore.mutableCookies)&&setHeader(\"set-cookie\",Array.from(headers.values())),setHeader(\"location\",redirectUrl)}else shouldBailoutToCSR||(res.statusCode=500,metadata.statusCode=res.statusCode);let[errorPreinitScripts,errorBootstrapScript]=getRequiredScripts(buildManifest,assetPrefix,crossOrigin,subresourceIntegrityManifest,getAssetQueryString(ctx,!1),nonce,\"/_not-found/page\");{let errorRSCPayload,errorServerStream;try{if(errorRSCPayload=await work_unit_async_storage_external_js_.workUnitAsyncStorage.run(requestStore,getErrorRSCPayload,tree,ctx,reactServerErrorsByDigest.has(err.digest)?null:err,errorType,!0),errorServerStream=work_unit_async_storage_external_js_.workUnitAsyncStorage.run(requestStore,renderToNodeFlightStream,ctx.componentMod,errorRSCPayload,clientModules,{filterStackFrame,onError:serverComponentsErrorHandler}),null===reactServerResult)throw endSpanWithError(err),err}catch(setupErr){throw endSpanWithError(setupErr),setupErr}try{let generateStaticHTML=!0!==supportsDynamicResponse||!!shouldWaitOnAllReady,{stream:errorHtmlStream,allReady:errorAllReady}=await work_unit_async_storage_external_js_.workUnitAsyncStorage.run(requestStore,renderToNodeFizzStream,(0,jsx_runtime.jsx)(ErrorApp,{reactServerStream:errorServerStream,ServerInsertedHTMLProvider:ServerInsertedHTMLProvider,preinitScripts:errorPreinitScripts,nonc...\n Line 208: ${stack}`),err}if(null===reactServerPrerenderResult)throw err;let isHTTPAccessFallback=(0,http_access_fallback.isHTTPAccessFallbackError)(err),isRedirect=(0,redirect_error.isRedirectError)(err);if(isHTTPAccessFallback)res.statusCode=(0,http_access_fallback.getAccessFallbackHTTPStatus)(err),metadata.statusCode=res.statusCode,errorType=(0,http_access_fallback.getAccessFallbackErrorTypeByStatus)(res.statusCode);else if(isRedirect){var value1;errorType=\"redirect\",res.statusCode=(0,components_redirect.getRedirectStatusCodeFromError)(err),metadata.statusCode=res.statusCode,value1=(0,add_path_prefix.addPathPrefix)((0,components_redirect.getURLFromRedirectError)(err),basePath),res.setHeader(\"location\",value1),setMetadataHeader(\"location\")}else res.statusCode=500,metadata.statusCode=res.statusCode;if(cacheComponents&&!isHTTPAccessFallback&&!isRedirect)throw reactServerErrorsByDigest.get(err.digest)??err;let[errorPreinitScripts,errorBootstrapScript]=getRequiredScripts(buildManifest,assetPrefix,crossOrigin,subresourceIntegrityManifest,getAssetQueryString(ctx,!1),nonce,\"/_not-found/page\");if(cacheComponents){let originalFlightPrerenderResult=reactServerPrerenderResult,originalFlightPrerenderResultIsDynamic=reactServerPrerenderResultIsDynamic,originalResumeDataCache=reactServerResumeDataCache,originalPrerenderStore=reactServerPrerenderStore;if(null===originalFlightPrerenderResult)throw Object.defineProperty(new invariant_error.InvariantError(\"Cache Components error recovery expected an original Flight prerender result\"),\"__NEXT_ERROR_CODE\",{value:\"E1283\",enumerable:!1,configurable:!0});if(null===originalFlightPrerenderResultIsDynamic)throw Object.defineProperty(new invariant_error.InvariantError(\"Cache Components error recovery expected to know whether the original Flight prerender result was dynamic\"),\"__NEXT_ERROR_CODE\",{value:\"E1282\",enumerable:!1,configurable:!0});if(null===originalResumeDataCache)throw Object.defineProperty(new invariant_error.InvariantError(\"Cache Componen...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js:\n Line 1: (()=>{var e,t,r={\"./dist/build/webpack/alias/react-dom-server.js\"(e,t,r){\"use strict\";var n;function a(){throw Object.defineProperty(Error(\"Internal Error: do not use legacy react-dom/server APIs. If you encountered this error, please open an issue on the Next.js repo.\"),\"__NEXT_ERROR_CODE\",{value:\"E1021\",enumerable:!1,configurable:!0})}t.version=(n=r(\"./dist/compiled/react-dom/cjs/react-dom-server.node.production.js\")).version,t.renderToReadableStream=n.renderToReadableStream,t.renderToString=a,t.renderToStaticMarkup=a,n.resume&&(t.resume=n.resume),n.renderToPipeableStream&&(t.renderToPipeableStream=n.renderToPipeableStream),n.resumeToPipeableStream&&(t.resumeToPipeableStream=n.resumeToPipeableStream)},\"./dist/compiled/@edge-runtime/cookies/index.js\"(e){\"use strict\";var t=Object.defineProperty,r=Object.getOwnPropertyDescriptor,n=Object.getOwnPropertyNames,a=Object.prototype.hasOwnProperty,i={},s={RequestCookies:()=>h,ResponseCookies:()=>p,parseCookie:()=>u,parseSetCookie:()=>c,stringifyCookie:()=>l};for(var o in s)t(i,o,{get:s[o],enumerable:!0});function l(e){var t;let r=[\"path\"in e&&e.path&&`Path=${e.path}`,\"expires\"in e&&(e.expires||0===e.expires)&&`Expires=${(\"number\"==typeof e.expires?new Date(e.expires):e.expires).toUTCString()}`,\"maxAge\"in e&&\"number\"==typeof e.maxAge&&`Max-Age=${e.maxAge}`,\"domain\"in e&&e.domain&&`Domain=${e.domain}`,\"secure\"in e&&e.secure&&\"Secure\",\"httpOnly\"in e&&e.httpOnly&&\"HttpOnly\",\"sameSite\"in e&&e.sameSite&&`SameSite=${e.sameSite}`,\"partitioned\"in e&&e.partitioned&&\"Partitioned\",\"priority\"in e&&e.priority&&`Priority=${e.priority}`].filter(Boolean),n=`${e.name}=${encodeURIComponent(null!=(t=e.value)?t:\"\")}`;return 0===r.length?n:`${n}; ${r.join(\"; \")}`}function u(e){let t=new Map;for(let r of e.split(/; */)){if(!r)continue;let e=r.indexOf(\"=\");if(-1===e){t.set(r,\"true\");continue}let[n,a]=[r.slice(0,e),r.slice(e+1)];try{t.set(n,decodeURIComponent(null!=a?a:\"true\"))}catch{}}return t}function c(e){if(!e)return;let[[t,r],...n]=u(e),{domai...\n Line 2: --${S}`,B),this._writecb=null,this._finalcb=null,this.write(d)}static detect(e){return\"multipart\"===e.type&&\"form-data\"===e.subtype}_write(e,t,r){let n;this._writecb=r,this._bparser.push(e,0),this._writecb&&(n=this._writecb,this._writecb=null,n&&n())}_destroy(e,t){this._hparser=null,this._bparser=y,e||(e=S(this));let r=this._fileStream;r&&(this._fileStream=null,r.destroy(e)),t(e)}_final(e){if(this._bparser.destroy(),!this._complete)return e(Error(\"Unexpected end of form\"));this._fileEndsLeft?this._finalcb=b.bind(null,this,e):b(this,e)}}},183:function(e,t,r){let{Writable:n}=r(203),{getDecoder:a}=r(827);function i(e,t,r,n){if(r>=n)return n;if(-1===e._byte){let a=l[t[r++]];if(-1===a)return -1;if(a>=8&&(e._encode=2),re.fieldNameSizeLimit){for(!e._keyTrunc&&e._lastPose.fieldSizeLimit){for(!e._valTrunc&&e._lastPos{let a=t.bind(null,n),i=c.get(r);if(i)i.push(a);else{let e=[a];c.set(r,e),r.addEventListener(\"abort\",()=>{for(let t=0;ti});var n=r(\"./dist/esm/server/lib/lru-cache.js\"),a=r(\"./tags-manifest.external\");function i(e){if(0===e)return{get:()=>Promise.resolve(void 0),set:()=>Promise.resolve(),refreshTags:()=>Promise.resolve(),getExpiration:()=>Promise.resolve(0),updateTags:()=>Promise.resolve()};let t=new n.q(e,e=>e.size),r=new Map,i=process.env.NEXT_PRIVATE_DEBUG_CACHE?console.debug.bind(console,\"DefaultCacheHandler:\"):void 0;return{async get(e){let n=r.get(e);n&&(null==i||i(\"get\",e,\"pending\"),await n);let s=t.get(e);if(!s){null==i||i(\"get\",e,\"not found\");return}let o=s.entry,l=o.revalidate;if(performance.timeOrigin+performance.now()>o.timestamp+1e3*l){null==i||i(\"get\",e,\"expired\");return}let u=o.revalidate;if((0,a.areTagsExpired)(o.tags,o.timestamp)){null==i||i(\"get\",e,\"had expired tag\");return}(0,a.areTagsStale)(o.tags,o.timestamp)&&(null==i||i(\"get\",e,\"had...\n Line 127: Read more: https://nextjs.org/docs/messages/failed-to-find-server-action`),\"__NEXT_ERROR_CODE\",{value:\"E974\",enumerable:!1,configurable:!0})}let t0=\"$ACTION_\",t1=\"$ACTION_REF_\",t2=\"$ACTION_ID_\",t3='{\"id\":\"',t4=k.createContext(null);function t8(e){let t=(0,k.useContext)(t4);t&&t(e)}function t6(){let e=[],t=t=>{e.push(t)};return{ServerInsertedHTMLProvider:({children:e})=>(0,_.jsx)(t4.Provider,{value:t,children:e}),renderServerInsertedHTML:()=>e.map((e,t)=>(0,_.jsx)(k.Fragment,{children:e()},\"__next_server_inserted__\"+t))}}function t9(e){return e.split(\"/\").map(e=>encodeURIComponent(e)).join(\"/\")}var t7=a(\"./dist/compiled/react-dom/index.js\");function t5(e,t,r,n,a,i,s){var o;let l,u=[],c={src:\"\",crossOrigin:r},d=((null==(o=e.rootMainFilesTree)?void 0:o[s])||e.rootMainFiles).map(t9);if(0===d.length)throw Object.defineProperty(Error(\"Invariant: missing bootstrap script. This is a bug in Next.js\"),\"__NEXT_ERROR_CODE\",{value:\"E459\",enumerable:!1,configurable:!0});if(n){c.src=`${t}/_next/`+d[0]+a,c.integrity=n[d[0]];for(let e=1;e{for(let e=0;e{for(let e=0;e(0,_.jsx)(\"script\",{...e},e.src)),o=(n||[]).map(({key:e,value:t},r)=>(0,_.jsx)(\"meta\",{name:e,content:t},`next-trace-data-${r}`));return async function(){let e=[];for(;i{let a,i=function(e=0){{let n=!0,a=null,i=!1,s=!1;function t(e){return i=!0,ak&&(0,aR.unpatchedSetImmediate)(()=>{s=!0}),e()}function r(e){return ak&&s&&(ak=!1,ax()),e()}return function(s){if(i)throw Object.defineProperty(new en.z(\"Cannot schedule more timers into a group that already executed\"),\"__NEXT_ERROR_CODE\",{value:\"E935\",enumerable:!1,configurable:!0});let o=setTimeout(n?t:r,e,s);if(n=!1,!ak)return o;try{\"_idleStart\"in o&&\"number\"==typeof o._idleStart?null===a?a=o._idleStart:o._idleStart=a:(ak=!1,ax())}catch(e){console.error(Object.defineProperty(new en.z(\"An unexpected error occurred while adjusting `_idleStart` on an atomic timer\",{cause:e}),\"__NEXT_ERROR_CODE\",{value:\"E933\",enumerable:!1,configurable:!0})),ak=!1,ax()}return o}}}(),s=[];s.push(i(()=>{try{(0,aR.DANGEROUSLY_runPendingImmediatesAfterCurrentTask)(),a=e(),(0,nV.Q)(a)&&a.then(aP,aP)}catch(e){for(let e=1;e{try{(0,aR.DANGEROUSLY_runPendingImmediatesAfterCurrentTask)(),r()}catch(e){for(;++a{try{(0,aR.expectNoPendingImmediates)(),r(a)}catch(e){n(e)}}))})}let aT=require(\"next/dist/server/app-render/console-async-storage.external.js\");class aA{constructor(){this.count=0,t...\n Line 162: ${e}`),V(m),m}if((0,eF.RM)(m))r.statusCode=(0,eF.jT)(m),l.statusCode=r.statusCode,t=(0,eF.qe)(r.statusCode);else if((0,eH.n)(m)){t=\"redirect\",r.statusCode=eq(m),l.statusCode=r.statusCode;let n=j(eB(m),v),a=new Headers;(0,eA.IN)(a,e.mutableCookies)&&J(\"set-cookie\",Array.from(a.values())),J(\"location\",n)}else o||(r.statusCode=500,l.statusCode=r.statusCode);let[u,f]=t5(b,d,w,O,ru(a,!1),h,\"/_not-found/page\");{let r,o;try{if(r=await tF.workUnitAsyncStorage.run(e,iP,i,a,c.has(m.digest)?null:m,t,!0),o=tF.workUnitAsyncStorage.run(e,eb,a.componentMod,r,Y,{filterStackFrame:n,onError:S}),null===G)throw V(m),m}catch(e){throw V(e),e}try{let t=!0!==D||!!A,{stream:r,allReady:n}=await tF.workUnitAsyncStorage.run(e,ew,(0,_.jsx)(iT,{reactServerStream:o,ServerInsertedHTMLProvider:M,preinitScripts:u,nonce:h,images:a.renderOpts.images}),{nonce:h,bootstrapScriptContent:q,bootstrapScripts:[f],formState:s},{waitForAllReady:t});return n.finally(()=>{X.isRecording()&&X.end()}),await es(r,{inlinedDataStream:em(G.consume(),h,s),isStaticGeneration:t,deploymentId:a.sharedContext.deploymentId,getServerInsertedHTML:re({polyfills:H,renderServerInsertedHTML:L,serverCapturedErrors:[],basePath:v,tracingMetadata:F}),getServerInsertedMetadata:U,validateRootLayout:!1})}catch(e){throw V(e),e}}}})}function iI(){return{shellStaticChunks:[],staticChunks:[],shellRuntimeChunks:[],runtimeChunks:[],dynamicChunks:[]}}async function i$(e,t,r){let n=iI();return await iN(n,e,t,r),n}async function iN(e,t,r,n){if(t instanceof ReadableStream){let i=t.getReader(),s=!1;function a(){s||(s=!0,i.cancel())}n&&n.addEventListener(\"abort\",a,{once:!0});try{for(;!s;){let{done:t,value:n}=await i.read();if(t||s){a();break}iM(e,r.currentStage,n)}}catch(e){if(!s)throw e}}else{let a=!1;n&&n.addEventListener(\"abort\",function(){a||(a=!0,t.destroy())},{once:!0});try{for await(let n of t){if(a)break;iM(e,r.currentStage,n)}}catch(e){if(!a)throw e}}}function iM(e,t,r){switch(t){case rC.D7.Before:throw Object.defineProperty(new en.z(\"Unexpec...\n Line 163: ${e}`),T}if(null===X)throw T;let l=(0,eF.RM)(T),v=(0,eH.n)(T);if(l)t.statusCode=(0,eF.jT)(T),a.statusCode=t.statusCode,e=(0,eF.qe)(t.statusCode);else if(v){var et;e=\"redirect\",t.statusCode=eq(T),a.statusCode=t.statusCode,et=j(eB(T),p),t.setHeader(\"location\",et),K(\"location\")}else t.statusCode=500,a.statusCode=t.statusCode;if(x&&!l&&!v)throw F.get(T.digest)??T;let[S,w]=t5(m,o,y,k,ru(r,!1),c,\"/_not-found/page\");if(x){let t=X,o=V,l=G,d=J;if(null===t)throw Object.defineProperty(new en.z(\"Cache Components error recovery expected an original Flight prerender result\"),\"__NEXT_ERROR_CODE\",{value:\"E1283\",enumerable:!1,configurable:!0});if(null===o)throw Object.defineProperty(new en.z(\"Cache Components error recovery expected to know whether the original Flight prerender result was dynamic\"),\"__NEXT_ERROR_CODE\",{value:\"E1282\",enumerable:!1,configurable:!0});if(null===l)throw Object.defineProperty(new en.z(\"Cache Components error recovery expected an original resume data cache\"),\"__NEXT_ERROR_CODE\",{value:\"E1285\",enumerable:!1,configurable:!0});if(null===d)throw Object.defineProperty(new en.z(\"Cache Components error recovery expected an original prerender store\"),\"__NEXT_ERROR_CODE\",{value:\"E1284\",enumerable:!1,configurable:!0});let f=Q(d.stale),m=new AbortController,y=new AbortController,v=(0,e8.uO)(b),E={type:\"prerender\",phase:\"render\",rootParams:O,fallbackRouteParams:s,implicitTags:u,renderSignal:y.signal,controller:m,stagedRendering:null,cacheSignal:null,dynamicTracking:v,revalidate:void 0!==(null==ee?void 0:ee.revalidate)?ee.revalidate:P.AR,expire:void 0!==(null==ee?void 0:ee.expire)?ee.expire:P.AR,stale:void 0!==(null==ee?void 0:ee.stale)?ee.stale:P.AR,tags:[...(null==ee?void 0:ee.tags)||u.tags],resumeDataCache:l,hmrRefreshHash:void 0,varyParamsAccumulator:null},R=await tF.workUnitAsyncStorage.run(E,iP,i,r,F.has(T.digest)?void 0:T,e,!1),k=await (0,aw.PR)(aC(async()=>{let e=tF.workUnitAsyncStorage.run(E,eE(g),R,Z,{filterStackFrame:n,signal:m.signal,onError:e=>B(e)});retur...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.dev.js:\n Line 1: (()=>{var leafPrototypes,getProto,installedChunks,__webpack_modules__={\"./dist/build/webpack/alias/react-dom-server.js\"(__unused_rspack_module,exports,__webpack_require__){\"use strict\";var b;function error(){throw Object.defineProperty(Error(\"Internal Error: do not use legacy react-dom/server APIs. If you encountered this error, please open an issue on the Next.js repo.\"),\"__NEXT_ERROR_CODE\",{value:\"E1021\",enumerable:!1,configurable:!0})}exports.version=(b=__webpack_require__(\"./dist/compiled/react-dom/cjs/react-dom-server.node.development.js\")).version,exports.renderToReadableStream=b.renderToReadableStream,exports.renderToString=error,exports.renderToStaticMarkup=error,b.resume&&(exports.resume=b.resume),b.renderToPipeableStream&&(exports.renderToPipeableStream=b.renderToPipeableStream),b.resumeToPipeableStream&&(exports.resumeToPipeableStream=b.resumeToPipeableStream)},\"./dist/compiled/@edge-runtime/cookies/index.js\"(module1){\"use strict\";var __defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropNames=Object.getOwnPropertyNames,__hasOwnProp=Object.prototype.hasOwnProperty,src_exports={},all={RequestCookies:()=>RequestCookies,ResponseCookies:()=>ResponseCookies,parseCookie:()=>parseCookie,parseSetCookie:()=>parseSetCookie,stringifyCookie:()=>stringifyCookie};for(var name in all)__defProp(src_exports,name,{get:all[name],enumerable:!0});function stringifyCookie(c){var _a;let attrs=[\"path\"in c&&c.path&&`Path=${c.path}`,\"expires\"in c&&(c.expires||0===c.expires)&&`Expires=${(\"number\"==typeof c.expires?new Date(c.expires):c.expires).toUTCString()}`,\"maxAge\"in c&&\"number\"==typeof c.maxAge&&`Max-Age=${c.maxAge}`,\"domain\"in c&&c.domain&&`Domain=${c.domain}`,\"secure\"in c&&c.secure&&\"Secure\",\"httpOnly\"in c&&c.httpOnly&&\"HttpOnly\",\"sameSite\"in c&&c.sameSite&&`SameSite=${c.sameSite}`,\"partitioned\"in c&&c.partitioned&&\"Partitioned\",\"priority\"in c&&c.priority&&`Priority=${c.priority}`].filter(Boolean),stringified=`${c.name}=${encodeURICompo...\n Line 2: --${i}`,ssCb),this._writecb=null,this._finalcb=null,this.write(h)}static detect(e){return\"multipart\"===e.type&&\"form-data\"===e.subtype}_write(e,t,i){let i1;this._writecb=i,this._bparser.push(e,0),this._writecb&&(i1=this._writecb,this._writecb=null,i1&&i1())}_destroy(e,t){this._hparser=null,this._bparser=k,e||(e=checkEndState(this));let i=this._fileStream;i&&(this._fileStream=null,i.destroy(e)),t(e)}_final(e){if(this._bparser.destroy(),!this._complete)return e(Error(\"Unexpected end of form\"));this._fileEndsLeft?this._finalcb=finalcb.bind(null,this,e):finalcb(this,e)}}},183:function(e,t,i){let{Writable:s}=i(203),{getDecoder:r}=i(827);function readPctEnc(e,t,i,s){if(i>=s)return s;if(-1===e._byte){let r=n[t[i++]];if(-1===r)return -1;if(r>=8&&(e._encode=2),ie.fieldNameSizeLimit){for(!e._keyTrunc&&e._lastPose.fieldSizeLimit){for(!e._valTrunc&&e._lastPos2&&\"\"===lines[1].trim()&&lines.splice(1,1),lines[1]&&lines[1].startsWith(\"Module not found: \")&&(lines=[lines[0],lines[1].replace(\"Error: \",\"\").replace(\"Module not found: Cannot find file:\",\"Cannot find file:\"),...lines.slice(2)]),lines[1]&&lines[1].match(/Cannot find module.+sass/)){let firstLine=lines[0].split(\"!\");lines[0]=firstLine[firstLine.length-1],lines[1]=\"To use Next.js' built-in Sass support, you first need to install `sass`.\\n\",lines[1]+=\"Run `npm i sass` or `yarn add sass` inside your workspace.\\n\",lines[1]+=\"\\nLearn more: https://nextjs.org/docs/messages/install-sass\",lines=lines.slice(0,2),hadMissingSassError=!0}else hadMissingSassError&&message.match(/(sass-loader|resolve-url-loader: CSS error)/)&&(lines=[]);if(verbose||(lines=(message=(message=(message=(message=lines.join(\"\\n\")).replace(/^\\s*at\\s((?!webpack:).)*:\\d+:\\d+[\\s)]*(\\n|$)/gm,\"\")).replace(/^\\s*at\\s(\\n|$)/gm,\"\")).replace(/File was processed with these loaders:\\n(.+[\\\\/](next[\\\\/]dist[\\\\/].+|@next[\\\\/]react-refresh-utils[\\\\/]loader)\\.js\\n)*You may need an additional loader to handle the result of these loaders.\\n/g,\"\")).split(\"\\n\")),loaderPaths.length>0)for(let loaderPath of loaderPaths)/[/\\\\]next[/\\\\]dist[/\\\\]/.test(loaderPath)||lines.push(` (from ${loaderPath})`);return(message=(lines=lines.filter((line,index,arr)=>0===index||\"\"!==line.trim()||line.trim()!==arr[index-1].trim())).join(\"\\n\")).trim()}function formatWebpackMessages(json,verbose){let formattedErrors=json.errors.map(message=>{let isUnknownNextFontError=...\n Line 190: `+(\"useParams()\"===expression?\" - [cache] For known params, prerender them with `generateStaticParams`\\n https://nextjs.org/docs/messages/blocking-prerender-client-hook#for-known-params-prerender\\n\":\"\")+\" - [block] Set `export const instant = false` to silence this warning and allow a blocking route\\n https://nextjs.org/docs/messages/blocking-prerender-client-hook#allow-blocking-route\"),this.digest=CLIENT_HOOK_DYNAMIC,Object.defineProperty(this,\"__NEXT_ERROR_CODE\",{value:\"E1315\",enumerable:!1,configurable:!0})}}function isClientHookDynamicError(err){return\"object\"==typeof err&&null!==err&&\"digest\"in err&&err.digest===CLIENT_HOOK_DYNAMIC}let abortListenersBySignal=new WeakMap;function makeHangingPromise(signal,route,expression){return makeHangingPromiseWithError(signal,new HangingPromiseRejectionError(route,expression))}function makeClientHookHangingPromise(signal,error){return makeHangingPromiseWithError(signal,error)}function makeHangingPromiseWithError(signal,error){if(signal.aborted)return Promise.reject(error);{let hangingPromise=new Promise((_,reject)=>{let boundRejection=reject.bind(null,error),currentListeners=abortListenersBySignal.get(signal);if(currentListeners)currentListeners.push(boundRejection);else{let listeners=[boundRejection];abortListenersBySignal.set(signal,listeners),signal.addEventListener(\"abort\",()=>{for(let i=0;ivalue1);return promise.catch(ignoreReject),promise}function makeDevtoolsIOAwarePromise(underlying,requestStore,stage){return requestStore.stagedRendering?requestStore.stagedRendering.delayUntilStage(stage,void 0,underlying):new Promise(resolve=>{setTimeout(()=>{resolve(underlying)},0)})}let RENDER_STAGES_BY_DATA_KIND={sessionData:{early:_app_render_staged_rendering__rspack_import_1.RenderStage.ShellEarlyRuntime,late:_...\n Line 197: `))}})}function chainTransformers(readable,transformers){let stream=readable;for(let transformer of transformers)transformer&&(stream=stream.pipeThrough(transformer));return stream}async function continueFizzStream(renderStream,{suffix,inlinedDataStream,isStaticGeneration,deploymentId,getServerInsertedHTML,getServerInsertedMetadata,validateRootLayout}){let suffixUnclosed=suffix?suffix.split(CLOSE_TAG,1)[0]:null;return isStaticGeneration?await renderStream.allReady:await (0,_lib_scheduler__rspack_import_3.waitAtLeastOneReactRenderTask)(),chainTransformers(renderStream,[createBufferedTransformStream(),deploymentId?createHtmlDataDplIdTransformStream(deploymentId):null,createMetadataTransformStream(getServerInsertedMetadata),null!=suffixUnclosed&&suffixUnclosed.length>0?createDeferredSuffixStream(suffixUnclosed):null,inlinedDataStream?createFlightDataInjectionTransformStream(inlinedDataStream,!0):null,validateRootLayout?createRootLayoutValidatorStream():null,createMoveSuffixStream(),createHeadInsertionTransformStream(getServerInsertedHTML)])}async function continueDynamicPrerender(prerenderStream,{getServerInsertedHTML,getServerInsertedMetadata,deploymentId}){return chainTransformers(prerenderStream,[createBufferedTransformStream(),new TransformStream({transform(chunk,controller){(0,_uint8array_helpers__rspack_import_5.isEquivalentUint8Arrays)(chunk,_encoded_tags__rspack_import_4.ENCODED_TAGS.CLOSED.BODY_AND_HTML)||(0,_uint8array_helpers__rspack_import_5.isEquivalentUint8Arrays)(chunk,_encoded_tags__rspack_import_4.ENCODED_TAGS.CLOSED.BODY)||(0,_uint8array_helpers__rspack_import_5.isEquivalentUint8Arrays)(chunk,_encoded_tags__rspack_import_4.ENCODED_TAGS.CLOSED.HTML)||(chunk=(0,_uint8array_helpers__rspack_import_5.removeFromUint8Array)(chunk,_encoded_tags__rspack_import_4.ENCODED_TAGS.CLOSED.BODY),chunk=(0,_uint8array_helpers__rspack_import_5.removeFromUint8Array)(chunk,_encoded_tags__rspack_import_4.ENCODED_TAGS.CLOSED.HTML),controller.enqueue(chunk))}}),depl...\n Line 202: Read more: https://nextjs.org/docs/messages/failed-to-find-server-action`),\"__NEXT_ERROR_CODE\",{value:\"E974\",enumerable:!1,configurable:!0})}let $ACTION_=\"$ACTION_\",$ACTION_REF_=\"$ACTION_REF_\",$ACTION_ID_=\"$ACTION_ID_\",ACTION_DESCRIPTOR_ID_PREFIX='{\"id\":\"',ServerInsertedHTMLContext=react_default().createContext(null);function useServerInsertedHTML(callback){let addInsertedServerHTMLCallback=(0,react.useContext)(ServerInsertedHTMLContext);addInsertedServerHTMLCallback&&addInsertedServerHTMLCallback(callback)}function createServerInsertedHTML(){let serverInsertedHTMLCallbacks=[],addInsertedHtml=handler=>{serverInsertedHTMLCallbacks.push(handler)};return{ServerInsertedHTMLProvider:({children})=>(0,jsx_runtime.jsx)(ServerInsertedHTMLContext.Provider,{value:addInsertedHtml,children:children}),renderServerInsertedHTML:()=>serverInsertedHTMLCallbacks.map((callback,index)=>(0,jsx_runtime.jsx)(react.Fragment,{children:callback()},\"__next_server_inserted__\"+index))}}function encodeURIPath(file){return file.split(\"/\").map(p=>encodeURIComponent(p)).join(\"/\")}var react_dom=__webpack_require__(\"./dist/compiled/react-dom/index.js\");function getRequiredScripts(buildManifest,assetPrefix,crossOrigin,SRIManifest,qs,nonce,pagePath){var _buildManifest_rootMainFilesTree;let preinitScripts,preinitScriptCommands=[],bootstrapScript={src:\"\",crossOrigin},files=((null==(_buildManifest_rootMainFilesTree=buildManifest.rootMainFilesTree)?void 0:_buildManifest_rootMainFilesTree[pagePath])||buildManifest.rootMainFiles).map(encodeURIPath);if(0===files.length)throw Object.defineProperty(Error(\"Invariant: missing bootstrap script. This is a bug in Next.js\"),\"__NEXT_ERROR_CODE\",{value:\"E459\",enumerable:!1,configurable:!0});if(SRIManifest){bootstrapScript.src=`${assetPrefix}/_next/`+files[0]+qs,bootstrapScript.integrity=SRIManifest[files[0]];for(let i=1;i{let result,scheduleTimeout=function(delayMs=0){{let isFirstCallback=!0,firstTimerIdleStart=null,didFirstTimerRun=!1,didImmediateRun=!1;function runFirstCallback(callback){return didFirstTimerRun=!0,shouldAttemptPatching&&(0,fast_set_immediate_external_js_namespaceObject.unpatchedSetImmediate)(()=>{didImmediateRun=!0}),callback()}function runSubsequentCallback(callback){return shouldAttemptPatching&&didImmediateRun&&(shouldAttemptPatching=!1,warnAboutTimers()),callback()}return function(callback){if(didFirstTimerRun)throw Object.defineProperty(new invariant_error.InvariantError(\"Cannot schedule more timers into a group that already executed\"),\"__NEXT_ERROR_CODE\",{value:\"E935\",enumerable:!1,configurable:!0});let timer=setTimeout(isFirstCallback?runFirstCallback:runSubsequentCallback,delayMs,callback);if(isFirstCallback=!1,!shouldAttemptPatching)return timer;try{\"_idleStart\"in timer&&\"number\"==typeof timer._idleStart?null===firstTimerIdleStart?firstTimerIdleStart=timer._idleStart:timer._idleStart=firstTimerIdleStart:(shouldAttemptPatching=!1,warnAboutTimers()...\n Line 207: ${stack}`),endSpanWithError(err),err}if((0,http_access_fallback.isHTTPAccessFallbackError)(err))res.statusCode=(0,http_access_fallback.getAccessFallbackHTTPStatus)(err),metadata.statusCode=res.statusCode,errorType=(0,http_access_fallback.getAccessFallbackErrorTypeByStatus)(res.statusCode);else if((0,redirect_error.isRedirectError)(err)){errorType=\"redirect\",res.statusCode=(0,components_redirect.getRedirectStatusCodeFromError)(err),metadata.statusCode=res.statusCode;let redirectUrl=(0,add_path_prefix.addPathPrefix)((0,components_redirect.getURLFromRedirectError)(err),basePath),headers=new Headers;(0,request_cookies.appendMutableCookies)(headers,requestStore.mutableCookies)&&setHeader(\"set-cookie\",Array.from(headers.values())),setHeader(\"location\",redirectUrl)}else shouldBailoutToCSR||(res.statusCode=500,metadata.statusCode=res.statusCode);let[errorPreinitScripts,errorBootstrapScript]=getRequiredScripts(buildManifest,assetPrefix,crossOrigin,subresourceIntegrityManifest,getAssetQueryString(ctx,!1),nonce,\"/_not-found/page\");{let errorRSCPayload,errorServerStream;try{if(errorRSCPayload=await work_unit_async_storage_external_js_.workUnitAsyncStorage.run(requestStore,getErrorRSCPayload,tree,ctx,reactServerErrorsByDigest.has(err.digest)?null:err,errorType,!0),errorServerStream=work_unit_async_storage_external_js_.workUnitAsyncStorage.run(requestStore,renderToNodeFlightStream,ctx.componentMod,errorRSCPayload,clientModules,{filterStackFrame,onError:serverComponentsErrorHandler}),null===reactServerResult)throw endSpanWithError(err),err}catch(setupErr){throw endSpanWithError(setupErr),setupErr}try{let generateStaticHTML=!0!==supportsDynamicResponse||!!shouldWaitOnAllReady,{stream:errorHtmlStream,allReady:errorAllReady}=await work_unit_async_storage_external_js_.workUnitAsyncStorage.run(requestStore,renderToNodeFizzStream,(0,jsx_runtime.jsx)(ErrorApp,{reactServerStream:errorServerStream,ServerInsertedHTMLProvider:ServerInsertedHTMLProvider,preinitScripts:errorPreinitScripts,nonc...\n Line 208: ${stack}`),err}if(null===reactServerPrerenderResult)throw err;let isHTTPAccessFallback=(0,http_access_fallback.isHTTPAccessFallbackError)(err),isRedirect=(0,redirect_error.isRedirectError)(err);if(isHTTPAccessFallback)res.statusCode=(0,http_access_fallback.getAccessFallbackHTTPStatus)(err),metadata.statusCode=res.statusCode,errorType=(0,http_access_fallback.getAccessFallbackErrorTypeByStatus)(res.statusCode);else if(isRedirect){var value1;errorType=\"redirect\",res.statusCode=(0,components_redirect.getRedirectStatusCodeFromError)(err),metadata.statusCode=res.statusCode,value1=(0,add_path_prefix.addPathPrefix)((0,components_redirect.getURLFromRedirectError)(err),basePath),res.setHeader(\"location\",value1),setMetadataHeader(\"location\")}else res.statusCode=500,metadata.statusCode=res.statusCode;if(cacheComponents&&!isHTTPAccessFallback&&!isRedirect)throw reactServerErrorsByDigest.get(err.digest)??err;let[errorPreinitScripts,errorBootstrapScript]=getRequiredScripts(buildManifest,assetPrefix,crossOrigin,subresourceIntegrityManifest,getAssetQueryString(ctx,!1),nonce,\"/_not-found/page\");if(cacheComponents){let originalFlightPrerenderResult=reactServerPrerenderResult,originalFlightPrerenderResultIsDynamic=reactServerPrerenderResultIsDynamic,originalResumeDataCache=reactServerResumeDataCache,originalPrerenderStore=reactServerPrerenderStore;if(null===originalFlightPrerenderResult)throw Object.defineProperty(new invariant_error.InvariantError(\"Cache Components error recovery expected an original Flight prerender result\"),\"__NEXT_ERROR_CODE\",{value:\"E1283\",enumerable:!1,configurable:!0});if(null===originalFlightPrerenderResultIsDynamic)throw Object.defineProperty(new invariant_error.InvariantError(\"Cache Components error recovery expected to know whether the original Flight prerender result was dynamic\"),\"__NEXT_ERROR_CODE\",{value:\"E1282\",enumerable:!1,configurable:!0});if(null===originalResumeDataCache)throw Object.defineProperty(new invariant_error.InvariantError(\"Cache Componen...\n\n/workspace/node_modules/next/dist/compiled/next-server/app-page-turbo-experimental.runtime.prod.js:\n Line 1: (()=>{var e,t,r={\"./dist/build/webpack/alias/react-dom-server-experimental.js\"(e,t,r){\"use strict\";var n;function a(){throw Object.defineProperty(Error(\"Internal Error: do not use legacy react-dom/server APIs. If you encountered this error, please open an issue on the Next.js repo.\"),\"__NEXT_ERROR_CODE\",{value:\"E1021\",enumerable:!1,configurable:!0})}t.version=(n=r(\"./dist/compiled/react-dom-experimental/cjs/react-dom-server.node.production.js\")).version,t.renderToReadableStream=n.renderToReadableStream,t.renderToString=a,t.renderToStaticMarkup=a,n.resume&&(t.resume=n.resume),n.renderToPipeableStream&&(t.renderToPipeableStream=n.renderToPipeableStream),n.resumeToPipeableStream&&(t.resumeToPipeableStream=n.resumeToPipeableStream)},\"./dist/compiled/@edge-runtime/cookies/index.js\"(e){\"use strict\";var t=Object.defineProperty,r=Object.getOwnPropertyDescriptor,n=Object.getOwnPropertyNames,a=Object.prototype.hasOwnProperty,i={},s={RequestCookies:()=>h,ResponseCookies:()=>p,parseCookie:()=>u,parseSetCookie:()=>c,stringifyCookie:()=>l};for(var o in s)t(i,o,{get:s[o],enumerable:!0});function l(e){var t;let r=[\"path\"in e&&e.path&&`Path=${e.path}`,\"expires\"in e&&(e.expires||0===e.expires)&&`Expires=${(\"number\"==typeof e.expires?new Date(e.expires):e.expires).toUTCString()}`,\"maxAge\"in e&&\"number\"==typeof e.maxAge&&`Max-Age=${e.maxAge}`,\"domain\"in e&&e.domain&&`Domain=${e.domain}`,\"secure\"in e&&e.secure&&\"Secure\",\"httpOnly\"in e&&e.httpOnly&&\"HttpOnly\",\"sameSite\"in e&&e.sameSite&&`SameSite=${e.sameSite}`,\"partitioned\"in e&&e.partitioned&&\"Partitioned\",\"priority\"in e&&e.priority&&`Priority=${e.priority}`].filter(Boolean),n=`${e.name}=${encodeURIComponent(null!=(t=e.value)?t:\"\")}`;return 0===r.length?n:`${n}; ${r.join(\"; \")}`}function u(e){let t=new Map;for(let r of e.split(/; */)){if(!r)continue;let e=r.indexOf(\"=\");if(-1===e){t.set(r,\"true\");continue}let[n,a]=[r.slice(0,e),r.slice(e+1)];try{t.set(n,decodeURIComponent(null!=a?a:\"true\"))}catch{}}return t}function c(e){if(!e)return;l...\n Line 2: --${S}`,B),this._writecb=null,this._finalcb=null,this.write(d)}static detect(e){return\"multipart\"===e.type&&\"form-data\"===e.subtype}_write(e,t,r){let n;this._writecb=r,this._bparser.push(e,0),this._writecb&&(n=this._writecb,this._writecb=null,n&&n())}_destroy(e,t){this._hparser=null,this._bparser=y,e||(e=S(this));let r=this._fileStream;r&&(this._fileStream=null,r.destroy(e)),t(e)}_final(e){if(this._bparser.destroy(),!this._complete)return e(Error(\"Unexpected end of form\"));this._fileEndsLeft?this._finalcb=b.bind(null,this,e):b(this,e)}}},183:function(e,t,r){let{Writable:n}=r(203),{getDecoder:a}=r(827);function i(e,t,r,n){if(r>=n)return n;if(-1===e._byte){let a=l[t[r++]];if(-1===a)return -1;if(a>=8&&(e._encode=2),re.fieldNameSizeLimit){for(!e._keyTrunc&&e._lastPose.fieldSizeLimit){for(!e._valTrunc&&e._lastPos\n
\n
Product Catalog
\n
\n Sync latest catalog\n
\n
\n\n
\n \n
\n
ID
\n
Name
\n
Price
\n
\n \n \n {products.map((product) => (\n
\n
{product.id}
\n
{product.name}
\n
\n ${product.price}\n
\n
\n ))}\n \n
\n \n )\n}\n"},"output":"","title":"app/page.tsx","metadata":{"diagnostics":{"/workspace/app/layout.tsx":[],"/workspace/app/page.tsx":[],"/workspace/lib/db.js":[],"/workspace/next.config.ts":[],"/workspace/lib/products.ts":[],"/workspace/node_modules/next/dist/server/web/spec-extension/revalidate.js":[{"range":{"start":{"line":1,"character":0},"end":{"line":3,"character":2}},"message":"File is a CommonJS module; it may be converted to an ES module.","severity":4,"code":80001,"source":"typescript"}]},"filepath":"/workspace/app/page.tsx","exists":true},"time":{"start":1781390658655,"end":1781390659408}}}}
+{"type":"step_finish","timestamp":1781390659420,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec3284f520014wqR91tB0U1mC5","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec3276c5c0010LHfKgws7GnJTx","type":"step-finish","reason":"tool-calls","snapshot":"d26a136dd540891a469ed57c47d075abe937b62c","cost":0.06777442,"tokens":{"input":50254,"output":1967,"reasoning":0,"cache":{"read":76032,"write":0}}}}
+{"type":"step_start","timestamp":1781390663185,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec3285e0a001JsGBA4PmjoJyVZ","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec3284f780013jEm6mno4nFWJo","type":"step-start","snapshot":"d26a136dd540891a469ed57c47d075abe937b62c"}}
+{"type":"tool_use","timestamp":1781390666743,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec3286a64001ClBKX55PkHTBKY","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec3284f780013jEm6mno4nFWJo","type":"tool","callID":"read_20","tool":"read","state":{"status":"completed","input":{"filePath":"/workspace/node_modules/next/dist/server/web/spec-extension/unstable-cache.d.ts"},"output":"\n00001| type Callback = (...args: any[]) => Promise;\n00002| /**\n00003| * This function allows you to cache the results of expensive operations, like database queries, and reuse them across multiple requests.\n00004| *\n00005| * Read more: [Next.js Docs: `unstable_cache`](https://nextjs.org/docs/app/api-reference/functions/unstable_cache)\n00006| */\n00007| export declare function unstable_cache(cb: T, keyParts?: string[], options?: {\n00008| /**\n00009| * The revalidation interval in seconds.\n00010| */\n00011| revalidate?: number | false;\n00012| tags?: string[];\n00013| }): T;\n00014| export {};\n00015| \n\n(End of file - total 15 lines)\n","title":"node_modules/next/dist/server/web/spec-extension/unstable-cache.d.ts","metadata":{"preview":"type Callback = (...args: any[]) => Promise;\n/**\n * This function allows you to cache the results of expensive operations, like database queries, and reuse them across multiple requests.\n *\n * Read more: [Next.js Docs: `unstable_cache`](https://nextjs.org/docs/app/api-reference/functions/unstable_cache)\n */\nexport declare function unstable_cache(cb: T, keyParts?: string[], options?: {\n /**\n * The revalidation interval in seconds.\n */\n revalidate?: number | false;\n tags?: string[];\n}): T;\nexport {};\n"},"time":{"start":1781390666738,"end":1781390666741}}}}
+{"type":"step_finish","timestamp":1781390666766,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec3286bf6001kEFfSJIgXmERNx","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec3284f780013jEm6mno4nFWJo","type":"step-finish","reason":"tool-calls","snapshot":"d26a136dd540891a469ed57c47d075abe937b62c","cost":0.02284323,"tokens":{"input":2061,"output":173,"reasoning":0,"cache":{"read":126208,"write":0}}}}
+{"type":"step_start","timestamp":1781390669723,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec3287797001baQ5FqPcPvaS9s","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec3286c2f0010lrbLJytBDuB73","type":"step-start","snapshot":"d26a136dd540891a469ed57c47d075abe937b62c"}}
+{"type":"tool_use","timestamp":1781390682374,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec3287ac7001tCBFSyfuZmZgiR","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec3286c2f0010lrbLJytBDuB73","type":"tool","callID":"bash_21","tool":"bash","state":{"status":"completed","input":{"command":"npm run build","description":"Build Next.js app to verify","timeout":300000},"output":"\n> build\n> next build\n\nAttention: Next.js now collects completely anonymous telemetry regarding usage.\nThis information is used to shape Next.js' roadmap and prioritize features.\nYou can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:\nhttps://nextjs.org/telemetry\n\n▲ Next.js 16.3.0-canary.50 (Turbopack)\n\n Creating an optimized production build ...\n✓ Compiled successfully in 6.4s\n Running TypeScript ...\n\n We detected TypeScript in your project and reconfigured your tsconfig.json file for you.\n The following suggested values were added to your tsconfig.json. These values can be changed to fit your project's needs:\n\n \t- include was updated to add '.next/dev/types/**/*.ts'\n\n Finished TypeScript in 2.4s ...\n Collecting page data using 1 worker ...\n Generating static pages using 1 worker (0/3) ...\n✓ Generating static pages using 1 worker (3/3) in 234ms\n Finalizing page optimization ...\n\nRoute (app)\n┌ ○ /\n└ ○ /_not-found\n\n\n○ (Static) prerendered as static content\n\n","title":"Build Next.js app to verify","metadata":{"output":"\n> build\n> next build\n\nAttention: Next.js now collects completely anonymous telemetry regarding usage.\nThis information is used to shape Next.js' roadmap and prioritize features.\nYou can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:\nhttps://nextjs.org/telemetry\n\n▲ Next.js 16.3.0-canary.50 (Turbopack)\n\n Creating an optimized production build ...\n✓ Compiled successfully in 6.4s\n Running TypeScript ...\n\n We detected TypeScript in your project and reconfigured your tsconfig.json file for you.\n The following suggested values were added to your tsconfig.json. These values can be changed to fit your project's needs:\n\n \t- include was updated to add '.next/dev/types/**/*.ts'\n\n Finished TypeScript in 2.4s ...\n Collecting page data using 1 worker ...\n Generating static pages using 1 worker (0/3) ...\n✓ Generating static pages using 1 worker (3/3) in 234ms\n Finalizing page optimization ...\n\nRoute (app)\n┌ ○ /\n└ ○ /_not-found\n\n\n○ (Static) prerendered as static content\n\n","exit":0,"description":"Build Next.js app to verify"},"time":{"start":1781390670831,"end":1781390682369}}}}
+{"type":"step_finish","timestamp":1781390682495,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec328a904001V3ma4ar7TFMcwz","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec3286c2f0010lrbLJytBDuB73","type":"step-finish","reason":"tool-calls","snapshot":"453cf69fc0c9058f32070a489861fd9f769cd986","cost":0.02119661,"tokens":{"input":387,"output":77,"reasoning":0,"cache":{"read":128256,"write":0}}}}
+{"type":"step_start","timestamp":1781390686423,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec328b8ce0011yplZ8V0135OpD","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec328a99e001h2dY8NWO5A6GvD","type":"step-start","snapshot":"453cf69fc0c9058f32070a489861fd9f769cd986"}}
+{"type":"tool_use","timestamp":1781390700514,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec328ebc60018CdM2wKg0xZZ4p","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec328a99e001h2dY8NWO5A6GvD","type":"tool","callID":"todowrite_22","tool":"todowrite","state":{"status":"completed","input":{"todos":[{"id":"1","content":"Create cached product fetcher with 'products' cache tag","status":"completed","priority":"high"},{"id":"2","content":"Implement admin catalog page with inline Server Action sync form","status":"completed","priority":"high"},{"id":"3","content":"Verify build passes","status":"completed","priority":"medium"}]},"output":"[\n {\n \"id\": \"1\",\n \"content\": \"Create cached product fetcher with 'products' cache tag\",\n \"status\": \"completed\",\n \"priority\": \"high\"\n },\n {\n \"id\": \"2\",\n \"content\": \"Implement admin catalog page with inline Server Action sync form\",\n \"status\": \"completed\",\n \"priority\": \"high\"\n },\n {\n \"id\": \"3\",\n \"content\": \"Verify build passes\",\n \"status\": \"completed\",\n \"priority\": \"medium\"\n }\n]","title":"0 todos","metadata":{"todos":[{"id":"1","content":"Create cached product fetcher with 'products' cache tag","status":"completed","priority":"high"},{"id":"2","content":"Implement admin catalog page with inline Server Action sync form","status":"completed","priority":"high"},{"id":"3","content":"Verify build passes","status":"completed","priority":"medium"}]},"time":{"start":1781390700507,"end":1781390700512}}}}
+{"type":"step_finish","timestamp":1781390700521,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec328efe1001tQkViud9fz1Hho","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec328a99e001h2dY8NWO5A6GvD","type":"step-finish","reason":"tool-calls","snapshot":"453cf69fc0c9058f32070a489861fd9f769cd986","cost":0.02402762,"tokens":{"input":486,"output":751,"reasoning":0,"cache":{"read":128512,"write":0}}}}
+{"type":"step_start","timestamp":1781390703953,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec328fd4c0010bbd2Kzhp6T8tc","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec328f03000132JPeKAmd9kzFc","type":"step-start","snapshot":"453cf69fc0c9058f32070a489861fd9f769cd986"}}
+{"type":"text","timestamp":1781390705755,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec3290011001KUTggkiTsxq70c","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec328f03000132JPeKAmd9kzFc","type":"text","text":"Implemented the admin catalog page.\n\n- `lib/products.ts` wraps `getAllProducts` in `unstable_cache` with tag `\"products\"`.\n- `app/page.tsx` renders the cached catalog and provides an inline Server Action form that calls `updateTag('products')` to trigger a sync.\n\nBuild passes.","time":{"start":1781390705750,"end":1781390705750}}}
+{"type":"step_finish","timestamp":1781390705758,"sessionID":"ses_13cdad348ffebF7uacyAybwt4o","part":{"id":"prt_ec3290456001I0wpupOpQGItbP","sessionID":"ses_13cdad348ffebF7uacyAybwt4o","messageID":"msg_ec328f03000132JPeKAmd9kzFc","type":"step-finish","reason":"stop","snapshot":"453cf69fc0c9058f32070a489861fd9f769cd986","cost":0.02210898,"tokens":{"input":1118,"output":111,"reasoning":0,"cache":{"read":128768,"write":0}}}}
\ No newline at end of file
diff --git a/results/kimi-k2.7-code/2026-06-13T22-40-06.944Z/agent-029-use-cache-directive/run-4/transcript.json b/results/kimi-k2.7-code/2026-06-13T22-40-06.944Z/agent-029-use-cache-directive/run-4/transcript.json
new file mode 100644
index 000000000..02b55d774
--- /dev/null
+++ b/results/kimi-k2.7-code/2026-06-13T22-40-06.944Z/agent-029-use-cache-directive/run-4/transcript.json
@@ -0,0 +1,2073 @@
+{
+ "agent": "vercel-ai-gateway/opencode",
+ "model": "vercel/moonshotai/kimi-k2.7-code",
+ "events": [
+ {
+ "timestamp": "2026-06-13T22:40:58.478Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "shell",
+ "originalName": "bash",
+ "args": {
+ "command": "ls -la",
+ "description": "List workspace files",
+ "_extractedCommand": "ls -la"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781390458478,
+ "sessionID": "ses_13cdad348ffebF7uacyAybwt4o",
+ "part": {
+ "id": "prt_ec3253c91001hFc386nwxwVbjB",
+ "sessionID": "ses_13cdad348ffebF7uacyAybwt4o",
+ "messageID": "msg_ec3252d2000177Wzw5soein6hy",
+ "type": "tool",
+ "callID": "bash_0",
+ "tool": "bash",
+ "state": {
+ "status": "completed",
+ "input": {
+ "command": "ls -la",
+ "description": "List workspace files"
+ },
+ "output": "total 184\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 187 Jun 13 22:40 .\ndrwxr-xr-x 20 root root 286 Jun 13 22:40 ..\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 154 Jun 13 22:40 .git\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 14 Jun 13 22:40 .gitignore\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 40 Jun 13 22:40 app\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 19 Jun 13 22:40 lib\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 101 Jun 13 22:40 next.config.ts\ndrwxr-xr-x 179 vercel-sandbox vercel-sandbox 8192 Jun 13 22:40 node_modules\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 1549 Jun 13 22:40 opencode.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 154377 Jun 13 22:40 package-lock.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 603 Jun 13 22:40 package.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 599 Jun 13 22:40 tsconfig.json\n",
+ "title": "List workspace files",
+ "metadata": {
+ "output": "total 184\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 187 Jun 13 22:40 .\ndrwxr-xr-x 20 root root 286 Jun 13 22:40 ..\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 154 Jun 13 22:40 .git\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 14 Jun 13 22:40 .gitignore\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 40 Jun 13 22:40 app\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 19 Jun 13 22:40 lib\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 101 Jun 13 22:40 next.config.ts\ndrwxr-xr-x 179 vercel-sandbox vercel-sandbox 8192 Jun 13 22:40 node_modules\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 1549 Jun 13 22:40 opencode.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 154377 Jun 13 22:40 package-lock.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 603 Jun 13 22:40 package.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 599 Jun 13 22:40 tsconfig.json\n",
+ "exit": 0,
+ "description": "List workspace files"
+ },
+ "time": {
+ "start": 1781390458380,
+ "end": 1781390458444
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T22:40:58.478Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "shell",
+ "originalName": "bash",
+ "result": "total 184\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 187 Jun 13 22:40 .\ndrwxr-xr-x 20 root root 286 Jun 13 22:40 ..\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 154 Jun 13 22:40 .git\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 14 Jun 13 22:40 .gitignore\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 40 Jun 13 22:40 app\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 19 Jun 13 22:40 lib\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 101 Jun 13 22:40 next.config.ts\ndrwxr-xr-x 179 vercel-sandbox vercel-sandbox 8192 Jun 13 22:40 node_modules\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 1549 Jun 13 22:40 opencode.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 154377 Jun 13 22:40 package-lock.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 603 Jun 13 22:40 package.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 599 Jun 13 22:40 tsconfig.json\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "command": "ls -la",
+ "description": "List workspace files"
+ },
+ "output": "total 184\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 187 Jun 13 22:40 .\ndrwxr-xr-x 20 root root 286 Jun 13 22:40 ..\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 154 Jun 13 22:40 .git\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 14 Jun 13 22:40 .gitignore\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 40 Jun 13 22:40 app\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 19 Jun 13 22:40 lib\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 101 Jun 13 22:40 next.config.ts\ndrwxr-xr-x 179 vercel-sandbox vercel-sandbox 8192 Jun 13 22:40 node_modules\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 1549 Jun 13 22:40 opencode.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 154377 Jun 13 22:40 package-lock.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 603 Jun 13 22:40 package.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 599 Jun 13 22:40 tsconfig.json\n",
+ "title": "List workspace files",
+ "metadata": {
+ "output": "total 184\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 187 Jun 13 22:40 .\ndrwxr-xr-x 20 root root 286 Jun 13 22:40 ..\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 154 Jun 13 22:40 .git\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 14 Jun 13 22:40 .gitignore\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 40 Jun 13 22:40 app\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 19 Jun 13 22:40 lib\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 101 Jun 13 22:40 next.config.ts\ndrwxr-xr-x 179 vercel-sandbox vercel-sandbox 8192 Jun 13 22:40 node_modules\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 1549 Jun 13 22:40 opencode.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 154377 Jun 13 22:40 package-lock.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 603 Jun 13 22:40 package.json\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 599 Jun 13 22:40 tsconfig.json\n",
+ "exit": 0,
+ "description": "List workspace files"
+ },
+ "time": {
+ "start": 1781390458380,
+ "end": 1781390458444
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T22:41:00.560Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "shell",
+ "originalName": "bash",
+ "args": {
+ "command": "ls -la app lib",
+ "description": "List app and lib directories",
+ "_extractedCommand": "ls -la app lib"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781390460560,
+ "sessionID": "ses_13cdad348ffebF7uacyAybwt4o",
+ "part": {
+ "id": "prt_ec32544d7001wPs324WYy8RS6I",
+ "sessionID": "ses_13cdad348ffebF7uacyAybwt4o",
+ "messageID": "msg_ec3253e7a001Nh4IjSPSNsvuda",
+ "type": "tool",
+ "callID": "bash_1",
+ "tool": "bash",
+ "state": {
+ "status": "completed",
+ "input": {
+ "command": "ls -la app lib",
+ "description": "List app and lib directories"
+ },
+ "output": "app:\ntotal 8\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 40 Jun 13 22:40 .\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 187 Jun 13 22:40 ..\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 329 Jun 13 22:40 layout.tsx\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 91 Jun 13 22:40 page.tsx\n\nlib:\ntotal 4\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 19 Jun 13 22:40 .\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 187 Jun 13 22:40 ..\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 364 Jun 13 22:40 db.js\n",
+ "title": "List app and lib directories",
+ "metadata": {
+ "output": "app:\ntotal 8\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 40 Jun 13 22:40 .\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 187 Jun 13 22:40 ..\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 329 Jun 13 22:40 layout.tsx\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 91 Jun 13 22:40 page.tsx\n\nlib:\ntotal 4\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 19 Jun 13 22:40 .\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 187 Jun 13 22:40 ..\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 364 Jun 13 22:40 db.js\n",
+ "exit": 0,
+ "description": "List app and lib directories"
+ },
+ "time": {
+ "start": 1781390460552,
+ "end": 1781390460559
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T22:41:00.560Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "shell",
+ "originalName": "bash",
+ "result": "app:\ntotal 8\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 40 Jun 13 22:40 .\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 187 Jun 13 22:40 ..\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 329 Jun 13 22:40 layout.tsx\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 91 Jun 13 22:40 page.tsx\n\nlib:\ntotal 4\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 19 Jun 13 22:40 .\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 187 Jun 13 22:40 ..\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 364 Jun 13 22:40 db.js\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "command": "ls -la app lib",
+ "description": "List app and lib directories"
+ },
+ "output": "app:\ntotal 8\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 40 Jun 13 22:40 .\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 187 Jun 13 22:40 ..\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 329 Jun 13 22:40 layout.tsx\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 91 Jun 13 22:40 page.tsx\n\nlib:\ntotal 4\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 19 Jun 13 22:40 .\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 187 Jun 13 22:40 ..\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 364 Jun 13 22:40 db.js\n",
+ "title": "List app and lib directories",
+ "metadata": {
+ "output": "app:\ntotal 8\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 40 Jun 13 22:40 .\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 187 Jun 13 22:40 ..\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 329 Jun 13 22:40 layout.tsx\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 91 Jun 13 22:40 page.tsx\n\nlib:\ntotal 4\ndrwxr-xr-x 2 vercel-sandbox vercel-sandbox 19 Jun 13 22:40 .\ndrwxr-xr-x 6 vercel-sandbox vercel-sandbox 187 Jun 13 22:40 ..\n-rw-r--r-- 1 vercel-sandbox vercel-sandbox 364 Jun 13 22:40 db.js\n",
+ "exit": 0,
+ "description": "List app and lib directories"
+ },
+ "time": {
+ "start": 1781390460552,
+ "end": 1781390460559
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T22:41:00.793Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "args": {
+ "filePath": "/workspace/package.json",
+ "_extractedPath": "/workspace/package.json"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781390460793,
+ "sessionID": "ses_13cdad348ffebF7uacyAybwt4o",
+ "part": {
+ "id": "prt_ec325468e001cLhlb60y9eNZIX",
+ "sessionID": "ses_13cdad348ffebF7uacyAybwt4o",
+ "messageID": "msg_ec3253e7a001Nh4IjSPSNsvuda",
+ "type": "tool",
+ "callID": "read_2",
+ "tool": "read",
+ "state": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/package.json"
+ },
+ "output": "\n00001| {\n00002| \"private\": true,\n00003| \"type\": \"module\",\n00004| \"scripts\": {\n00005| \"dev\": \"next dev\",\n00006| \"build\": \"next build\",\n00007| \"start\": \"next start\"\n00008| },\n00009| \"dependencies\": {\n00010| \"@ai-sdk/react\": \"2.0.0-beta.28\",\n00011| \"@modelcontextprotocol/sdk\": \"^1.17.0\",\n00012| \"ai\": \"5.0.59\",\n00013| \"next\": \"^16.3.0-canary.50\",\n00014| \"react\": \"19.1.0\",\n00015| \"react-dom\": \"19.1.0\",\n00016| \"zod\": \"^4.0.10\"\n00017| },\n00018| \"devDependencies\": {\n00019| \"@types/node\": \"^20\",\n00020| \"@types/react\": \"^19\",\n00021| \"@types/react-dom\": \"^19\",\n00022| \"@vitejs/plugin-react\": \"^4.4.1\",\n00023| \"typescript\": \"^5\",\n00024| \"vite-tsconfig-paths\": \"^5.1.4\",\n00025| \"vitest\": \"^3.1.3\"\n00026| }\n00027| }\n00028| \n\n(End of file - total 28 lines)\n",
+ "title": "package.json",
+ "metadata": {
+ "preview": "{\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"next dev\",\n \"build\": \"next build\",\n \"start\": \"next start\"\n },\n \"dependencies\": {\n \"@ai-sdk/react\": \"2.0.0-beta.28\",\n \"@modelcontextprotocol/sdk\": \"^1.17.0\",\n \"ai\": \"5.0.59\",\n \"next\": \"^16.3.0-canary.50\",\n \"react\": \"19.1.0\",\n \"react-dom\": \"19.1.0\",\n \"zod\": \"^4.0.10\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^20\",\n \"@types/react\": \"^19\","
+ },
+ "time": {
+ "start": 1781390460774,
+ "end": 1781390460790
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T22:41:00.793Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| {\n00002| \"private\": true,\n00003| \"type\": \"module\",\n00004| \"scripts\": {\n00005| \"dev\": \"next dev\",\n00006| \"build\": \"next build\",\n00007| \"start\": \"next start\"\n00008| },\n00009| \"dependencies\": {\n00010| \"@ai-sdk/react\": \"2.0.0-beta.28\",\n00011| \"@modelcontextprotocol/sdk\": \"^1.17.0\",\n00012| \"ai\": \"5.0.59\",\n00013| \"next\": \"^16.3.0-canary.50\",\n00014| \"react\": \"19.1.0\",\n00015| \"react-dom\": \"19.1.0\",\n00016| \"zod\": \"^4.0.10\"\n00017| },\n00018| \"devDependencies\": {\n00019| \"@types/node\": \"^20\",\n00020| \"@types/react\": \"^19\",\n00021| \"@types/react-dom\": \"^19\",\n00022| \"@vitejs/plugin-react\": \"^4.4.1\",\n00023| \"typescript\": \"^5\",\n00024| \"vite-tsconfig-paths\": \"^5.1.4\",\n00025| \"vitest\": \"^3.1.3\"\n00026| }\n00027| }\n00028| \n\n(End of file - total 28 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/package.json"
+ },
+ "output": "\n00001| {\n00002| \"private\": true,\n00003| \"type\": \"module\",\n00004| \"scripts\": {\n00005| \"dev\": \"next dev\",\n00006| \"build\": \"next build\",\n00007| \"start\": \"next start\"\n00008| },\n00009| \"dependencies\": {\n00010| \"@ai-sdk/react\": \"2.0.0-beta.28\",\n00011| \"@modelcontextprotocol/sdk\": \"^1.17.0\",\n00012| \"ai\": \"5.0.59\",\n00013| \"next\": \"^16.3.0-canary.50\",\n00014| \"react\": \"19.1.0\",\n00015| \"react-dom\": \"19.1.0\",\n00016| \"zod\": \"^4.0.10\"\n00017| },\n00018| \"devDependencies\": {\n00019| \"@types/node\": \"^20\",\n00020| \"@types/react\": \"^19\",\n00021| \"@types/react-dom\": \"^19\",\n00022| \"@vitejs/plugin-react\": \"^4.4.1\",\n00023| \"typescript\": \"^5\",\n00024| \"vite-tsconfig-paths\": \"^5.1.4\",\n00025| \"vitest\": \"^3.1.3\"\n00026| }\n00027| }\n00028| \n\n(End of file - total 28 lines)\n",
+ "title": "package.json",
+ "metadata": {
+ "preview": "{\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"next dev\",\n \"build\": \"next build\",\n \"start\": \"next start\"\n },\n \"dependencies\": {\n \"@ai-sdk/react\": \"2.0.0-beta.28\",\n \"@modelcontextprotocol/sdk\": \"^1.17.0\",\n \"ai\": \"5.0.59\",\n \"next\": \"^16.3.0-canary.50\",\n \"react\": \"19.1.0\",\n \"react-dom\": \"19.1.0\",\n \"zod\": \"^4.0.10\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^20\",\n \"@types/react\": \"^19\","
+ },
+ "time": {
+ "start": 1781390460774,
+ "end": 1781390460790
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T22:41:00.901Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "args": {
+ "filePath": "/workspace/next.config.ts",
+ "_extractedPath": "/workspace/next.config.ts"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781390460901,
+ "sessionID": "ses_13cdad348ffebF7uacyAybwt4o",
+ "part": {
+ "id": "prt_ec3254775001R0DCRYQwjcdkHA",
+ "sessionID": "ses_13cdad348ffebF7uacyAybwt4o",
+ "messageID": "msg_ec3253e7a001Nh4IjSPSNsvuda",
+ "type": "tool",
+ "callID": "read_3",
+ "tool": "read",
+ "state": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/next.config.ts"
+ },
+ "output": "\n00001| import type { NextConfig } from 'next'\n00002| \n00003| const nextConfig: NextConfig = {}\n00004| \n00005| export default nextConfig\n00006| \n\n(End of file - total 6 lines)\n",
+ "title": "next.config.ts",
+ "metadata": {
+ "preview": "import type { NextConfig } from 'next'\n\nconst nextConfig: NextConfig = {}\n\nexport default nextConfig\n"
+ },
+ "time": {
+ "start": 1781390460887,
+ "end": 1781390460892
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T22:41:00.901Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| import type { NextConfig } from 'next'\n00002| \n00003| const nextConfig: NextConfig = {}\n00004| \n00005| export default nextConfig\n00006| \n\n(End of file - total 6 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/next.config.ts"
+ },
+ "output": "\n00001| import type { NextConfig } from 'next'\n00002| \n00003| const nextConfig: NextConfig = {}\n00004| \n00005| export default nextConfig\n00006| \n\n(End of file - total 6 lines)\n",
+ "title": "next.config.ts",
+ "metadata": {
+ "preview": "import type { NextConfig } from 'next'\n\nconst nextConfig: NextConfig = {}\n\nexport default nextConfig\n"
+ },
+ "time": {
+ "start": 1781390460887,
+ "end": 1781390460892
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T22:41:02.600Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "args": {
+ "filePath": "/workspace/app/layout.tsx",
+ "_extractedPath": "/workspace/app/layout.tsx"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781390462600,
+ "sessionID": "ses_13cdad348ffebF7uacyAybwt4o",
+ "part": {
+ "id": "prt_ec3254dc4001XgRhGGbZjVXmBD",
+ "sessionID": "ses_13cdad348ffebF7uacyAybwt4o",
+ "messageID": "msg_ec3254801001FuxDQyZJpSzYFd",
+ "type": "tool",
+ "callID": "read_4",
+ "tool": "read",
+ "state": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/app/layout.tsx"
+ },
+ "output": "\n00001| import type { Metadata } from 'next'\n00002| \n00003| export const metadata: Metadata = {\n00004| title: 'Create Next App',\n00005| description: 'Generated by create next app',\n00006| }\n00007| \n00008| export default function RootLayout({\n00009| children,\n00010| }: Readonly<{\n00011| children: React.ReactNode\n00012| }>) {\n00013| return (\n00014| \n00015| {children}\n00016| \n00017| )\n00018| }\n00019| \n\n(End of file - total 19 lines)\n",
+ "title": "app/layout.tsx",
+ "metadata": {
+ "preview": "import type { Metadata } from 'next'\n\nexport const metadata: Metadata = {\n title: 'Create Next App',\n description: 'Generated by create next app',\n}\n\nexport default function RootLayout({\n children,\n}: Readonly<{\n children: React.ReactNode\n}>) {\n return (\n \n {children}\n \n )\n}\n"
+ },
+ "time": {
+ "start": 1781390462587,
+ "end": 1781390462598
+ }
+ }
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T22:41:02.600Z",
+ "type": "tool_result",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "result": "\n00001| import type { Metadata } from 'next'\n00002| \n00003| export const metadata: Metadata = {\n00004| title: 'Create Next App',\n00005| description: 'Generated by create next app',\n00006| }\n00007| \n00008| export default function RootLayout({\n00009| children,\n00010| }: Readonly<{\n00011| children: React.ReactNode\n00012| }>) {\n00013| return (\n00014| \n00015| {children}\n00016| \n00017| )\n00018| }\n00019| \n\n(End of file - total 19 lines)\n",
+ "success": true
+ },
+ "raw": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/app/layout.tsx"
+ },
+ "output": "\n00001| import type { Metadata } from 'next'\n00002| \n00003| export const metadata: Metadata = {\n00004| title: 'Create Next App',\n00005| description: 'Generated by create next app',\n00006| }\n00007| \n00008| export default function RootLayout({\n00009| children,\n00010| }: Readonly<{\n00011| children: React.ReactNode\n00012| }>) {\n00013| return (\n00014| \n00015| {children}\n00016| \n00017| )\n00018| }\n00019| \n\n(End of file - total 19 lines)\n",
+ "title": "app/layout.tsx",
+ "metadata": {
+ "preview": "import type { Metadata } from 'next'\n\nexport const metadata: Metadata = {\n title: 'Create Next App',\n description: 'Generated by create next app',\n}\n\nexport default function RootLayout({\n children,\n}: Readonly<{\n children: React.ReactNode\n}>) {\n return (\n \n {children}\n \n )\n}\n"
+ },
+ "time": {
+ "start": 1781390462587,
+ "end": 1781390462598
+ }
+ }
+ },
+ {
+ "timestamp": "2026-06-13T22:41:02.813Z",
+ "type": "tool_call",
+ "tool": {
+ "name": "file_read",
+ "originalName": "read",
+ "args": {
+ "filePath": "/workspace/app/page.tsx",
+ "_extractedPath": "/workspace/app/page.tsx"
+ }
+ },
+ "raw": {
+ "type": "tool_use",
+ "timestamp": 1781390462813,
+ "sessionID": "ses_13cdad348ffebF7uacyAybwt4o",
+ "part": {
+ "id": "prt_ec3254e85001MaiKzyLfwE4bWM",
+ "sessionID": "ses_13cdad348ffebF7uacyAybwt4o",
+ "messageID": "msg_ec3254801001FuxDQyZJpSzYFd",
+ "type": "tool",
+ "callID": "read_5",
+ "tool": "read",
+ "state": {
+ "status": "completed",
+ "input": {
+ "filePath": "/workspace/app/page.tsx"
+ },
+ "output": "\n00001| export default function Page() {\n00002| return (\n00003|
\n00004|
Home
\n00005|
\n00006| )\n00007| }\n00008| \n\n(End of file - total 8 lines)\n",
+ "title": "app/page.tsx",
+ "metadata": {
+ "preview": "export default function Page() {\n return (\n