Vue.js was developed with performance in mind and each new feature added to the core framework is thoroughly checked for that particular aspect. However, our applications could become slower at times due to the continuous development and extending the initial project with more and more features.
There are many ways we can make our Vue apps faster and we will be releasing new articles about that but in this article we would like to focus on one particular approach - server side rendering (SSR).
But, to understand how server side rendering can help make our Vue app more performant, first it would be beneficial to understand how Vue and SSR work under the hood.
Vue.js for client-side apps
As a framework, Vue was built primarily to serve client-side applications - by producing and manipulating DOM in the browser. It covers the most common features needed for web applications. The web's diversity means projects can vary greatly in form and scale and, to address this, Vue is designed with flexibility and incremental adoption in mind.
The two main features of Vue are:
- Declarative Rendering - Vue extends standard HTML with a template syntax that allows us to declaratively describe HTML output based on JavaScript state.
- Reactivity - Vue automatically tracks JavaScript state changes and efficiently updates the DOM when changes happen.
There are ways however to render Vue components into HTML strings on the server side, send them to the browser, and “hydrate” the static markup to enable full interactivity on the client. Because of the fact that the majority of the code runs both on the server and the client, SSR Vue apps can also be called isomorphic or universal.
What is server side rendering (SSR)?
Server-side rendering (SSR) involves the server processing requests from the browser and generating HTML content by executing JavaScript. This process includes data fetching, component rendering, and style application. The server then sends the complete HTML to the browser for immediate display. SSR can improve initial load times and performance compared to client-side rendering (CSR).
This diagram explains how server-side rendering and hydration work for Nuxt.
In contrast, client side rendering involves the server sending raw data (typically JSON) and a JavaScript bundle to the browser. The browser then handles data parsing, JavaScript execution, and HTML content generation.
This approach can lead to slower initial load times due to the additional processing required on the client side.
Benefits of using SSR
There are few significant benefits of using server side rendering in comparison to client side rendering (CSR) like:
- Performance - SSR boosts website performance by handling rendering on the server, reducing browser load. This leads to faster initial loading and better user experience. Server-generated HTML minimizes client-side processing, resulting in quicker page rendering and smoother navigation.
- SEO - Search engines use web crawlers to index and rank websites. SSR generates complete HTML on the server, making it easier for crawlers to process content, especially compared to JavaScript-heavy CSR sites. This can potentially improve search engine rankings by providing more accessible and indexable content.
- User Experience - CSR can lead to slower initial content display, potentially frustrating users and increasing bounce rates. SSR addresses this by delivering complete pages instantly, providing a smoother user experience.
How to render a Vue app on the server side
There are two main ways you could achieve that: manually or by using an already developed solution. Below you will learn what steps need to be done to build a Vue SSR app from scratch and how to use tools like Nuxt, Quasar, or Vite-plugin-ssr/Vike to build your next SSR Vue application.
Manual rendering
To manually render Vue app on the server side, you would need to follow these steps:
- Initialize the new project with
npm init -y
- Add
"type": "module"
in package.json file to instruct the Node.js engine to run in ES modules mode. - Install
vue
as a dependencynpm install vue
- Create an
index.js
file with following content:
import { createSSRApp } from "vue";
import { renderToString } from "vue/server-renderer";
const app = createSSRApp({
data: () => ({ count: 1 }),
template: `<button @click="count++">{{ count }}</button>`,
});
renderToString(app).then((html) => {
console.log(html);
});
- Run this file with
node index.js
which should print<button>1</button>
This is a rather simple example, so let’s make it a bit more difficult by adding a Node.js server request handler express
. To do that, we would need to:
- Install express dependency
npm install express
- Create a
server.js
file:
import express from "express";
import { createSSRApp } from "vue";
import { renderToString } from "vue/server-renderer";
const server = express();
server.get("/", (req, res) => {
const app = createSSRApp({
data: () => ({ count: 1 }),
template: `<button @click="count++">{{ count }}</button>`,
});
renderToString(app).then((html) => {
res.send(`
<!DOCTYPE html>
<html>
<head>
<title>Vue SSR Example</title>
</head>
<body>
<div id="app">${html}</div>
</body>
</html>
`);
});
});
server.listen(3000, () => {
console.log("ready");
});
- Run the server with
node server.js
command and see the button in the browser
There are few things that we would need to take care in order to have a fully working SSR application like handling Client Hydration for example that you can read more about here
Using already developed solutions
Vue documentation recommends to use already developed solutions for handling server side rendering for example:
- Nuxt
- Quasar
- Vite
Server side rendering with Nuxt
Nuxt is a framework built on Vue that simplifies the development of universal Vue applications and also functions as a static site generator. This is the recommended solution for building SSR Vue apps.
In Nuxt, server side rendering (here called universal rendering) is enabled by default so no additional configuration is needed. You can however disable it or enable any other rendering rules in your `nuxt.config.ts file like following:
export default defineNuxtConfig({
routeRules: {
"/client/**": { ssr: false },
},
});
You can read more about specific rendering modes here.
Quasar
Quasar is a comprehensive Vue-based framework for developing applications across multiple platforms. It supports single page applications (SPA), server side rendering (SSR), progressive web apps (PWA), mobile apps, desktop apps, and browser extensions from a single codebase. Quasar manages build configuration and offers a set of Material Design UI components.
In Quasar, we need to enable SSR as it is not a default mode and we can do so like: quasar dev -m ssr
. This will add SSR mode automatically and will create a new folder in your project folder with following structure:
- middlewares/ - SSR middleware files
- production-export.js - SSR web server production export
There are many ways how you can configure SSR in your Quasar app that you can check out here.
Vite SSR
Vite offers basic server side rendering support but you can also try the community plugin called vite-plugin-ssr
or vike
. This solution is recommended for developers who have experience with SSR and build tools who need full control over the architecture.
For Vite’s SSR approach you can add the vike
package to your project and configure vite.config.ts
file accordingly:
import vue from '@vitejs/plugin-vue
import vike from 'vike/plugin'
export default {
plugins: [vue(), vike()]
}
If you are starting a new project from scratch, the recommended approach here is to use vike-vue
instead.
Server Side Rendering vs Static Site Generation vs Incremental Static Regeneration
Apart from Server Side Rendering, there are also two other rendering modes worth mentioning while thinking about the performance of Vue applications: Static Site Generation and Incremental Static Regeneration. They both use SSR under the hood but can be more beneficial for certain scenarios.
Static site generation
With Static Site Generation (SSG) you render pages once during the build process instead of on-demand each for each request. This creates static HTML files that can be served without dynamic processing.
SSG offers similar performance benefits to server side rendering (SSR), with faster content delivery. It's more cost-effective and simpler to deploy than SSR, as it produces static HTML and assets.
However, SSG is limited to pages with static data - information known at build time that doesn't change between requests. Any data updates require a new deployment. SSG is ideal for improving SEO on marketing pages (like /home, /about, or /contact) and works well for content-heavy sites such as documentation or blogs.
Incremental Static Regeneration
Incremental Static Regeneration (ISR) is a relatively new concept in the modern web and the main idea behind it is to solve the biggest caveats of both SSR and SSG applications.
The problem with SSR applications is that if the application grows complex, building each page dynamically on the request by the user can be time consuming. This can be mitigated with caching but, if we have an e-commerce application with millions of pages, this can be complex.
With SSG however, the problem is different as the build time can grow a lot due to the amount of pages we need to build to be able to serve them statically.
ISR promises to solve this problem by combining both SSR and SSG into one concept allowing you to build your application once as a SSG but also an ability to rebuild only certain parts of the application when needed (for example when content from CMS changes).
As stated by Vercel, Incremental Static Regeneration (ISR) enables content creation or updates without redeployment, which comes with following benefits:
-
Performance - with ISR you can cache generated pages across a global Edge Network (for example Vercel or Netlify), ensuring consistently fast static pages and durable storage.
-
Backend Efficiency - ISR reduces backend load by utilizing cached content and minimizing data source requests.
-
Build Speed - Pages are generated on-demand or via API, rather than during build time, accelerating build processes as applications scale.
Summary
Enabling server side rendering for your Vue application brings several benefits like Performance, SEO, User Experience or Accessibility. In this article, you learned how to do that both the manual way and by using the already existing solutions like Nuxt, Quasar, Vite-plugin-ssr/Vike.
Keep in mind that going with server side rendering does not mean that your page does not have any interactivity on the client side. SSR can be used for the initial page/application load to improve the user experience and performance of the content while JavaScript can still work on the client side to add a little bit of interactivity after load. That is why SSR Vue apps are named universal applications as they can serve many use cases.
In certain use cases, you may also want to try out Static Site Generation or Incremental Static Regeneration as they utilize SSR under the hood but can be used in certain scenarios to make it even more performant.
Bonus: Monitor SSR Performance with DebugBear
To see all the performance benefits of server side rendering in your Vue app, you would need to audit Lighthouse Performance and Core Web Vitals. By using DebugBear, you get all this valuable data, information about competitors, ability to run tests from multiple locations, and all that from a single dashboard! Sign up for a free trial here!
Apart from the dashboard, you could also use the HTML Size Analyzer to see exactly what content is contributing to your document size. Find issues like inline images, large hydration state or code duplication.
This can be extremely useful when working with SSR as you will be sending HTML with content to the browser and you can analyse it here easily.
Additional resources
If you would like to learn more about these concepts, please check out the following articles: