Create a Blog With Nuxt Content v2
Tags: nuxt, vue, blog
Published: 2022-06-02 15:15:36

---
title: Create a Blog With Nuxt Content v2
published: true
date: 
tags: nuxt, vue, blog, nuxtjs, vuejs
canonical_url: https://www.mokkapps.de/blog/create-a-blog-with-nuxt-content-v2/
cover_url: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ikrq2doimplyus7mk6t3.jpg
---

I prefer simple Markdown files as the content source for my blog posts. In this article, I want to show you how can set up a simple blog using [Nuxt Content v2](https://content.nuxtjs.org/).

## Nuxt Content v2[<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#nuxt-content-v2)

[Nuxt Content v2](https://content.nuxtjs.org/) is a [Nuxt 3](https://v3.nuxtjs.org/) module that reads local files from the `/content` directory in your project. It supports `.md`, `.yml`, `.csv` and `.json` files. Additionally, it’s possible to use Vue components in Markdown with the [MDC Syntax](https://content.nuxtjs.org/guide/writing/mdc).

## Setup Nuxt App[<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#setup-nuxt-app)

First, let’s start a new Nuxt Content project with:

```bash
npx nuxi init nuxt-demo-blog -t content
```

Then we need to install the dependencies in the `nuxt-demo-blog` folder:

```bash
yarn install
```

Now we can start the Nuxt content app in development mode:

```bash
yarn dev
```

A browser window should automatically open for `http://localhost:3000`. Alternatively, you can start playing with Nuxt Content in your browser using [StackBlitz](https://stackblitz.com/github/nuxt/starter/tree/content) or [CodeSandbox](https://codesandbox.io/s/github/nuxt/starter/tree/content).

The following StackBlitz sandbox demonstrates the simple blog application we create in this article:

{% embed https://stackblitz.com/edit/nuxt-content-v2-blog-demo?embed=1 %}

## Blog Content Structure

Our demo blog will have this structure inside the `/content` directory:

```
├── blog
│ ├── _index.md
│ ├── a-great-article
│ └── cover.jpg
│ │ └── index.md
│ └── another-great-article
│ └── cover.jpg
│ └── index.md
```

`blog/_index.md` is a [Partial](https://content.nuxtjs.org/guide/writing/content-directory#partials) content that will show a list of all available blog posts.

Each blog post has its directory, including an `index.md` and a `cover.jpg` file.

The `index.md` files include [Front-matter](https://content.nuxtjs.org/guide/writing/markdown#front-matter) at the top of the file to provide meta-data to pages, like title, date, and the cover image URL:

```
---
title: A Great Article
date: 2018-05-11
cover: /content/blog/a-great-article/cover.jpg
---

This is a great article body!
```

## Simple Navigation[<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#simple-navigation)

First, we need simple navigation in our application to be able to navigate to our blog page.

Let’s start by adding a [default layout](https://v3.nuxtjs.org/guide/directory-structure/layouts) in `layouts`:

```vue
<template>
  <div>
    <nav>
      <NuxtLink to="/" class="link">Home</NuxtLink>
      <NuxtLink to="/blog" class="link">Blog</NuxtLink>
    </nav>
    <main>
      <slot />
    </main>
  </div>
</template>

<style>
.link {
  margin-right: 1rem;
}
</style>
```

In our `app.vue` we need to wrap the NuxtPage component with the NuxtLayout component:

```vue
<template>
  <div>
    <NuxtLayout>
      <NuxtPage />
    </NuxtLayout>
  </div>
</template>
```

Finally, we create a `index.vue` in `pages` directory:

```vue
<template>
  <h1>Home</h1>
</template>
```

[![Home Page](https://www.mokkapps.de/static/f4e1924058d702f1cc714567e5d5a53e/ca501/home.png "Home Page")](/static/f4e1924058d702f1cc714567e5d5a53e/ca501/home.png)
_Home Page_

## Blog List[<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#blog-list)

Let’s look at how we can implement a list of all available blog posts.

First, we need to create a `BlogPosts.vue` Vue component in `components/content/` that queries and renders all available blog posts:

```vue
<template>
  <h1>Blog</h1>
  <ul>
    <li v-for="{ _path: slug, title } in blogPosts" :key="slug">
      <NuxtLink :to="slug">{{ title }}</NuxtLink>
    </li>
  </ul>
</template>

<script setup lang="ts">
const blogPosts = await queryContent('/blog')
  .sort({ date: -1 }) // show latest articles first
  .where({ _partial: false }) // exclude the Partial files
  .find();
</script>
```

We use the [queryContent function](https://content.nuxtjs.org/guide/displaying/querying#querying-content) from Nuxt to query a list of our blog posts.

Now we can reference this Vue component inside our `content/blog/_index.md` file:

```
---
title: Blog
---

::blog-posts
```

We can use any component in the `components/content/` directory or any component made available globally in your application in Markdown files.

If we now click on the “Blog” navigation link in our application, we can see a list of all available blog posts:

[![Blog Post List](https://www.mokkapps.de/static/f2c7dd1f3ea8d6b1eed52086c841a5d2/b910a/blog.png "Blog Post List")](/static/f2c7dd1f3ea8d6b1eed52086c841a5d2/b910a/blog.png)
_Blog Post List_

I reported a [Nuxt content bug](https://github.com/nuxt/content/issues/1197) that you need to reload some routes; otherwise, their content is not visible.

## Blog Post Page[<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#blog-post-page)

Finally, we need to create a [dynamic route](https://v3.nuxtjs.org/guide/directory-structure/pages#dynamic-routes=) for the blog posts. Thus, we create a `[...slug].vue` file in `pages/blog`:

```vue
<template>
  <ContentDoc
    :path="$route.params.slug ? `/blog/${$route.params.slug[0]}` : '/blog'"
  >
    <template #not-found>
      <h2>Blog slug ({{ $route.params.slug }}) not found</h2>
    </template>
  </ContentDoc>
</template>
```

We use the current slug in the route parameters (`$route.params.slug`) to determine whether we want to render the blog post list or an individual blog post.

We can now see the content of the corresponding blog post:

[![Blog Post](https://www.mokkapps.de/static/0d099326fef0a0ca9c1d520f8dbfd1d7/6b9fd/blog-post.png "Blog Post")](/static/0d099326fef0a0ca9c1d520f8dbfd1d7/6b9fd/blog-post.png)
_Blog Post_

## Conclusion[<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#conclusion)

It’s effortless to create a Markdown file-based blog using [Nuxt Content v2](https://content.nuxtjs.org/). This article demonstrates the basic steps to set up such a blog.

You can expect more [Nuxt 3](https://v3.nuxtjs.org/) posts in the following months as I plan to blog about interesting topics that I discover while rewriting my portfolio website.

If you liked this article, follow me on [Twitter](https://twitter.com/mokkapps) to get notified about new blog posts and more content from me.

Alternatively (or additionally), you can also [subscribe to my newsletter](https://mokkapps.de/newsletter).