Eleventy + Nunjucks
Operational defaults for Eleventy v3 and Nunjucks static sites — directory layout, configuration surface, filter inventory, autoescape rules, stability and security checks. Load this skill when authoring templates, editing build config, or reviewing static output before merge or deploy.
Version boundary (verified August 6, 2026): Eleventy 3.1.6 is the stable production baseline. Build Awesome 4.0.0-alpha.10 is a prerelease available through @11ty/eleventy@canary or @awesome.me/buildawesome@alpha. Existing Eleventy commands remain compatible, but v4 changes runtime and template behavior. Keep stable guidance as the default and load references/build-awesome-v4.md before any v4 install or migration.
When this skill applies
Trigger on any of:
- Paths mentioning
.eleventy.js, eleventy.config.{js,mjs,cjs}, .njk, .11tydata.js, .data.js, .11ty.js, .server.js, src/_includes/, or src/_data/
package.json lists @11ty/eleventy or @awesome.me/buildawesome
- Topics: 11ty, Eleventy, Nunjucks, SSG, JAMstack, static site, layout chain, permalink, collection, shortcode, filter, dev server, CSP, JSON-LD in templates
Operating procedure
- Open
package.json, its lockfile, and the active Eleventy config. Identify the installed package/version, module type, Node engine, and the first config filename Eleventy resolves. Checked-in project behavior always wins.
- Choose the track. Use the stable v3 guidance by default. If the project uses a v4 canary, the Build Awesome package, or the generic
.data.* / .server.* suffixes, load build-awesome-v4.md and enforce its version-drift stop condition.
- Open the task-specific reference from the table below. Avoid loading every reference unless the change is large.
The portable core targets Eleventy 3.1.6 + Mozilla Nunjucks 3.2.4. Version-sensitive v4 guidance is isolated in the prerelease reference. For upstream drift, prefer 11ty.dev, 11ty/buildawesome, and the active package metadata; treat dated claims as revalidation markers.
Completion gate
Before calling work complete, verify the project-specific result rather than only applying this skill's defaults:
- The relevant Eleventy build, dev-server smoke check, or project test command passes.
- Site shells that need layout frontmatter, cascade behavior, or layout chaining use Eleventy
layout: and render {{ content | safe }} intentionally; any Nunjucks extends usage is reviewed as a separate inheritance path.
- Every new or changed
| safe, {% autoescape false %}, inline JSON/script data path, and markdown html setting has been reviewed against the trust boundary.
- The task-specific reference checklist was applied when relevant (
review-shipping.md for PR review, security-checklist.md for deploy/security, etc.).
- Rendered output or generated HTML was inspected for the touched page, layout, filter, shortcode, or data cascade.
Mental model (30 seconds)
| Topic |
Common default |
| Eleventy |
Stable v3.1.6 by default; Build Awesome v4 remains prerelease and version-gated |
| Node |
v3 package floor >=18; use a supported LTS (Node 24 preferred, Node 22 supported). v4 prerelease requires >=22.15. |
| Config name |
Search order: .eleventy.js, eleventy.config.js, eleventy.config.mjs, eleventy.config.cjs; the first match wins |
| Engines |
.njk, .md, .html — markdown runs through Nunjucks when markdownTemplateEngine is njk |
| Output dir |
Eleventy default _site/; the opinionated production profile in this skill uses out/ |
| Input |
Eleventy default project root; the production profile often uses src/pages/ or flat src/ |
| Layouts |
Under src/_includes/layouts/; chain via layout: in frontmatter |
| Sections / macros |
src/_includes/sections/…, src/_includes/macros/… |
| Data |
src/_data/*.{json,js} plus directory and template data — see references/data-cascade.md |
| CSS |
Project-selected; the optional profile uses Tailwind v4 CLI + concurrently --kill-others-on-fail |
Non-negotiable rules
Layout chain: prefer layout: and {{ content | safe }} for site shells that require Eleventy layout frontmatter, cascade behavior, or layout chaining. Nunjucks {% extends %} is supported, but frontmatter in the extended parent template is not processed.
Autoescape: treat every | safe as a security boundary. Never mark user, CMS, or external HTML safe without sanitization. dump is for debug in <pre>, not inside executable <script>.
Inline data in <script>: use jsonScript or jsonCompact (see references/filters.md), not raw JSON.stringify or dump | safe.
Flat permalinks + nginx try_files $uri.html: page.url may end in .html. Ship normalize_path (see references/filters.md) for nav active state and canonical URLs.
Passthrough copy: prefer explicit { "src/path": "dest/path" } maps — never copy src/**/* blindly.
CSP: prefer production HTTP headers. If the project uses a CSP <meta>, omit or adapt it during --serve so live reload is allowed. Deliver frame-ancestors via HTTP headers, never <meta>.
Macros and scope: {% import %} does not inherit page scope by default. If macros read page.* / site.*, use with context or pass arguments explicitly (see references/nunjucks-syntax.md).
Markdown-it html: keep html: false unless every markdown author is trusted; changing to true widens XSS risk.
Before adding a new filter: grep the project config for an existing filter with the same role — common 11ty projects duplicate where with incompatible coercion across files.
Data cascade (priority order)
Highest priority wins. When a variable is missing or wrong, trace this official order before considering Eleventy-supplied values such as page, collections, or eleventy.
eleventyComputed
- Template frontmatter
- Template data files
- Directory data files, ascending through parent directories
- Layout frontmatter
eleventyConfig.addGlobalData
- Global data files
Worked examples and pagination: references/data-cascade.md.
Autoescape and the safe filter
Assume foo holds untrusted HTML such as a tag with an event handler.
| State |
Result of {{ foo }} |
autoescape: true (default) |
Escaped — safe for text nodes |
autoescape: true and value piped through the safe filter |
Raw HTML — XSS if foo is untrusted |
autoescape: false |
Raw HTML — treat like global XSS risk |
autoescape: false and escape filter applied |
Escaped again |
Rules of thumb:
- Apply the
safe filter only to trusted, sanitized HTML (or to the output of jsonScript / jsonCompact inside <script> as documented in references/filters.md).
- Avoid
{% autoescape false %} except in tightly reviewed fragments; prefer narrowing with per-value filters.
- Markdown piped through a custom
md filter is only as safe as markdown-it’s html flag — keep html: false for anything not fully trusted.
Full Nunjucks tag and macro rules: references/nunjucks-syntax.md.
Reference files
| File |
Load when |
| references/eleventy-config-api.md |
v2→v3 migration, config skeletons, addFilter / events / collections / server options |
| references/build-awesome-v4.md |
Build Awesome v4 prerelease detection, migration gates, Node/Nunjucks/data changes |
| references/conventions.md |
Directory layout, dir matrix, naming, scripts shape, when to deviate |
| references/data-cascade.md |
Merge order, eleventyComputed, pagination, worked traces |
| references/filters.md |
Canonical filter source, normalize_path, jsonScript, async filters |
| references/nunjucks-syntax.md |
Tags, macros, with context, built-in filters, extends vs 11ty layouts |
| references/build-pipeline.md |
Tailwind v4 + concurrently, lint/format, clean targets |
| references/production-patterns.md |
CSP, View Transitions contract, nginx, after-build hooks, OG/JSON-LD patterns |
| references/review-shipping.md |
PR greps, stability checklist, anti-patterns, page recipes |
| references/security-checklist.md |
Pre-deploy XSS, headers, passthrough, secrets audit |
| references/troubleshooting.md |
404 on --serve, double sections, autoescape surprises, hung builds |
Related skills
Same monorepo (skills4sh): agent-memory (cross-session context), localhost-screenshots (visual regression for static sites).
Ground truth wins: when a project's checked-in .eleventy.js / eleventy.config.js disagrees with this skill, the project wins. Always read the actual config and package.json scripts before applying conventions from here.
Minimal layout reminder
{# Child page #}
---
layout: layouts/page.njk
title: Example
---
<section>Page body</section>
{# layouts/page.njk #}
---
layout: layouts/base.njk
---
<main>{{ content | safe }}</main>
Each parent renders the child’s compiled body through content, then pipes through safe where the child emits HTML (11ty layouts that slot HTML always use safe on content).
1---2name: eleventy-nunjucks3description: Eleventy v3, Build Awesome v4 prerelease, and Nunjucks operating guide for static-site authoring, templates, build pipelines, migrations, and security review. Use when the user asks to "create an 11ty page", "add a Nunjucks filter", "fix my layout chain", "review my .njk template", "set up Eleventy", "migrate to Build Awesome", or "audit my static site"; when `package.json` includes `@11ty/eleventy` or `@awesome.me/buildawesome`; when paths include `.eleventy.js`, `eleventy.config.js`, `.njk`, `.11tydata.js`, `.data.js`, `.11ty.js`, or `.server.js`; or when debugging data cascades, filters, shortcodes, async Nunjucks, autoescape, or static-site security.4license: MIT5---67# Eleventy + Nunjucks89Operational defaults for **Eleventy v3** and **Nunjucks** static sites — directory layout, configuration surface, filter inventory, autoescape rules, stability and security checks. Load this skill when authoring templates, editing build config, or reviewing static output before merge or deploy.1011> **Version boundary (verified August 6, 2026):** Eleventy `3.1.6` is the stable production baseline. Build Awesome `4.0.0-alpha.10` is a prerelease available through `@11ty/eleventy@canary` or `@awesome.me/buildawesome@alpha`. Existing Eleventy commands remain compatible, but v4 changes runtime and template behavior. Keep stable guidance as the default and load [`references/build-awesome-v4.md`](references/build-awesome-v4.md) before any v4 install or migration.1213## When this skill applies1415Trigger on any of:1617- Paths mentioning `.eleventy.js`, `eleventy.config.{js,mjs,cjs}`, `.njk`, `.11tydata.js`, `.data.js`, `.11ty.js`, `.server.js`, `src/_includes/`, or `src/_data/`18- `package.json` lists `@11ty/eleventy` or `@awesome.me/buildawesome`19- Topics: 11ty, Eleventy, Nunjucks, SSG, JAMstack, static site, layout chain, permalink, collection, shortcode, filter, dev server, CSP, JSON-LD in templates2021---2223## Operating procedure24251. **Open `package.json`, its lockfile, and the active Eleventy config.** Identify the installed package/version, module type, Node engine, and the first config filename Eleventy resolves. Checked-in project behavior always wins.262. **Choose the track.** Use the stable v3 guidance by default. If the project uses a v4 canary, the Build Awesome package, or the generic `.data.*` / `.server.*` suffixes, load `build-awesome-v4.md` and enforce its version-drift stop condition.273. **Open the task-specific reference** from the table below. Avoid loading every reference unless the change is large.2829The portable core targets **Eleventy 3.1.6 + Mozilla Nunjucks 3.2.4**. Version-sensitive v4 guidance is isolated in the prerelease reference. For upstream drift, prefer [11ty.dev](https://www.11ty.dev/docs/), [`11ty/buildawesome`](https://github.com/11ty/buildawesome), and the active package metadata; treat dated claims as revalidation markers.3031### Completion gate3233Before calling work complete, verify the project-specific result rather than only applying this skill's defaults:34351. The relevant Eleventy build, dev-server smoke check, or project test command passes.362. Site shells that need layout frontmatter, cascade behavior, or layout chaining use Eleventy `layout:` and render `{{ content | safe }}` intentionally; any Nunjucks `extends` usage is reviewed as a separate inheritance path.373. Every new or changed `| safe`, `{% autoescape false %}`, inline JSON/script data path, and markdown `html` setting has been reviewed against the trust boundary.384. The task-specific reference checklist was applied when relevant (`review-shipping.md` for PR review, `security-checklist.md` for deploy/security, etc.).395. Rendered output or generated HTML was inspected for the touched page, layout, filter, shortcode, or data cascade.4041---4243## Mental model (30 seconds)4445| Topic | Common default |46|---|---|47| Eleventy | Stable v3.1.6 by default; Build Awesome v4 remains prerelease and version-gated |48| Node | v3 package floor `>=18`; use a supported LTS (Node 24 preferred, Node 22 supported). v4 prerelease requires `>=22.15`. |49| Config name | Search order: `.eleventy.js`, `eleventy.config.js`, `eleventy.config.mjs`, `eleventy.config.cjs`; the first match wins |50| Engines | `.njk`, `.md`, `.html` — markdown runs **through** Nunjucks when `markdownTemplateEngine` is `njk` |51| Output dir | Eleventy default `_site/`; the opinionated production profile in this skill uses `out/` |52| Input | Eleventy default project root; the production profile often uses `src/pages/` or flat `src/` |53| Layouts | Under `src/_includes/layouts/`; chain via `layout:` in frontmatter |54| Sections / macros | `src/_includes/sections/…`, `src/_includes/macros/…` |55| Data | `src/_data/*.{json,js}` plus directory and template data — see `references/data-cascade.md` |56| CSS | Project-selected; the optional profile uses Tailwind v4 CLI + `concurrently --kill-others-on-fail` |5758---5960## Non-negotiable rules6162**Layout chain:** prefer `layout:` and `{{ content | safe }}` for site shells that require Eleventy layout frontmatter, cascade behavior, or layout chaining. Nunjucks `{% extends %}` is supported, but frontmatter in the extended parent template is not processed.6364**Autoescape:** treat every `| safe` as a security boundary. Never mark user, CMS, or external HTML safe without sanitization. `dump` is for debug in `<pre>`, not inside executable `<script>`.6566**Inline data in `<script>`:** use `jsonScript` or `jsonCompact` (see `references/filters.md`), not raw `JSON.stringify` or `dump | safe`.6768**Flat permalinks + nginx `try_files $uri.html`:** `page.url` may end in `.html`. Ship `normalize_path` (see `references/filters.md`) for nav active state and canonical URLs.6970**Passthrough copy:** prefer explicit `{ "src/path": "dest/path" }` maps — never copy `src/**/*` blindly.7172**CSP:** prefer production HTTP headers. If the project uses a CSP `<meta>`, omit or adapt it during `--serve` so live reload is allowed. Deliver `frame-ancestors` via HTTP headers, never `<meta>`.7374**Macros and scope:** `{% import %}` does not inherit page scope by default. If macros read `page.*` / `site.*`, use `with context` or pass arguments explicitly (see `references/nunjucks-syntax.md`).7576**Markdown-it `html`:** keep `html: false` unless every markdown author is trusted; changing to `true` widens XSS risk.7778**Before adding a new filter:** grep the project config for an existing filter with the same role — common 11ty projects duplicate `where` with incompatible coercion across files.7980---8182## Data cascade (priority order)8384Highest priority wins. When a variable is missing or wrong, trace this official order before considering Eleventy-supplied values such as `page`, `collections`, or `eleventy`.85861. `eleventyComputed`872. Template frontmatter883. Template data files894. Directory data files, ascending through parent directories905. Layout frontmatter916. `eleventyConfig.addGlobalData`927. Global data files9394Worked examples and pagination: `references/data-cascade.md`.9596---9798## Autoescape and the safe filter99100Assume `foo` holds untrusted HTML such as a tag with an event handler.101102| State | Result of `{{ foo }}` |103|---|---|104| `autoescape: true` (default) | Escaped — safe for text nodes |105| `autoescape: true` and value piped through the **safe** filter | Raw HTML — XSS if `foo` is untrusted |106| `autoescape: false` | Raw HTML — treat like global XSS risk |107| `autoescape: false` and **escape** filter applied | Escaped again |108109Rules of thumb:110111- Apply the `safe` filter only to trusted, sanitized HTML (or to the output of `jsonScript` / `jsonCompact` inside `<script>` as documented in `references/filters.md`).112- Avoid `{% autoescape false %}` except in tightly reviewed fragments; prefer narrowing with per-value filters.113- Markdown piped through a custom `md` filter is only as safe as `markdown-it`’s `html` flag — keep `html: false` for anything not fully trusted.114115Full Nunjucks tag and macro rules: `references/nunjucks-syntax.md`.116117---118119## Reference files120121| File | Load when |122|---|---|123| [references/eleventy-config-api.md](references/eleventy-config-api.md) | v2→v3 migration, config skeletons, `addFilter` / events / collections / server options |124| [references/build-awesome-v4.md](references/build-awesome-v4.md) | Build Awesome v4 prerelease detection, migration gates, Node/Nunjucks/data changes |125| [references/conventions.md](references/conventions.md) | Directory layout, `dir` matrix, naming, scripts shape, when to deviate |126| [references/data-cascade.md](references/data-cascade.md) | Merge order, `eleventyComputed`, pagination, worked traces |127| [references/filters.md](references/filters.md) | Canonical filter source, `normalize_path`, `jsonScript`, async filters |128| [references/nunjucks-syntax.md](references/nunjucks-syntax.md) | Tags, macros, `with context`, built-in filters, `extends` vs 11ty layouts |129| [references/build-pipeline.md](references/build-pipeline.md) | Tailwind v4 + concurrently, lint/format, clean targets |130| [references/production-patterns.md](references/production-patterns.md) | CSP, View Transitions contract, nginx, after-build hooks, OG/JSON-LD patterns |131| [references/review-shipping.md](references/review-shipping.md) | PR greps, stability checklist, anti-patterns, page recipes |132| [references/security-checklist.md](references/security-checklist.md) | Pre-deploy XSS, headers, passthrough, secrets audit |133| [references/troubleshooting.md](references/troubleshooting.md) | 404 on `--serve`, double sections, autoescape surprises, hung builds |134135---136137## Related skills138139**Same monorepo (skills4sh):** `agent-memory` (cross-session context), `localhost-screenshots` (visual regression for static sites).140141**Ground truth wins:** when a project's checked-in `.eleventy.js` / `eleventy.config.js` disagrees with this skill, the project wins. Always read the actual config and `package.json` scripts before applying conventions from here.142143---144145## Minimal layout reminder146147```nunjucks148{# Child page #}149---150layout: layouts/page.njk151title: Example152---153<section>Page body</section>154```155156```nunjucks157{# layouts/page.njk #}158---159layout: layouts/base.njk160---161<main>{{ content | safe }}</main>162```163164Each parent renders the child’s compiled body through `content`, then pipes through `safe` where the child emits HTML (11ty layouts that slot HTML always use `safe` on `content`).