Zach’s ugly mug (his face) Zach Leat­herman

One weird trick to reduce Eleventy Image Build Times by 60%

941 00 August 01, 2025

This web site does a fair bit of build-time Image Optimization using the HTML Transform method provided by the Eleventy Image plugin. I took a bit of a set-it-and-forget-it approach with the plugin on this site, mostly for my own convenience. My usage looked something like this:

import { eleventyImageTransformPlugin } from "@11ty/eleventy-img";

export default function(eleventyConfig) {
	eleventyConfig.addPlugin(eleventyImageTransformPlugin, {
		failOnError: false,
		formats: ["svg", "avif", "jpeg"],
		svgShortCircuit: true,
	});
};

Eleventy Image includes a fair number of caches and performance optimizations to make this default behavior pretty fast.

  • It uses a memory cache to de-duplicate multiple requests to optimize the same input image.
  • It uses an on-request image processing engine to avoid processing images during local development.
  • It uses a hash for output file name and checks the target file location to avoid reprocessing images.

The biggest drawback with the third method is that when you’re building on a deployment server, these environments start with an empty output folder (and thus, an empty disk cache). What can we do to re-use the disk cache and avoid reprocessing unchanged images on each new deploy?

With just a few lines of configuration code to create an intermediate output folder in a location that is persisted between builds (.cache), I was able to drop my site’s build time from an embarrasing 9:40 down to a respectable 3:56 (trophy icon) (for throughput info, the output folder has 7,779 files weighing 492.7 MB).

I think this approach is very reusable and we’ll likely bundle it into a future version of Eleventy Image. Until then, you can use it yourself by adding the following lines of configuration:

+import path from "node:path";
+import fs from "node:fs";
 import { eleventyImageTransformPlugin } from "@11ty/eleventy-img";

 export default function(eleventyConfig) {
 	eleventyConfig.addPlugin(eleventyImageTransformPlugin, {
+		urlPath: "/img/built/",
+		outputDir: ".cache/@11ty/img/",
 		failOnError: false,
 		formats: ["svg", "avif", "jpeg"],
 		svgShortCircuit: true,
 	});

+	eleventyConfig.on("eleventy.after", () => {
+		fs.cpSync(".cache/@11ty/img/", path.join(eleventyConfig.directories.output, "/img/built/"), {
+			recursive: true
+		});
+	});
 };

You could improve the above example by restricting the copy step using the process.env.ELEVENTY_RUN_MODE environment variable.

You may also need to persist .cache on your web host. This behavior is provided for-free if you’re using Vercel or Cloudflare Pages.

Subscribe to github.com/11ty/eleventy-img/issues/285 for future updates.


< Older
Never write your own Date Parsing Library
Newer >
A note from my late Grandmother about Eleventy

Zach Leatherman IndieWeb Avatar for https://zachleat.com/is a builder for the web at Font Awesome and the creator of Build Awesome (née IndieWeb Avatar for https://www.11ty.devEleventy/11ty), an award-winning open source website generator. He measures website performance with speedlify and at one point became too fixated on web fonts. He has given 89 talks in nine different countries at events like Beyond Tellerrand, Smashing Conference, Jamstack Conf, CSSConf, and The White House. Formerly part of CloudCannon, Netlify, Filament Group, NEJS CONF, and NebraskaJS. Learn more about Zach »

Shamelessly plug your related post

These are webmentions via the IndieWeb and webmention.io.

Sharing on social media?

This is what will show up when you share this post on Social Media:

How did you do this? I automated my Open Graph images. (Peer behind the curtain at the test page)