The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more
A prerendered Nuxt page is HTML generated at build time, but it is still a Vue application when it loads in the browser. Hydration runs your component code again on the client, so any data call written directly in component setup can run a second time there. The CMS request you see in the browser is usually that call, not a sign that prerendering failed.
What prerendering does and does not change
Prerendering produces static output for the routes you select. The server renders each page once during the build, writes the HTML to disk, and serves that file on request. It does not stop the browser from running your JavaScript afterward. When the page loads, Nuxt hydrates the HTML, which means Vue attaches to the existing markup and executes the component logic again. Any network request that logic makes is a new request from the browser.
So the question is not whether the page was prerendered. The question is whether the data it needs was fetched in a way Nuxt can transfer from the server to the client. If it was not, the client has to ask for it again.
Why a direct $fetch call repeats the request
Nuxt’s documentation describes this exact case. Calling $fetch directly in the setup function of a component is a common source of duplicate requests. The official wording is:
#1 Best Overall
“If the $fetch function is used to perform data fetching in the setup function of a Vue component, this may cause data to be fetched twice, once on the server (to render the HTML) and once again on the client (when the HTML is hydrated).”
The reason is that a plain $fetch result is not stored in the Nuxt payload. The server has the data and renders it into the HTML, but the client has no record of that response, so the setup code requests it again during hydration. Prerendering does not change this, because the build-time render goes through the same server path.
How useFetch and useAsyncData avoid the second request
For data that should be fetched once on the server and reused on the client, Nuxt’s supported pattern is useFetch or useAsyncData. These composables serialize the result into the payload. When the client hydrates and the data is present, Nuxt reads it from the payload rather than sending the request again.
Rank #2
Several options change this behavior, and they are the first thing to check:
| Setting or pattern | Where the data is fetched | Stored in payload | Browser request on hydration |
|---|---|---|---|
Direct $fetch in component setup |
Server render, then again in the browser | No | Yes, a repeat of the server request |
useFetch or useAsyncData (defaults) |
Server during SSR or prerender | Yes | No, if the payload has the data |
useAsyncData with server: false |
Browser only, after hydration | Not applicable | Yes, by design; the fetch waits until hydration |
useAsyncData with serialize: false |
Server during SSR or prerender | No | Yes, if the data is rendered on the client |
The server: false row is the one most often misread. It is not a bug when the request appears after hydration, because you asked for that behavior. The serialize: false row is the one most often overlooked. The server still fetches the data, but it is kept out of the payload, so the client fetches it again if the component uses it.
Check whether the request is a CMS call at all
Before changing code, confirm what the browser is requesting. A request to a URL ending in _payload.json is Nuxt loading its own payload, not a CMS API call. Depending on the payload extraction option in your Nuxt configuration, the initial page may embed the payload, or client-side navigation may fetch an extracted _payload.json file. Neither case is a CMS request, and neither means your data is being refetched from the CMS.
Rank #3
A step-by-step diagnosis
- Open the affected URL in a fresh tab with the browser developer tools open on the Network panel. Enable Preserve log, then reload the page.
- Find the CMS request. Note whether it is listed during the initial document load, after the page has finished hydrating, or only when you navigate to the page from another route inside the app.
- Open the Initiator column for that request. If it points to a component or composable file, you have found the call site. If it points to Nuxt’s internal files, check the timing against the hydration step.
- Open Nuxt DevTools and go to the Payload tab for the same route. Look for the CMS result in the payload data.
- Choose the branch that matches what you found:
- The payload is missing the CMS data. Look for direct
$fetchin setup,server: false,serialize: false, or a fetch inside client-only code such as a<ClientOnly>block or aprocess.clientcheck. - The payload contains the CMS data, but a CMS request still appears. Assume prerendering worked. Search for a second call in a plugin, a watcher, a refresh action, or a client navigation handler. Decide whether that call is intentional freshness behavior or an unnecessary repeat of the initial fetch.
- The request appears only on client-side navigation. This is expected for pages that were not fetched during the initial render, or for a route that depends on changing parameters. Check that the key and the fetch options match your intent.
- The payload is missing the CMS data. Look for direct
The steps above follow from Nuxt’s documented fetch behavior. The exact cause in a given project depends on its code and request trace, which only you can check.
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Clear out junk files and repair common Windows errors3Scan for outdated or missing drivers - takes under a minuteDynamic routes and shared keys
Shared data across routes needs a key that identifies the content. If two pages share a key that does not include the slug or route parameter, the payload can hand one page’s data to another during prerendering. Nuxt’s upgrade guidance warns about this case specifically. Include the dynamic part in the key:
const { data } = await useAsyncData(`article-${route.params.slug}`, () => fetchArticle(route.params.slug))
Check this whenever a prerendered article shows another article’s content, or when a request repeats for each slug.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Choosing a fix
When you change the code, compare the options on four axes:
Recommended Free Tools
- Must the data be in the HTML on the first response? If yes, fetch on the server and serialize the result. If no,
server: falseis a valid choice. - Should the request happen once or refresh reactively? A one-time payload read suits static content. A reactive fetch suits data that changes with user input.
- Is the content specific to a route? Give it a key that identifies the route or slug.
- Is the content public or does it need credentials? Credentials that depend on the request may need server-side handling so they are not exposed to the browser.
The Nuxt documentation supports comparing these behaviors, but it does not prescribe a CMS-specific delivery pattern. The right choice depends on your site’s requirements.
Best Value
Version notes
The behavior described here applies across Nuxt versions, but option names, defaults, and the payload extraction setting can differ. Nuxt’s documentation states that Nuxt 3 reached end of life on 31 July 2026 and no longer receives bug fixes or security patches. If you are on Nuxt 3, plan your upgrade before you change fetch code, and check the versioned documentation for your release. The Nuxt 4 prerendering page in the current documentation identifies version 4.5.2.
If you do not know your version, run npx nuxi --version in the project directory, or check the nuxt entry in package.json.
Nuxt’s official documentation for prerendering, useFetch, and useAsyncData is the authoritative reference for these options. Confirm option names there before you apply the changes in your project.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

