intertwingly

It’s just data

Upgrading Eleventy After 5 Years


As I mentioned in my previous post, I've re-retired and am back to working on my own projects. With more time to focus on my personal tools and infrastructure, I decided it was time to catch up on five years of Eleventy improvements.

Five years ago, I migrated this blog to Eleventy v0.12.1. At the time, I wrote about how fast it was and how well it captured the "it's just data" philosophy. This week, with Claude Code's help, I upgraded to v3.1.2. Here's what happened.

The Upgrade Process

Claude Code handled the upgrade from v0.12.1 to v3.1.2 in one step, jumping across three major versions. Here's what it did:

Package Updates

Configuration Changes

Claude identified that Eleventy v3 is stricter about file extensions and added:

eleventyConfig.configureErrorReporting({ allowMissingExtensions: true });

It switched from using template formats to handle static files to using addPassthroughCopy, which is more explicit and performant:

eleventyConfig.addPassthroughCopy("src/css/*.css");
eleventyConfig.addPassthroughCopy("src/images");

Environment-Aware Configuration

Claude made the pathPrefix environment-aware so development doesn't use the /blog/ prefix that production needs:

pathPrefix: process.env.ELEVENTY_ENV === "production" ? "/blog/" : "/"

It also updated the channel data to be environment-aware so the header link points to / in development instead of the full production URL.

The Dev Server

The new Eleventy v3 dev server includes live reload and DOM diffing, replacing the old BrowserSync setup:

{
  "scripts": {
    "dev": "./node_modules/.bin/eleventy --serve --incremental"
  }
}

The Draft Posts Feature

Claude added draft support using config preprocessors:

eleventyConfig.addPreprocessor("drafts", "*", (data, content) => {
  if (data.draft && process.env.ELEVENTY_ENV === "production") {
    return false;
  }
});

Now posts marked with draft: true in frontmatter work locally but won't appear in production builds.

Looking Back

When I first migrated to Eleventy in 2020, I had concerns about the lack of incremental builds. Back then, I noted that "the only option is to rebuild the entire site, and doing so updates every output file." Fast forward to 2025, and guess what? The new dev server supports --incremental mode! This was a pleasant surprise that addressed my original concern.

I also worried about search functionality back then. I started implementing ElasticLunr for client-side search, but apparently never finished it. The search filter code existed, but there was no search UI and the index wasn't being generated. While writing this post, I asked Claude Code to complete the implementation. It added the search input, JavaScript, CSS, and fixed the search filter to work with Eleventy v3's new data structure. The search is now working - you can try it on the index page.

Looking Forward

This upgrade reminded me why I chose Eleventy in the first place. It's still fast, flexible, and respects the complexity budget of a simple blog. The maintainers have clearly been thoughtful about backward compatibility while adding genuinely useful features like preprocessors and incremental builds.

If you're running an old version of Eleventy, I'd encourage you to take the plunge. The ecosystem has matured nicely, and the upgrade path is smoother than you might expect. Five years later, Eleventy still embodies the "it's just data" philosophy I appreciate.