Building Personal Static Site with Eleventy

I built this site with Eleventy (aka. 11ty), a modern static site generator. Why did I choose 11ty? How to set it up? Is it a good choice? Are there any gotchas? Read on!

As a long time web developer 👩🏼‍💻, I've never used any site generator before, not even WordPress... for the past 10+ years. Only vanilla JavaScript, frameworks & jQuery. The web dev scene is so diverse, right? 😄

(If you just want to see the code, here's the GitHub repo jec-11ty-starter.)

Why 11ty?

Honestly, I thought about rolling my own site from scratch using frameworks (Angular, Preact), because why not? 😆 Then I defeat myself with my own laziness.

Let's just pick a modern, shiny JAM stack or static site generator from the market!

The immediate "framework-ish" choices for me are Scully (Angular), Nuxt (Vue) and Gatsby (React). Nope, if I am going to use frameworks, I want to build from scratch, hah! (What weird logic 😂)

I recalled several people mentioning 11ty. Did a quick check on the official site, getting started and the documentation. Although the documentation looks a bit overwhelming, it seems legit and easy to start. One interesting & convincing discovery for me was that, Chrome Dev Summit 2019, ESLint, and Google V8 blog are built with 11ty! is built with 11ty is built with 11ty

Googling further, I found this step-by-step tutorial by Jon Keeping. I followed through the steps to build a basic blog. The tutorial gave a good overview on what 11ty provides. In short - minimal setup yet customizable through several out-of-the-box features.

As a developer that is familiar with Angular and Vue, the out-of-the-box features are similar to these frameworks' concept of filter, pipe, component, and directive. I feel comfortable with it.

Sorry WordPress, Hugo, Jekyll, and Hexo! I did not really do detailed research and comparison.

Building a personal blog is not a big life decision anyway. The tooling choice is personal. Pick a comfortable one and just go for it. If it fails, just dump it and pick another lah~

That being said, I like the 11ty experience so far!

My 11ty configuration

Although 11ty works with zero config out of the box, that's not what I want. The good news is we can customize that. I will go through a few of my settings.

Setup folder structure

This is the standard folder structure that I want my project to be.

- assets  /* images, etc */
- src /* all source files */
- dist /* all files to be deployed */
- package.json
- .eleventy.js /* 11ty config file */

Out of the box, the 11ty configuration is different. We can customize that in the config file .eleventy.js.

/* .eleventy.js */

module.exports = function (eleventyConfig) {

// set copy asset folder to dist

// set input and output folder
return {
dir: { input: 'src', output: 'dist' },

More configuration options can be found in the documentation.

Pick template languages

11ty supports quite a number of template languages, full list of languages available here. That being said, each language support and documentation varies, though. You can actually mix and use all of the template languages 😆, but let's deduce, pick, and focus.

I decided to go with:

Another common option is Shopify's Liquid. After reading both docs, Nunjucks obviously has more advanced features (e.g. extends and macro). Honestly, I'm not sure if I need these features, but no harm going with that, given both languages' syntax are quite similar. By the way, you may also use EJS, PUG, HAML, Mustache, Handlebars and more.

Let's update our configuration file to reflect that.

/* .eleventy.js */

module.exports = function (eleventyConfig) {

// set copy asset folder to dist

// set input and output folder
return {
dir: { input: 'src', output: 'dist' },
dataTemplateEngine: 'njk',
markdownTemplateEngine: 'njk'

Setting up NPM scripts

Let's take a look at my package.json and see some of the helper scripts I have.

/* .package.json */

"name": "jec-fyi",
"scripts": {
"clean": "npx del dist",
"serve": "ELEVENTY_ENV=dev npx eleventy --serve",
"start": "npm run serve",
"build": "ELEVENTY_ENV=dev npx eleventy",
"build:prod": "ELEVENTY_ENV=prod npx eleventy",
"debug": "DEBUG=* npx eleventy"
"devDependencies": {
"@11ty/eleventy": "^0.10.0",
"del-cli": "^3.0.0"

A very clean start indeed, only two dev dependencies. 😆

Here're the explanation of the setup above:

  1. I always like my project to have a start script, to indicate the project starting point.
  2. Setting up clean script to completely clear the output directory.
  3. To build an 11ty project, the eleventy command is all you need. To run a local server, just add --serve behind it.
  4. In my script, I use ELEVENTY_ENV environment variable to indicate the dev and prod. I'll need this to enable / disable some of my code. It's entirely optional, and you may not need this. (Alternatively, you can use a .env file or set it in your terminal / cmd)

Take note that the eleventy command will not clean your output directory, but update the files within the directory instead. If you want a clean build every time, add the two scripts below:

/* .package.json */

"scripts": {
"prestart": "npm run clean",
"prebuild": "npm run clean",

I did not add the two scripts above because I'll run my build on my CI/CD server (will write about GitHub Actions in a coming post), it would be a clean build every time. It didn't bother me that much in local (sometimes it does, heh).

Extra notes:

  • npx is a built-in command in npm, allowing you to run local packages' commands. More details here
  • npm provides pre and post hook for commands. e.g. in our setup, when you run npm start, it will first run prestart automatically.

Cool! Let's run npm install then npm start now. We are good to go!

Building first page

Let's start building a page to see if this works. Create an index.njk file in the src folder.

Assuming you are running the npm start command, 11ty will watch your src folder for changes.

<!-- index.njk -->
title: Home page
date: 2020-05-10
<html lang="en">
<title>{{ title }}</title>
{% set greeting = 'hello' %}

Yay, {{ greeting | upper }} world!

Now check the dist folder, and you can see index.html file is generated. Open browser and hit localhost:8080. You should see Yay, HELLO world! showing on screen with Home page as the title.

From the example above, you can already see some of the features provided by 11ty and Nunjucks.

  1. .njk file will be rendered into .html file in dist folder.
  2. Nunjucks uses {% %} and {{ }} syntax.
  3. The top part enclosed with --- is called Front Matter. It's a way for us to set and pass data around. (Will explore further in upcoming posts)
  4. upper is something we refer to as filter. There are quite some number of built-in filters, check Nunjucks filters and 11ty fitlers. In the coming post, we will explore how to create our own filter! 😃

IDE Extensions & Settings

I am using VSCode. These are the few VSCode plugins that can help boost your development productivity. After all, who likes to keep typing {% %}, hah.


There is a bug in the Nunjucks by ronnidc extension as of the time of writing. Syntax autocomplete (Emmet) doesn't work, refer to this GitHub issue. There is a workaround, add the below setting in your vscode settings.json file manually (shortcut to open the file: CMD + OPTION + P > Open Settings (JSON)) and restart your IDE.

/* vscode settings.json */

"emmet.includeLanguages": {
"njk": "html",
"nunjucks": "html"

Alrighty, what's next?

That's all for now. We have successfully set up the project. That's how my site was set up as well. In the coming posts, I plan to write about:

Let me know if the above topics interest you. I highly recommend you to try out 11ty yourself! The development experience has been great so far.

Here's the GitHub repo for the code above: jec-11ty-starter. I'll update the repo whenever I write a new post.

Happy coding!

The website itself isn't open source yet, but it will soon! Some housekeeping is needed before that. 😛

Have something to say? Leave me comments on Twitter 👇🏼

Follow my writing:

Hand-crafted with love by Jecelyn Yeen © Licenses | RSS Feed