Loading Data From Markdown Files With Gridsome [2021 Guide]

June 5, 2020 · Updated January 23, 2021 · 4 min read

Sleepy cat in front of MacBook Photo by Catherine Heath on Unsplash

This is part two of a series on building a file-based blog from scratch with Gridsome. Find the full series here.

In the last part, we started with a basic static site built with Gridsome. Now, we will write Markdown files, load them into Gridsome with a source-plugin, and display them as blog posts using template components.

Gridsome offers a plugin system. With it you can e.g. add an RSS feed to your site, add search, add analytics, or load data from a CMS of your choice.

Take a look at the plugins list to discover what's possible!

How to Load Markdown Files

When you want to add data to your Gridsome project, you need to add a source plugin. To load files from the local filesystem, we'll add the source-filesystem plugin: yarn add @gridsome/source-filesystem

Add plugin to gridsome.config.js

module.exports = {
  siteName: 'Gridsome',
  plugins: [
      use: '@gridsome/source-filesystem',
      options: {
        typeName: 'BlogPost',
        path: './content/blog/**/*.md',
  templates: {
    BlogPost: '/blog/:year/:month/:day/:slug'

To parse markdown files, we need to add the remark plugin: yarn add @gridsome/transformer-remark We don't need to configure anything, Gridsome uses it automatically.

Adding a Blog Post

First, add the folder where Gridsome looks for blog posts: mkdir -p content/blog.

Now, let's create a blog post. Create a file under content/blog/2020-06-05-first-post.md with the following content:

slug: "first-post"
date: "2020-06-05"
title: "Hipster Ipsum"

I'm baby chartreuse knausgaard gastropub deep v mlkshk pickled crucifix chicharrones meggings. Listicle jianbing tbh sriracha tofu, waistcoat post-ironic copper mug williamsburg scenester. Banh mi tilde swag beard. PBR&B disrupt affogato 8-bit fanny pack. Tacos fam brooklyn jean shorts. Taiyaki fam +1 tote bag chia palo santo.

Banh mi authentic fashion axe affogato shoreditch umami bicycle rights keytar put a bird on it drinking vinegar pitchfork taxidermy. Synth pinterest bespoke, taiyaki williamsburg chambray cloud bread readymade. Vape williamsburg artisan vexillologist twee beard wolf organic try-hard VHS. Artisan polaroid jianbing semiotics retro mumblecore. Hexagon YOLO gastropub sriracha DIY next level.

Ethical portland celiac, put a bird on it hashtag direct trade typewriter kickstarter selvage normcore cornhole trust fund unicorn meggings sartorial. Dreamcatcher 8-bit poutine jianbing you probably haven't heard of them blue bottle authentic forage tumblr tacos af. Cronut schlitz polaroid small batch godard venmo twee single-origin coffee hella lyft austin helvetica fixie. Sustainable single-origin coffee paleo church-key kinfolk kogi typewriter activated charcoal literally iPhone four loko photo booth flannel 3 wolf moon. Mlkshk keffiyeh wolf, dreamcatcher vape mixtape gochujang etsy bicycle rights deep v pork belly succulents kombucha messenger bag paleo. Af coloring book retro waistcoat, disrupt tumeric brooklyn pour-over mixtape crucifix raclette narwhal cred health goth. Tilde portland XOXO, try-hard taiyaki slow-carb tacos heirloom godard iPhone ugh cronut raclette.

Selvage twee viral, lyft chartreuse swag crucifix hexagon lo-fi meggings literally. Jianbing knausgaard vexillologist, sustainable yr twee tote bag cray keytar schlitz slow-carb DIY dreamcatcher brooklyn listicle. Chambray letterpress flexitarian meditation gentrify. Single-origin coffee lyft iPhone street art, hot chicken yr live-edge gentrify waistcoat.

Dummy text? More like dummy thicc text, amirite?

The first 5 lines are called "front matter". It contains the metadata for your posts. This post contains a slug (human readable part of URL), the publishing date, and the title.

After that, we write our post in regular Markdown syntax.

How to Display The Blog Post

Now let us add the BlogPost.vue template under src/templates:

    <h1>{{ $page.post.title }}</h1>
    <span>{{ $page.post.date }}</span>
    <div v-html="$page.post.content" />

query Post ($path: String!) {
  post: blogPost (path: $path) {
    date (format: "MMMM D, Y")

export default {
  metaInfo () {
    return {
      title: this.$page.post.title

You can see that the page-query this time loads all blog posts with the blogPost(path) query. This works because the current path in Gridsome is always available as $path.

In the script section, we define the page's <title> meta tag as the blog post title.

The template section defines our HTML. We can access the results of the post query as $page.post. There we have the title, date, and content available, because we request these properties in the blogPost page-query.

In our template, we use these three properties. First the title as a h1 heading, then the post date. Finally, we load the post's content into a div. v-html is Vue's property to directly inject HTML into a DOM node. This property is unsafe, because it does not validate the HTML, which can lead to XSS vulnerabilities. We can use it in this case, because we generate the Blog post HTML from Markdown files we write ourselves.

Let's start up our blog with gridsome develop. We get can go to our /pages overview site and voilà, our blog post appears! The pages overview of our blog.

When we click on the link, we see our blog post: Our new Markdown post.

Next part: style your blog with Tailwind CSS

That’s it for this post on loading Markdown files with Gridsome. In the next part of this series, we will add styling to this blog with Tailwind CSS. We'll also improve UX by adding a blog posts overview page!