Nuxt 4 Request Flow

How requests travel through layouts, middleware, and components

Request Flow Diagram

flowchart TD
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.vue by 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

  1. Request received by the server

    Nuxt server handles the incoming request for /dashboard

  2. Global middleware execution

    Any global middleware in middleware/*.global.ts runs first

    // middleware/auth.global.ts
    export default defineNuxtRouteMiddleware((to, from) => {
      // Check authentication status
    })

  3. Route-specific middleware

    Middleware defined in the page runs next

    // pages/dashboard.vue
    definePageMeta({
      middleware: ['auth']
    })

  4. Layout selection

    Based on page metadata, Nuxt selects the appropriate layout

    // pages/dashboard.vue
    definePageMeta({
      layout: 'admin'
      // Uses layouts/admin.vue
    })

  5. Page component rendering

    The pages/dashboard.vue component is rendered inside the layout

  6. Component rendering

    All components within the page are rendered:

    • Regular components (.vue)
    • Server components (.server.vue)
    • Client components (.client.vue)
  7. Response sent to client

    The fully rendered HTML is sent to the client

  8. 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')
  }
})