Overview
Nuxt Data Fetching Fundamentals
Nuxt provides three data-fetching approaches. Understanding the differences helps you choose the right Movk Nuxt wrapper.
$fetch: The low-level HTTP client, based on ofetch, usable on both server and client.// Called on user interaction — use $fetch async function handleSubmit() { const result = await $fetch('/api/login', { method: 'POST', body: { username, password } }) }useFetch: A syntactic sugar wrapper arounduseAsyncData+$fetch.// Fetch data on page load — use useFetch const { data: posts, status, error } = await useFetch('/api/posts')useAsyncData: The most flexible data-fetching composable.// Aggregate multiple endpoints — use useAsyncData const { data } = await useAsyncData('dashboard', async () => { const [users, stats] = await Promise.all([ $fetch('/api/users'), $fetch('/api/stats') ]) return { users, stats } })
Key Parameters Explained
Three core parameters of useFetch (and useApiFetch) determine when and how requests are executed.
server
Controls whether data fetching is executed on the server. Defaults to true.
Behavior comparison:
server: true(default) — During SSR the request is made on the server; data is transferred to the client via payload and not re-fetched on the client.server: false— Executed on the client only. On first load, data starts fetching after hydration completes;datais initiallynull.
Use cases:
server: true— SEO-relevant data, content required on first render.server: false— Non-SEO-sensitive data (user comments, personalized recommendations, analytics), reducing server load.
// Article list needs SEO — server: true (default)
const { data: posts } = await useApiFetch<Post[]>('/posts')
// Comment data doesn't need SSR — server: false
const { data: comments } = useApiFetch('/comments', {
server: false,
lazy: true,
})
server: false is typically paired with lazy: true, which is exactly the preset behavior of useClientApiFetch.lazy
Controls whether client-side navigation is blocked. Defaults to false.
Behavior comparison:
lazy: false(default) — Blocks navigation via Vue Suspense, waiting for data before completing the route transition. The user never sees a loading state.lazy: true— Does not block navigation; the page displays immediately while data loads in the background. You must handle the loading state manually.
Use cases:
lazy: false— Core page data without which the page cannot render correctly.lazy: true— Secondary data, non-above-the-fold data, scenarios where a skeleton screen can be shown first.
// Core data — block navigation and wait for data (default)
const { data: article } = await useApiFetch<Article>(`/articles/${id}`)
// Secondary data — don't block navigation, load in background
const { data: related, status } = useLazyApiFetch<Article[]>(
`/articles/${id}/related`
)
<template>
<!-- Handle loading state when using lazy -->
<div v-if="status === 'pending'">
<USkeleton class="h-20 w-full" />
</div>
<RelatedArticles v-else :articles="related" />
</template>
lazy behaves nearly the same as non-lazy (both wait for data); the difference primarily applies during client-side navigation.immediate
Controls whether the request fires immediately when the composable is initialized. Defaults to true.
Behavior comparison:
immediate: true(default) — Triggers the request on creation.immediate: false— No automatic request;statusisidle. You must callexecute()manually.
Use cases:
immediate: true— Data needed as soon as the page loads.immediate: false— Requests that should only be triggered after a user action.
// Pre-define a form-submit request, don't auto-execute
const { data, execute, status, error } = useApiFetch('/login', {
method: 'POST',
body: credentials,
immediate: false,
lazy: true,
})
// Trigger manually when the user clicks the login button
async function handleLogin() {
await execute()
if (!error.value) {
navigateTo('/dashboard')
}
}
immediate: false is commonly paired with lazy: true. If only immediate: false is set without lazy: true, Suspense will still wait (even though the request never fires), which may cause the page to hang.Movk Nuxt API System
Movk Nuxt provides an API client factory based on $fetch.create() (the $api plugin) and a set of composables that wrap useFetch, adding unified auth, business code checking, Toast notifications and other enhancements on top of Nuxt's native data-fetching capabilities.
nuxt.config.ts (movk.api config)
|
v
api.factory.ts plugin — creates $api instance
|
v
Interceptor chain
├── onRequest: Auth injection -> debug logging -> movk:api:request hook
├── onResponse: Business check -> data unwrap -> movk:api:response hook -> Toast
└── onResponseError: 401 handling -> movk:api:error hook -> Toast
|
v
Composables
├── useApiFetch useFetch + $api (SSR/CSR universal)
├── useLazyApiFetch lazy: true preset
├── useClientApiFetch server: false, lazy: true preset
├── useUploadWithProgress XHR upload + progress
└── useDownloadWithProgress fetch + ReadableStream download + progress
Multi-Endpoint Support
Multiple API endpoints can be configured, each with its own baseURL, auth, Toast and response rules. Switch endpoints with the endpoint option or $api.use().
Automatic Authentication
Integrates with nuxt-auth-utils. When enabled, each request automatically extracts the token from the session and injects it into the request headers. Supports nested paths (e.g. user.accessToken) and multiple token formats (Bearer, Basic, Custom).
Business Status Code Check
The $api interceptor automatically checks whether the response code is in successCodes, throwing an ApiError and showing a Toast on business failure.
Data Unwrapping
The $api interceptor automatically extracts the dataKey field (default data) from the response; the generic T directly maps to the business data type.
Toast Notifications
Success/failure Toasts are shown automatically. Supports four levels of configuration priority: request-level > endpoint-level > global-level > built-in defaults. Can be disabled or customized at any level.
401 Unauthorized Handling
When an HTTP 401 is received, the default behavior clears the session and redirects to the login page. This can be intercepted via API Hooks to implement custom logic (e.g. token refresh).
Pagination & Load More
Client-side auto pagination, server-side manual pagination with loading state, and bottom-trigger load-more for infinite scroll.
$api
The enhanced $fetch instance created by the api.factory plugin, supporting auth injection, data unwrapping, business code checking and multi-endpoint switching.