Back to main page

How to create a blog with Gridsome

This tutorial assumes you have some familiarity with Vue.

What is Gridsome?

Gridsome Is a very fast Jamstack framework made with Vue. It allows for great SEO, has a GraphQL data layer, a robust plugin ecosystem and is easy to connect to a CMS.


Initial Setup

Check your node version and make sure you have the correct version installed. It's recommended to use 14+ I'm using 16.3 for this tutorial. You can check your node version by typing node -v in your terminal.


Installing Packages

When installing, use Yarn or NPM, don't mix and match the two.


We'll first need to install the Gridsome CLI globally. This will allow us to use gridsome create for our new project.

npm install --global @gridsome/clioryarn global add @gridsome/cli

Creating our first project

You can choose whatever name you want for the project. I'll name mine gridsome-blog. After creating your project go into the folder and then run the project.

gridsome create gridsome-blogcd gridsome-bloggridsome develop

You should see your new project on http://localhost:8080 Now that the boilerplate layout is set up by gridsome create, let's install some packages specific to creating a blog.


// transforms content for graphqlyarn add @gridsome/source-filesystemornpm install @gridsome/source-filesystem// Syntax highlighter for markdown code blocksyarn add @gridsome/remark-prismjsornpm install @gridsome/remark-prismjs// markdown transformeryarn add @gridsome/transformer-remarkornpm install @gridsome/transformer-remark

Config Setup

Now let's set up the packages we just installed. Open up your gridsome.config.js file and add the below code.

module.exports = {  plugins: [    {      use: '@gridsome/source-filesystem',      options: {        typeName: 'Post',        path: './content/blog/**/*.md',      },    },  ],  transformers: {    remark: {      externalLinksTarget: '_blank',      externalLinksRel: ['nofollow', 'noopener', 'noreferrer'],      plugins: ['@gridsome/remark-prismjs'],    },  },  templates: {    Post: '/:title',  },};

  • The plugins section is telling Gridsome to look for blog posts in the file path ./content/blog/**/*.md which we have not made yet.
  • The transfomers section is adding link options and using the plugin remark-prismjs that we installed earlier for markdown highlighting.
  • The templates section is for the Post.vue template we are going to make later on in the tutorial. It which will produce a url path of the blog title automatically. For example: http://localhost:8080/blog-post-two/

Optional Packages

For styling, I'm going to be using scss and Bulma. To match the card styles in this tutorial you'll need to set up Bulma and create an src/assets/style/index.scss file path.


Install Bulma, sass and sass-loader. Gridsome 0.7.0 is still on Webpack 4 which requires a lower sass-loader version.

yarn add -D sass-loader@^10.1.1 sass
yarn add bulma

In our newly created index.scss file, import bulma.

@import "~bulma";

In our main.js file, import our newly created index.scss file to load bulma and any additional partial scss stylesheets you might create

import '~/assets/style/index.scss';

Now we're ready to create our blog list and blog pages that will show the text in the .md files we created earlier.


Create Blog Pages

To get the path we need for Gridsome to read our markdown files, create a content and blog folder starting in the root file ./content/blog/. I'm going to create two markdown files first-blog.md and second-blog.md. These will be our two blog posts.


Add some fake data to your blog post using an Ipsum. I use Lorem Ipsum and Cat Ipsum in mine.


Here's an example of the blog structure in the .md file. I got some images from unsplash for my blog posts.

---title: Blog post twodate: 2022-09-22published: trueseries: falsecover_image: ../images/mountains.jpgcanonical_url: falsealt: mountainsdescription: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.'---Cat ipsum dolor sit amet

Blog Post Template

All of our individual blog posts that contain the data in our markdown files will have the same template layout. Under the templates folder create a file called Post.vue


Add the code below to Post.vue to create the HTML layout with Bulma styles and query to get the data from our markdown files we created earlier. The page will have a title, an image, and the content of the blog.


After adding this code you should be able to go to /blog-post-one/ and see the image and content of your blog post

<template>  <Layout>    <div class="has-text-centered">      <h1 class="title is-1">        {{ $page.post.title }}      </h1>    </div>    <div class="post content section container">      <figure v-if="$page.post.cover_image" class="image is-16by9">        <g-image :alt="$page.post.alt" :src="$page.post.cover_image" />      </figure>      <div v-html="$page.post.content" />    </div>  </Layout></template><script>export default {  metaInfo() {    return {      title: this.$page.post.title,      meta: [        {          name: 'description',          content: this.$page.post.description,        },      ],    };  },};</script><page-query>query Post($id: ID!) {  post: post(id: $id) {    title    path    description    alt    content    cover_image(width: 860, blur: 10)  }}</page-query>

Blog List Card

Now that we have our markdown files and blog page created, let's create a blog post card list that will allow us to show all the blogs at once.


In our components folder create a file named PostList.vue. Here, we're going to create the card style that will show up for each individual blog post on our landing page.

<template>  <div class="card">    <!-- if there is an image show it. If user clicks image take to url path -->    <g-link v-if="post.cover_image" class="card-image" :to="post.path">      <figure class="image is-16by9">        <g-image :alt="post.alt" :src="post.cover_image" fit="contain" />      </figure>    </g-link>    <div class="card-content  has-text-centered">      <!-- click the title link to go to blog post -->      <g-link :to="post.path" class=" has-text-weight-bold is-size-3">        {{ post.title }}      </g-link>      <!-- show description section of blog -->      <div class="content" v-html="post.description" />    </div>  </div></template><script>export default {  props: {    post: {      type: Object,      default() {        return {};      },    },  },};</script><style lang="scss">.card {  width: 500px;  height: max-content;  margin-top: 30px;}</style>

Under our pages folder in the index.vue file, let's loop through or PostList card component to show all the blog posts we have.

<template>  <Layout>    <header class="header">      <h1 class="title size-1 has-text-centered pt-5">Gridsome Blog Tutorial</h1>    </header>    <main>      <div class="container">        <!-- loop through blog card component to show blogs -->        <PostList v-for="edge in $page.posts.edges" :key="edge.node.id" :post="edge.node" />      </div>    </main>  </Layout></template><page-query>  query {    posts: allPost(filter: { published: { eq: true } }) {      edges {        node {          id          title          description          alt          cover_image( blur: 10)          path        }      }    }  }  </page-query><script>import PostList from '~/components/PostList.vue';export default {  components: {    PostList,  },  metaInfo: {    title: 'Gridsome Blog Tutorial',  },};</script><style>.container {  display: grid;  justify-content: center;}main {  margin: 4% 0;}</style>

Now you should be able to see your blog cards on the landing page and click the title link to go see the indvidual blog page.


Source code

You can get the code for the tutorial on my Github page. If you found this tutorial helpful please star it on github!