Home / Blog / Hybrid Rendering in Nuxt.js 3
Hybrid Rendering in Nuxt.js 3

Hybrid Rendering in Nuxt.js 3

Daniel Kelly
Daniel Kelly
Updated: October 28th 2022

Nuxt 3 gives you plenty of options when it comes to rendering your app. There’s static rendering, server side rendering, client side rendering, universal rendering, and incremental generation with swr caching.

Sometimes all the options can be overwhelming. Let me briefly break down each one and then show you a super cool trick to implement multiple rendering modes in a single app!

If your only here for the hybrid rendering, you can jump to the Hybrid Rendering section at the end of this article.

Client Side Rendering (SPA)

client-side-rendering-spa diagram

Icons in this image and all below images are by Font Awesome

Client side rendering is where the application is rendered purely in the browser. The server sends back only a minimal amount of HTML just to give the Vue app something to mount to. The HTML served from the browser contains NO content.

This is how a typical Vue application without Nuxt works (that is an app built with Vue CLI or Vite with npm init vue@3. Often times apps built with this approach are called a Single Page Application or SPA for short. This designation comes from the fact that the nearly empty HTML file is served for all routes and all navigation is done on the client side.

This is accomplished in Nuxt with the the following option in nuxt.config.ts

ssr: false

Best for

  • admin dashboards
  • sites that don’t require SEO
  • highly interactive pages

Pros

  • Simpler development as you only have to concern yourself with a single environment (the browser)
  • Can power very interactive pages
  • All the power of a typical Vue.js SPA with some handy built in conventions and developer conveniences from Nuxt
  • Cheaper to host (no server side processing to pay for)
  • Navigating between pages never reloads the entire page and easily supports page transitions

Cons

  • Not all search engines run JS before crawling
  • Some search engines are slower to index JS rendered pages
  • SPA’s don’t work great with page preview cards on social platforms
  • JavaScript app must run before end user sees anything (and this is dependent on the quality of the user’s device)

Server Side Rendering (SSR)

server-side-rendering-ssr diagram

Most of the Nuxt apps that you see in the wild are server-side rendered. That means the HTML for the Vue application is rendered on the server and then the full page HTML is delivered (content and all) to the browser.

That’s one of the big advantages of using Nuxt over a regular client side Vue.js app. However, most of these apps are also hydrated on the client side. We’ll talk about that more in just a moment (see Universal Rendering).

In Nuxt 3, as of winter 2022, it is possible to only render pages on the server with an experimental module from Nuxt core team member Daniel Roe. The module is called nuxt-zero-js. It “removes all client-side JS from your Nuxt 3 app”.

Best for

  • Experimental sites (right now anyway)
  • Information driven sites
  • Sites without alot of client-side interaction
  • Sites that cater to an audience with slow devices

Pros

  • Works better on low-end devices (no JS to run in client)
  • Better TTI (time-to-interactive)
  • Works great with content that’s updated often since pages are rendered on the server on request
  • Great for sites that aren’t super interactive
  • SEO and Social sharing works great

Cons

  • nuxt-zero-js module is still experimental
  • Not great for very interactive sites that benefit from client side Vue applications (JS)
  • increased hosting costs

Universal Rendering (SSR + Hydration)

universal-rendering diagram

Usually when you hear about SSR and Nuxt, usually what’s really being talked about is Universal Rendering. The purely SSR approach mentioned above is far from mainstream (understandably as the package that supports it is experimental).

Universal rendering is a mix of both SSR and SPA. Universal apps are first rendered on the server and then “hydrated” on the client. Hydration is the process of injecting the client-side Vue.js application into the existing server rendered HTML.

This is the default rendering mode for Nuxt.

Best for

  • Sites with a mix of informational pages and interactive pages
  • Sites with content that changes often

Pros

  • Best of both worlds (SPA & SSR)
  • User immediately sees content when HTML arrives in browser
  • Page can be interactive after hydration
  • Navigating between pages never reloads the entire page and easily supports page transitions
  • SEO and Social sharing works great

Cons

  • Development is a bit more complex. You have to keep 2 environments in mind that don’t always work quite the same (server and client)
  • Increased server costs

Static Rendering (SSG)

static-site-generation diagram

Static site generation is like a universal app in that the full HTML is delivered from the server and then hydrated on the client side. Where it differs is WHEN the HTML is generated on the server. With universal rendering it’s generated at request time. With static rendering (aka Static Site Generation or SSG) it’s generated during a build step.

This build step typically happens on a push to a remote github repo and triggers all pages of the site to be re-generated. Then the static HTML files are served at request time.

This approach was made popular by Netlify. It’s the backbone of the so called “Jamstack”.

You can generate a static site in Nuxt 3 with npx nuxi generate or in Nuxt 2 with npm run generate.

Best for

  • Smaller sites that have a limited number of pages (though much larger sites have been built with this approach, however the scale on the Jamstack does introduce it’s own issues)
  • Sites where the content doesn’t change very often

Pros

  • Very performant since static files are delivered via CDN
  • Cheap since requests require no server side processing
  • Secure since there’s no server side processing

Cons

  • Can still be dynamic but requires a bit more effort and thought
  • Larger sites incur larger build times

Incremental Static Generation

incremental-static-generation-isg diagram

Just like Universal rendering mixes SSR and SPA in terms of WHERE the app is rendered, incremental static generation (ISG) is a mix of SSG and SSR in terms of WHEN the app is rendered. In my opinion, it’s basically a glorified cache.

The caching strategy used by ISG is known as SWR or “stale-while-revalidate”. The flow looks like this:

  1. On the first request of a page, the server renders it but also caches the rendered HTML
  2. All subsequent requests for a specified time period receive the cached HTML and the server does no processing (This time period is 1 minute in Nuxt 3 by default but can be configured)
  3. After the 1 minute (or whatever) the server still sends the cached HTML but in the background re-renders the page and stores the fresh version in the cache.
  4. Then the process starts back at step 2 and loops indefinitely.

This approach avoids some of the hurdles you face with SSG while still giving you the same great performance.

Best for

  • Interactive sites where SEO and/or social sharing is a concern
  • Content driven sites that update frequently

Pros

  • No build step to slow down deployment
  • Very performant
  • Reduces some complexity compared to SSG

Cons

  • Not as cheap as SSG because still using server processing power (though not as expensive as plain SSR/universal)
  • Few visitors will still get slightly stale content

Hybrid Rendering

hybrid-rendering diagram

Now that you know about all the other rendering modes, understanding Hybrid rendering is pretty simple. Hybrid rendering is the ability to mix and match the above approaches within a single app based on route. That means you might have:

  • an admin section that’s purely an SPA under a /admin route.
  • articles published with ISG under a /blog route.
  • a homepage that very rarely changes and so it’s statically generated like an SSG (though it is generated on first request like ISG but it has no timeout to regenerate).

This is possible since Nuxt RC 12. You can configure it with the routeRules option in nuxt.config.ts. Here is an example taken from the Nuxt 3 docs (modified to remove options not related to rendering mode).

export default defineNuxtConfig({  
    routeRules: {    
        // Static page generated on-demand, revalidates in background (ISG)   
        '/blog/**': { swr: true },    

    // Static page generated on-demand once (SSG - or at least mighty close)    
    '/articles/**': { static: true }, 

    // Render these routes on the client (SPA)
    '/admin/**': { ssr: false },    

  }  
})

I got to play around with this first hand recently for our Nuxt.js 3 Fundamental course and honestly it was just so exciting to me I’ve got to share the video with you. View this lesson for free from the premium course and get a first hand look at hybrid rendering in action.

Conclusion

All the options for rendering your Nuxt app can be confusing but rest assured there is one that’s fit for your use case. Plus, with hybrid rendering you can even tailor a single site by route to get just the right result.

If you’d like to learn more about the fundamentals of Nuxt.js 3 then checkout our course Nuxt.js 3 Fundamentals.

If you’d like to learn Nuxt 3 in the context of a real world application, then checkout the course Mastering Nuxt 3. In it, avid Vue content creator Michael Thiessen will take you step by step through the build of a video course application.

Related Courses

Start learning Vue.js for free

Daniel Kelly
Daniel Kelly
Daniel is the lead instructor at Vue School and enjoys helping other developers reach their full potential. He has 10+ years of developer experience using technologies including Vue.js, Nuxt.js, and Laravel.

Comments

Latest Vue School Articles

Generating Fake Data with Faker.js

Generating Fake Data with Faker.js

Discover the power of Faker.js, the essential JavaScript library for generating realistic fake data, in our new video course created in collaboration with the developers at Vehikl (vehikl.com).
Felipe Flor
Felipe Flor
Database Seeds with the Nuxt Task Runner

Database Seeds with the Nuxt Task Runner

Learn how to integrate Drizzle ORM with Nuxt for type-safe database operations, including database migrations and seeding with Faker.js and Nitro tasks.
Daniel Kelly
Daniel Kelly

Our goal is to be the number one source of Vue.js knowledge for all skill levels. We offer the knowledge of our industry leaders through awesome video courses for a ridiculously low price.

More than 200.000 users have already joined us. You are welcome too!

Follow us on Social

© All rights reserved. Made with ❤️ by BitterBrains, Inc.