Headless CMS for Metalsmith
Storyblok is the first headless CMS that works for developers & marketers alike.
The idea of Metalsmith is quite simple: "An extremely simple, pluggable static site generator". So in this quick walkthrough, we will have a look at how we can use the data from the Storyblok API with a Metalsmith project to create some pages. At the end of this article, you will have a Metalsmith project which renders components filled with data from the Storyblok API.
We're about to use Storyblok as headless CMS - so what is it?
Let me start with a short explanation of Storyblok: It is a hosted headless CMS in which you can create nested components per content entry. The author of one content entry, therefore, can create components that act as Content-type like articles or products but also easily can create nestable components to create landing pages - but would allow you to add Storyblok to existing solutions to enrich your current content as well.
What are we going to build?
During this article, we will use the default component
page which acts as layout/content-type and the nested components teaser, grid and feature to create a sample layout for landing pages. You will receive this setup during this tutorial, however, if you've already created a space that structure is already available in the content entry with the name "home".
Let’s start with Metalsmith
You can either clone the whole repository to access their example called
static-site or use this link to download only that subfolder. I would recommend you to download only the subfolder to be honest.
Navigate to your
static-site folder in your cloned(downloaded project and execute:
Finally - let's build your downloaded Metalsmith project, you could either use their Makefile (
make build) or simply go with:
By default you should now have a simple "blog setup" using Markdown files and end up as static files in your
build folder. At this point you won't see a server running on your side - we will add
express to serve those static files later. You can do this step
node index.js after each step below to have a look what changes or what will be added.
If you're facing any troubles feel free to leave a comment below or check out their Github Repository.
By creating a new Storyblok space you should already have a basic setup of content components including teaser, grid, and feature which we're going to use in this tutorial.
You should now have that dependency in your
package.json - since we want to use it we have to require it in the index.js.
Add the following line in your
Let's create a Storyblok space
If you're not registered already simply sign up using the web-interface. You will be guided through the creating of your first space.
The default set of components and a content entry called "home" will be generated for you. You will also see the on-boarding with some code examples in different programming languages by clicking on that "home" content entry.
You will also see the preview token (sometimes called private token) which allows us to load draft versions of your content, you can copy that from one of the code examples or from your space dashboard. We will need this token in the next step, because we're about to load that!
Create a simple plugin to inject Storyblok content entries in the Metalsmith "files".
To allow a generation of pages according to your content in Storyblok, we will write a custom plugin to load the data from the API. You can customize it as you want and transform the data as you need it. It uses the Storyblok Content Delivery API and the endpoint Stories in this example. Add the plugin below in your
index.js you can read the comments to see what's happening - you can also
response.body to have a look at the JSON from the API.
Add the content below to your
Use your custom plugin
Since everything in Metalsmith is done using plugins, all we need to do is to tell Metalsmith to also use our
storyblok plugin. You can do this by simply adding
.use(storyblok) to their plugin chain.
Simply replace your current Metalsmith task from above with the code below - or enter the new line right above the
.source('(./src') in your
Our first custom layout
Since the default Metalsmith setup ships with
layouts/layout.html we simply reuse that structure by adding our own layout. The root component (eg. content-type) by default in Storyblok is called "page". By accessing the API of Storyblok you can already see that
You can create as many content-types as you want, to allow different layouts and fieldsets (think of something like:
project or similar).
Let's create the new file
layouts/page.html for now:
again you can see it's actually nothing more than simple HTML page (
build/home/index.html) using the rendering engine Handlebars to output the loaded data from the Storyblok API. We're not using the field
contents here since most plugins out there expect it to be a Buffer and would break if it is not (or if it was empty). However, you can change the behavior of the plugin as you like.
The custom plugin loads defines the
layout according to the first component (content-type) in the content. As mentioned by default Storyblok comes with a content-type named "page". You can create new components such as this as you want. By creating a file
layouts/page.html with the above content, you can see how the data you receive from Storyblok actually looks like.
The page component contains a field called
body which is a simple array of other (now with the flag nestable) components. Let's try to iterate through that array called
body and output the containing components. I've removed the
<body> tag from the
page.html contents beflow to reduce the length a little bit.
<div class="root"> of the
layouts/page.html with the one below:
Don't forget to execute
node index.js to see the changes you just made.
Use Handlebars partials to create reusable components
Handlebars ships with the possibility to define "partials", which are reusable code snippets. In Storyblok we call those reusable parts simply "Components", actually everything in Storyblok is a component - some are acting as content-types other are nestable - those are the nestable once. The content we received from the API already has the components (
feature) of which we saw two already above. Now let's switch to the Handlebars partials to allow dynamically add those new components.
index.js you can replace we will have to tell the
metalsmith-layouts plugin that we're not only using
handlebars but also their partials options, which is bascially adding a line to tell the plugin in which folder to look for our partials.
Add the content below to your
and of course we will have to iterate through those components and include them. Handlebars allows us to dynamically include partials by default.
New content for the
We're about to include
grid as those are the components we could see before, to allow Handlebars to include them, we need to create the files in the folder
Create partials/teaser.html and partials/grid.html
Above we can see that all information for one such component is in the
blok property and therefore we are able to access all information of a component like shown below.
Use the fields of the teaser component
We can now see that every field defined in Storyblok for one component can be used as a property in Handlebars partial files. Let's access the
headline field of the
teaser component and output it as an actual headline not just as a JS object above, simply change the content of the
The Grid: Let's move on to nested components
grid Storyblok already comes with, is a component with an array field called
body, similar to the
page component. Currently, its only purpose is to allow a nesting, so let's iterate through that field. As in the
teaser before we will access the
body simply using the
body property passed as context by Handlebars during the include in
You should now be able to see the name of the next nested components
feature. We also need a file for that particular component in the
partials folder as well, otherwise we won't be able to include it.
Nested component "feature"
You can create as many components with as many fields as you like - so you're not limited to those we've just created for you to get started faster. Create more components, nest them and arrange them to beautiful landing pages or enrich existing pages or posts, or create new component as content-type for things like posts, projects and similar.
Let's get back to the
feature component for now: Same as with the
grid we can simply create a new file in
and replace the content of the
grid.html component to actually include the nested
Well done! Lets prepare editing!
Now you should have seen the key concept of Storyblok and our nested components, if you only need flat structures simply create a new component as content-type and add your required fields directly.
You can find a line similar to the one below in your onboarding screen add it to the bottom of your
layouts/page.html - right before the closing
Now we need to update our components, in the draft version of the content from the Storyblok API each component ships with a
_editable property - containing an HTML comment, place this right before every partial we've just created - just like we did in the
Updated content for the
Rebuild on content change
You can skip this - if you don't want to have an instant preview and prefer to run Metalsmith everytime in the console to see your changes - this won't be used in production (because you don't need that instant preview) and is not necessary to use the data added in Storyblok. You can also use our Webhooks to trigger a build pipeline.
Let's add a call to rebuild in the
layouts/page.html, right before the closing
</body> tag again:
You notice that it will call the
/rebuild route, which isn't available using a default Metalsmith setup because there is no server running. To allow us doing that we're about to add a simple Express server that serves the generated static files and allows us to trigger Metalsmith using a simple GET call. So let's install express using NPM.
We're now able to add some more JS to our
index.js. We'll have to require
Add the content below to your
You can see that we're calling a function
build which has another function as parameter. You can wrap your Metalsmith task in a function and instead of writing "Build finished" in the console we simply call that function - so let's update that. You can change the way we did that in this example anytime - feedback in Github or as comment down below appreciated.
Updated content for the Metalsmith task in your
Now we can start our NodeJS app just like before, but now it will start an Express server on http://localhost:4000/:
You can extract that Express part into another
.js file like
preview.js and or define a task that you can start for that preview purpose - to keep that tutorial short I've just extended my current
index.js to showcase the basic idea.
You won't need this in production or wherever you want to publish your pages, this express server only needs to run to allow an instant preview since you don't want to run a command yourself everytime you've changed something in Storyblok. Of course, you could go with a command every time, or once after you've added your changes - but using it like this you will be much faster during content creation, because you see what you change!
Embed your local environment as preview source
The last step in the onboarding, and to finally allow you to edit your components in that visual editor, you can simply enter http://localhost:4000/ in the input at the onboarding screen. It will switch to your local address directly - you can change that later in your space settings of course.
I've added some simple styles to the components to make it look better than plain HTML. Simply include those styles to your project and you should see the screen below if you're working in Storyblok, you can change the appearance of all components as you want - since Storyblok only provides the content you're free to do whatever you want with that content.
Using Storyblok as your CMS with Metalsmith is, as you can see, just loading JSON instead of Markdown files. The visual editor can be plugged-in pretty straightforward and only needs a small amount of additional code for that instant rebuild. I really liked using Metalsmith because the idea of adding more functionality via plugins to allow that kind of flexibility is as flexible as Storyblok itself. I would love to receive and read your feedback and maybe have a look at some of your implementations. As always you can download the whole source code from Github and comment below.