---
title: "Learn How to Create a Blog with Contentful and Nuxt"
description: "Check out this this tutorial to learn how to set up a blog with Contentful and Nuxt. Contentful has gotten a lot of traction lately as a modern CMS that offers a headless model to allow for both rich content editing and the ability to build modern web applications."
source: "https://www.netlify.com/blog/2020/04/20/create-a-blog-with-contentful-and-nuxt/"
last_updated: "2026-07-10T23:59:46.000Z"
---
In this tutorial, we’ll pair [Contentful](https://www.contentful.com/) with Vue by using the metaframework [Nuxt](https://nuxtjs.org/) — pulling in the posts from our application via an API. The [demo is here](https://contentful-nuxt-example.netlify.app/), and [the open-source repo is here](https://github.com/sdras/contentful-nuxt-netlify).

If you wish to skip all the steps below, I’ve prepared a template for you- technically I set up a blog for my stepdaughter about Animal Crossing and turned it into a template, which is why it’s fairly fanciful-looking. You can hit the deploy button below and modify it to your needs, most of the styles live in the main.css file so you can ditch or update that file if you wish to reskin it. There are also a few steps necessary to wire it up properly to your own content, let’s go over that now.

[![](https://www.netlify.com/img/deploy/button.svg "Deploy to Netlify")](https://app.netlify.com/start/deploy?repository=https://github.com/sdras/contentful-nuxt-netlify)

[![preview shot of the contentful blog](/v3/img/blog/preview-blog.jpg)](https://contentful-nuxt-example.netlify.app/)

Immediately following is a comprehensive tutorial of how we set this all up, in case you want to understand where everything is and how to modify it. Let’s dig in!

## How to Set up Contentful

If you haven’t already, set up an account with Contentful- as of this writing, this meant clicking the _‘get started’_ button and _‘try for free’_ in the developer panel. Once you’ve logged in, select _‘I develop content-rich products’_

![I develop content-rich products'](/v3/img/blog/work-content.jpg)

When you select this, it will prompt you to deploy, but this setup with work with Gatsby, not Nuxt, so, select _‘skip’_

![Show skipping the main screen](/v3/img/blog/skip.jpg)

After this, select _‘create a new space’_ then click on the highlighted free tier (unless you plan on working with more folks).

The next step will ask you if you want to create an empty space, instead select _‘create an example space’_ and select the _‘blog’_ template.

![Select create an example space](/v3/img/blog/second-option.jpg)

Once that’s set up, if you go to the top bar, you’ll see ‘Content Model’ where you should now have two types- **Blog Posts** and **Authors**. This is where we define the API structure and fields, and in the Content tab, as you might expect that’s where we’ll create our content. :)

![Content Model](/v3/img/blog/content-model.jpg)

You can click the JSON preview pane to see the structure of the data you’ll receive from the API:

![JSON Preview](/v3/img/blog/json-preview.jpg)

From here, if you go to Settings > API Keys, you will find an example token all set up for you. It’s probably worthwhile to rename this and add a good description. From here, we will copy the `Space ID` and `Content Delivery API- access token`, we will use those in the next section.

## Set up with Netlify

If you click the **deploy to netlify button** on this very post, you will be prompted to sign in and we’ll deploy the site for you!

If you prefer going through the steps with a Nuxt application from scratch, you can set the build command to be `npm run generate` or `yarn generate` and our directory for deployment to be `dist`, and you’re on your way!

From here, within the site dashboard, go to **Settings > Build & Deploy**, and set a few environment variables:

![Environment Variables in the Netlify Dashboard](/v3/img/blog/env-var.jpg)

-   `CONTENTFUL_ACCESSTOKEN` – this will be the Content Delivery API- access token
-   `CONTENTFUL_SPACE` – this will be the Space ID
-   `CONTENTFUL_ENVIRONMENT` (optional, it will default to master)

## Add the Local Environment Variable for Nuxt

When we deployed from the button earlier in the article, Netlify will have added a the whole template as a repo to your GitHub/GitLab account. Inside that codebase, we will need create a file called `.env`. This file is `.gitignored` by Nuxt, so it won’t be committed to your repo, we need to add these values so that you can develop locally.

```
CONTENTFUL_ACCESSTOKEN=your_token_hereCONTENTFUL_ENVIRONMENT=masterCONTENTFUL_SPACE=your_space_here
```

## Ta-da!

You should be all set up! Now every time you make a change and push to master, you can deploy your site. You can also add more content within the Netlify dashboard, or alter all the blog content and users on your blog.

* * *

# Project Setup

The following section isn’t required reading, but if you choose to set up this project from scratch or want to get to know all the pieces in order to best use it, this section will guide you.

## Bringing in Contentful

We just talked about how we’re using that `.env` file to use our environment variables locally, let’s talk a bit about how we’re bringing in data from the Contentful API and using those environment variables.

We install a few packages:

-   `dotenv`: allows you to use those environment variables locally
-   `contentful`
-   `node-sass` and `sass-loader`: allows us to use scss in our project
-   `@nuxtjs/markdownit`– A Nuxt module that allows us to take a string of markdown and parse it into HTML

In our nuxt.config.js file, we’ll import dotenv and use the .config method. From there, we’ll also designate the environment variables with [Nuxt’s env property](https://nuxtjs.org/api/configuration-env/).

```
import dotenv from "dotenv"; dotenv.config();
export default {...  env: {   CONTENTFUL_SPACE: process.env.CONTENTFUL_SPACE,   CONTENTFUL_ACCESSTOKEN: process.env.CONTENTFUL_ACCESSTOKEN,   CONTENTFUL_ENVIRONMENT: process.env.CONTENTFUL_ENVIRONMENT },}
```

We will create a plugin for Contentful. It will require the Contentful package `plugins/contentful.js`

```
const contentful = require("contentful");
module.exports = contentful.createClient({  space: process.env.CONTENTFUL_SPACE,  accessToken: process.env.CONTENTFUL_ACCESSTOKEN});
```

Back in `nuxt.config.js`:

```
plugins: ["~/plugins/contentful", "~/plugins/posts"],
```

and that plugins/posts.js file is responsible for kicking off an action on in the store to get the posts

```
export default async ({ store }) => {  await store.dispatch("getPosts"); };
```

In `store/index.js`, the Vuex store, we’ll bring in the client from our Contentful plugin, and in state, we’ll have a placeholder for posts. We’ll also create a mutation to update the posts. We’ll create an action to commit a mutation- it will use a getEntries method from the Contentful API, and gather the content via the content\_type of blogPost (if you remember, we also have the option to gather author data as well).

```
import client from "~/plugins/contentful";
export const state = () => ({ posts: null});
export const mutations = { updatePosts: (state, posts) => {   state.posts = posts; }};
export const actions = { async getPosts({ commit }) {   try {     if (!client) return;     const response = await client.getEntries({       content_type: "blogPost"     });     if (response.items.length > 0) commit("updatePosts", response.items);   } catch (err) {     console.error(err);   } }};
```

## Using the Contentful Data in our Application

Any `.vue` component in the pages directory is automatically routed for us. You’ll see in the `index.vue` file, we can create a home page. We’ll want to bring the posts on to this page, so we’ll gather them from the store as a computed property.

```
<script>export default { computed: {   posts() {     return this.$store.state.posts;   } }, head: {   title: "Paw Waves, Latest Posts" }};</script>
```

The `head` property here allows us to set per-page metadata, such as what we’d like the page title to read.

From there, we can loop through our posts and expose what we like in that first view. That preview page within Contentful’s dashboard in the JSON panel before is the data that will be exposed here, you can also see what’s available in the Vuex tab in devtools.

```
<template> <main>   <div class="container">     <h1 class="title">Paw Waves</h1>     <section v-for="post in posts" :key="post.fields.slug">       <div         class="image"         :style="           `background: url(https:${post.fields.heroImage.fields.file.url}) center center no-repeat`         "       ></div>       <h2 class="title">         <nuxt-link :to="post.fields.slug">{% raw %}{{ post.fields.title }}{% endraw %}</nuxt-link>       </h2>       <p class="author">By {% raw %}{{ post.fields.author.fields.name }}{% endraw %}</p>       <p class="description">         {% raw %}{{ post.fields.description }}{% endraw %}<br />         <nuxt-link :to="post.fields.slug" class="more">Read more ⟶</nuxt-link>       </p>     </section>   </div> </main></template>
```