Global Callbacks Setup
Global callbacks are configured in plugins/api-callbacks.ts. You need to create this file manually in your Nuxt project.
Plugin Boilerplate
Create plugins/api-callbacks.ts with the following structure:
// plugins/api-callbacks.ts
export default defineNuxtPlugin(() => {
const globalCallbacks = {
// onRequest, onSuccess, onError, onFinish
}
return {
provide: {
getGlobalApiCallbacks: () => globalCallbacks
}
}
})WARNING
The provide: { getGlobalApiCallbacks: () => globalCallbacks } block is mandatory. Without it, the composables runtime cannot find the global callbacks.
Authentication
The most common use case � add an auth token to every request and redirect on 401:
// plugins/api-callbacks.ts
export default defineNuxtPlugin(() => {
const globalCallbacks = {
onRequest: ({ headers }) => {
const token = useCookie('auth-token').value
if (token) {
return {
headers: { ...headers, 'Authorization': `Bearer ${token}` }
}
}
},
onError: (error) => {
if (error.status === 401) {
useCookie('auth-token').value = null
navigateTo('/login')
return false // Prevent local onError from also handling this
}
}
}
return {
provide: {
getGlobalApiCallbacks: () => globalCallbacks
}
}
})Error Handling
Centralized error handling for all requests:
// plugins/api-callbacks.ts
export default defineNuxtPlugin(() => {
const toast = useToast()
const globalCallbacks = {
onError: (error) => {
switch (error.status) {
case 401:
navigateTo('/login')
return false
case 403:
toast.error('Access denied')
return false
case 404:
toast.error('Resource not found')
break
default:
if (error.status >= 500) {
toast.error('Server error, please try again')
}
}
}
}
return {
provide: {
getGlobalApiCallbacks: () => globalCallbacks
}
}
})Using Nuxt Composables
Use any Nuxt composable at the plugin level (not inside the callbacks):
// plugins/api-callbacks.ts
export default defineNuxtPlugin(() => {
const authStore = useAuthStore() // �S& Call composables here
const { locale } = useI18n()
const globalCallbacks = {
onRequest: ({ headers }) => {
return {
headers: {
...headers,
...(authStore.token ? { 'Authorization': `Bearer ${authStore.token}` } : {}),
'Accept-Language': locale.value
}
}
}
}
return {
provide: {
getGlobalApiCallbacks: () => globalCallbacks
}
}
})Plugin Loading Order
Nuxt loads plugins alphabetically. Use numeric prefixes when the callbacks plugin depends on another plugin (e.g. an auth store):
plugins/
01.auth.ts # Sets up auth store first
02.api-callbacks.ts # Uses auth storeOr specify order explicitly in nuxt.config.ts:
export default defineNuxtConfig({
plugins: [
'~/plugins/auth.ts',
'~/plugins/api-callbacks.ts'
]
})Client vs Server
Use Nuxt file suffixes to restrict where the plugin runs:
// plugins/api-callbacks.client.ts � client only
export default defineNuxtPlugin(() => {
const globalCallbacks = {
onRequest: ({ headers }) => {
return { headers: { ...headers, 'X-User-Agent': navigator.userAgent } }
}
}
return { provide: { getGlobalApiCallbacks: () => globalCallbacks } }
})Or use conditional logic inside a single plugin:
// plugins/api-callbacks.ts
export default defineNuxtPlugin(() => {
const globalCallbacks = {
onRequest: ({ headers }) => {
const extra = process.client
? { 'X-User-Agent': navigator.userAgent }
: { 'X-Server-ID': process.env.SERVER_ID ?? '' }
return { headers: { ...headers, ...extra } }
}
}
return { provide: { getGlobalApiCallbacks: () => globalCallbacks } }
})Best Practices
�S& Do
// �S& Return modifications from onRequest
onRequest: ({ headers }) => {
return { headers: { ...headers, 'X-Custom': 'value' } }
}
// �S& Return false to cancel local callback execution
onError: (error) => {
if (error.status === 401) {
navigateTo('/login')
return false
}
}
// �S& Call composables at plugin level, not inside callbacks
export default defineNuxtPlugin(() => {
const store = useAuthStore() // �S& here
const globalCallbacks = {
onRequest: () => {
store.token // use it here
}
}
})�R Don't
// �R Don't mutate headers directly � won't work
onRequest: ({ headers }) => {
headers['Authorization'] = 'Bearer token' // �R
}
// �R Don't call composables inside callbacks
onRequest: ({ headers }) => {
const store = useAuthStore() // �R Call this at plugin level instead
}
// �R Don't make async API calls inside callbacks
onRequest: async () => {
await $fetch('/other-endpoint') // �R Race conditions
}