Why I migrated my website from GatsbyJs to Eleventy

Boom, it’s been two years since I wrote the first version of this post, and Plausible tells me that you folks still read this. That you still might be curious about the migration to Eleventy. Let’s get things straight before you read on. The two years were incredible, and I’m still more than happy to use Eleventy for my site and most of my client’s sites. Sometimes just plain HTMLHyperText Markup Language
generated by Eleventy other sites are backed by WordPress or other headless CMSContent Management System
s. I’m on Eleventy 2.0.0-beta.1 and love all the new features, including WebC. I assume that the migration from GatsbyJs to Eleventy is still a thing. So I decided to update this post.

What might be interesting to you before you continue? This post is not a straightforward tutorial on how to build an eleventy site when you migrate from GatsbyJs. If you take some time to get into Eleventy, you won’t need a step-by-step migration tutorial. Instead, I’ll try to explain why I struggled with GatsbyJs and why I chose Eleventy for my website. And I say this today while many folks migrated to other JavaScript-heavy frameworks or site generators. I strongly recommend you no I urge you to look at such powerful tools like Eleventy and Astro instead of jumping on the “blazing” fast JavaScript heavy marketing train to LCPLargest Contentful Paint
failure. You won’t regret it.

But now away with the raised index finger. Here you go with my blog post about the migration from GatsbyJs to 11ty. In this post, I explain why I migrated to Eleventy, my challenges, and how you can avoid them. I read much about Eleventy the last month and its creator Zach Leatherman. I got curious as I saw that it needs zero client-side JavaScript.

Eleventy is a simpler static site generator.

I spend about 2 hours to one day a week trying something new for educational purposes. So I decided to try out Eleventy. I could use it for my clients who only need a static landing page. I ended up migrating my whole website from GatsbyJs to 11ty.


In this post, I show you why I migrated my website from GatsbyJs to Eleventy, my challenges, and how you can avoid them. This post tries to outline Eleventy’s main advantages and disadvantages compared to GatsbyJs.

Table of Contents

  1. What is Eleventy, and how does it work?
  2. What is GatsbyJs, and how does it work?
  3. Why I struggled with GatsbyJs?
  4. My migration from GatsbyJs to Eleventy
  5. Is GatsbyJs a wrong choice?
  6. Next steps
  7. Conclusion

What is Eleventy, and how does it work?

Eleventy is a simple static site generator. That’s it. It uses data and templates to generate HTML files you can upload to your hoster and serve them statically.

That is almost all you need to say about Eleventy. It is fascinatingly simple. Of course, we will dive more in-depth, and there is a lot more to mention, but the paragraph above describes 11ty in its core concept.

You start with Eleventy by choosing your preferred template engine. Probably the easiest is markdown. The following file shows a simple markdown example for eleventy. Eleventy uses your file structure to generate HTMLHyperText Markup Language


# My custom headline

Now let’s run this simple example with: npx @11ty/eleventy. This command will generate a _site directory with an index.html containing the following markup.


<h1>My custom headline</h1>

What if you have more complex content that you can not display with markdown? Eleventy supports multiple template engines you can use.

Template engines

  • HTML *.html
  • Markdown *.md
  • WebC *.webc
  • JavaScript *.11ty.js
  • Liquid *.liquid
  • Nunjucks *.njk
  • Handlebars *.hbs
  • Mustache *.mustache
  • EJS *.ejs
  • Haml *.haml
  • Pug *.pug
  • Custom

Since v1.0.0, besides the built-in template engines, you can add a custom one. Eleventy can process any file extension and compile it to the site’s output folder. One of the easy-to-understand examples is a SASSSyntactically Awesome Style Sheets
compilation from the eleventy docs. The code below shows how to add a custom template engine for SASS files and compile them to CSSCascading Style Sheets

´.elevent.js´ (example from 11ty docs)

// Don’t forget to `npm install sass`!
const sass = require("sass");

module.exports = function(eleventyConfig) {

  // Creates the extension for use
  eleventyConfig.addExtension("scss", {
    outputFileExtension: "css", // optional, default: "html"

    // `compile` is called once per .scss file in the input directory
    compile: async function(inputContent) {
      let result = sass.compileString(inputContent);

      // This is the render function, `data` is the full data cascade
      return async (data) => {
        return result.css;


While I tried out some of the templates, I recognized how fast I could create pages. I went with Nunjucks as it is very flexible. In no time, I created pages and wrapped them with layouts. Layouts are some special templates in Eleventy you can refer to from your pages. A layout for our example above could look like this:


layout: main.njk

# My custom headline


title: My tutorial

<!DOCTYPE html>
<html lang="en">
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Why I migrated my website from GatsbyJs to Eleventy</title>
    ... contents

The layout in the _includes folder wraps the index.md page and outputs all to the _sites folder.

Data Cascade

Working with data in eleventy is very simple. The data is merged from different sources before the engine renders the template. The data-merging is called Data Cascade, and it contains the following parts.

  1. Computed Data
  2. Front Matter Data in a Template
  3. Template Data Files
  4. Directory Data Files (and ascending Parent Directories)
  5. Front Matter Data in Layouts (moved in 1.0)
  6. Configuration API Global Data
  7. Global Data Files


You can use Eleventy without any configuration, but if you want to add some additional features or use a plugin, you can add it to your .eleventy.js file and expand the functionality. Since v2.0.0-beta.1 you can also use eleventy.config.js or eleventy.config.cjs as configuration files.

Filters and Shortcodes

With filters and shortcodes, you can expand the template functionality. For example, you could define a shortcode that renders a button or a filter that formats a date. Another powerful functionality that filters make possible is content translation. I have global data files for each language and can use a filter to translate the content. With shortcodes, I created responsive images before WebC got released.

Regarding production code, I enrich myself with another Eleventy feature: Transformations. With transforms, I can modify any generated output file. I use it to minify my HTML and CSS files.

What is GatsbyJs, and how does it work?

Gatsby is a static site generator as well. It is React-based and uses GraphQL. It is preconfigured and has used many tools you need to implement, usually by yourself, like webpack or a service worker. Gatsby uses the pages directory to create each page for your site. It has a huge community and a wide range of plugins with whom you can expand your website’s functionality.

It builds its data-layer with GraphQL and transforms your JSON, markdown files, or external API data to nodes you can use and query in your templates. You can start very fast with your first GatsbyJs site with the Quick Start on the GatsbyJs documentation site.

Why I struggled with GatsbyJs?

GatsbyJs is a JavaScript-heavy framework, and in my later experience, Gatsby or React is often used because the developer experience is valued higher than the final user experience. My site was slow even while I used “blazing-fast” GatsbyJs. Of course, some issues weren’t related to Gatsby, but Gatsby was part of the problem. I spend hours over hours optimizing my site. Even though I know what I am doing, it was pretty challenging and took much longer than developing my website from scratch.

Gatsby needs much client-side JavaScript to work. If you work on web performance, you know it’s good to reduce client-side JavaScript to a minimum. Especially if you don’t need JavaScript, if you are not into that topic, check out how the browser parses JavaScript in my blog post about JavaScript high performance and especially my series about the Business Value of Speed where I go through the sequence of steps the browser needs to process before it can paint a pixel.

It might also be interesting:

I wanted to reduce the amount of JavaScript and was quite successful with a plugin called gatsby-plugin-preact. It replaces React with Preact and cut the bundle file size of my framework-[hash].js from ~40kB to 8.6kB. That was great, but at the same time, it was a bit strange to erase the developing framework React at build time.

Nevertheless, I still struggled with all of my components. I did some research and found the plugin gatsby-plugin-no-javascript. It removes JavaScrpt at build time. I looked at the file size and was happy for a moment. Just for a moment because I knew it would break my website. I’ll tell you the truth. I couldn’t reduce the amount of JS to the proper file size. While I write this post, I still have 81.8kB of JavaScript for the main app rendering my primarily “static site”.

Not to mention that I use lazy loading like a freak, so additionally, I have 20 requests to JS files that are loaded later between 2kB and 25kB. You could say let’s reduce the JavaScript of our components. I did this for hours. I deleted code, changed libraries, and I removed functionality.

My migration from GatsbyJs to Eleventy

Here comes Eleventy. I now migrated all my content to 11ty and implemented all interactions with just a bit of JavaScript. I now have one main.js of 2.2kB and two bundles that are lazy-loaded with webpack on the pages that need them. One with 941 B and one with 678 B. The significant point is that I didn’t remove any functionality.

The following table shows you the size of all MIME Types before and after the migration.


MIME TypeBytesUncompressed


MIME TypeBytesUncompressed

So, where did I start? index.js. Nope. As my home page is an overview page, I started with my last blog post. I write my blog posts in markdown and use frontmatter in the file’s head for additional information. This blog post you are currently reading looks like this:

  - 'javascript'
  - 'webperformance'
layout: layouts/post.njk
article: true
title: 'Why I migrated my website from GatsbyJs to Eleventy'
date: '2020-08-05'
author: Marc Radziwill
    follow: 'index,follow',
      'Why I migrated my website from GatsbyJs to Eleventy - Marc
      'Eleventy is the new runner up in the JAMstack community. Read why I
      struggled with GatsbyJs and why I choose Eleventy for my website >>',
categories: ['javascript', 'webperformance', 'business']
  - webperformance
  - frameworks
    src: ./src/blog/business-value-of-speed-part-two-metrics-and-mapping-of-business-values/images/business-value-of-speed-part-two-metrics.jpg,
    alt: 'alt text',
    title: 'image title',
readingDependencies: You must be at least a level beginner to make this happen
readerLevel: beginner
published: true
isTechArticle: true

These files have quite some information in them. In Gatsby, I needed to create NodeFields to query them. So for every entry, I did:

  name: 'title',
  value: node.frontmatter.title,

In Eleventy, and due to their data cascade, these values are already accessible in the template file. For example, if you loop through a collection of pages with in the data Object like this:

{%- for page in collections.all -%}
  <h2>{{ page.data.title }}</h2>
{%- endfor -%}

I was convinced and decided to migrate my entire content. After one hour, I migrated all my post’s content without the images. That was what I was looking for.

I continued by defining a layout for my base pages and my blog pages to serve different CSS and JS files. I built the main components and Nunjunk partials like the header and the footer, and I created some shortcode components like a button.

One week later, I was ready for my first test with my site running completely on Eleventy. I was fast. Faster than I ever thought, I could be re-writing my whole website. But I also was struggling with some parts.


Hello and welcome! Don't miss out on crucial web performance insights, plus the latest on accessibility and sustainability, delivered directly to your inbox. Elevate your craft in creating fast, user-friendly, and eco-conscious websites. Sign up now to access seasoned expertise and the freshest news!

Words about images

Images were my biggest problem. At the time of migration, my site contained many header images I wanted to render in a picture-tag with the correct sizes and formats so that the browser could decide which image to download. Gatsby has a smooth plugin that handles images, and for Eleventy, I chose the plugin eleventy-img and wrote a Nunjunk async shortcode to render the images before the blog content starts.

Async image shortcode

{% resImage theme.logo.src, "alt text", theme.logo.options, "title text" %}

That worked well for all Nunjunk templates, but I could not use them in my 11ty blog posts as they are based on markdown. For all markdown images below the fold, I implemented a different approach.

First, I encounter all img-tags with an eleventy transformer for all HTML files in my _site folder. I use the npm package jsdom to make the content of each page selectable and query all images with the following:

document.querySelectorAll('.post-content :not(picture) img[src]:not([srcset]):not([src$=".svg"])'

I loop through them and create a picture-tag with my resImage async shortcode. The idea for this and some parts of the code is from Nicolas Hoizey - Eleventy Image Responsiver. After all, images are converted to a picture-tag with the correct source path, I write them back to the page’s content.

Additionally, I wanted to have my image files located where the blog post file is. This structure makes it easier for me to maintain them and cross-post them to dev.to.

So my file structure looks like this:

│ └───images
│          image-1.png
│          image-2.png
│  index.md

To make this file structure work, I had to change the path of the images depending on their original location. The transformer I wrote resolves the output path depending on the input path. I adjust the output path differently for images located in/assets/images/**for blog posts.

Is Gatsby a wrong choice?

In a previous version of this article, I wrote this paragraph:

No, not at all. Gatsby was the wrong choice for me, having my requirements and wanting to have a site without much JavaScript, but Gatsby provides some great features. If you are struggling with JavaScript, you should consider migrating to Eleventy. Eleventy is fast and flexible not only while you are developing but also during runtime.

As of today, I changed my opinion. You may ask me, where do I need GatsbyJs? Is GatsbyJs the wrong choice for me and similar websites? Yes, it is the wrong choice. Static sites don’t need GatsbyJs or similar site generators that rely on JavaScript in the frontend. Even if you have some interactive components on your website, you don’t need GatsbyJs. They have a use cases site, but I doubt that you really need JavaScript to render a Technical Documentation, a Company Blog or a Custom Landing Page. Suppose you need components that need client-side rendering due to architectural reasons. It would be best if you consider using web components. IMHO, they are the future of the dynamic and JavaScript-heavy web, and in their simplest version, all major browsers support them.

Next steps

I migrated my website in one week from Gatsby to Eleventy. So for the moment, I am delighted and satisfied. For sure, there are still some open tasks that I will work on in the next weeks. If you are thinking about migration, I recommend you try out Eleventy. It is fun, and you will love it! ♥️


In this post, I tried to show you why I migrated my website from GatsbyJs to Eleventy and why I think this is important for a fast site.

Cheers Marc


2021-04-22: updated the “Is Gatsby a wrong choice” section, added Custom Global Data
2023-02-01: updated the introduction and the template engine section, updated the “Is Gatsby a wrong choice” section

Likes 14
Like from Eleventy
Like from Kamil Havlicek
Like from hisophiabrandt
Like from edgemesh
Like from kooperative web
Like from 4formedia
Like from Sabine Köhler
Like from ⚜️Brigita J.⚜️
Like from Bi M.
Like from Daily Allgäu
Like from Svenja Weber
Like from Alex
Like from iq.code
Like from Work With Me Call Center™
Reposts 2
Like from Eleventy
Like from Giamma