Vue.js and Nuxt.js Optimization: Tips and Tricks
Vue.js is fast. But only if you use it correctly.
A visitor waits for your site to load, but after three seconds, they leave. Unfortunately, this isn't science fiction—it's the reality for many modern websites, even those built on frameworks like Vue.js or Nuxt.js.
Let's clarify what's on the agenda here:
- Vue.js is one of the most popular JavaScript frameworks for building web applications.
- Nuxt.js is a meta-framework that allows Vue.js to run on the server, among other things, to boost performance.
Proper optimization isn't just a technical finesse for programmers. It's an investment that translates into higher conversions, better search engine rankings, and more satisfied users.
Clients of PageSpeed.ONE like Dr. Max and Airstop who use Vue.js achieve better results through proper optimization.
Why Speed is Critical for Websites
You might think, "So what if the site loads a second slower?" Reality is ruthless and numbers don't lie. Website speed has a direct and measurable impact on your business. Let's consider a few examples:
-
Google found that if a page meets Web Vitals, it is 24% less likely that users will leave before it loads.
-
The conversion rate of an e-shop drops by an average of 0.3% with each additional second of loading time.
-
Speed is a direct ranking factor for SEO in the Google algorithm.
Speed isn't a luxury; it's a necessity. Every millisecond counts. These numbers hold doubly true for websites built on modern JS frameworks like React or Vue.js.
Why? Because they almost always load and run more JavaScript than traditional websites and have to go through a more complex initialization process.
But don't worry. With the right approach, you can make a Vue.js site faster than many static pages.
Is Vue.js "Inherently" Slow? Distinguishing Myths from Reality
There's a common belief that Vue.js and similar modern frameworks are inherently slow. Yes, more JavaScript means more work during the speed optimization process. But Vue.js is designed for performance, and sites built on it can be very fast.
Performance issues usually stem from human error, not from the framework itself:
-
Incorrect architecture Using Single Page Application (SPA) where server-side rendering would be better.
-
Lack of optimization Ignoring best practices. Some of which we outline in this text.
-
Testing only on fast devices Developers often don't see the real problems of regular users and ignore the so-called Performance Inequality Gap.
Vue.js can be fast on its own. The key is to use it correctly and know when to use which technique.
How to Tell if Your Vue.js Site is Lagging
You might think your site is fine because it runs quickly for you. But are you testing it properly?
Measure your site's speed on PageSpeed.ONE.
Core Web Vitals: The Three Pillars of Speed
Core Web Vitals are three key metrics that determine whether your site is fast from a user's perspective:
| Metric | Meaning | Recommended Value |
|---|---|---|
| Largest Contentful Paint (LCP) | Load speed. Time to load the largest visible element on the page. | ≤ 2.5 seconds |
| Interaction to Next Paint (INP) | Interaction speed. Response speed to user actions (clicks, taps). | ≤ 200 milliseconds |
| Cumulative Layout Shift (CLS) | Layout stability. Stability of the visual layout of the page. | ≤ 0.1 |
Seven Steps to a Faster Vue.js Site
Now comes the most important part. Let's look at the basic tips to speed up your Vue.js site.
1. Proper Architecture: SSR and SSG Instead of Pure SPA
The acronyms sound complicated, but the essence is simple. Instead of your site waiting to download and run JavaScript, send the user ready-made HTML code.
To exaggerate a bit, it's like the difference between getting a ready-made meal or having to wait for someone to cook it at the table in front of you.
Let's break down the acronyms:
-
SPA (Single Page Application) is a site that loads most things right at the start and then pretends to handle everything on the client device without reloads, but at the cost of a very slow start and other disadvantages. It cooks your meal at the table. Today, it's an outdated approach.
-
Server Side Rendering (SSR) means the server generates ready-made HTML code for each page. The user sees the content immediately while interactive JavaScript loads in the background. That's what we want.
-
Static Site Generation (SSG) goes even further. HTML files are generated in advance (during an internal development process called build) and served as static files. This is the fastest possible option. However, it's not suitable for e-shops and other more dynamic sites.
-
Hybrid approach combines both methods based on the type of page—static pages like blog posts as SSG, dynamic ones as SSR. Consider whether you can use this for your site.
Here's a schematic configuration of SSR for the server part of Vue.js, called Nuxt.js:
// nuxt.config.ts or nuxt.config.js for SSR
export default defineNuxtConfig({
// Enable server-side rendering
ssr: true,
nitro: {
prerender: {
// Pre-generate static pages
routes: ['/about-us', '/contact', '/blog']
}
}
});
If your site is sensitive to loading speed, avoid a purely client-side SPA. Consider combinations of SSR and SSG.
2. Progressive Rendering: Lazy Loading as a Lifesaver
Imagine building a house. You don't carry all the bricks at once but gradually as needed. Your Vue.js site should behave the same way.
How to achieve this?
-
Lazy loading components means components load only when they're actually needed. Typically, these are components that the user doesn't see on the first screen or uses only occasionally.
-
Progressive hydration is the process where JavaScript gradually "connects" to the HTML generated by the server. The user sees the content immediately, but interactivity is added gradually where needed.
-
Code splitting automatically divides your code into smaller parts according to pages or features. Instead of downloading one large file, only the necessary parts are gradually downloaded.
Example of lazy loading components:
// Use lazy loading
const HeavyChart = defineAsyncComponent(() => import('./HeavyChart.vue'));
// With a loading state (e.g., spinner)
const HeavyTable = defineAsyncComponent({
loader: () => import('./HeavyTable.vue'),
loadingComponent: LoadingSpinner,
delay: 200
});
Load only what's visible. The rest can wait.
We have a whole separate article on lazy loading in general.
3. Bundle Size: Less JavaScript, More Speed
Every kilobyte of JavaScript needs to be downloaded, parsed, and executed. On slow devices or weaker connections, this can take forever. Therefore, it's crucial to keep your JavaScript bundle size as small as possible. How to do it?
-
Tree shaking is a process that automatically removes unused code from your bundle. Modern bundlers like Webpack or Vite do this automatically, but you need to help them by importing correctly.
-
Audit dependencies means regularly checking which libraries you actually need. Often, libraries remain in a project that you no longer use but still increase the bundle size.
-
File compression can shrink the bundle size by up to 70%. Modern Brotli compression is even more effective than traditional Gzip.
// Bad – imports the entire library (several MB)
import _ from 'lodash';
// Good – imports only the needed function (a few kB)
import { debounce } from 'lodash-es';
// 💡 Even better – simple custom implementation
const debounce = (fn, delay) => {
let timeoutId;
return (...args) => {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => fn.apply(this, args), delay);
};
};
Simple tip: the tool bundlephobia.com shows you the size of each dependency and suggests alternatives.
Every kilobyte counts. Keep the bundle on a diet.
4. Optimization for Better INP: Quick Click Responses
Interaction to Next Paint (INP) measures how quickly a site responds to user actions. If a user clicks a button and nothing happens, or it happens slowly, our dear user gets frustrated.
The most common problem is demanding operations performed in the main browser thread, known as long tasks (measurable by the JS Long Tasks (JSLT) metric or synthetically by the TBT metric). When your JavaScript processes a lot, the browser can't respond to clicks in the meantime.
Hydration, or reviving the application, can burden the browser and prevent user interactions. We addressed this issue, for example, in the Airstop.cz project.
What to do about it?
-
Use lazy hydration. Especially for components where it's clear that the user won't activate them immediately. These are typically menus, modals, filters, footers, etc.
-
Debouncing and throttling are techniques that limit the number of functions called during rapid action repetition. Typically when typing into a search box or scrolling.
-
Reduce the DOM. The dynamic HTML structure (DOM) is the foundation. Keep it as small as possible, ideally under 3,000 DOM nodes.
Debouncing for search:
// Debouncing for search – reacts only after 300 ms from the last keystroke
import { debounce } from 'lodash-es';
const searchProducts = debounce((query) => {
// Search runs only after a pause
}, 300);
// 🖱️ Throttling for scroll – triggers at most once every 100 ms
import { throttle } from 'lodash-es';
const handleScroll = throttle(() => {
// Optimized scroll listener
}, 100);
Heavy operations like filtering large datasets or complex calculations should be moved to the server via API calls.
Keep the main browser thread free. The user must feel immediate response.
5. List Virtualization: Thousands of Items Without Lag
If you have a list with thousands of products, articles, or comments, you can't render them all at once. That would slow the site down to an unbearable degree.
Virtualization means rendering only visible items plus a small buffer around them. As you scroll, items dynamically exchange. It's like reading a book—you don't read all the pages at once, just the current one.
There are ready-made libraries for Vue.js that implement virtualization for you. The most popular are vue-virtual-scroller or vue-virtual-scroll-grid.
Virtualization can improve the performance of a list by hundreds of percent, especially on mobile devices with limited performance.
Render only what the user sees. Thousands of items can wait.
6. Proper Image Handling: Modern Formats and Lazy Loading
Images for some websites make up the majority of data volume that needs to be loaded. Proper image optimization can be the most effective way to speed up a site.
-
Modern formats like WebP and AVIF offer 25-50% better compression than traditional JPEG while maintaining quality. Modern browsers already support WebP and AVIF.
-
Responsive images mean delivering the right sizes for different devices. Why load a 2000px wide image on a mobile phone with a 400px wide display?
-
Lazy loading images means images load only when they come into the user's viewport. This significantly speeds up the initial page load.
-
Placeholder images prevent layout shifts (content jumping) during loading. You can use blurred thumbnails, colored backgrounds, or skeleton loaders. But be careful with them, as improper use can worsen speed.
Example in code—responsive images with lazy loading:
<!-- AVIF image with fallback to WebP + lazy loading -->
<picture>
<source src="product-image.avif" type="image/avif" />
<img src="product-image.webp" loading="lazy" alt="Product description" width="800" height="600" />
</picture>
Carefully optimize images, especially if they are your LCP element.
7. Profiling: Measurement is the Foundation of Improvement
Without measurement, you're optimizing blindly. You might be optimizing something that isn't a problem at all, while overlooking the real bottleneck.
What tools to use beyond the absolute basics, which are synthetic and CrUX monitoring?
-
Chrome DevTools Performance panel shows you where your code spends the most time. You can see which components render the slowest or which functions burden the CPU. More on measuring Core Web Vitals in the browser.
-
Vue DevTools provide specific Vue.js metrics—which components re-render, how long it takes to mount or update.
-
Real User Monitoring (RUM) tracks real users on real devices with real internet. Lab tests are important, but RUM shows reality. It's the most accurate of all three types of speed measurements.
What you don't measure, you can't improve.
Advanced Tricks: CDN, Prefetching, and Modern Technologies
If you've mastered the basics, you can go further. Here are some tips for optimizations beyond the above:
-
Choose good infrastructure and a Content Delivery Network (CDN). CDN means your files load from the server closest to the user. It's like having store branches in every city instead of one headquarters. Use Cloudflare or AWS CloudFront.
-
Optimize BFCache, i.e., fast returns to the previous page, can yield good results with little work.
-
Speculation Rules API brings intelligent navigation prediction, but implementation is advanced, so be careful.
PageSpeed.ONE Successes: Real Optimization Results
Theory is nice, but what about practice? We've worked with several Vue.js projects where performance optimization has made a significant impact.
One of them is the vacation retailer website Airstop.cz, where we helped the development team from DesignDev improve user experience during an ongoing redesign.
The project is still in progress, but we're already seeing improvements in Core Web Vitals metrics by tens of percent:
Airstop.cz shows that Vue.js projects can make significant speed advances. And it’s still early days.
For another client, the pharmacy chain Dr. Max, we already have green LCP and CLS metrics, and activities to improve interactivity (INP) are underway. Examples of these optimizations include:
- Optimizing user interactions with loaders using the
nextTickmethod across the entire site. - Speeding up user interactions in complex product searches.
- Optimizing events triggered from GTM (Google Tag Manager).
Every project is unique, but the principles remain the same—without optimization following development, speed cannot be maintained at a good level. The most important thing is to start with measurement and gradually implement changes.
How PageSpeed.ONE Monitoring Can Help You
In our PageSpeed.ONE speed monitoring, you can track Core Web Vitals metrics in real-time and identify specific issues. We often see problems with large JavaScript bundles or slow hydration (the process of attaching interactive JavaScript to HTML) on Vue.js sites.
We monitor the development of Core Web Vitals metrics long-term for our client Dr. Max and its competitors.
Measurement is the foundation. Without data, you're optimizing blindly.
Our PageSpeed.ONE monitoring PLUS offers these advantages:
- Continuous monitoring of Core Web Vitals from CrUX data and synthetically.
- Comparison with competitors in your industry and other domain data.
- Detailed analyses from every test.
- Watchdog and alerting upon performance deterioration with the ability to react quickly.
We highly recommend automating monitoring so you can focus on optimizations.
Conclusion: Speed as a Competitive Advantage
Optimizing Vue.js applications shouldn't be a one-off action but a continuous process. Vue.js itself isn't slow; problems arise from incorrect use or insufficient optimization.
Start by measuring with Core Web Vitals, consider implementing SSR, and gradually optimize according to our list. Remember, every millisecond counts, and speed can be your competitive advantage.
Don't know what to do next? Feel free to contact us.
The result of Vue.js optimization will be a faster site, happier users, better search engine rankings, and ultimately higher revenue.