How to Build a Vue Front End for a Headless CMS

Originally published at:

In this guide, we’ll learn how to build a modern blog website using Vue.js and GraphCMS, a headless CMS platform.

If you’re looking to start a quick blog today, my recommendation is to go straight to WordPress.

But what if you’re a media powerhouse and you want to deliver your content as fast as possible to multiple devices? You’ll probably also need to integrate your content with ads and other third-party services. Well, you could do that with WordPress, but you’ll come across a few problems with that platform.

  1. You’ll need to install a plugin to implement additional features. The more plugins you install, the slower your website becomes.
  2. PHP is quite slow compared to most JavaScript web frameworks. From a developer’s perspective, it’s much easier and faster to implement custom features on a JavaScript-powered front end.

JavaScript offers superior performance to PHP in browser loading tests. In addition, modern JavaScript and its ecosystem provides a far more pleasant development experience when it comes to building new web experiences fast.

So there’s been a growth of headless CMS solutions — which are simply back ends for managing content. With this approach, developers can focus on building fast and interactive front ends using a JavaScript framework of their choice. Customizing a JavaScript-powered front end is much easier than making changes on a WordPress site.

GraphCMS differs from most Headless CMS platforms in that, instead of delivering content via REST, it does so via GraphQL. This new technology is superior to REST, as it allows us to construct queries that touch on data belonging to multiple models in a single request.

Consider the following model schema:


  • id: Number
  • title: String
  • content : String
  • comments : array of Comments


  • id: Number
  • name: String
  • message: String

The above models have a one(Post)-to-many(Comments) relationship. Let’s see how we can fetch a single Post record attached with all linked Comment records.

If the data is in a relational database, you have to construct either one inefficient SLQ statement, or two SQL statements for fetching the data cleanly. If the data is stored in a NoSQL database, you can use a modern ORM like Vuex ORM to fetch the data easily for you, like this:

const post = Post.query()

Quite simple! You can easily pass this data via REST to the intended client. But here’s the problem: whenever the data requirement changes at the client end, you’ll be forced to go back to your back-end code to either update your existing API endpoint, or create a new one that provides the required data set. This back and forth process is tiring and repetitive.

What if, at the client level, you could just ask for the data you need and the back end will provide it for you, without you doing extra work? Well, that’s what GraphQL is for.


Before we begin, I’d like to note that this is a guide for intermediate to advanced users. I won’t be going over the basics, but rather will show you how to quickly build a Vue.js blog using GraphCMS as the back end. You’ll need to be proficient in the following areas:

  • ES6 and ES7 JavaScript
  • Vue.js (using CLI version 3)
  • GraphQL

That’s all you need to know to get started with this tutorial. Also, a background in using REST will be great, as I’ll be referencing this a lot. If you’d like a refresher, this article might help: “REST 2.0 Is Here and Its Name Is GraphQL”.

About the Project

We’ll build a very simple blog application with a basic comment system. Below are the links you can visit to check out the completed project:

Please note that a READ-ONLY token has been used in the demo and consequently the comments system won’t work. You’ll need to supply your OPEN permission token and endpoint as per the instructions in this tutorial for it to work.

Create GraphCMS Project Database

Head over to the GraphCMS website and click the “Start Building for Free” button. You’ll be taken to their signup page.

Sign up using your preferred method. Once you’ve completed the account authentication and verification process, you should be able to access the main dashboard.

In the above example, I’ve already created a project called “BlogDB”. Go ahead and create a new one, and call it whatever you want. After you’ve entered the name, you can leave the rest of the fields in their defaults. Click Create and you’ll be taken to their project plan.

For the purposes of this tutorial, select the free Developer plan then click Continue. You’ll be taken to the project’s dashboard, which looks something like this:

Go to the Schema tab. We’re going to create the following models, each with the following fields:


  • name: Single line text, required, unique


  • slug: Single line text, required, unique
  • title: Single line text, required, unique
  • content: Multi line text


  • name: Single line text, required
  • message: Multi line text, required

Use the Create Model button to create models. On the right side, you should find a hidden panel for Fields, which is activated by clicking the Fields button. Drag the appropriate field type onto the model’s panel. You will be presented with a form to fill in your field’s attributes. Do note at the bottom there’s a pink button labeled Advanced. Clicking it will expand the panel to give you more field attributes you can enable.

Next, you’ll need to add the relationship between models as follows:

  • Post > Categories (many-to-many)
  • Post > Comments (one-to-many)

Use the Reference field to define this relationship. You can add this field to any side; GraphCMS will automatically create the opposite relation field in the referenced model. When you’ve completed defining the models, you should have something like this:

You’ve now completed the first part. Let’s now provide some data to our models.

GraphQL Data Migration

To add content to your models, you can simply click the Content tab in the project dashboard where you can create new records for each of your models. However, if you find this to be a slow method, you’ll be happy to know that I’ve created a GraphCMS migration tool that copies data from CSV files and uploads them to your GraphCMS database. You can find the project here in this GitHub repository. To start using the project, simply download it into your workspace like this:

git clone
cd graphcsms-data-migration
npm install

Next, you’ll need to grab your GraphCMS project’s API endpoint and token from the dashboard’s Settings page. You’ll need to create a new token. For the permission level, use OPEN, as this will allow the tool to perform READ and WRITE operations on your GraphCMS database. Create a file called .env and put it at the root of the project:

ENDPOINT=<Put api endpoint here>
TOKEN=<Put token with OPEN permission here>

Next, you may need to populate the CSV files in the data folder with your own. Here’s some sample data that has been used:

// Categories.csv

// Posts.csv
Food Post 1,food-post-1,Breeze through Thanksgiving by making this Instant Pot orange cranberry sauce,Food|Featured
Food Post 2,food-post-2,This is my second food post,Food
Food Post 3,food-post-3,This is my last and final food post,Food
Fashion Post 1,fashion-post-1,This is truly my very first fashion post,Fashion|Featured
Fashion Post 2,fashion-post-2,This is my second fashion post,Fashion
Fashion Post 3,fashion-post-3,This is my last and final fashion post,Fashion
Beauty Post 1,Beauty-post-1,This is truly my very first Beauty post,Beauty|Featured
Beauty Post 2,Beauty-post-2,This is my second beauty post,Beauty

You can change the content if you want. Make sure not to touch the top row, as otherwise you’ll change the field names. Please note, for the column categories, I’ve used the pipe | character as a delimiter.

To upload the CSV data to your GraphCMS database, execute the following commands in this order:

npm run categories
npm run posts

Each script will print out records that have uploaded successfully. The reason we uploaded categories first is so that the posts records can link successfully to existing category records.

If you want to clean out your database, you can run the following command:

npm run reset

This script will delete all your model’s contents. You’ll get a report indicating how many records were deleted for each model.

I hope you find the tool handy. Go back to the dashboard to confirm that data for the Posts and Categories have successfully been uploaded.

With the back end taken care of, let’s start building our front-end blog interface.

Building the Blog’s Front End Using Vue.js

As mentioned earlier, we are going to build a very simple blog application powered by a GraphCMS database back end. Launch a terminal and navigate to your workspace.

If you haven’t got Vue CLI installed, do that now:

npm install -g @vue/cli

Then create a new project:

vue create vue-graphcms

Choose to manually select features, then select the following options:

  • Features: Babel, Router
  • Router History Mode: Y
  • ESLint with error prevention only
  • Lint on save
  • Config file placement: Dedicated Config Files
  • Save preset: your choice

Once the project creation process is complete, change into the project directory and install the following dependencies:

npm install bootstrap-vue axios

To set up Bootstrap-Vue in our project, simply open src/main.js and add the following code:

import BootstrapVue from "bootstrap-vue";
import "bootstrap/dist/css/bootstrap.css";
import "bootstrap-vue/dist/bootstrap-vue.css";

Vue.config.productionTip = false;

Next, we need to start laying down our project structure. In the src/components folder, delete the existing files and create these new ones:

  • CommentForm.vue
  • CommentList.vue
  • Post.vue
  • PostList.vue

In the src/views folder, delete About.vue and create a new file called PostView.vue. As seen from the demo, we’ll have several category pages each displaying a list of posts filtered by category. Technically, there will only be one page that will display a different list of posts based on an active route name. The PostList component will filter posts based on the current route.

Let’s first set up the routes. Open src/router.js and replace the existing code with this:

import Vue from "vue";
import Router from "vue-router";
import Home from "./views/Home.vue";
import Post from "./views/PostView.vue";


export default new Router({
mode: "history",
base: process.env.BASE_URL,
linkActiveClass: "active",
routes: [
path: "/",
name: "Featured",
component: Home
path: "/food",
name: "Food",
component: Home
path: "/fashion",
name: "Fashion",
component: Home
path: "/beauty",
name: "Beauty",
component: Home
path: "/post/:slug",
name: "Post",
component: Post

Now that we have our routes, let’s set up our navigation menu. Open src/App.vue and replace the existing code with this:

  <div id="app">
    <b-navbar toggleable="md" type="dark" variant="info">
      <b-navbar-toggle target="nav_collapse"></b-navbar-toggle>
      <b-navbar-brand href="#">GraphCMS Vue</b-navbar-brand>
      <b-collapse is-nav id="nav_collapse">
          <router-link  class="nav-link" to="/" exact>Home</router-link>
          <router-link  class="nav-link" to="/food">Food</router-link>
          <router-link  class="nav-link" to="/fashion">Fashion</router-link>
          <router-link  class="nav-link" to="/beauty">Beauty</router-link>


This will add a nav bar to the top of our site with links to our different categories.

Save the file and update the following files accordingly:


  <div class="home">
    <PostList />

import PostList from "@/components/PostList.vue";

export default {
name: "home",
components: {


  <section class="post-list">
    <h1>{{ category }} Articles</h1>
    <p>Put list of posts here!</p>

export default {
name: "PostList",
data() {
return {
category: ""
created() {
this.category = this.$;
watch: {
$route() {
this.category = this.$;

Notice that, in the PostList component, we’re using a custom watcher to update our category data property, based on our current URL.

Now we’re ready to perform a quick test to confirm the routes are working. Spin up the Vue.js server using the command npm run serve. Open a browser at localhost:8080 and test each navigation link. The category property should output the same value we defined in route name’s attribute.

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.