Tutorial

A Brief Tour of the Eleventy Static Site Generator

Published on April 2, 2020
author

Alligator.io

A Brief Tour of the Eleventy Static Site Generator

Static site generators are very ร  la mode right now and with the JAMStack becoming a more-than-viable alternative for many web projects these days, itโ€™s no wonder!

JAMStack or not, static site generators (SSGs) offer some major advantages over more traditional CMSs, and when it comes to SSGs, there are plenty of options to choose from. Jekyll, Hugo, Gatsby, Next.jst, Sapper,โ€ฆ Oh my!

I was recently shopping around to see what would be my best static site generator option for a project of mine called Spiral11. I was first leaning towards Gatsby because it packs some modern goodies like image optimization, but then I looked further at Eleventy and fell in love.

11ty is easy to use, doesnโ€™t get in your way and spits out exactly what you put in, so thereโ€™s no surprise or hidden code bloat. At its most basic, 11ty just compiles files it finds from your working directory into static HTML files. Plus, since itโ€™s written in JavaScript, you gain access to the whole of npm in terms of packages you can use in your project.

Letโ€™s take a tour and see how it worksโ€ฆ

Eleventy Site Setup

Start by installing Eleventy globally on your machine using npm or Yarn:

# with npm
$ npm install -g @11ty/eleventy

# with Yarn
$ yarn global add @11ty/eleventy

Now you can run the eleventy command in any directory that contains valid template files.

For example, say we have a directory called best-site-ever, with an index.md file in it:

index.md
## Chomp Chomp **Chomp** 🐊🐊🐊

You can now run eleventy in that directory, youโ€™ll see that Eleventy creates a _site directory with an index.html file in it that contains what we expect:

_site/index.html
<h2>Chomp Chomp <strong>Chomp</strong> 🐊🐊🐊</h2>

Speaking of template languages, you have plenty of options. You can use Markdown, Nunjucks, Liquid, Mustache,โ€ฆ And you can mix and match, so you can have some files written in Liquid and some in Nunjucks and Eleventy will handle everything just fine.

eleventy command options

The eleventy command also accepts a few useful flags. For example:

  • โ€“watch: Rewrite output files when any of your project files change.
  • โ€“serve: Serve the outputted site via a local web server and watch for changes.
  • โ€“dryrun: Test out the processing without actually outputting any files.
  • โ€“output: Specify a different output location.

That means that very often, when working locally, youโ€™ll want to serve and rebuild on changes with the following command:

$ eleventy --serve

Directory Structure

With Eleventy youโ€™re not only free to choose your favorite template language, but you can also choose your own directory structure.

Say we have another markdown file in our project, but this time itโ€™s in two nested sub-directories:

/one/two/blog-post.md
One day *I will write* my 1st blog post!

Now if we run eleventy, the output in _site will look like this:

๐Ÿ“ _site/
  index.html
  ๐Ÿ“ one/
    ๐Ÿ“ two/
      ๐Ÿ“ blog-post/
        index.html

So youโ€™ll notice that the directory structure is kept, that the file name is used as the slug/URI and that Eleventy creates a directory for each outputted template with an index.html file within it which contains the HTML output.

What if we wanted our files organized in directories that are reflected differently in the final output? Easy, we can just specify the permalink for a particular template inside a front matter section at the top.

/one/two/blog-post.md
---
permalink: '/blog-post/'
---

One day *I will write* my 1st blog post!

Just run eleventy again and youโ€™ll now see that now blog-post appears at the root level in _site. This way, specifying a permalink allows you full flexibility.

Front matter

Speaking of front matter, you can put all sorts of metadata in it, which will then be available to layouts (more on that later). Itโ€™s in the front matter, for example, that youโ€™ll specify things like the title, meta description/excerpt and tags for a post, and most of the keys can be named whatever youโ€™d like.

Hereโ€™s an example to illustrate:

/one/two/blog-post.md
---
title: "My first blog post 😊"
date: 2020-04-02
excerpt: "This post talks about how one day I'll write a 1st post."
permalink: '/blog-post/'
emotion: happy
tags:
  - blog
  - getting-started
---

One day *I will write* my 1st blog post!

Collections

I wonโ€™t go too deep on the topic here, and I invite you to read the docs to learn more, but Eleventy uses the tags you provide in the front matter to populate collections, which can be iterated over in other templates like, say, category pages.

Thereโ€™s also a special collection called all which by default includes every single post. With the all collection, you may end up with something like a sitemap that includes posts/pages you donโ€™t want, so thereโ€™s an easy way to opt out of having a post or page included in collections:

---
eleventyExcludeFromCollections: true
---

Layouts

So far what weโ€™ve done is just output HTML from the markdown files weโ€™ve created. Most of the time though such markdown files should be wrapped in a layout to provide things like the boilerplate HTML, header, navigation bar, sidebar and footer.

By default layout templates should live in the _includes directory.

Letโ€™s create some sample layouts using Nunjucks syntax. One will be the default layout with our HTML boilerplate and the other one will be our blog layout:

_includes/default.njk
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>{{ title }} | My Site</title>
</head>
<body>
   {{ content | safe }}
</body>
</html>
_includes/blog.njk
---
layout: default
---

<h1>{{ title }}</h1>
<div>
  Published on {{ date }}
</div>

<article>
  {{ content | safe }}
</article>

As you can see, a layout can call another layout and our layouts can access the data thatโ€™s in the front matter of our regular template files.

We can use a layout by specifying it in the front matter of any of our content templates:

---
layout: blog.njk
title: "My first blog post 😊"
date: 2020-04-02
excerpt: "This post talks about how one day I'll write a 1st post."
---

One day *I will write* my 1st blog post!

Eleventy Configuration

So far weโ€™ve done everything without even touching a configuration file, and it goes to show the simplicity of using Eleventy. But as your website gains in complexity, youโ€™ll surely want to be able to set some configuration options. You can do that in an .eleventy.js file at the root of your project.

Hereโ€™s a sample configuration file which copies our static assets to the output directory and specifies a different output directory name (public):

.eleventy.js
module.exports = eleventyConfig => {
  // Copy our static assets to the output folder
  eleventyConfig.addPassthroughCopy('css');
  eleventyConfig.addPassthroughCopy('js');
  eleventyConfig.addPassthroughCopy('images');

  // Returning something from the configuration function is optional
  return {
    dir: {
      output: 'public'
    }
  };
};

You can do all sorts of things in your config file like minifying the HTML output, using plugins and configuring shortcodes. Again, I invite you to look at the docs to learn more about what can be configured. But if you start to get overwhelmed at first, just remember that by default Eleventy doesnโ€™t even need a config file and can do most of the heavy lifting without one.

Using a Starter

So far weโ€™ve been creating a site from scratch to see how things work, but often youโ€™ll want to get started with a good base thatโ€™s already configured and/or styled in a way that you like. You can browse through a list of 11ty starters here.

I personally really like the Skeleventy starter, which uses Tailwind CSS for styling and is configured with PurgeCSS to get rid of unused styles in production. If youโ€™re starting a blog, the official Eleventy blog starter would also be a great place to start.

Learning More

โœจโœจ Thatโ€™s it for this brief introduction, but I invite you to learn more by checking out these resources:

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the authors
Default avatar
Alligator.io

author

While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the โ€œreport an issueโ€œ button at the bottom of the tutorial.

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
ย 
Leave a comment
๏ปฟ

This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Become a contributor for community

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

DigitalOcean Documentation

Full documentation for every DigitalOcean product.

Resources for startups and SMBs

The Wave has everything you need to know about building a business, from raising funding to marketing your product.

Get our newsletter

Stay up to date by signing up for DigitalOceanโ€™s Infrastructure as a Newsletter.

New accounts only. By submitting your email you agree to our Privacy Policy

The developer cloud

Scale up as you grow โ€” whether you're running one virtual machine or ten thousand.

Get started for free

Sign up and get $200 in credit for your first 60 days with DigitalOcean.*

*This promotional offer applies to new accounts only.