
Make your websites/apps fast with strategies like lazy loading, stable prop design, virtual lists, v-once and v-memo, plus more!
Daniel Kelly
September 16, 2024
Vue.js is known for its excellent performance out of the box, but as applications grow in complexity, it's crucial to implement optimization techniques to ensure they remain fast and responsive. This article will explore various strategies to enhance the performance of your Vue.js applications.
TLDR: Checkout out course all about optimizing your Vue.js apps for blazing fast performance TODO: insert link here
Lazy loading is a technique that delays the loading of non-critical resources at page load time. In Vue.js, this can be achieved using dynamic imports.
Example:
const UserDashboard = () => import('./components/UserDashboard.vue')
const router = createRouter({
routes: [
{ path: '/dashboard', component: UserDashboard }
]
})
If you’re working in a Nuxt application this is automatically done for routes, and components can be lazy loaded by prefixing them with the Lazy keyword.
<LazyMyComponent v-if="showMyComponent" />
Vue.js provides two directives for conditionally rendering elements: v-show and v-if. Understanding when to use each can improve your app's performance.
Example:
<!-- Frequently toggled -->
<div v-show="isVisible">Heavy content</div>
<!-- Rarely changed -->
<div v-if="isLoggedIn">
<user-profile></user-profile>
<user-settings></user-settings>
</div>
When using v-for to render lists, always use the key attribute with a unique value. This helps Vue optimize re-renders and improves overall performance.
Example:
<ul>
<li v-for="item in items" :key="item.id">{{ item.name }}</li>
</ul>
When dealing with large datasets, rendering all items at once can significantly slow down your application.
Example using a third-party library like vue-virtual-scroller:
<template>
<RecycleScroller
class="scroller"
:items="items"
:item-size="32"
>
<template v-slot="{ item }">
<div class="user">
{{ item.name }}
</div>
</template>
</RecycleScroller>
</template>
Not all data has to be defined as reactive data with the ref function. If it’s some hardcoded configuration object you can save a bit of memory as Vue doesn’t have to watch the data for changes.
ref or reactive function.ref or reactivif you do need reactivity.Example:
<script setup>
const navItems = [
{ label: "Home", link: "/" },
{ label: "About", link: "/about" },
{ label: "Blog", link: "/blog" },
{ label: "Contact Me", link: "/contact" },
]
</script>
<template>
<nav>
<ul>
<li v-for="item in navItems" :key="item.link" >
...
</li>
</ul>
</nav>
</template>
By default, Vue is deeply reactive. This is great for DX but can cause performance issues with large datasets. Replace ref with shallowRef when working with arrays with 1000s of items and trigger updates by replacing the entire array.
shallowRef.Example:
const mySuperBigArray = shallowRef([
// thousands of items in here
]);
function addNewItemToMySuperBigArray(newItem){
// ❌ this won't trigger updates to the DOM
mySuperBigArray.value.push(newItem)
// ✅ instead replace the entire dataset
mySuperBigArray.value = [...mySuperBigArray.value, newItem]
}
Vue.js provides two powerful directives, v-once and v-memo, that can help optimize rendering performance by skipping unnecessary updates to parts of your template.
The v-once directive renders an element or component once and then skips future updates. This is useful for content that never needs to change.
v-once for static content that won't change after initial render.v-once on elements that might need to update based on changing data.Example:
<template>
<div>
<!-- This will only be rendered once -->
<h1 v-once>{{ title }}</h1>
<!-- This will update as usual -->
<p>{{ dynamicContent }}</p>
</div>
</template>
The v-memo directive allows you to memoize a sub-tree of your template. It takes an array of dependencies and only re-renders the sub-tree when one of these dependencies changes.
v-memo for expensive sub-trees that depend on specific values.v-memo, as it adds complexity and can harm performance if used incorrectly.Example:
<template>
<div>
<div v-memo="[item.id, item.completed]">
<!-- This block will only re-render when item.id or item.completed changes -->
<span>{{ item.name }}</span>
<span>{{ item.description }}</span>
<complex-component :data="item.data"></complex-component>
</div>
</div>
</template>
In this example, the content inside the v-memo directive will only re-render if item.id or item.completed changes, even if other properties of item are updated.
In Vue, a child component only updates when at least one of its received props has changed. Therefore you should design props to change only when necessary.
Example:
<!-- ❌ this will re-render every ListItem component
in the list when activeId changes-->
<ListItem
v-for="item in list"
:id="item.id"
:active-id="activeId" />
<!-- ✅ this will only re-render the ListItem that's becoming active
and the one that is becoming inactive-->
<ListItem
v-for="item in list"
:id="item.id"
:active="item.id === activeId" />
Optimizing Vue.js applications involves a combination of using Vue's built-in features effectively and implementing general web performance best practices. By applying these techniques, you can ensure your Vue.js applications remain fast and responsive, providing an excellent user experience even as they grow in complexity.
Remember, performance optimization is an ongoing process. Always measure the impact of your optimizations using Vue's devtools and browser performance profiling tools to ensure you're making meaningful improvements.
If you'd like to test your skills and deepen your knowledge of making your Vue.js apps performant, checkout the Senior Vue.js Developer Exam.
Get the latest news and updates on developer certifications. Content is updated regularly, so please make sure to bookmark this page or sign up to get the latest content directly in your inbox.

Events and Listeners: The Event System From the Inside Out
Laravel events are more than a way to decouple application logic. This article explores how the event system works under the hood, from dispatching and listeners to the internals that frequently appear on Laravel certification exams, helping you build a deeper understanding beyond basic usage.
Steve McDougall
Jun 11, 2026

Building 3D Scenes with TresJS
A hands-on walkthrough of TresJS, the Vue custom renderer for Three.js. From a blank canvas to a reactive 3D scene.
Reza Baar
Jun 10, 2026

`using` in JavaScript: Automatic Resource Management
Learn how the new using keyword and Symbol.dispose replace try/finally for cleaner resource management in JavaScript. With ES2026 support details.
Martin Ferret
Jun 9, 2026