Nuxt.js over Vue.js: when should you use it and why

Nuxt.js is a frontend framework built upon Vue.js that offers great development features such as server-side rendering, automatically generated routes, improved meta tags managing and SEO improvement.

Our Front-end team didn’t really consider using Nuxt.js as a main technology on the client side until we recently received a request for a unique project with a number of very specific features. As this was also the first time a couple of members of our team used Nuxt.js, I decided to write this blog to explain how it worked for us.

Why would you use Nuxt.js over Vue?

Nuxt.js offers many benefits to front-end developers, but there was one key feature that made our decision to use this framework final – SEO improvement. Our application needs this feature because it is not a typical internal SPA (single-page application). It’s a public web application that includes social sharing features and management.

Speaking of social sharing, Nuxt.js has great meta tags management, so we could easily make specific and customizable social share windows depending on the data received from the back end. Here’s one example.

So, how does SEO improvement work?

To improve SEO, Nuxt.js uses SSR (Server Side Rendering). SSR is fetching AJAX data and rendering Vue.js components into HTML strings on the server (Node.js). It sends them directly to the browser when all asynchronous logic is done, and then finally serves the static markup into a fully interactive app on the client. This feature allows for great parsing through DOM elements with the Google SEO parser. SEO parser is parsing through DOM elements with enormous speed immediately when the website DOM is loaded.

On the other hand, typical SPA applications built with frameworks like Vue.js, React, Angular and similar are fetching data from backend with AJAX after DOM is loaded, and therefore SEO parser is not able to parse all of the DOM elements, because there are not yet rendered. AJAX fetching is asynchronous, while SEO parsing is not.

Image: Nuxt.js SEO audit grade
Image: Vue.js SEO audit grade

Nuxt.js needs a different mindset than Vue

Nuxt.js and Vue.js handle logic very differently. The main difference is that Vue is always running on the client side, while Nuxt is not, and that can cause major problems in some cases. For example – if you want to select a DOM element right after the application is loaded, there is a possibility that the app is running on the Node.js side, and of course, there are no DOM elements in Node.js.

The same would happen when accessing a browser’s local storage. That is the main reason why Nuxt is using cookies over local storage – because they are always accessible.

With Vue, we don’t have those kinds of problems because it is always running on the client, and therefore we do not have to bother with those kinds of potential problems.

Let’s see how to handle these types of potential problems in Vue and how to do it in Nuxt – with actual code examples.

Image: Nuxt.js server/client handling

The most important thing in this picture is the early return in the “created” method. Nuxt has a globally accessible object “process” that shows us whether are we currently running on the server side or the client side. The logic behind the code we see is focused on managing socket connection, and obviously, we do not want to update the DOM on receiving socket events if we are running on the server, because there is no DOM on the server side. If this was a Vue.js application, the code would be identical, except for the early return part – because the process would always be running on the client and there would never be a need to check that particular statement.

Image: Nuxt.js generated router based on the folder structure

Nuxt.js generates its own router based on the folder structure, while with Vue.js, it must be done manually – but keep in mind that there are pros and cons to both principles. Automatically generated routers' pros are that it's easier and faster to create one. You just create the directory and files, and Nuxt does all of the work. But the cons are that it is less controllable and manageable than a manually written one.

Image: Vue.js manual router

With Vue.js you can easily add your own logic to the router, import services and have more control in managing routes than with a manually generated router. This principle is more time-consuming and more complex, but that doesn’t always mean it is worse because of it.

Is Nuxt ready for enterprise-scale applications?

There used to be two main factors that made Nuxt.js unready for enterprise-scale applications:

  1. Poor typescript support
  2. Bad server-side error handling

While we were in the research phase of our project (some 6 months ago), there were no reliable Typescript start-kits or configurations whose usage was worth the risk. There were plenty of linting errors and missing types, so we decided to go with vanilla JS (ES6+). In the meantime, Typescript support for Nuxt.js has drastically improved and now there are new start-kits and configurations ready to be used without worrying about Typescript-related issues.

Bad server-side error handling was the biggest and the most demanding issue we had to deal with while developing a Nuxt.js application. While code was executing on the Nuxt.js server (Node.js) side, the application was throwing very unrelated error messages, and it was really hard and complex to debug and fix those same errors. It was necessary to handle errors on the Node.js side in a specific way in order to make debugging simpler.

Now, with better Typescript support and a deeper understanding of SSR, I can reliably say that Nuxt.js is ready for mid-scale and enterprise-scale applications, but there is still room for improvement – like better error handling and AJAX managing on the Node.js side of Nuxt.

Nuxt application structure

Nuxt.js has a very similar architecture to Vue.js. There are only two major differences:

  1. Router
  2. Main App.vue component

Nuxt generates router logic and its routes based on the directory and file structure for pages. For example, if we create a directory and file “about/index.vue”, Nuxt.js automatically creates the route “/about” for that page. There is no need to define or configure routes anywhere else in the application.

For nested routes, creating a directory inside the parent directory is all that is necessary – “about/me/index.vue” will generate the “about/me” route. And for creating dynamic nested routes or nested route parameters, all that is required is to name the subdirectory with the lodash prefix – “user/_id/index.vue” will create a dynamic nested route for users based on their id.

Image: Nuxt.js pages directory structure

Nuxt.js has one more structure-related feature that is very interesting – layouts. Vue.js applications have the main App.vue file, which is the main root component wrapper for all application components. Nuxt.js uses layouts, where every layout serves as an individual wrapper for application components. For example, if we want some specific pages to use different UI libraries, global CSS styles, font families, design systems, meta tags, or other elements, we can define what layout to use as its parent root component. By default, all Nuxt.js pages are using the default.vue layout.

Vuex in Nuxt.js is structured almost identically to the usual Vue.js environment – with store modules. This type of structuring is optional but highly recommended for better structure and code maintenance. Every store should be structured and modularized based on the application logic and data flow. For instance, if the application contains authorization logic, we must create the authorization store module for managing all authorization data and logic, such as log-in, log-out, cookies, tokens, user data, etc.

Image: Nuxt.js store modules structure
Image: Nuxt.js root application structure


Developing your first Nuxt.js project will surely be confusing and complex at first, especially if you have Vue.js background without SSR knowledge. But just like any other technology, it takes time, mistakes and a lot of lines of code to truly understand the power and the benefits of the Nuxt.js framework. As for me, I’m eagerly awaiting my next Nuxt.js project where I’ll get to use my acquired knowledge (and hopefully Typescript) without encountering any obstacles from the previous Nuxt.js + Typescript project I worked on.

If you’re interested in learning more about Nuxt.js, I highly recommend you check out these sources:

  1. Udemy course: Nuxt.js – Vue.js on Steroids
  2. freeCodeCamp article: Client-side vs. server-side rendering

Nuxt.js is a very powerful framework with many useful features that make developing front-end applications easier and more entertaining. But keep in mind that it is not the best choice for all types of client-side applications and websites.

So, to answer the main question – Nuxt.js or Vue.js? The answer is that you have to know the strengths and weaknesses of each, and you also need to know when to use one over the other based on the project type, goals and requirements.

Nuxt offers better SEO improvement with its server-side rendering feature, faster development with the auto-generic router, public share features and management with great configuration options and meta tags methods, and automatic code splitting with pre-rendered pages – all of this is impossible or extremely complex to achieve with Vue.js. If these features are required for your next project, I assure you that Nuxt.js will be an excellent choice.

On the other hand, if your goals are internal product, expanded code managing and coverage, typical client-side SPA, no need for SEO rate and performance, and manual code logic over generic solutions, then the obvious choice is Vue.js, as it’s far superior to Nuxt.js when it comes to handling all that.