Setting up a full static Nuxt site

Alex Jover Morales

Alex Jover Morales

Jul 14, 2020
6 min read
Share on Twitter or LinkedIn

When I start a project these days I usually choose Nuxt for it. Why? Because I can do all the things I do with plain Vue.js in less time, thanks to its conventions and the amazing Nuxt modules.

Some people think because of these conventions you lose flexibility. That's far from the truth: I've been using Nuxt for the last 2 years and I haven't found a case where I can't do what I wanted to do.

I've been using it even in Sprinter, one of the biggest Spanish sports E-Commerce. I spoke about the challenges we faced in this talk on Vue Day 2019.

But what I love the most about Nuxt is that you can produce 3 types of applications mostly with the same code:

  • SSR (Server Side Rendered): they're rendered on the server for every request. Sprinter works like that.
  • SPA (Single Page Application): client-only javascript based apps. Nowadays, they're quite well-known.
  • Static Generated: a.k.a. Jam Stack. Similar to SSR, but the html is rendered at compile time, so they don't need a server while also being SEO friendly.

VueDose is built as a static generated site, for different reasons:

  • SEO friendly
  • Very fast: HTML is already rendered
  • Saving on resources: it doesn't need a server, so you're saving money and the planet

Since Nuxt 2.13, we can create full static websites. In other words: you can generate a pure HTML + CSS + JavaScript site. All the Ajax calls to any API's are made at compile time, and then stored in json files locally.

What does that mean? Easy: huge performance boost.

But hey that's too much introduction, right? Let's start building NarutoDose!

# The Stack

# Nuxt.js

I think I showed enough love to Nuxt, right? Ok fine let's show Nuxt love once more 💚💚💚

# Storyblok (vs Nuxt Content Module)

Nuxt's recent release, @nuxt/content: an amazing module for creating your contents under a content/ folder by default. Your contents can be in Markdown, Yaml, JSON and other formats and it exposes an API where you can query those contents. Honestly, this was the missing part in the Nuxt ecosystem for indie tech bloggers.

You might think, couldn't you create VueDose with @nuxt/content? Yeah, I definitely could. But I didn't.

Why? Because, even though they both have things in common such as:

  • A flexible API to query contents, including full-text search
  • Ability to schedule content
  • Ability to use rich text format, such Markdown

There are definitely different:

  • @nuxt/content: it acts as a git-based CMS, meaning that people need to be familiar with git. That's ok for most tech blog cases, just something to be aware of.
  • Storyblok: it's much more than that. Although easy to use, it's a fully cloud-based CMS product that has more features for working with content such as, being able to define a schema, relationships and even a visual editor. It can be extended with plugins, although by default you also have roles, on-the-fly image resizing service, assets managements, and more. It can be managed by a non-dev user.

Since I wanted to leverage the power of Storyblok on VueDose, that was an easy decision to make. No worries, soon you'll know how to do it too 😉.

# TailwindCSS

You know that there are many CSS frameworks out there... the well-known Vuetify, the new exciting Chakra UI for Vue, Buefy, Bootstrap Vue and of course the marvelous [INSERT YOUR NEW UI FRAMEWORK HERE].

But Aarón and I decided to design VueDose from scratch, creating our own Design System, carefully thought out for giving the best reading experience and a beautiful UI.

TailwindCSS is not opinionated and is perfect for this case. Check out the next article to find out all the whys and how-tos 😏

# Create a Nuxt project

The easiest way is to use npx (install it if you haven't) to run create-nuxt-app:

npx create-nuxt-app mini-vuedose

That will open a prompt where you can select the features you want. For this project we'll choose TailwindCSS and it's important to choose Universal (SSR / SSG) as a rendering mode and Static (Static/JAMStack hosting) as a deployment target:

Now let's clean up some things:

  • Remove the folders store and middleware. You don't need them for now.
  • Remove components/Logo.vue
  • In pages/index.vue, remove the <style> tag and empty the <template>.

Starting clean, now is a good time to create the ArticleCard.vue component. Let's temporarily place it under the components folder.

As you can guess by the name, the ArticleCard component is used for displaying the list (or grid) of articles in the home page. Create it with the following structure:

      <nuxt-link :to="`/${slug}`">{{ title }}</nuxt-link>
    <p>{{ description }}</p>
      <img :src="author.image" :alt="" />
      <span>{{ }}</span>

export default {
  props: {
    title: String,
    slug: String,
    description: String,
    author: Object,

It's simple: it has a title, description, slug and an author.

Now go to pages/index.vue and create an articles array in the asyncData function. For now it will be static, but later we'll use Storyblok to get the real data. Use the ArticleCard component we created to display the article data:

        v-for="article in articles"

export default {
  asyncData() {
    const articles = [
        title: 'How to make your articles Vuetiful',
          'This article guides you through all the steps to make an article shine with your favourite framework, Vue',
        author: {
          name: 'Naruto Uzumaki',
          image: '',

    return { articles }

Do you see the ArticleCard being imported? No, because from Nuxt 2.13 the @nuxt/components modules is built-in Nuxt and activated by default, meaning... no more component imports!

Let's make sure things work. Run npm run dev in your terminal and open http://localhost:3000. The page should look like this:

Don't worry too much about the card design right now, you will see that in the next article!

# Recap

Up to this point, you have set up Nuxt with TailwindCSS in full static mode. Easy right? Yes, Nuxt does a lot of things for you out of the box, and based on the choices you made using the installer, things are configured out of the box. Later in this guide you'll see how to generate the production page but hold on for now.

This was just an introduction to get you started, but things are about to get fun 😎

Hold on there! In the next article you'll learn to design the app UI based on a Design System while following a simple yet solid component structure that I use on my projects.

You'll also learn why TailwindCSS fits so well for that purpose.

Pssst: you can find this article's code on Github.

Don't miss out anything about Vue, your favourite framework.

Subscribe to receive all the articles we publish in a concise format, perfect for busy devs.

Related Articles

How to use script setup in Nuxt 2

If you love Vue script setup and want to use it in your current Nuxt 2 project, the Nuxt team has made it possible to start using it today!

Paul Melero

Paul Melero

Feb 14, 2022

How to use the new Fetch in Nuxt.js

The Nuxt team is on fire, releasing new stuff every week! In this tip Samuel shows you a feature that might've gone unnoticed... till now.

Samuel Snopko

Samuel Snopko

Sep 7, 2020

Advanced i18n in Nuxt using Interpolations

Internationalization it's necessary in a multi-language site. Learn how to do i18n the right way in Nuxt and Vue using the nuxt-i18n module.

Debbie O'Brien

Debbie O'Brien

Aug 17, 2020


VueDose is proudly supported by its sponsors. If you enjoy it, consider supporting it to ensure the project maintainability.

Learning Partner