Vue.js Performance Optimization Tips
Best practices for building fast Vue applications with optimal Core Web Vitals scores.
Why Vue.js Performance Matters
Vue.js is known for being lightweight and performant, but poorly optimized Vue apps can still be slow. With Vue 3's Composition API and improved reactivity system, you have powerful tools for optimization.
Component Loading
Lazy load components to reduce initial bundle size.
Reactivity
Vue's reactivity can be optimized to reduce computations.
Bundle Size
Tree-shaking and code splitting keep bundles small.
Rendering
Optimize Virtual DOM updates and avoid unnecessary renders.
1. Use Vue 3 for Better Performance
Vue 3 offers significant performance improvements over Vue 2:
Vue 3 Performance Benefits
- Faster rendering: Up to 2x faster Virtual DOM
- Smaller bundle size: Tree-shakable, ~10KB lighter
- Better TypeScript support: Improved developer experience
- Composition API: More flexible and performant than Options API
- Fragment support: No wrapper div needed
Migration Tips
- Use Vue 3 for new projects
- Migrate existing Vue 2 apps gradually with Vue Compat
- Adopt Composition API for better code organization
2. Implement Lazy Loading
Load components only when needed:
Async Components with defineAsyncComponent
import { defineAsyncComponent } from 'vue';
const AsyncComponent = defineAsyncComponent(() => import('./components/HeavyComponent.vue'));
// With loading and error statesconst AsyncComponentWithStates = defineAsyncComponent({ loader: () => import('./components/HeavyComponent.vue'), loadingComponent: LoadingSpinner, errorComponent: ErrorDisplay, delay: 200, // Show loading after 200ms timeout: 3000, // Give up after 3s});Route-Based Code Splitting
// router/index.jsconst routes = [ { path: '/dashboard', component: () => import('./views/Dashboard.vue') }, { path: '/profile', component: () => import('./views/Profile.vue') }];3. Optimize Component Rendering
Reduce unnecessary re-renders and computations:
Use v-once for Static Content
<!-- This content never changes, render once --><div v-once> <h1>{{ title }}</h1> <p>{{ staticDescription }}</p></div>Use v-memo to Skip Updates
<!-- Only re-render when dependency changes --><div v-memo="[userId]"> <UserProfile :id="userId" /></div>Computed Properties Over Methods
<script setup>import { computed } from 'vue';
// Bad - recalculates on every renderconst getTotal = () => { return items.reduce((sum, item) => sum + item.price, 0);};
// Good - cached until items changeconst total = computed(() => { return items.reduce((sum, item) => sum + item.price, 0);});</script>4. Optimize List Rendering
Lists are common performance bottlenecks:
Always Use :key with v-for
<!-- Bad - no key --><div v-for="item in items">
<!-- Good - unique key --><div v-for="item in items" :key="item.id">Virtual Scrolling for Long Lists
Use vue-virtual-scroller for lists with 100+ items:
<template> <RecycleScroller :items="items" :item-size="50" key-field="id" > <template v-slot="{ item }"> <div class="item">{{ item.name }}</div> </template> </RecycleScroller></template>Avoid Nested v-for
- •Extract nested lists into separate components
- •Use computed properties to flatten data when possible
- •Consider pagination for very large datasets
5. Leverage Composition API
The Composition API provides better performance and code organization:
Reusable Composables
// composables/useFetch.jsimport { ref } from 'vue';
export function useFetch(url) { const data = ref(null); const error = ref(null); const loading = ref(false);
async function executeFetch() { loading.value = true; try { const response = await fetch(url); data.value = await response.json(); } catch (e) { error.value = e; } finally { loading.value = false; } }
return { data, error, loading, executeFetch };}shallowRef and shallowReactive
Use shallow reactivity for large objects you don't need to deeply watch:
import { shallowRef } from 'vue';
// Only tracks changes to the array itself, not nested objectsconst items = shallowRef([/* large array */]);6. Reduce Bundle Size
Smaller bundles load faster:
Tree-Shaking
// Bad - imports entire lodashimport _ from 'lodash';
// Good - imports only what you needimport debounce from 'lodash/debounce';
// Better - use lodash-es for tree-shakingimport { debounce } from 'lodash-es';Optimize Dependencies
Replace Heavy Libraries
Replace moment.js with day.js or date-fns to save ~200KB
Analyze Bundle
Use Vue Devtools to analyze bundle composition
Remove Unused Libraries
Remove unused UI component libraries and dependencies
Dynamic Imports
Use dynamic imports for large dependencies
Vite Configuration
// vite.config.jsexport default { build: { rollupOptions: { output: { manualChunks: { 'vendor': ['vue', 'vue-router'], 'ui': ['@/components/ui'] } } } }}7. Server-Side Rendering with Nuxt
Use Nuxt 3 for optimal SSR performance:
Nuxt 3 Features
Automatic Code Splitting
Nuxt automatically splits your code for optimal loading
Image Optimization
Built-in image optimization with Nuxt Image module
Hybrid Rendering
Mix SSR and SSG for optimal performance per route
Auto-Imports
Auto-imports for components and composables
Nuxt Image Optimization
<template> <NuxtImg src="/hero.jpg" width="800" height="600" format="webp" loading="lazy" /></template>useFetch for Data Loading
<script setup>const { data, pending, error } = await useFetch('/api/data');</script>8. Optimize Images and Assets
Images typically account for most of the page weight:
Lazy Load Images
<template> <img v-lazy="imageUrl" alt="Description" /></template>
<script setup>// Use vue3-lazyload or vue-lazyloadimport VueLazyload from 'vue3-lazyload';</script>Responsive Images
<img srcset="small.jpg 480w, medium.jpg 800w, large.jpg 1200w" sizes="(max-width: 600px) 480px, (max-width: 1000px) 800px, 1200px" src="medium.jpg" alt="Responsive image"/>9. Performance Monitoring
Measure and track performance over time:
Vue Devtools Performance Tab
- •Profile component render times
- •Identify slow components
- •Track re-renders
Web Vitals Tracking
import { onLCP, onINP, onCLS } from 'web-vitals';
onLCP(console.log);onINP(console.log);onCLS(console.log);Build Analysis
- •Use rollup-plugin-visualizer to analyze bundle
- •Set up Lighthouse CI in your pipeline
- •Monitor bundle size with size-limit
10. Production Best Practices
Ensure optimal production builds:
- •Enable production mode:
NODE_ENV=production - •Remove Vue Devtools in production
- •Enable compression (gzip/Brotli)
- •Use a CDN for static assets
- •Implement proper caching headers
- •Minify HTML, CSS, and JavaScript
- •Remove console.log statements
Test Your Vue.js App
Get Vue-specific optimization recommendations powered by AI.
Analyze Your Vue Site