
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 o reactive function.ref o 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 o 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.

Cómo funciona realmente el bucle del trabajador de la cola
Domina las colas de Laravel comprendiendo qué ocurre entre bastidores cuando se envían y procesan las tareas. Esta guía analiza los trabajadores de colas, la serialización de modelos, los reintentos, las tareas fallidas, el encadenamiento y el procesamiento por lotes: conceptos clave para crear aplicaciones fiables y superar con éxito los exámenes de certificación de Laravel.
Steve McDougall
25 de junio de 2026

Primeros pasos con rstore en Vue
Una guía paso a paso sobre rstore, el almacén de datos reactivo para Vue con almacenamiento en caché normalizado, consultas tipadas y un sistema de complementos.
Reza Baar
24 de junio de 2026

Promise.withResolvers(): el patrón «Deferred» integrado
Promise.withResolvers() sustituye al patrón «deferred» manual en JavaScript. Una sola desestructuración, sin ejecutor, sin «let». ES2024, compatible con todos los entornos de ejecución modernos.
Martin Ferret
23 de junio de 2026