Quickly develop static websites with VueJS, a headless CMS and GraphQL

Marc Mintel
Aug 23, 2018 · 7 min read

Static websites are awesome! But what is a static website actually? It’s quite simple: a website that’s built only with HTML, CSS and JS without any server behind (yet it’s able to talk to an API via Ajax requests). However I don’t want to waste time talking about what a static website is and why it matters, there are enough resources on that, e.g. the article The Static Web Returns.


  • Basic ES6 knowledge
  • Basic VueJS knowledge (I personally recommend these books for newbies and for advanced)
  • Basic GraphQL knowledge (Read this book first if you are not familiar with GraphQL)

VueJS is overkill for static sites

Of course it is! You can start a static website without any tools at all, just upload an html file to your server and you are done. Although there are few problems you will be facing sooner or later:

  • Reusability
  • Structure
  • Maintainability

Talking to APIs, state management, animations and so much more is very easy to achieve with VueJS.

SEO and performance

If you are new to VueJS and the world of static websites, I guess this will be the first question you are asking. Yes there might be SEO problems when only using VueJS on the client side. To address these issues our website will be generated with NuxtJS upfront and then uploaded to our server. That means we will have plain HTML files on the server. And I can tell you.. performance will not be a problem if you do it right. The user will first see the pregenerated HTML files and all JS files including VueJS plus some other packages will be loaded afterwards.

Setting up your project

To start your project we will simply use the NuxtJS starter template. You can find a very good documentation about setting this up on the NuxtJS documentation, but I will go through this very quickly.

You will first have to install vue-cli if you didn’t already. Then let’s initialize our project using the starter template and the vue-cli with $ vue init nuxt-community/starter-template <project-name>

Example project setup with NuxtJS

Then you will have to cd into your project and run npm install . Using npm run dev you can already start a development server and open your project in the browser.

Great! That’s the first part. With npm run generate you can now create a static site made with VueJS! Super easy.

Managing the content

The next question might be “How can I manage contents?” or even “How could my clients manage contents?”. Until today most static site generators require you to edit your contents on a flat file basis. That means you have a content directory inside your project source where you have something like markdown files or whatever. I am not really a fan of that. It’s easy for you as the developer but you cannot give this to a client. Markdown is not that easy for many non-techie people and there is no content validation or anything like that. The solution is a headless CMS.

A headless CMS, wtf?

A headless CMS is simply a decoupled system. That means you can query contents via an API like REST or GraphQL. And that in turn means you can use almost any frontend framework and even spread your whole frontend via a CDN and still access the same content. You can also query the same data from a website and a smartphone app at the same time. Do some research and you will see there is a booming market on headless CMSs and that for good reason.

Here comes DatoCMS! A CMS I really fell in love with and which I am using on my own website. The main reason I chose DatoCMS over others: they will give you a very simple to use GraphQL API.

Preparing our contents on DatoCMS

This should not be a detailed tutorial on how to use DatoCMS, because they have an excellent documentation on that, but let’s go through it quickly. If you log in to your dashboard you will see the admin panel is divided into Content, Media and Settings. Go to Settings > Models, create a new model “Post”.

Next we need fields to manage our content. Let’s add them.

In this case we will add a title (single line string), text (multi line string) and a slug (single line string).

Next head over to the API explorer of DatoCMS (which uses GraphiQL). Paste your read only API token and there you go. If you dont know GraphiQL you can simply start by typing curly brackets and then pressing CTRL+Space to get auto complete suggestions for the fields you can query from the database.

What we need here is “allPosts” and “post”. But I will show you the exact queries later. If you choose allPosts for now and enter our fields you will see something like this.

allPosts shows and empty array. Why is that? Simple because we didn’t create any post! To fix that go to the “Content” tab in your admin panel and create a new post.

Make sure to save your post! Then go back to the API explorer and hit CTRL+Enter to refresh your query. Now you will see your first post!

Getting the content into your static files

Next question: How to receive the content from DatoCMS and using it in our NuxtJS application? We need Apollo to query a GraphQL API! Fortunately there is also a NuxtJS plugin for apollo. To install this module you first need to add it to your project with npm install --save @nuxtjs/apollo . Next we have to register the plugin in our nuxt.config.js .

modules: [

and then configure it (in the same file):

apollo: {
clientConfigs: {
default: {
httpEndpoint: 'https://graphql.datocms.com',
getAuth: () => 'Bearer XXXXXXXXXXXXXXXX'

Important: You must replace XXXXXXXXXXXXXXXX with the API key from DatoCMS. You can get it under Settings > Site Settings > API Tokens.

Running queries on a page

Alright! Everything is installed and we still don’t have any content in our page. Let’s create two files in our pages/blog directory. The first one will be the index.vue which will list all blog posts that we have and the second will be called _slug.vue and is responsible for a single blog posts detail page. The index.vue will look something like this:

Let’s quickly go through it: apollo will be configured as a property in our VueComponent . We are fetching all posts with the graphql-tag query syntax and for each post we are requesting the fields title , text and slug . We will need the slug to navigate to a single blog post.

Now let’s have a look at a blog post detail page, which is a big more complex, because we need to find the right blog post in our database.

Do you see the difference? Our apollo property is now split into a query , a prefetch and a variables property. In the query we define the $slug as a variable to pass into the filter parameter. This $slug comes from the variables (client side) and prefetch (server side, when generating the files). Those methods get the slug from our router parameters. If this is too much magic for you, have a look at the router documentation of NuxtJS.

Deploying our new content automatically

So the next thing you might think “And now I need to run nuxt generate every time I updated content and upload the files to my server again and again. Well, you could do that of course, but I recommend to setup a Continuous Deployment Pipeline to do that automatically. It’s not that easy to do so but with DatoCMS you have a Netlify integration built-in.

Do you see the little button “build site” on the top right? Press this when you are done editing your contents and your website will be automatically rebuilt on Netlify. Besides that your website will be generated again on each commit you push to a specific branch!

It’s not possible to send mails from a static website

Not true! It’s possible! You can use a serverless computing plattform like AWS Lambda. Fortunately this is already built-in with Netlify Functions. See my next article:

That’s it, any questions?

Let me know in the comments! Don’t forget to clap if this was helpful to you!

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade