Nuxt 4 Request Flow
How requests travel through layouts, middleware, and components
Request Flow Diagram
A[Request Received] –> B[Middleware Processing]
B –> C[Route Validation]
C –> D{Layout Selection}
D –> E[app.vue]
E –> F[Layout Component]
F –> G[Page Component]
G –> H[Component Rendering]
H –> I[Client/Server Components]
I –> J[Response Sent]
subgraph Middleware
B
end
subgraph Layout
D
F
end
subgraph Page
G
end
subgraph Components
H
I
end
style A fill:#dcfce7
style B fill:#e9d5ff
style D fill:#fef3c7
style F fill:#bbf7d0
style G fill:#bfdbfe
style I fill:#fed7aa
style J fill:#fbcfe8
1. app.vue – The Root Component
Every request starts at app.vue, which serves as the root component of your Nuxt application.
- Initializes the Vue application
- Provides context to all components
- Can contain global UI elements
- Wraps all page content
- Rarely bypassed – usually always executed
<template>
<div id="app">
<NuxtLayout>
<NuxtPage />
</NuxtLayout>
</div>
</template>
2. Layout Selection
Nuxt automatically selects a layout based on route metadata or default conventions.
- Uses
layouts/default.vueby default - Can use other layouts via page metadata
- Layouts wrap page content
- Provide consistent structure across pages
Using a custom layout:
// pages/dashboard.vue
definePageMeta({
layout: 'admin'
})
This would use layouts/admin.vue
3. Middleware Execution
Middleware runs before navigation completes and can redirect or modify requests.
- Runs on client and server
- Can be global, named, or inline
- Used for authentication, logging, etc.
- Can redirect requests
// middleware/auth.ts
export default defineNuxtRouteMiddleware((to, from) => {
const auth = useAuth()
if (!auth.isAuthenticated) {
return navigateTo('/login')
}
})
4. Page Rendering
The page component corresponding to the route is rendered within the layout.
- File-based routing:
pages/index.vue→/ - Dynamic routes:
pages/users/[id].vue→/users/123 - Nested routes with folders
- Can use route parameters
// pages/users/[id].vue
<template>
<div>
<h1>User {{ $route.params.id }}</h1>
</div>
</template>
5. Client-Side Components
Components with .client.vue suffix render only on the client.
- Use for browser-specific functionality
- Interactive components
- Components using window/DOM APIs
- Rendered only after hydration
// components/Chart.client.vue
<template>
<div>
<!-- Client-only charting component -->
</div>
</template>
<script setup>
// This code runs only on the client
const canvas = ref(null)
onMounted(() => {
// DOM-related code
})
</script>
6. Server-Side Components
Components with .server.vue suffix render only on the server.
- Optimized for server rendering
- Can use server-only APIs
- No client-side JavaScript bundle
- Good for static content
// components/UserInfo.server.vue
<template>
<div>
<!-- Server-rendered user info -->
</div>
</template>
<script setup>
// This code runs only on the server
const { data } = await useFetch('/api/user')
</script>
Complete Request Flow Example
URL: https://example.com/dashboard
-
Request received by the server
Nuxt server handles the incoming request for
/dashboard -
Global middleware execution
Any global middleware in
middleware/*.global.tsruns first// middleware/auth.global.ts export default defineNuxtRouteMiddleware((to, from) => { // Check authentication status }) -
Route-specific middleware
Middleware defined in the page runs next
// pages/dashboard.vue definePageMeta({ middleware: ['auth'] }) -
Layout selection
Based on page metadata, Nuxt selects the appropriate layout
// pages/dashboard.vue definePageMeta({ layout: 'admin' // Uses layouts/admin.vue }) -
Page component rendering
The
pages/dashboard.vuecomponent is rendered inside the layout -
Component rendering
All components within the page are rendered:
- Regular components (.vue)
- Server components (.server.vue)
- Client components (.client.vue)
-
Response sent to client
The fully rendered HTML is sent to the client
-
Client-side hydration
Vue takes over on the client and hydrates the application
When to Use Middleware
Authentication Guard
Redirect unauthenticated users to login page
// middleware/auth.ts
export default defineNuxtRouteMiddleware((to, from) => {
const { status } = useAuth()
if (status.value !== 'authenticated') {
return navigateTo('/login')
}
})
Logging
Track page views and user actions
// middleware/analytics.ts
export default defineNuxtRouteMiddleware((to, from) => {
// Send analytics data
useTrackPageView(to.path)
})
Feature Flags
Control access to features based on conditions
// middleware/feature.ts
export default defineNuxtRouteMiddleware((to, from) => {
const flags = useFeatureFlags()
if (!flags.value.newDashboard) {
return navigateTo('/old-dashboard')
}
})
Input Validation
Validate route parameters before processing
// middleware/validate.ts
export default defineNuxtRouteMiddleware((to, from) => {
const id = Number(to.params.id)
if (isNaN(id)) {
return abortNavigation('Invalid ID')
}
})