11ty (Eleventy) — Simple JavaScript Static Site Generator
In this tutorial, you will learn about 11ty (eleventy). We cover key concepts, practical examples, and best practices to help you master this topic.
Eleventy is a zero-config JavaScript SSG that supports multiple template languages and produces fast static sites without client-side JS overhead.
What You'll Learn
By the end of this tutorial, you'll understand Eleventy's architecture, how to use its multi-template support, configure data cascading, create collections, and build efficient static sites.
Why It Matters
Eleventy (11ty) offers a refreshingly simple approach to SSG. No client-side framework, no build-time JavaScript in the browser, no complex configuration. Just templates, content, and static output.
Real-World Use
A developer portfolio site uses Eleventy with Nunjucks templates and markdown content. The site builds in under 2 seconds, has zero JavaScript in the critical path, and scores 100/100 on Lighthouse performance.
Eleventy Architecture
graph TD
A[Eleventy Build] --> B[Input Files]
B --> C[.md Markdown]
B --> D[.njk Nunjucks]
B --> E[.liquid Liquid]
B --> F[.hbs Handlebars]
B --> G[.11ty.js JavaScript]
C --> H[Eleventy Engine]
D --> H
E --> H
F --> H
G --> H
H --> I[.eleventy.js config]
H --> J[Data cascade]
J --> K[Global data]
J --> L[Directory data]
J --> M[Frontmatter data]
H --> N[_site/ — Static output]
style H fill:#e67e22,color:#fff
style N fill:#27ae60,color:#fff
Project Setup
// .eleventy.js — Configuration
module.exports = function (eleventyConfig) {
// Passthrough copy (files copied directly to output)
eleventyConfig.addPassthroughCopy('src/css');
eleventyConfig.addPassthroughCopy('src/images');
// Add custom collections
eleventyConfig.addCollection('posts', function (collectionApi) {
return collectionApi.getFilteredByGlob('src/posts/*.md')
.sort((a, b) => b.date - a.date);
});
// Add custom filters
eleventyConfig.addFilter('readableDate', function (date) {
return new Date(date).toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric'
});
});
// Add shortcodes
eleventyConfig.addShortcode('year', function () {
return `${new Date().getFullYear()}`;
});
return {
dir: {
input: 'src',
output: '_site',
includes: '_includes',
layouts: '_layouts',
data: '_data'
}
};
};
Template Examples
{% comment %}
src/_layouts/base.njk — Base layout
{% endcomment %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>{{ title }} — {{ site.name }}</title>
<meta name="description" content="{{ description }}">
<link rel="stylesheet" href="/css/main.css">
</head>
<body>
<header>
<nav>
<a href="/">Home</a>
<a href="/blog">Blog</a>
<a href="/about">About</a>
</nav>
</header>
<main>
{{ content | safe }}
</main>
<footer>
<p>(c) {% year %} {{ site.author }}</p>
</footer>
</body>
</html>
{% comment %}
src/_layouts/post.njk — Post layout
{% endcomment %}
---
layout: base
---
<article>
<h1>{{ title }}</h1>
<time datetime="{{ date | date: '%Y-%m-%d' }}">
{{ date | readableDate }}
</time>
{% if tags %}
<div class="tags">
{% for tag in tags %}
<a href="/tags/{{ tag | slugify }}/">{{ tag }}</a>
{% endfor %}
</div>
{% endif %}
<div class="content">
{{ content | safe }}
</div>
</article>
Markdown Content
---
# src/posts/eleventy-guide.md
title: "Eleventy Guide — Static Sites without the Bloat"
description: "Learn how Eleventy generates fast static sites with zero JavaScript overhead."
date: 2026-06-28
tags: ["eleventy", "ssg", "static-site"]
layout: "post"
---
Eleventy is a simpler static site generator. It transforms templates and content into static HTML files.
## Why Eleventy?
- Zero KB JavaScript by default
- Works with multiple template languages
- Flexible data cascade
- Fast build times
## Template Languages
You can mix template languages in the same project:
{% raw %}
```nunjucks
<!-- Nunjucks template -->
<ul>
{% for item in collections.posts %}
<li><a href="{{ item.url }}">{{ item.data.title }}</a></li>
{% endfor %}
</ul>
{% comment %} Liquid template {% endcomment %}
{% for post in collections.posts %}
<h2>{{ post.data.title }}</h2>
{% endfor %}
{% endraw %}
Data Cascade
Eleventy merges data from multiple sources in order:
- Computed data
- Frontmatter data
- Directory data files
- Global data files (_data/*)
Later sources override earlier ones for the same key.
## Collections and Pagination
```nunjucks
{% comment %}
src/blog.njk — Blog listing with pagination
{% endcomment %}
---
layout: base
title: Blog
pagination:
data: collections.posts
size: 5
alias: posts
permalink: "blog{% if pagination.pageNumber > 0 %}/{{ pagination.pageNumber }}{% endif %}/"
---
<h1>Blog</h1>
<div class="posts">
{% for post in posts %}
<article>
<h2><a href="{{ post.url }}">{{ post.data.title }}</a></h2>
<time>{{ post.date | readableDate }}</time>
<p>{{ post.data.description }}</p>
</article>
{% endfor %}
</div>
<nav class="pagination">
{% if pagination.previousPageHref %}
<a href="{{ pagination.previousPageHref }}">Previous</a>
{% endif %}
{% for pageEntry in pagination.pages %}
<a href="{{ pagination.hrefs[loop.index0] }}"
{% if page.url == pagination.hrefs[loop.index0] %}class="active"{% endif %}>
{{ loop.index }}
</a>
{% endfor %}
{% if pagination.nextPageHref %}
<a href="{{ pagination.nextPageHref }}">Next</a>
{% endif %}
</nav>
Common Mistakes
- Assuming JavaScript templates require client-side JS. 11ty.js templates run at build time. The output is pure HTML. No JavaScript reaches the browser unless you add it.
- Not using the data cascade properly. Conflicting data sources cause unexpected overrides. Understand the cascade order: frontmatter > directory data > global data.
- Forgetting passthrough copies for static assets. CSS, images, and JavaScript files need addPassthroughCopy() in the config. Otherwise they're not included in the output.
- Mixing template syntax in the wrong file type. Different template languages have different syntax. A .njk file expects Nunjucks syntax, not Liquid.
- Not using permalink customization. Default file paths become URLs. Use permalink in frontmatter or config for clean, short URLs.
Practice Questions
- What template languages does Eleventy support?
- How does Eleventy's data cascade determine which data takes priority?
- What is the purpose of addPassthroughCopy in Eleventy config?
- How do you create paginated collections in Eleventy?
- How does Eleventy avoid sending JavaScript to the browser?
Challenge: Build an Eleventy portfolio with 5+ markdown posts, paginated blog listing, tag-based collections, custom Nunjucks filters, and zero client-side JavaScript.
FAQ
Mini Project
Create an Eleventy documentation site with 10 markdown pages, a navigation collection, search-friendly URLs, tag-based category pages, and paginated content listing. Build with zero client-side JavaScript.
What's Next
You've mastered Eleventy. Now explore Astro — a modern static site Builder that combines SSG with islands architecture for dynamic content.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro