Decoupled websites can be pretty great. The idea is simple: make pre-rendered static webpages ahead of time and put them on a web server. The result is speedy, secure and trendy.

The advantages come from doing the hardest, slowest work at build time rather than request time. In a traditional app, databases and APIs are queried within the interval between the user clicking a link and the new webpage appearing. For a decoupled, static site, all that work happens as part of a build process, which is re-run whenever the site needs to change. This doesn’t work for highly personalised or fast-changing apps, but most of the web is still relatively long-lived content: a great fit for this approach.

Despite this simple promise, lots of tools for making these kinds of websites are surprisingly complicated or opinionated. Gatsby, arguably the most popular framework to embody this JAMstack approach, is highly opinionated and strings together several bleeding-edge technologies, including React and GraphQL.

Gatsby can be enjoyable, but there’s no denying that you need to buy into React to use it, even if your website is simple enough to gain no benefit from it. You shouldn’t need to know React to start making static, pre-rendered websites, and making do with unnecessary front-end JavaScript is a great way to accidentally compromise the accessibility of your website.

So, can we take a minimum viable approach to making decoupled websites? Yes!

Introducing Eleventy

Eleventy is a static site generator that’s getting a lot of positive attention. It has a few features that make it a good fit for us:

  • it’s terse, complicated tasks like programmatically generating pages from data can be done in 2–3 lines of configuration
  • it has an unopinionated data layer. Eleventy calls it a “data cascade” and you can inject whatever data you like into it, from local data files or APIs. If you know how to fetch the data using vanilla JavaScript, you can bring it into Eleventy. No need to learn a whole new query language like GraphQL

Let’s consider an example where we fetch posts from a WordPress API and display it in an Eleventy website. Nowadays, WordPress comes with a built-in API. The URL will look something like

In an Eleventy project’s directory, we can create a folder called /data and add a different file for each data source we want to use. We could add a file called posts.js

and fill it with:

  • const fetch = require("node-fetch") module.exports = async () => {
    const res = await fetch("")
    return await res.json()

That’s it. That’s the whole file. The only dependency is node-fetch, which lets us make API requests with the familiar browser syntax.

Now, in our website templates, we’ll have access to a variable called “posts”, which will hold whatever the file exports. The variable comes from the filename. In this case, it’ll be an array of all the posts on our website. We can use the data in our templates like this:

  • {% for post in posts %}
    <a href="/post/{{post.slug}}">{{ post.title.rendered }}</a>
    {% endfor %}

We can even use Eleventy’s pagination features to programmatically create pages based on the data. When we come to define a template, the config at the top of the file would look something like this:

data: posts
size: 1
alias: post
permalink: "post/{{ post.slug }}/"

This is a very simple example, but we’ve done a great deal with a very small amount of code. There’s no reason we should limit ourselves to one data source either: decoupled websites really come into their own when we need to marshall data from many places.

It would take only a modest extension of what we’ve learned here to show products from a WordPress WooCommerce store, schedules from Airtable and blog posts from Medium, all on one website.

Get in touch

We’re always happy to answer any questions you have about FutureGov and discuss how we can work together.

Contact us