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 insteadQuick 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 delayavoids spinner flash;timeoutfails slow loadsonError(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
- Vue Suspense Component
- Async Components with defineAsyncComponent
- Streaming SSR with renderToWebStream
- Deferred Hydration Strategies