Back

Create a Blog using Nuxt Content Module

A guide on how you can create your own blog in Nuxt.js using the Nuxt Content module.

Article thumbnail image

Installing the Nuxt Content Module

Don't have an existing Nuxt project yet? Follow this quick guide on how to.

Open your terminal in your Nuxt project and install the @nuxt/content package:

terminal
# Using NPM
npm install @nuxt/content
# Using Yarn
yarn add @nuxt/content

Now, open your project in your preferred editor of use.

Open the nuxt.config.js file and add @nuxt/content to the modules array.

nuxt.config.js
export default {
  // ...
  modules: [
    // ...
    '@nuxt/content'
    // ...
  ]
  // ...
};

Writing Content for the Blog

Create a content folder in the root directory of your Nuxt project, and inside of that folder create a blog folder.

Create a markdown file inside of the content/blog folder, for example first-post.md.

Inside of first-post.md put the following:

content/blog/first-post.md
---
title: First Blog Post Made using the Nuxt Content Module
description: This is my very first blog post that makes use of the Nuxt Content module.
---

## This is a H2 Heading

This is a paragraph with a [link](/) that directs to the homepage

Displaying your Content

Create a blog folder inside of your pages folder, and inside of that folder create an index.vue and _slug.vue file.

Open the index.vue file that's inside of the pages/blog folder and put the following inside of it:

pages/blog/index.vue
<template>
  <div>
    <h1>My Blog Posts</h1>

    <ul>
      <li v-for="(post, index) in posts" :key="index">
        <nuxt-link :to="`/blog/${post.slug}`">
          <h3>{{post.title}}</h3>
          <p>{{post.description}}</p>
        </nuxt-link>
      </li>
    </ul>
  </div>
</template>

<script>
  export default {
    async asyncData({ $content }) {
      const posts = await $content("blog")
        .only(["slug", "title", "description"])
        .fetch();

      return {
        posts
      }
    }
  }
</script>

I'll explain what the code above does.

The asyncData uses the $content module function, since we passed blog as the param in $content(), it will fetch all posts from the content/blog folder. Using the only chainable function, we tell the content module to only fetch the slug, title, and description of the posts. We finish off the fetch request by using the fetch() function to fetch the posts. We then return the array of posts in the asyncData.

In the HTML, we just loop over the posts data and display it nicely.

If you now navigate to http://localhost:3000/blog, it shows you a list of posts.

Displaying a Single Post

Open the pages/blog/_slug.vue file and put the following inside of it:

pages/blog/_slug.vue
<template>
  <article>
    <h1>{{ post.title }}</h1>

    <p>{{post.description}}</p>

    <nuxt-content :document="post" />
  </article>
</template>

<script>
export default {
  async asyncData({ $content, params, error }) {
    const post = await $content("blog", params.slug)
      .fetch()
      .catch(() => {
        error({
          statusCode: 404,
          message: "This post could not be found"
        });
      });

    return {
      post
    };
  }
};
</script>

Again, I'll explain what the code above does.

The asyncData uses the $content module function to fetch the post from content/blog with the current URL parameter of slug. If it can't find it, it will throw an error and redirect you to the error page.

In the HTML, we use the custom <nuxt-document/> component to display the post as HTML.

Here are some useful links that can help you make an even better blog!

Source Code

You can find the source code of this article on GitHub.