Build a website using Nuxt and Contentful : a step by step guide

Nuxt.jsXcontentful header image
June 14, 2019


As a frontend developer, working with static site generators and serverless architecture is a joy. We can create very powerful and amazing applications which we can also server-side render.

This article gives you a step by step guide for building a very basic website using Nuxtjs and Contentful — including a simple Vuex example.

Find the full GIT repo here:

Personally, I run my own website on a Nuxt/Contentful setup with continuous deployment, with GIT repo connected to Netlify. This, combined with Contentful’s webhooks that rebuild your site automatically when publishing new content, is just...awesome.

What is Nuxt?

If you’ve built Vue applications before, you probably know what NuxtJS is, which is the equivalent to what NextJS is for React.

Nuxt is a framework that builds on top of Vue that simplifies the development of universal or single page Vue apps, which is great if you are building a website and want to make sure it can get indexed by Google.

Derick Sozo has written a great piece on why you should choose Nuxt for your next web application, which can be found here:

What is Contentful?

Contentful is a content platform, which means it unifies content in a single hub, structures it for any digital channel and seamlessly integrates with hundreds of complementary tools.

Learn much more about Contentful on their own website:

In this article you’ll learn how to build a very simple Nuxt website that pulls data from Contentful. Once you’ve gotten a grasp of both and how you can use Nuxt and the content platform together, you can really start building powerful and amazing applications.

Nuxt setup

Before we can start building, we need to install Nuxt. We’ll do that by using the VueCLI. If you haven’t installed this on your system before, you need to install it by using the terminal:

npm install -g vue-cli

Now you can use the VueCLI to setup a Nuxt project.

vue init nuxt/starter nuxt-contentful-demo

Follow the instructions and give the project a name, description and author.


When done, cd into the folder of you project and run

Beautiful 😊 We’re now one step closer and we have a foundation to build upon.

Contentful setup

Go to Contentful and login with your username and password. If you aren’t a user yet, you need to create a profile to be able to use Contentful. They have a free plan which you can use.

Once logged in, first thing we need to do is set up a new space for our website.

When you’re in Contentful, click on “Create space.”


When creating a new space, we’ll need to fill in a few details.

Choose the free plan and give your space a name and confirm the creation.


Integrate Contentful into Nuxt

When wanting to use Contentful in Nuxt projects, we need to install the javascript SDK. We can do this by running the following command:

npm install --save contentful

When done installing, we can go to our project in our IDE, and create a new file under “plugins”. This will be basically be the file that are telling Nuxt to use contentful as a plugin, which enables us to easily fetch our data from Contentful.

Go ahead a create a new file:


As you might have noticed we are referencing some environment variables that we haven’t created yet.

For this to work, we will need to create a new file “contentful.json”, which we’ll place in our root directory. This file will need to hold some configuration.

You can find these settings by navigating to > Settings > Api Keys in the Contentful dashboard

When done, save the file and go to the nuxt.config.js.

We need to require the newly created config file and add a bit of code to our nuxt.config.js file.

The env property is a way to define values that will be available when using process.env when the site is run in a node.js context.

Now that we’ve gotten all the basics setup for using Contentful, next step is to create some content, we can pull into our nuxt application.

Build content in Contentful

Before we can fetch content into the application, we need to create a content type and some content. Start off by navigating to the tab: Content Model and set up a new content type.


Once the content type is created, we need to add some fields to it. In this example, we’ll set up a very basic model with the following fields:


Next up, we’ll need a few pages. Go ahead and create some pages based on the content type created. You can do this in the “Content” tab.


Awesome — now we have some content created and we’re ready to do some more work in our code.

Creating the navigation

Our website needs a navigation so our users can navigate between pages. In the “Components” folder, create a new component called “Navigation.”

Next, go to the folder “pages” and open up the index.vue file. In this file we’ll need our navigation component to be included, so we can add it to the file.

As you might notice, in the Navigation.vue, we are passing a prop called navItems with some data that doesn’t exist yet. To pass the pages down to the navigation component, we first need to fetch the data from Contentful.

Fetch data from Contentful

First thing we need to do is import the client from the Contentful plugin we created earlier in the plugins directory.

1*C0 UrQmwNmO-DhjxAxsKvQ

Add the following to the code:

Next, we need to make use of the asyncData method. This allows us to fetch and render the data server-side. In this we’ll fetch all pages created in Contentful.

Interested in learning more about asyncData? Check out this link:

What happens is, we start off by fetching all content created with the content-type of page ordered by date of creation.

When we have the data, we assign it to the property pages, which is also the prop data passed to our navigation component:

Your index.vue file should now resemble something like this:

And your page something like this:



1*L aETcsEt7HbMxvKZss7Bg

Just had to include a meme for this. 😊 Ok, maybe not the prettiest thing, but again, style and design as you see fit :) far, so goof. Now, what happens if you try clicking one of the navigation items? Argh, you get an error page. ☹


Let’s fix this.

The problem is Nuxt will automatically look for a component with the name same as the child route, which means if you have a url like: /about — Nuxt will look for an about.vue component or folder structure like /about/index.vue.

To fix this, we need to create a new component in “pages/_id” — Call this index.vue.

This will tell Nuxt to use this component for all child routes, ex: /about.

We can easily test it out and see if it works by adding some hardcoded html:

Now when clicking one of the links in our navigation, you should see something like this:


Next step is to fetch the contents of the current page. Again, we’ll import the {createClient} from our contentful plugin and assign it to a variable...

...and again, we need to use the asyncData method, but this time, we’ll get the data by matching the slug and the params from the url.

Now we have access to the data in the property: page. You can now create your template HTML and style it as you like — the full component should look something like this:

And your page will look something like:


Almost there...

We now have a working website, but it’s still lacking a few things. The navigation is missing whenever we are looking at a page and whenever we are on the front page, we have no control on the order of our navigation items. Not really the best UX pattern. Let’s fix this as well.

Move the navigation component out of our “pages/index”, and place it in “layouts/default” and remove the props passed to our navigation component (also remember to remove it inside the actual component).

Unfortunately, Nuxt doesn’t allow us to make use of the asyncData method in the layout. If we try, we’ll get an error when fetching content from Contentful.

More about that here:

Go Vuex

In this case, we’ll use make use of Vuex so solve our problem. Go to the store folder and create an index.js file.

As you can see, we’re importing a file called navigation that doesn’t exist yet, so we’ll need to create this and do a little work:

Note: Remember to remove all asyncData from the pages/index.vue, as we have no need of this anymore.

We are creating an action that commits our navigation items. When committing, we’ll mutate the state, and save basically save the navigation items in the state.

Next up, we’ll need to refactor our navigation component to get data from the store.

Now, when checking, our navigation should be fully functional again and when going to a page, our navigation will be visible.


For controlling the order of the navigation items, you could add an order field in your content type. It’s also possible to create a separate content type for navigation items: Create a global “container” and make use of the reference field in Contentful.

1*hFE6A3wkLreidwiP OzlpA

There are a ton of different ways you could do this, and it all depends on how you choose to structure and manage your data in Contentful, as there are no specific guidelines on how to structure content.

You’re at the finish line

You’ve now built your first very basic app with Nuxt and Contentful, and although this is a very basic example, I hope you get the idea of how you can use these to platforms to create very powerful and awesome applications.

Find the full repo here:

Next steps

Now that you’ve gotten hold of the basics, I urge you to try building a real website using what you’ve learned.

In the future, I’ll try to cover topics like:

  • How you connect and deploy your static site to Netlify

  • How to generate a sitemap using Nuxt

  • Generate files from dynamic routes

  • Rendering markdown from your content fields in Contentful

  • Rendering content from a WYSIWYG field in Contentful

  • And much more...

I hope you enjoyed the article and found it useful, and that you can start building awesome applications using Nuxt & Contentful.

About the author

Don't miss the latest

Get updates in your inbox
Discover new insights from the Contentful developer community each month.
add-circle arrow-right remove style-two-pin-marker subtract-circle