@nuxt/docs 4.3.1 → 4.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/1.getting-started/02.installation.md +2 -1
  2. package/1.getting-started/09.transitions.md +100 -0
  3. package/1.getting-started/16.deployment.md +2 -3
  4. package/1.getting-started/17.testing.md +63 -8
  5. package/1.getting-started/18.upgrade.md +138 -2
  6. package/2.directory-structure/1.app/1.layouts.md +60 -1
  7. package/3.guide/2.best-practices/hydration.md +13 -13
  8. package/3.guide/2.best-practices/performance.md +2 -3
  9. package/3.guide/3.ai/1.mcp.md +1 -1
  10. package/3.guide/3.ai/2.llms-txt.md +1 -1
  11. package/3.guide/5.recipes/3.custom-usefetch.md +36 -67
  12. package/3.guide/5.recipes/4.sessions-and-authentication.md +1 -1
  13. package/3.guide/6.going-further/1.experimental-features.md +81 -5
  14. package/4.api/1.components/12.nuxt-route-announcer.md +4 -0
  15. package/4.api/1.components/14.nuxt-announcer.md +81 -0
  16. package/4.api/1.components/3.nuxt-layout.md +29 -0
  17. package/4.api/1.components/8.nuxt-island.md +1 -1
  18. package/4.api/2.composables/create-use-async-data.md +90 -0
  19. package/4.api/2.composables/create-use-fetch.md +97 -0
  20. package/4.api/2.composables/use-announcer.md +128 -0
  21. package/4.api/2.composables/use-async-data.md +2 -2
  22. package/4.api/2.composables/use-cookie.md +24 -0
  23. package/4.api/2.composables/use-fetch.md +5 -5
  24. package/4.api/2.composables/use-lazy-fetch.md +1 -0
  25. package/4.api/2.composables/use-route-announcer.md +4 -0
  26. package/4.api/3.utils/clear-nuxt-state.md +4 -2
  27. package/4.api/3.utils/define-page-meta.md +61 -4
  28. package/4.api/4.commands/build.md +3 -2
  29. package/4.api/4.commands/dev.md +2 -1
  30. package/4.api/4.commands/generate.md +2 -1
  31. package/4.api/6.advanced/1.hooks.md +1 -1
  32. package/5.community/2.getting-help.md +1 -1
  33. package/package.json +1 -1
@@ -10,19 +10,46 @@ The [`$fetch`](/docs/4.x/api/utils/dollarfetch) utility function (used by the [`
10
10
 
11
11
  However, Nuxt provides a way to create a custom fetcher for your API (or multiple fetchers if you have multiple APIs to call).
12
12
 
13
- ## Custom `$fetch`
13
+ ## Recipe: API Client with Auth
14
14
 
15
- Let's create a custom `$fetch` instance with a [Nuxt plugin](/docs/4.x/directory-structure/app/plugins).
15
+ Let's say you have an external API at `https://api.nuxt.com` that requires JWT authentication via [nuxt-auth-utils](https://github.com/atinux/nuxt-auth-utils), and you want to redirect to `/login` on `401` responses.
16
+
17
+ ```ts [app/composables/useAPI.ts]
18
+ export const useAPI = createUseFetch({
19
+ baseURL: 'https://api.nuxt.com',
20
+ onRequest ({ options }) {
21
+ const { session } = useUserSession()
22
+ if (session.value?.token) {
23
+ options.headers.set('Authorization', `Bearer ${session.value.token}`)
24
+ }
25
+ },
26
+ async onResponseError ({ response }) {
27
+ if (response.status === 401) {
28
+ await navigateTo('/login')
29
+ }
30
+ },
31
+ })
32
+ ```
33
+
34
+ Now every call to `useAPI` automatically includes the auth header and handles 401 redirects:
35
+
36
+ ```vue [app/pages/dashboard.vue]
37
+ <script setup lang="ts">
38
+ const { data: profile } = await useAPI('/me')
39
+ const { data: orders } = await useAPI('/orders')
40
+ </script>
41
+ ```
42
+
43
+ :read-more{to="/docs/4.x/api/composables/create-use-fetch"}
44
+
45
+ ## Recipe: Custom `$fetch` Instance
46
+
47
+ If you need lower-level control, you can create a custom `$fetch` instance with a [Nuxt plugin](/docs/4.x/directory-structure/app/plugins) and either use it with `useAsyncData` directly or pass it to `createUseFetch`.
16
48
 
17
49
  ::note
18
50
  `$fetch` is a configured instance of [ofetch](https://github.com/unjs/ofetch) which supports adding the base URL of your Nuxt server as well as direct function calls during SSR (avoiding HTTP roundtrips).
19
51
  ::
20
52
 
21
- Let's pretend here that:
22
- - The main API is https://api.nuxt.com
23
- - We are storing the JWT token in a session with [nuxt-auth-utils](https://github.com/atinux/nuxt-auth-utils)
24
- - If the API responds with a `401` status code, we redirect the user to the `/login` page
25
-
26
53
  ```ts [app/plugins/api.ts]
27
54
  export default defineNuxtPlugin((nuxtApp) => {
28
55
  const { session } = useUserSession()
@@ -31,7 +58,6 @@ export default defineNuxtPlugin((nuxtApp) => {
31
58
  baseURL: 'https://api.nuxt.com',
32
59
  onRequest ({ request, options, error }) {
33
60
  if (session.value?.token) {
34
- // note that this relies on ofetch >= 1.4.0 - you may need to refresh your lockfile
35
61
  options.headers.set('Authorization', `Bearer ${session.value?.token}`)
36
62
  }
37
63
  },
@@ -42,7 +68,6 @@ export default defineNuxtPlugin((nuxtApp) => {
42
68
  },
43
69
  })
44
70
 
45
- // Expose to useNuxtApp().$api
46
71
  return {
47
72
  provide: {
48
73
  api,
@@ -51,7 +76,7 @@ export default defineNuxtPlugin((nuxtApp) => {
51
76
  })
52
77
  ```
53
78
 
54
- With this Nuxt plugin, `$api` is exposed from `useNuxtApp()` to make API calls directly from the Vue components:
79
+ You can then use the custom `$fetch` instance directly:
55
80
 
56
81
  ```vue [app/app.vue]
57
82
  <script setup>
@@ -61,65 +86,9 @@ const { data: modules } = await useAsyncData('modules', () => $api('/modules'))
61
86
  ```
62
87
 
63
88
  ::callout
64
- Wrapping with [`useAsyncData`](/docs/4.x/api/composables/use-async-data) **avoid double data fetching when doing server-side rendering** (server & client on hydration).
65
- ::
66
-
67
- ## Custom `useFetch`/`useAsyncData`
68
-
69
- Now that `$api` has the logic we want, let's create a `useAPI` composable to replace the usage of `useAsyncData` + `$api`:
70
-
71
- ```ts [app/composables/useAPI.ts]
72
- import type { UseFetchOptions } from 'nuxt/app'
73
-
74
- export function useAPI<T> (
75
- url: string | (() => string),
76
- options?: UseFetchOptions<T>,
77
- ) {
78
- return useFetch(url, {
79
- ...options,
80
- $fetch: useNuxtApp().$api as typeof $fetch,
81
- })
82
- }
83
- ```
84
-
85
- Let's use the new composable and have a nice and clean component:
86
-
87
- ```vue [app/app.vue]
88
- <script setup>
89
- const { data: modules } = await useAPI('/modules')
90
- </script>
91
- ```
92
-
93
- If you want to customize the type of any error returned, you can also do so:
94
-
95
- ```ts
96
- import type { FetchError } from 'ofetch'
97
- import type { UseFetchOptions } from 'nuxt/app'
98
-
99
- interface CustomError {
100
- message: string
101
- status: number
102
- }
103
-
104
- export function useAPI<T> (
105
- url: string | (() => string),
106
- options?: UseFetchOptions<T>,
107
- ) {
108
- return useFetch<T, FetchError<CustomError>>(url, {
109
- ...options,
110
- $fetch: useNuxtApp().$api,
111
- })
112
- }
113
- ```
114
-
115
- ::note
116
- This example demonstrates how to use a custom `useFetch`, but the same structure is identical for a custom `useAsyncData`.
89
+ Wrapping with [`useAsyncData`](/docs/4.x/api/composables/use-async-data) **avoids double data fetching when doing server-side rendering** (server & client on hydration).
117
90
  ::
118
91
 
119
92
  :link-example{to="/docs/4.x/examples/advanced/use-custom-fetch-composable"}
120
93
 
121
94
  :video-accordion{title="Watch a video about custom $fetch and Repository Pattern in Nuxt" videoId="jXH8Tr-exhI"}
122
-
123
- ::note
124
- We are currently discussing to find a cleaner way to let you create a custom fetcher, see https://github.com/nuxt/nuxt/issues/14736.
125
- ::
@@ -210,7 +210,7 @@ We've successfully set up a very basic user authentication and session managemen
210
210
 
211
211
  As next steps, you can:
212
212
  - Add authentication using the [20+ supported OAuth providers](https://github.com/atinux/nuxt-auth-utils?tab=readme-ov-file#supported-oauth-providers)
213
- - Add a database to store users, see [Nitro SQL Database](https://nitro.build/guide/database) or [NuxtHub SQL Database](https://hub.nuxt.com/docs/features/database)
213
+ - Add a database to store users, see [Nitro SQL Database](https://nitro.build/guide/database) or [NuxtHub SQL Database](https://hub.nuxt.com/docs/database)
214
214
  - Let user signup with email & password using [password hashing](https://github.com/atinux/nuxt-auth-utils?tab=readme-ov-file#password-hashing)
215
215
  - Add support for [WebAuthn / Passkeys](https://github.com/atinux/nuxt-auth-utils?tab=readme-ov-file#webauthn-passkey)
216
216
 
@@ -238,12 +238,19 @@ export default defineNuxtConfig({
238
238
 
239
239
  ## payloadExtraction
240
240
 
241
- Enables extraction of payloads of pages generated with `nuxt generate`.
241
+ Controls how payload data is delivered for prerendered and cached (ISR/SWR) pages.
242
+
243
+ - `'client'` - Payload is inlined in HTML for the initial server render, and extracted to `_payload.json` files for client-side navigation. This avoids a separate network request on initial load while still enabling efficient client-side navigation.
244
+ - `true` - Payload is extracted to a separate `_payload.json` file for both the initial server render and client-side navigation.
245
+ - `false` - Payload extraction is disabled entirely. Payload is always inlined in HTML and no `_payload.json` files are generated.
246
+
247
+ The default is `true`, or `'client'` when `compatibilityVersion: 5` is set.
242
248
 
243
249
  ```ts twoslash [nuxt.config.ts]
244
250
  export default defineNuxtConfig({
245
251
  experimental: {
246
- payloadExtraction: true,
252
+ // Inline payload in HTML, extract for client-side navigation only
253
+ payloadExtraction: 'client',
247
254
  },
248
255
  })
249
256
  ```
@@ -253,7 +260,7 @@ Payload extraction also works for routes using ISR (Incremental Static Regenerat
253
260
  ```ts twoslash [nuxt.config.ts]
254
261
  export default defineNuxtConfig({
255
262
  experimental: {
256
- payloadExtraction: true,
263
+ payloadExtraction: 'client',
257
264
  },
258
265
  routeRules: {
259
266
  // Payload files will be generated for these cached routes
@@ -303,11 +310,27 @@ export default defineNuxtConfig({
303
310
  })
304
311
  ```
305
312
 
313
+ You can also pass an object to configure [view transition types](/docs/4.x/getting-started/transitions#view-transition-types), which allow different CSS animations based on the type of navigation:
314
+
315
+ ```ts twoslash [nuxt.config.ts]
316
+ export default defineNuxtConfig({
317
+ experimental: {
318
+ viewTransition: {
319
+ enabled: true,
320
+ types: ['slide'],
321
+ },
322
+ },
323
+ })
324
+ ```
325
+
306
326
  :link-example{to="https://stackblitz.com/edit/nuxt-view-transitions?file=app.vue" target="_blank"}
307
327
 
308
328
  ::read-more{icon="i-simple-icons-mdnwebdocs" to="https://developer.mozilla.org/en-US/docs/Web/API/View_Transition_API" target="_blank"}
309
329
  Read more about the **View Transition API**.
310
330
  ::
331
+ ::read-more{icon="i-simple-icons-google" to="https://developer.chrome.com/blog/view-transitions-update-io24" target="_blank"}
332
+ Read more about the **View Transition API**.
333
+ ::
311
334
 
312
335
  ## writeEarlyHints
313
336
 
@@ -370,7 +393,11 @@ Out of the box, this will enable typed usage of [`navigateTo`](/docs/4.x/api/uti
370
393
  You can even get typed params within a page by using `const route = useRoute('route-name')`.
371
394
 
372
395
  ::important
373
- If you use `pnpm` without `shamefully-hoist=true`, you will need to have `unplugin-vue-router` installed as a devDependency in order for this feature to work.
396
+ If you use `pnpm` without `shamefully-hoist=true`, you will need to add `unplugin-vue-router` as a hoist pattern in your `pnpm-workspace.yaml` in order for this feature to work.
397
+ ```yaml
398
+ publicHoistPattern:
399
+ - "unplugin-vue-router"
400
+ ```
374
401
  ::
375
402
 
376
403
  :video-accordion{title="Watch a video from Daniel Roe explaining type-safe routing in Nuxt" videoId="SXk-L19gTZk"}
@@ -603,6 +630,30 @@ But in order to auto-import it, you would need to use `SomeFolderMyComponent`.
603
630
 
604
631
  By setting `experimental.normalizeComponentNames`, these two values match, and Vue will generate a component name that matches the Nuxt pattern for component naming.
605
632
 
633
+ ## normalizePageNames
634
+
635
+ Ensure that page component names match their route names. This sets the `__name` property on page components so that Vue's `<KeepAlive>` can correctly identify them by name.
636
+
637
+ By default, Vue assigns component names based on the filename. For example, `pages/foo/index.vue` and `pages/bar/index.vue` would both have the component name `index`. This makes name-based `<KeepAlive>` filtering unreliable because multiple pages share the same name.
638
+
639
+ With `normalizePageNames` enabled, page components are named after their route (e.g. `foo` and `bar`), so you can use `<KeepAlive>` with `include`/`exclude` without manually adding `defineOptions({ name: '...' })` to each page.
640
+
641
+ This flag is enabled when `future.compatibilityVersion` is set to `5` or higher, but you can disable this feature:
642
+
643
+ ```ts twoslash [nuxt.config.ts]
644
+ export default defineNuxtConfig({
645
+ experimental: {
646
+ normalizePageNames: false,
647
+ },
648
+ })
649
+ ```
650
+
651
+ ```vue [app.vue]
652
+ <template>
653
+ <NuxtPage :keepalive="{ include: ['foo'] }" />
654
+ </template>
655
+ ```
656
+
606
657
  ## spaLoadingTemplateLocation
607
658
 
608
659
  When rendering a client-only page (with `ssr: false`), we optionally render a loading screen (from `~/spa-loading-template.html`).
@@ -722,7 +773,9 @@ export default defineNuxtConfig({
722
773
 
723
774
  ## decorators
724
775
 
725
- This option enables enabling decorator syntax across your entire Nuxt/Nitro app, powered by [esbuild](https://github.com/evanw/esbuild/releases/tag/v0.21.3).
776
+ This option enables decorator syntax across your entire Nuxt/Nitro app.
777
+
778
+ When using the Vite builder (default), decorators are lowered via [Babel](https://babeljs.io/) using [`@babel/plugin-proposal-decorators`](https://babeljs.io/docs/babel-plugin-proposal-decorators). When using the webpack or rspack builders, decorators are lowered via [esbuild](https://github.com/evanw/esbuild/releases/tag/v0.21.3).
726
779
 
727
780
  For a long time, TypeScript has had support for decorators via `compilerOptions.experimentalDecorators`. This implementation predated the TC39 standardization process. Now, decorators are a [Stage 3 Proposal](https://github.com/tc39/proposal-decorators), and supported without special configuration in TS 5.0+ (see https://github.com/microsoft/TypeScript/pull/52582 and https://devblogs.microsoft.com/typescript/announcing-typescript-5-0-beta/#decorators).
728
781
 
@@ -742,6 +795,24 @@ export default defineNuxtConfig({
742
795
  })
743
796
  ```
744
797
 
798
+ When using the Vite builder or the Nitro server build, you will need to install additional Babel packages as dev dependencies:
799
+
800
+ ::code-group
801
+ ```bash [npm]
802
+ npm install -D @babel/plugin-proposal-decorators @babel/plugin-syntax-jsx
803
+ ```
804
+ ```bash [pnpm]
805
+ pnpm add -D @babel/plugin-proposal-decorators @babel/plugin-syntax-jsx
806
+ ```
807
+ ```bash [yarn]
808
+ yarn add -D @babel/plugin-proposal-decorators @babel/plugin-syntax-jsx
809
+ ```
810
+ ::
811
+
812
+ ::tip
813
+ Nuxt will prompt you to install these automatically if they are not already present.
814
+ ::
815
+
745
816
  ```ts [app/app.vue]
746
817
  function something (_method: () => unknown) {
747
818
  return () => 'decorated'
@@ -778,11 +849,16 @@ export default defineNuxtConfig({
778
849
  useAsyncData: {
779
850
  deep: true,
780
851
  },
852
+ useState: {
853
+ resetOnClear: true,
854
+ },
781
855
  },
782
856
  },
783
857
  })
784
858
  ```
785
859
 
860
+ The `useState.resetOnClear` option controls whether [`clearNuxtState`](/docs/4.x/api/utils/clear-nuxt-state) resets state to its initial value (provided by the `init` function of [`useState`](/docs/4.x/api/composables/use-state)) instead of setting it to `undefined`. This defaults to `true` with `compatibilityVersion: 5`.
861
+
786
862
  ## purgeCachedData
787
863
 
788
864
  Whether to clean up Nuxt static and asyncData caches on route navigation.
@@ -52,3 +52,7 @@ To achieve full customization, you can implement your own one based on [its sour
52
52
  ::callout
53
53
  You can hook into the underlying announcer instance using [the `useRouteAnnouncer` composable](/docs/4.x/api/composables/use-route-announcer), which allows you to set a custom announcement message.
54
54
  ::
55
+
56
+ ::callout
57
+ For announcing in-page content changes (form validation, toast notifications, loading states, etc.), use the [`<NuxtAnnouncer>`](/docs/4.x/api/components/nuxt-announcer) component with the [`useAnnouncer`](/docs/4.x/api/composables/use-announcer) composable instead.
58
+ ::
@@ -0,0 +1,81 @@
1
+ ---
2
+ title: '<NuxtAnnouncer>'
3
+ description: 'The <NuxtAnnouncer> component adds a hidden element to announce dynamic content changes to assistive technologies.'
4
+ links:
5
+ - label: Source
6
+ icon: i-simple-icons-github
7
+ to: https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/nuxt-announcer.ts
8
+ size: xs
9
+ ---
10
+
11
+ ::important
12
+ This component is available in Nuxt v3.17+.
13
+ ::
14
+
15
+ ## Usage
16
+
17
+ Add `<NuxtAnnouncer/>` in your [`app.vue`](/docs/4.x/directory-structure/app/app) or [`app/layouts/`](/docs/4.x/directory-structure/app/layouts) to enable announcing dynamic content changes to screen readers. This is useful for form validation, toast notifications, loading states, and other in-page updates.
18
+
19
+ ```vue [app/app.vue]
20
+ <template>
21
+ <NuxtAnnouncer />
22
+ <NuxtRouteAnnouncer />
23
+ <NuxtLayout>
24
+ <NuxtPage />
25
+ </NuxtLayout>
26
+ </template>
27
+ ```
28
+
29
+ Then use the [`useAnnouncer`](/docs/4.x/api/composables/use-announcer) composable anywhere in your app to announce messages:
30
+
31
+ ```vue [app/pages/contact.vue]
32
+ <script setup lang="ts">
33
+ const { polite, assertive } = useAnnouncer()
34
+
35
+ async function submitForm () {
36
+ try {
37
+ await $fetch('/api/contact', { method: 'POST', body: formData })
38
+ polite('Message sent successfully')
39
+ } catch (error) {
40
+ assertive('Error: Failed to send message')
41
+ }
42
+ }
43
+ </script>
44
+ ```
45
+
46
+ ## Slots
47
+
48
+ You can pass custom HTML or components through the announcer's default slot.
49
+
50
+ ```vue
51
+ <template>
52
+ <NuxtAnnouncer>
53
+ <template #default="{ message }">
54
+ <p>{{ message }}</p>
55
+ </template>
56
+ </NuxtAnnouncer>
57
+ </template>
58
+ ```
59
+
60
+ ## Props
61
+
62
+ - `atomic`: Controls if screen readers announce only changes or the entire content. Set to true for full content readouts on updates, false for changes only. (default `true`)
63
+ - `politeness`: Sets the default urgency for screen reader announcements: `off` (disable the announcement), `polite` (waits for silence), or `assertive` (interrupts immediately). (default `polite`)
64
+
65
+ ## Differences from `<NuxtRouteAnnouncer>`
66
+
67
+ | Aspect | `<NuxtRouteAnnouncer>` | `<NuxtAnnouncer>` |
68
+ |--------|------------------------|-------------------|
69
+ | **Purpose** | Announces route/page changes | Announces any dynamic content |
70
+ | **Trigger** | Automatic on navigation | Manual via `polite()`/`assertive()` |
71
+ | **Message source** | Page `<title>` | Developer-provided |
72
+ | **atomic default** | `false` | `true` |
73
+
74
+ ::callout
75
+ This component is optional. :br
76
+ To achieve full customization, you can implement your own one based on [its source code](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/nuxt-announcer.ts).
77
+ ::
78
+
79
+ ::callout
80
+ You can hook into the underlying announcer instance using [the `useAnnouncer` composable](/docs/4.x/api/composables/use-announcer), which allows you to set custom announcement messages.
81
+ ::
@@ -86,6 +86,35 @@ console.log(layoutCustomProps.title) // I am a custom layout
86
86
  </script>
87
87
  ```
88
88
 
89
+ ## Layout Props from Page Meta
90
+
91
+ When using [`definePageMeta`](/docs/4.x/api/utils/define-page-meta) with the object syntax for `layout`, props are automatically passed to the layout component. The layout can receive them with `defineProps`:
92
+
93
+ ```vue [app/pages/dashboard.vue]
94
+ <script setup lang="ts">
95
+ definePageMeta({
96
+ layout: {
97
+ name: 'admin',
98
+ props: {
99
+ sidebar: true,
100
+ },
101
+ },
102
+ })
103
+ </script>
104
+ ```
105
+
106
+ ```vue [app/layouts/admin.vue]
107
+ <script setup lang="ts">
108
+ const props = defineProps<{
109
+ sidebar?: boolean
110
+ }>()
111
+ </script>
112
+ ```
113
+
114
+ ::read-more{to="/docs/4.x/directory-structure/app/layouts#passing-props-to-layouts"}
115
+ Read more about passing props to layouts.
116
+ ::
117
+
89
118
  ## Transitions
90
119
 
91
120
  `<NuxtLayout />` renders incoming content via `<slot />`, which is then wrapped around Vue’s `<Transition />` component to activate layout transition. For this to work as expected, it is recommended that `<NuxtLayout />` is **not** the root element of the page component.
@@ -74,4 +74,4 @@ Some slots are reserved to `NuxtIsland` for special cases.
74
74
  - **parameters**:
75
75
  - **error**:
76
76
  - **type**: `unknown`
77
- - **description**: emitted when when `NuxtIsland` fails to fetch the new island.
77
+ - **description**: emitted when `NuxtIsland` fails to fetch the new island.
@@ -0,0 +1,90 @@
1
+ ---
2
+ title: 'createUseAsyncData'
3
+ description: A factory function to create a custom useAsyncData composable with pre-defined default options.
4
+ links:
5
+ - label: Source
6
+ icon: i-simple-icons-github
7
+ to: https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/asyncData.ts
8
+ size: xs
9
+ ---
10
+
11
+ `createUseAsyncData` creates a custom [`useAsyncData`](/docs/4.x/api/composables/use-async-data) composable with pre-defined options. The resulting composable is fully typed and works exactly like `useAsyncData`, but with your defaults baked in.
12
+
13
+ ::note
14
+ `createUseAsyncData` is a compiler macro. It must be used as an **exported** declaration in the `composables/` directory (or any directory scanned by the Nuxt compiler). Nuxt automatically injects de-duplication keys at build time.
15
+ ::
16
+
17
+ ## Usage
18
+
19
+ ```ts [app/composables/useCachedData.ts]
20
+ export const useCachedData = createUseAsyncData({
21
+ getCachedData (key, nuxtApp) {
22
+ return nuxtApp.payload.data[key] ?? nuxtApp.static.data[key]
23
+ },
24
+ })
25
+ ```
26
+
27
+ ```vue [app/pages/index.vue]
28
+ <script setup lang="ts">
29
+ const { data: mountains } = await useCachedData(
30
+ 'mountains',
31
+ () => $fetch('https://api.nuxtjs.dev/mountains'),
32
+ )
33
+ </script>
34
+ ```
35
+
36
+ The resulting composable has the same signature and return type as [`useAsyncData`](/docs/4.x/api/composables/use-async-data), with all options available for the caller to use or override.
37
+
38
+ ## Type
39
+
40
+ ```ts [Signature]
41
+ function createUseAsyncData (
42
+ options?: Partial<AsyncDataOptions>,
43
+ ): typeof useAsyncData
44
+
45
+ function createUseAsyncData (
46
+ options: (callerOptions: AsyncDataOptions) => Partial<AsyncDataOptions>,
47
+ ): typeof useAsyncData
48
+ ```
49
+
50
+ ## Options
51
+
52
+ `createUseAsyncData` accepts all the same options as [`useAsyncData`](/docs/4.x/api/composables/use-async-data#params), including `server`, `lazy`, `immediate`, `default`, `transform`, `pick`, `getCachedData`, `deep`, `dedupe`, `timeout`, and `watch`.
53
+
54
+ See the full list of options in the [`useAsyncData` documentation](/docs/4.x/api/composables/use-async-data#params).
55
+
56
+ ## Default vs Override Mode
57
+
58
+ ### Default Mode (plain object)
59
+
60
+ When you pass a plain object, the factory options act as **defaults**. Callers can override any option:
61
+
62
+ ```ts [app/composables/useLazyData.ts]
63
+ export const useLazyData = createUseAsyncData({
64
+ lazy: true,
65
+ server: false,
66
+ })
67
+ ```
68
+
69
+ ```ts
70
+ // Uses the defaults (lazy: true, server: false)
71
+ const { data } = await useLazyData('key', () => fetchSomeData())
72
+
73
+ // Caller overrides server to true
74
+ const { data } = await useLazyData('key', () => fetchSomeData(), { server: true })
75
+ ```
76
+
77
+ ### Override Mode (function)
78
+
79
+ When you pass a function, the factory options **override** the caller's options. The function receives the caller's options as its argument:
80
+
81
+ ```ts [app/composables/useStrictData.ts]
82
+ // deep is always enforced as false
83
+ export const useStrictData = createUseAsyncData(callerOptions => ({
84
+ deep: false,
85
+ }))
86
+ ```
87
+
88
+ :read-more{to="/docs/4.x/guide/recipes/custom-usefetch"}
89
+
90
+ :read-more{to="/docs/4.x/api/composables/use-async-data"}
@@ -0,0 +1,97 @@
1
+ ---
2
+ title: 'createUseFetch'
3
+ description: A factory function to create a custom useFetch composable with pre-defined default options.
4
+ links:
5
+ - label: Source
6
+ icon: i-simple-icons-github
7
+ to: https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/fetch.ts
8
+ size: xs
9
+ ---
10
+
11
+ `createUseFetch` creates a custom [`useFetch`](/docs/4.x/api/composables/use-fetch) composable with pre-defined options. The resulting composable is fully typed and works exactly like `useFetch`, but with your defaults baked in.
12
+
13
+ ::note
14
+ `createUseFetch` is a compiler macro. It must be used as an **exported** declaration in the `composables/` directory (or any directory scanned by the Nuxt compiler). Nuxt automatically injects de-duplication keys at build time.
15
+ ::
16
+
17
+ ## Usage
18
+
19
+ ```ts [app/composables/useAPI.ts]
20
+ export const useAPI = createUseFetch({
21
+ baseURL: 'https://api.nuxt.com',
22
+ })
23
+ ```
24
+
25
+ ```vue [app/pages/modules.vue]
26
+ <script setup lang="ts">
27
+ const { data: modules } = await useAPI('/modules')
28
+ </script>
29
+ ```
30
+
31
+ The resulting `useAPI` composable has the same signature and return type as [`useFetch`](/docs/4.x/api/composables/use-fetch), with all options available for the caller to use or override.
32
+
33
+ ## Type
34
+
35
+ ```ts [Signature]
36
+ function createUseFetch (
37
+ options?: Partial<UseFetchOptions>,
38
+ ): typeof useFetch
39
+
40
+ function createUseFetch (
41
+ options: (callerOptions: UseFetchOptions) => Partial<UseFetchOptions>,
42
+ ): typeof useFetch
43
+ ```
44
+
45
+ ## Options
46
+
47
+ `createUseFetch` accepts all the same options as [`useFetch`](/docs/4.x/api/composables/use-fetch#parameters), including `baseURL`, `headers`, `query`, `onRequest`, `onResponse`, `server`, `lazy`, `transform`, `getCachedData`, and more.
48
+
49
+ See the full list of options in the [`useFetch` documentation](/docs/4.x/api/composables/use-fetch#parameters).
50
+
51
+ ## Default vs Override Mode
52
+
53
+ ### Default Mode (plain object)
54
+
55
+ When you pass a plain object, the factory options act as **defaults**. Callers can override any option:
56
+
57
+ ```ts [app/composables/useAPI.ts]
58
+ export const useAPI = createUseFetch({
59
+ baseURL: 'https://api.nuxt.com',
60
+ lazy: true,
61
+ })
62
+ ```
63
+
64
+ ```ts
65
+ // Uses the default baseURL
66
+ const { data } = await useAPI('/modules')
67
+
68
+ // Caller overrides the baseURL
69
+ const { data } = await useAPI('/modules', { baseURL: 'https://other-api.com' })
70
+ ```
71
+
72
+ ### Override Mode (function)
73
+
74
+ When you pass a function, the factory options **override** the caller's options. The function receives the caller's options as its argument, so you can read them to compute your overrides:
75
+
76
+ ```ts [app/composables/useAPI.ts]
77
+ // baseURL is always enforced, regardless of what the caller passes
78
+ export const useAPI = createUseFetch(callerOptions => ({
79
+ baseURL: 'https://api.nuxt.com',
80
+ }))
81
+ ```
82
+
83
+ This is useful for enforcing settings like authentication headers or a specific base URL that should not be changed by the caller.
84
+
85
+ ## Combining with a Custom `$fetch`
86
+
87
+ You can pass a custom `$fetch` instance to `createUseFetch`:
88
+
89
+ ```ts [app/composables/useAPI.ts]
90
+ export const useAPI = createUseFetch({
91
+ $fetch: useNuxtApp().$api as typeof $fetch,
92
+ })
93
+ ```
94
+
95
+ :read-more{to="/docs/4.x/guide/recipes/custom-usefetch"}
96
+
97
+ :read-more{to="/docs/4.x/api/composables/use-fetch"}