Vue Async Components: Defer Loading Until Needed
Vue async components defer loading a component's code until it's rendered, speeding up initial app loads. Use them for heavy components not needed right away, like modals or admin panels. The footgun is a blank UI if you don't handle loading/error states.
WHY IT EXISTS Large single-page applications can become slow because the browser must download all the JavaScript upfront, even for components the user may never see. This increases initial load time. Async components solve this by splitting the app into smaller chunks that are loaded on demand.
THE MENTAL MODEL Think of an async component as a "promise to render." Instead of having the component's code ready immediately, you have a wrapper that says, "When I'm needed on screen, I will go fetch my code and then render myself." This wrapper seamlessly passes down any props or slots, so from the parent's perspective, it looks and behaves just like a regular component.
HOW IT WORKS You use the defineAsyncComponent function, which accepts a loader function that returns a Promise. The easiest way to do this is with a dynamic import('./MyComponent.vue') statement, which modern bundlers recognize as a code-splitting point. Vue waits until the component is about to be mounted, then executes the loader. Once the component code is fetched, Vue renders it in place of the temporary wrapper.
WHEN TO USE IT Use async components for parts of your application that are not critical for the initial page view. Good candidates include: components for routes the user hasn't visited yet, large modals or dialogs, complex charts that are conditionally shown, or any heavy content that appears "below the fold."
WHEN NOT TO USE IT Avoid using async components for critical, above-the-fold UI like your main navigation or header. The slight loading delay can cause layout shifts and a poor user experience. For small, simple components, the overhead of creating a separate network request is often not worth the benefit.
ONE CANONICAL EXAMPLE To lazy-load an admin page, you can define it with loading and error states. In your parent component's script, you would write:
import { defineAsyncComponent } from 'vue' import LoadingComponent from './Loading.vue' import ErrorComponent from './Error.vue'
const AdminPage = defineAsyncComponent({ loader: () => import('./components/AdminPage.vue'), loadingComponent: LoadingComponent, errorComponent: ErrorComponent, delay: 200, timeout: 3000 })
In the template, you can then use <AdminPage /> as if it were a normal, synchronously imported component.
Read the original → vuejs.org
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.