0Pricing
Vue Academy · Lesson

Async Components with defineAsyncComponent

defineAsyncComponent(), loadingComponent, errorComponent, delay and timeout options.

Async Components with defineAsyncComponent is a free Vue Academy lesson on CoddyKit — lesson 2 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Vue Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Why Async Components

defineAsyncComponent lets you load a component lazily — its code is fetched only when the component is first rendered.

This enables route-level and component-level code splitting, shrinking your initial bundle and speeding up first paint.

The Loader Function Form

The simplest usage passes a loader function that returns a dynamic import(). Vite/webpack code-splits that import into its own chunk automatically.

<script setup>
import { defineAsyncComponent } from 'vue'

const SettingsModal = defineAsyncComponent(() =>
  import('./SettingsModal.vue')
)
</script>

<template>
  <SettingsModal v-if="showSettings" />
</template>

The Options Object Form

For finer control, pass an options object. The key fields are:

  • loader — the dynamic import function
  • loadingComponent — shown while loading
  • errorComponent — shown if loading fails
  • delay / timeout — timing controls
import { defineAsyncComponent } from 'vue'
import Loading from './Loading.vue'
import ErrorView from './ErrorView.vue'

const AsyncChart = defineAsyncComponent({
  loader: () => import('./Chart.vue'),
  loadingComponent: Loading,
  errorComponent: ErrorView,
  delay: 200,
  timeout: 5000
})

delay: Avoiding Spinner Flash

The delay option (default 200ms) is how long Vue waits before showing the loadingComponent. If the chunk loads faster than the delay, no spinner appears at all.

Set delay: 0 to show the loading state immediately.

const AsyncPanel = defineAsyncComponent({
  loader: () => import('./Panel.vue'),
  loadingComponent: Spinner,
  // wait 300ms before showing Spinner
  delay: 300
})

timeout: Failing Slow Loads

The timeout option sets the maximum time to wait. If the loader does not resolve within timeout ms, the errorComponent is shown and an error is logged.

By default there is no timeout — the load waits indefinitely.

const AsyncReport = defineAsyncComponent({
  loader: () => import('./Report.vue'),
  errorComponent: ErrorView,
  // fail if not loaded within 10s
  timeout: 10000
})

The onError Callback

The onError handler runs when the loader rejects. It receives the error, a retry function, a fail function, and the current attempt count.

This is where you implement retry-with-limit logic for flaky networks.

const AsyncWidget = defineAsyncComponent({
  loader: () => import('./Widget.vue'),
  onError(error, retry, fail, attempts) {
    if (attempts <= 3) {
      retry()   // try loading again
    } else {
      fail()    // give up, show errorComponent
    }
  }
})

Retry vs Fail Decision

Inside onError you must call exactly one of retry() or fail() (or neither, which also fails). A common strategy: retry network errors a few times, but fail immediately on a syntax/chunk error that retrying cannot fix.

onError(error, retry, fail, attempts) {
  const isNetwork = /Loading chunk/.test(error.message)
  if (isNetwork && attempts <= 2) {
    retry()
  } else {
    fail()
  }
}

Pairing with Suspense

When an async component lives inside a Suspense boundary, the boundary controls the loading state instead. In that case the component's own loadingComponent is ignored — Suspense's fallback wins.

<template>
  <Suspense>
    <AsyncChart />  <!-- loadingComponent ignored here -->
    <template #fallback>Loading chart...</template>
  </Suspense>
</template>

Named Chunks for Debugging

You can name the generated chunk with a magic comment. This makes network requests and bundle reports easier to read.

const AsyncEditor = defineAsyncComponent(() =>
  import(
    /* webpackChunkName: "editor" */
    './RichTextEditor.vue'
  )
)

Async Components and Props

Async components accept props and emit events exactly like normal components. Vue forwards everything transparently once the real component resolves — you do not change the call site.

<template>
  <AsyncProfile
    :user-id="id"
    @save="handleSave"
  />
</template>

<!-- AsyncProfile resolves to the real component, props/events pass through -->

Best Practice: Lazy Above the Fold Carefully

Lazy-load components that are off-screen, behind interactions (modals, tabs), or rarely used. Avoid lazy-loading critical above-the-fold UI — the extra round trip can hurt perceived performance.

// Good candidate: modal only opened on click
const Modal = defineAsyncComponent(() => import('./Modal.vue'))

// Poor candidate: hero shown immediately on load
// import Hero directly instead

Quick Check

Test your understanding of defineAsyncComponent.

Recap

You learned async component loading with defineAsyncComponent:

  • Loader form returns a dynamic import() for code splitting
  • Options form adds loadingComponent, errorComponent, delay, timeout
  • delay avoids spinner flash; timeout fails slow loads
  • onError(error, retry, fail, attempts) implements retry-or-fail logic
  • Inside Suspense, the boundary's fallback takes over the loading UI

Frequently asked questions

Is the “Async Components with defineAsyncComponent” lesson free?

Yes — the full text of “Async Components with defineAsyncComponent” is free to read here on the web, and the Vue Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Vue Academy course, upgrade to CoddyKit PRO.

What will I learn in “Async Components with defineAsyncComponent”?

defineAsyncComponent(), loadingComponent, errorComponent, delay and timeout options. You practise Vue Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Vue Academy?

No prior experience is required. Vue Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Async Components with defineAsyncComponent” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Vue Academy lesson?

Yes. Every Vue Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Vue Suspense Component
  2. Async Components with defineAsyncComponent
  3. Streaming SSR with renderToWebStream
  4. Deferred Hydration Strategies
← Back to Vue Academy