3 gotchas when moving from Vue to Nuxt

Adam Wattis
4 min readOct 17, 2020

I’ve been using Nuxt.js for a project that I’ve been working on for some time now. Having worked with Vue.js previously it wasn’t too difficult to get into the groove of things, but there are some significant differences between Vue.js and Nuxt.js that are important to understand. In this article I will go over the three main differences that I experienced coming from Vue, uncovering the features to focus on when entering into the world of Nuxt and Server Side Rendering.

Server Side Rendering

For those who are completely unfamiliar with Nuxt, it is based on Vue.js but adds the ability to render components and data on the server instead of on the client. The main benefit that this brings is the content on your web app will be available upon page load, which makes it possible for search engines such as Google to correctly index your website’s content.

Or at least this was the benefit I was looking for when choosing framework for the project I was working on; it required a web app that would contain information that had to be discoverable by search engines. I needed server side rendering for this project.

Perhaps unsurprisingly, most of the ‘gotchas’ that I encountered when working with Nuxt were related to the mechanics of the SSR feature. This is a bit different than working with asynchronously fetched data like in a regular singe page application.

Routing and project structure

Creating a new Nuxt app is made super simple with the create-nuxt-app command line tool. After creating a new Nuxt application I was ready to start developing, but the first thing I noticed was that the project folder seemed different from a regular Vue project. It turns out this project structure is also tied to how Nuxt handles routing for the application and that it is critical to understand this to develop Nuxt applications.

Nuxt comes with a directory called pages/ which contains all the pages for the application. Nuxt automatically derives the routing from the naming of these pages: For example, if you have file in pages/user/posts.vue this will create a route to ‘/user/posts’ on your website. You can also create dynamic routes by appending a underscore to the Vue file name: pages/user/_post.vue

Although this routing solution is different from a typical Vue router it’s easy to understand and work with. The reason for this routing solution is due to the SSR functionality. Each page must be rendered on the backend before served to the client. Therefore, each route is a new request instead of routing with Javascript.

Fetching data

After creating some pages and components it was time to populate the application with some data from the database. In a typical application I would fetch this data using AJAX requests from the client side. Obviously this solution would not suffice since this data would be fetched after the page is rendered, thus eliminating the possibility for search engines to index the data.

This problem is solved in Nuxt is by using the asyncData method to pre-fetch data on the server. That way the data is already inserted into the HTML when it arrives to the client, making it visible to search engines.

Nuxt also recommends you to use Axios Nuxt to make network requests together with asyncData. It works well and is very convenient:

asyncData({ $axios }) {
const endpoints = [
{url: '/api/posts', title: 'posts'},
{url: '/api/comments', title: 'comments'},
const promises = endpoints.map((endpoint) => {
return $axios.$get(endpoint.url)
return Promise.all(promises).then((res) => {
const data = {}
endpoints.forEach((endpoint, index) => {
return data[endpoint.title] = res[index]
// Returns to the data() on the component, how convenient!
return data
}).catch((error) => {

Above code passes the asyncData method Axios and creates an array of promises that each makes a request to one url endpoint. Then these promises are all resolved, the fetched data is placed inside the data object and finally returned. When the asyncData method returns it automatically places the fetched data into the components data() storage, ready to be used. Very convenient!

Rendering components client-side

Finally, the issue of rendering components on the client but not on the server. This might seem like a simple thing to do — and it is. You can easily render components dynamically, just like you would in Vue, but there are some pitfalls and they can be difficult to catch.

I found myself scratching my head as I encountered the following cryptic error messages:

Not exactly clear what went wrong here.

Not only that, but it was messing with how my components were (or were not) being rendered on the page. Eventually, I realized why this was happening.

When a user signs in I save a token and a ‘user’ object into the browser tabs localStorage. If a signed in user visits the page the application grabs this token and ‘user’ object and shows the user some components that are only available to authenticated users. However, since this all happens after the page is already rendered, it creates different versions of the DOM tree in the client and what was represented by the server.

To render components after page load we can use the <client-only></client-only> element tags. This states that the markup in between these tags will only be rendered on the client side and not on the server. After implementing this fix the error went away and the component renders as expected.


Moving from Vue to Nuxt is not a big transition, but understanding how SSR works can be an adjustment. Hopefully the above mentioned pitfalls will help others not to make the same mistakes I did!