Lazy-Loaded Routes

Code-Split Per Route

Lazy-Loaded Routes

Replace a static import with a dynamic one and the bundler splits the route into its own chunk — only loaded when visited.

3 min read Level 2/5 #vue#router#performance
What you'll learn
  • Wrap component imports in dynamic imports
  • See the chunk in the build output
  • Combine with Suspense for loading UI

By default every route’s component is bundled into the main chunk. Switch to a dynamic import and Vite (or webpack) splits it into a separate file that loads on demand.

Dynamic Imports

import { createRouter, createWebHistory } from 'vue-router'

export const router = createRouter({
  history: createWebHistory(),
  routes: [
    { path: '/', component: () => import('./pages/Home.vue') },
    { path: '/admin', component: () => import('./pages/Admin.vue') },
    { path: '/reports', component: () => import('./pages/Reports.vue') },
  ],
})

After vite build you’ll see separate chunks for each lazy route in dist/assets/.

Loading UI With Suspense

If the chunk takes time to load on a slow connection, wrap the view in <Suspense>.

<template>
  <Suspense>
    <template #default>
      <router-view />
    </template>
    <template #fallback>
      <p>Loading…</p>
    </template>
  </Suspense>
</template>

Rules of Thumb

  • Lazy-load every route that isn’t on the initial paint path.
  • Keep the landing page eagerly imported so first paint stays fast.
  • Group related chunks with a webpack magic comment (/* webpackChunkName: "admin" */) if needed.
Nested Routes →