Diagnosing Slow Eleventy Builds Caused by Large Data Files and Excessive Includes
A step‑by‑step guide to spot whether big _data files or many template includes are slowing your Eleventy site, with checks, fixes, and when to escalate.
01 May 2026, 03:43 UTC

Recognizable Condition
Your Eleventy site builds noticeably slower than expected—for example, the eleventy --timings output shows a Data phase that takes several seconds even though the site has fewer than 500 pages. You may also see repeated console lines indicating that the same large JSON or YAML file in _data is being read on every build, or notice many {% include %} statements scattered across templates.
Cause/Diagnostic Table
| Symptom | Likely Cause | What to Look For |
|---|---|---|
| Data phase > 2 s (or > 30 % of total build time) | Large _data files being fully loaded each build | File size of individual _data JSON/YAML > 500 KB; timings show repeated reads of the same file |
| Template phase > 2 s with many small includes | Excessive file‑system lookups from deep or duplicated includes | High count of {% include %} per template; includes referencing many small files or nested directories |
Incremental builds (--incremental) still reload all data |
Watch targets or cache keys not detecting unchanged data | Eleventy version < 2.0 or missing setDataDeepMerge(true); custom watch targets not covering _data |
Ordered Checks
-
Run the build with timings – in your project root, execute:
Record the Data and Template phase times. No special permissions are needed beyond read access to the project.npx @11ty/eleventy --timings -
Isolate the _data impact – temporarily rename the data directory and rebuild:
If the Data phase drops dramatically (e.g., from 4 s to < 0.5 s), the data files are the primary bottleneck.mv _data _data.backup npx @11ty/eleventy --timings mv _data.backup _data -
Quantify include usage – from the project root, run:
This returns the total number of include statements. A high count (hundreds) across few templates suggests excessive lookups.grep -r "{% include" . --include="*.njk" --include="*.html" | wc -l -
Check include depth – list the deepest include chains:
Look for includes that reference files deep in nested folders or that are reused many times.grep -r "{% include" . --include="*.njk" | awk -F'"' '{print $2}' | sort | uniq -c | sort -nr | head -10 -
Verify incremental behavior – with
_dataunchanged, run two consecutive builds:
If the second build still shows a full Data phase, the watch/cache mechanism is not detecting unchanged data.npx @11ty/eleventy --incremental --timings npx @11ty/eleventy --incremental --timings
Fixes Tied to Findings
Large _data files
- Split data into smaller, purpose‑specific files – move large arrays or objects into separate JSON/YAML files under
_dataand only include the needed file in a template via Eleventy’s data cascade (e.g., create_data/products.jsonand_data/site.yml). - Enable deep merge for Eleventy < 2.0 – if you are on Eleventy 1.x, add to
.eleventy.js:
This prevents Eleventy from re‑merging the entire data set on each build when only a subset changed.module.exports = function(eleventyConfig) { eleventyConfig.setDataDeepMerge(true); return {}; }; - Load large data lazily in JavaScript templates – for templates that need the big payload, switch to a JavaScript template (
.mdor.njkwithdatafront matter) andrequirethe file inside the template:
This way the file is read only when that specific template is rendered.const bigData = require('../_data/big.json'); return `- ${bigData.items.map(i => `
- ${i.name} `).join('')}
Excessive or deep includes
- Consolidate repeated snippets – create a single
_includes/macros.njkfile that exports multiple macros or holds common markup, then replace many small includes with one call:{% from "macros.njk" import card, button %} {{ card(item) }} {{ button('Submit') }} - Use layout chaining instead of deep include trees – define a base layout and extend it, reducing the need for nested includes:
--- layout: base.njk --- {% set title = "Page" %} {% set body %} {% endset %} - Limit include depth – refactor any include that itself includes another file more than two levels deep; flatten the hierarchy or move the shared content to a macro.
Escalation Criteria
If after applying the above fixes the build time remains above your acceptable baseline (e.g., Data phase > 1 s for a sub‑500‑page site), consider the following steps:
- Upgrade to Eleventy 2.0 or later, which introduces an improved data cache and better handling of large data files.
- Review custom watch targets in
.eleventy.js; ensureaddWatchTargetonly includes files that actually change. - As a last resort, evaluate whether a different static‑site generator with incremental build capabilities (e.g., Astro, Hugo) better fits your content size.
Always verify changes by running eleventy --timings before and after each adjustment, and keep a backup of the original _data directory in case a rollback is needed.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.