Eleventy: Global vs Directory Data Override Confusion
0 reputation · 31 Oct 2023, 23:35 UTC
0 reputation · 31 Oct 2023, 23:35 UTC
Eleventy resolves template data through a hierarchical cascade: front matter overrides directory data, which in turn overrides global data from the _data folder. When a global data file and a directory‑specific data file share identical keys, the expected precedence is deterministic, but real projects sometimes observe unexpected overrides, especially in deeply nested structures.
The goal is to confirm whether Eleventy’s documented cascade guarantees that a directory‑level site.json will always supersede _data/site.json for templates within that folder, and whether any edge cases exist when multiple directories contain the same key.
Additionally, I want to understand the performance impact: does Eleventy re‑process a large global data file for every template, or does it cache the data across the build?
Questions:
31775 reputation · 31 Oct 2023, 23:57 UTC
Yes — by design, a directory-level site.json deterministically overrides _data/site.json for templates in that directory subtree. The data cascade merges sources in increasing priority: global data files (_data) are lowest, directory data files come next, and template front matter is highest. If you are seeing the global value win, something outside the simple cascade is almost always responsible.
Confirmed: Eleventy does a deep merge by default. This is the most common source of confusion. If _data/site.json has {"nav": {"a": 1, "b": 2}} and your directory site.json has {"nav": {"b": 99}}, templates in that directory see a: 1, b: 99 — the directory value wins only for the keys it redefines; other nested keys are inherited from global. It can look like "the global file overrode mine" when really the merge combined both.
Likely explanations for apparent priority inversions:
eleventyComputed resolves after the cascade, so a computed value can override directory data and front matter. Check for computed keys matching your colliding key.setDataDeepMerge(false), which switches collisions to shallow replacement and changes what "wins" at nested levels.addDataExtension join the same cascade and can collide with a .json file of the same basename.Create a minimal reproduction before assuming a bug:
# _data/site.json
{"key": "global"}
# posts/site.json
{"key": "dir"}
# posts/page.md (front matter + body)
{{ site.key }}Build and the page should render dir. Then add a nested object with a non-colliding key to the global file and confirm that key still appears in the output — that confirms deep merge is active. Also check your version, because cascade and merge defaults have changed across major releases:
npx @11ty/eleventy --versionReview the data cascade docs for that major version rather than relying on generic advice.
Global data files are loaded once per build and cached in memory — Eleventy does not re-read them from disk for every template. The per-template cost is the cascade merge operating on already-loaded data. The practical impacts of a very large global file are:
To measure rather than guess, run a build with Eleventy's debug output and compare timing with and without the large file:
DEBUG=Eleventy* npx @11ty/eleventyThe priority is deterministic: directory data beats global data, front matter beats both, computed data beats everything. When results look wrong, check for deep-merge inheritance, a computed key, or a version-specific config change before suspecting the cascade itself. If you can share your Eleventy version and whether the colliding key is a nested object, that would pin down which of these applies to your case.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.