Eleventy: How to Work Around the “git Last Modified” Performance Bottleneck
Published on Feb 26, 2026, filed under development, performance. (Share this post, e.g. on Mastodon or on Bluesky.)
Eleventy supports a special value for the date field, git Last Modified:
---
date: git Last Modified
---This tells Eleventy to use the date of the last Git commit that touched each file as that file’s page.date.
The problem: For every template file it processes, Eleventy spawns a separate git log subprocess. On a site with hundreds of posts, this adds up, which is why the Eleventy docs warn about its use.
Some Numbers
On a site with 1,000 posts, git Last Modified means 1,000 git log subprocesses per build. A single call may take anywhere from ~15 ms (warm Git object cache) to ~300 ms (cold cache, large repo). At the slow end, that’s five minutes of Git overhead.
The variance explains why builds that would otherwise take 10 seconds can start taking several minutes as a site grows: The Git object store gets larger, cache misses get more expensive, and the cost compounds across all the subprocesses.
An Optimization
If you still want to use git Last Modified, you can work around the performance penalty:
Replace the per-file Git calls with a single git log run that builds a filepath-to-date map once, then look up from that map via eleventyComputed:
_data/git.js
import { execSync } from 'child_process';
// Build a file path to `Date` map from one `git log` call
export default function () {
const dates = {};
try {
// `--name-only` doesn’t capture renames—accepted limitation
const log = execSync('git log --format="DATE:%ci" --name-only', {
encoding: 'utf8',
maxBuffer: 50 * 1024 * 1024,
});
let currentDate = null;
for (const line of log.split('\n')) {
if (line.startsWith('DATE:')) {
currentDate = new Date(line.slice(5).trim());
} else if (line.trim() && currentDate) {
// Commits are newest-first; first occurrence of a path = its last modification
if (!dates[line.trim()]) {
dates[line.trim()] = currentDate;
}
}
}
} catch {
// Git unavailable or not a repo
}
return dates;
}You can scope the call to a subdirectory by appending -- posts/ (or wherever your content lives) to the git log command, which keeps the output smaller on large repos. Eleventy exposes this as data.git across the data cascade (named after the file).
_data/eleventyComputed.js
Add a computed date property that looks up each template's input path in the map:
export default {
// Assumes Eleventy project root = Git repo root
date: data => data.git?.[data.page?.inputPath?.replace(/^\.\//, '')],
};For any file not found in the map, this returns undefined, leaving Eleventy's existing date behavior intact.
The Data File
Optionally, replace "date": "git Last Modified" with "date": "Last Modified" (filesystem mtime), here in a directory data file:
{
"date": "Last Modified"
}This makes what’s happening more explicit and serves as a fast, explicit fallback.
A Side Note
If you build Eleventy in CI, e.g. through a GitHub workflow, you may need to fetch the full history:
- uses: actions/checkout@v6
with:
fetch-depth: 0 # Fetches all history for all branches and tagsWithout fetch-depth: 0, git log would otherwise only see the most recent commit, which means every file would look like it was last modified by the latest push.
A Result
With these changes—tried and proven on this very site—, all the individual Git subprocesses become one. On a 1,000-post site, builds that could exceed a minute again start taking seconds, and build time becomes more predictable again.
If you like to use Eleventy’s git Last Modified, that should help you mitigate the performance impact, too. Cheers.
Update
As per Zach Leatherman (the creator of Eleventy), Eleventy 4 is improving Git-related performance, so take note to build this back eventually.
About Me
I’m Jens (long: Jens Oliver Meiert), and I’m an engineering lead, guerrilla philosopher, and indie publisher. I’ve worked as a technical lead and engineering manager for companies you use every day (like Google) and companies you’ve never heard of, I’m an occasional contributor to web standards (like HTML, CSS, WCAG), and I write and review books for O’Reilly and Frontend Dogma.
I love trying things, not only in web development and engineering management, but also with respect to politics and philosophy. Here on meiert.com I talk about some of my experiences and perspectives. (Please share feedback: Interpret charitably, but do be critical.)
