Harnessing Eleventy's JavaScript Data Files: Build‑Time Flexibility vs. Performance
Eleventy lets you drop JavaScript into _data to compute site data on build. This blog shows how that works, a practical example, and the trade‑offs you should consider before adding heavy logic to your data files.
03 Jun 2026, 06:12 UTC

Why Eleventy's JavaScript Data Files Matter
When you build a static site, the data that feeds your templates is usually static JSON or YAML. Eleventy extends this model by allowing .js files in the _data directory. Because a .js file is a normal Node module, you can import other modules, read files, call APIs, or perform any JavaScript you need. The result of the module.exports is merged into Eleventy's global data cascade, making it available everywhere in your templates.
This flexibility is especially useful when you need derived data—e.g., a list of authors with computed URLs, a cache of external API responses, or a build‑time transformation of a CSV file. However, the same power can also slow your build or expose secrets if misused.
How It Works Under the Hood
During a build, Eleventy walks the _data folder (and any nested subfolders). For each file it does the following:
- Requires the module using Node’s
require(). - Expects the exported value to be an object, a function, or a promise.
- If it’s a function, Eleventy calls it with the current
eleventyConfigand thedataobject that has already been merged. - If it returns a promise, Eleventy waits for it to resolve.
- The resolved value is merged into the global data cascade, just like any static JSON file.
Because the module runs in the same environment as your build script, you have full access to Node APIs, third‑party libraries, and environment variables.
Concrete Example: A Dynamic Author List
Suppose you want every page to have a list of authors with friendly URLs. You can create _data/authors.js like this:
// _data/authors.js
module.exports = () => {
// In a real project you might read a JSON file or query a CMS.
return [
{ name: 'Ada Lovelace', slug: 'ada' },
{ name: 'Grace Hopper', slug: 'grace' }
];
};
Eleventy will execute this function during the build and merge the array into the global data. Inside any template you can now loop over collections.authors (Eleventy automatically creates a collection for each top‑level data key) or reference authors directly if you prefer:
{# _templates/_includes/authors.njk #}
{% for author in collections.authors %}
- {{ author.name }}
{% endfor %}
When you run npx eleventy --serve and open /authors.html, you should see the list rendered. Use npx eleventy --debug to confirm that Eleventy required _data/authors.js during the build.
Performance & Security Trade‑offs
Because the entire .js file runs on every build, any expensive I/O or heavy computation can noticeably increase build time. For example, fetching a large dataset from a remote API inside _data.js will block the build until the request completes. If you anticipate frequent rebuilds (e.g., during local development), consider pre‑fetching the data into a static JSON file and importing that JSON instead.
Another caution is security: a _data.js file is executed on every build, and its contents may end up bundled into the generated site if you use a build step that copies the file. Never commit API keys, passwords, or other secrets to a public repository. Prefer environment variables and keep the _data.js file in a private repo or use eleventyConfig.addPassthroughCopy() to exclude sensitive files from the output.
Practical Checklist Before Adding JS Data Files
| Consideration | Action |
|---|---|
| Build Speed | Benchmark with time npx eleventy. If the file adds >1 s, pre‑compute. |
| Data Size | Large arrays or objects can bloat the output. Slice or paginate if necessary. |
| Secrets | Do not store keys; use process.env and .env files. |
| Caching | Wrap external calls in a cache layer (e.g., node-cache) to avoid repeated requests. |
Actionable Takeaway
Use Eleventy's .js data files when you need dynamic data that can’t be represented statically, such as API responses or computed values. Keep the logic lightweight, cache external calls, and avoid secrets. If your data set grows or your build starts lagging, shift the heavy lifting to a pre‑build script that outputs a static JSON file and let Eleventy consume that instead.
Try it out: create a _data/quotes.js that fetches a random quote from an API, render it on a page, then measure the build time. This hands‑on experiment will give you a clear sense of the performance impact and help you decide whether to keep the logic in a data file or move it out.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.