Menu
- Why Eleventy?
- Get Started
- Community
- Working with Templates
- Using Data
- Configuration
- Template Languages
- Plugins
- API Services
- Release History
- Advanced
5.81s
12.52s
Image
Low level utility to perform build-time image transformations for both vector and raster images. Output multiple sizes, save multiple formats, cache remote images locally. Uses the sharp image processor.
Features Jump to heading
You maintain full control of the HTML. Use with <picture>
or <img>
or CSS background-image
, or others! Works great to add width
and height
to your images!
- Accepts a variety of image types as input:
jpeg
,png
,webp
,gif
,tiff
,avif
, andsvg
. - Output multiple sizes, keeping the original aspect ratio. Never upscales raster images larger than original size (with the option to upscale SVG input).
- Output multiple formats, supports:
jpeg
,png
,webp
,avif
, andsvg
(requires SVG input)
Even more features Jump to heading
- Easily add
width
andheight
attributes on<img>
elements for proper aspect ratio mapping. - Does not require or rely on file extensions (like
.png
or.jpg
) in URLs or local files, which may be missing or inaccurate. - Save remote images locally to prevent broken image URLs (using
eleventy-fetch
). - Fast: de-duplicates image requests and uses both an in-memory and disk cache.
Installation Jump to heading
Published as @11ty/eleventy-img
on npm.
npm install @11ty/eleventy-img
Usage Jump to heading
This utility returns a Promise and works best in async
friendly functions, filters, shortcodes. It can also work in synchronous environments (Synchronous Usage).
const Image = require("@11ty/eleventy-img");
(async () => {
let url = "https://images.unsplash.com/photo-1608178398319-48f814d0750c";
let stats = await Image(url, {
widths: [300]
});
console.log( stats );
})();
Three things happen here:
- If the first argument is a full URL (not a local file path), we download the remote image and cache it locally using the Fetch plugin. This cached original is then used for the cache duration to avoid a bunch of network requests.
- From that cached full-size original, images are created for each format and width, in this case:
./img/6dfd7ac6-300.webp
and./img/6dfd7ac6-300.jpeg
. - A metadata object is returned, describing those new images.
Expand to see a sample returned metadata object
{
webp: [
{
format: 'webp',
width: 300,
height: 300,
filename: '6dfd7ac6-300.webp',
outputPath: 'img/6dfd7ac6-300.webp',
url: '/img/6dfd7ac6-300.webp',
sourceType: 'image/webp',
srcset: '/img/6dfd7ac6-300.webp 300w',
size: 10184
}
],
jpeg: [
{
format: 'jpeg',
width: 300,
height: 300,
filename: '6dfd7ac6-300.jpeg',
outputPath: 'img/6dfd7ac6-300.jpeg',
url: '/img/6dfd7ac6-300.jpeg',
sourceType: 'image/jpeg',
srcset: '/img/6dfd7ac6-300.jpeg 300w',
size: 15616
}
]
}
Expand to see the full list of options (defaults shown)
const Image = require("@11ty/eleventy-img");
(async () => {
let stats = await Image("…", {
// Array of integers or "auto"
widths: ["auto"],
// Array of file format extensions or "auto"
formats: ["webp", "jpeg"],
// the URLs in markup are prefixed with this
urlPath: "/img/",
// the images are written here
outputDir: "./img/",
// skip raster formats if SVG available
svgShortCircuit: false,
// SVG file sizes can report the compressed size
svgCompressionSize: "",
// allow svg to upscale beyond supplied dimensions?
svgAllowUpscale: true,
// the file name hash length
hashLength: 10,
// Custom file name callback (see below)
filenameFormat: function() {},
// Advanced options passed to eleventy-fetch
cacheOptions: {},
// Advanced options passed to sharp
sharpOptions: {},
sharpWebpOptions: {},
sharpPngOptions: {},
sharpJpegOptions: {},
sharpAvifOptions: {},
// Custom full URLs (use with hosted services, see below)
urlFormat: function() {},
});
})();
Output Widths Jump to heading
Controls how many output images will be created for each image format. Aspect ratio is preserved.
widths: ["auto"]
(default, keep original width)"auto"
.widths: [200]
(output one 200px width)widths: [200, "auto"]
(output 200px and original width)
Output Formats Jump to heading
Use almost any combination of these:
formats: ["webp", "jpeg"]
(default)formats: ["png"]
formats: ["auto"]
(keep original format)"auto"
formats: ["svg"]
(requires SVG input)formats: ["avif"]
Output Locations Jump to heading
URL Path Jump to heading
A path-prefix-esque directory for the <img src>
attribute. e.g. /img/
for <img src="/img/MY_IMAGE.jpeg">
:
urlPath: "/img/"
(default)
Output Directory Jump to heading
Where to write the new images to disk. Project-relative path to the output image directory. Maybe you want to write these to your output directory directly (e.g. ./_site/img/
)?
outputDir: "./img/"
(default)
Options for SVG Jump to heading
Skip raster formats for SVG Jump to heading
If using SVG output (the input format is SVG and svg
is added to your formats
array), we will skip all of the raster formats even if they’re in formats
. This may be useful in a CMS-driven workflow when the input could be vector or raster.
svgShortCircuit: false
(default)svgShortCircuit: true
svgShortCircuit: "size"
Added in Image v3.1.8
Using svgShortCircuit: "size"
means that raster image format entries will only be thrown out if the optimized raster size is larger than the SVG. This helps with large SVG images that compress to smaller raster sizes at smaller widths and will prefer the SVG over raster formats when the SVG file size is smaller.
To use Brotli compressed SVG sizes when making file size comparisons, use the svgCompressionSize: "br"
option Added in Image v3.1.8.
Related:
Allow SVG to upscale Jump to heading
While we do prevent raster images from upscaling (and filter upscaling widths
from the output), you can optionally enable SVG input to upscale to larger sizes when converting to raster format.
svgAllowUpscale: true
(default)svgAllowUpscale: false
Custom Filenames Jump to heading
Don’t like those hash ids? Make your own!
{
// Define custom filenames for generated images
filenameFormat: function (id, src, width, format, options) {
// id: hash of the original image
// src: original image path
// width: current width in px
// format: current file format
// options: set of options passed to the Image call
return `${id}-${width}.${format}`;
}
}
Custom Filename Example: Use the original file slug
const path = require("path");
const Image = require("@11ty/eleventy-img");
await Image("./test/bio-2017.jpg", {
widths: [300],
formats: ["auto"],
filenameFormat: function (id, src, width, format, options) {
const extension = path.extname(src);
const name = path.basename(src, extension);
return `${name}-${width}w.${format}`;
}
});
// Writes: "test/img/bio-2017-300w.jpeg"
Use this in your templates Jump to heading
WebC Jump to heading
Added in Image v3.1.0 Eleventy Image now provides a built-in <eleventy-image>
WebC component for use in your Eleventy project.
Using Eleventy Image in WebC offers all the same great benefits you’re used to from Eleventy Image with an intuitive declarative HTML-only developer experience.
First, add the following to your project’s configuration file:
const eleventyWebcPlugin = require("@11ty/eleventy-plugin-webc");
const { eleventyImagePlugin } = require("@11ty/eleventy-img");
// Only one module.exports per configuration file, please!
module.exports = function(eleventyConfig) {
// WebC
eleventyConfig.addPlugin(eleventyWebcPlugin, {
components: [
// …
// Add as a global WebC component
"npm:@11ty/eleventy-img/*.webc",
]
});
// Image plugin
eleventyConfig.addPlugin(eleventyImagePlugin, {
// Set global default options
formats: ["webp", "jpeg"],
urlPath: "/img/",
// Notably `outputDir` is resolved automatically
// to the project output directory
defaultAttributes: {
loading: "lazy",
decoding: "async"
}
});
};
Now you can use the <eleventy-image>
WebC component in your templates:
<img webc:is="eleventy-image" src="cat.jpg" alt="photo of my tabby cat">
<eleventy-image src="cat.jpg" alt="photo of my tabby cat"></eleventy-image>
<!-- Specify widths: -->
<img webc:is="eleventy-image" width="100, 200" src="cat.jpg" alt="photo of my tabby cat" >
<img webc:is="eleventy-image" :width="[100, 200]" src="cat.jpg" alt="photo of my tabby cat">
<!-- Specify formats (overriding defaults set via the configuration) -->
<img webc:is="eleventy-image" formats="avif, png" src="cat.jpg" alt="photo of my tabby cat">
<img webc:is="eleventy-image" :formats="['avif', 'png']" src="cat.jpg" alt="photo of my tabby cat">
<!-- Change the url path or output dir (overriding defaults set via the configuration above) -->
<img webc:is="eleventy-image" url-path="/some-dir/" output-dir="_site/some-dir/" src="cat.jpg" alt="photo of my tabby cat">
Nunjucks, Liquid, JavaScript (Asynchronous Shortcodes) Jump to heading
The examples below require an async-friendly shortcodes (works in Nunjucks, Liquid, JavaScript, and WebC).
If you want to use Eleventy Image in WebC, take note that it is possible to wire up the method below in WebC. However it is recommended to use the provided <eleventy-image>
WebC component instead.
const Image = require("@11ty/eleventy-img");
// Only one module.exports per configuration file, please!
module.exports = function(eleventyConfig) {
eleventyConfig.addShortcode("image", async function(src, alt, sizes) {
let metadata = await Image(src, {
widths: [300, 600],
formats: ["avif", "jpeg"]
});
let imageAttributes = {
alt,
sizes,
loading: "lazy",
decoding: "async",
};
// You bet we throw an error on a missing alt (alt="" works okay)
return Image.generateHTML(metadata, imageAttributes);
});
};
The addShortcode
method is async-friendly in Eleventy 2.0+. Use addAsyncShortcode
in older versions of Eleventy. You can also add these shortcodes to individual template engines, if you’d like!
Now you can use the image
shortcode in your templates and the appropriate HTML will be generated for you (based on your specified Image options).
{% image "cat.jpg", "photo of my tabby cat" %}
{% image "cat.jpg", "photo of my tabby cat", "(min-width: 30em) 50vw, 100vw" %}
The comma between arguments is optional in Liquid templates.
{% image "cat.jpg", "photo of my tabby cat" %}
{% image "cat.jpg", "photo of my tabby cat", "(min-width: 30em) 50vw, 100vw" %}
The comma between arguments is required in Nunjucks templates.
module.exports = function() {
let img1 = await this.image("cat.jpg", "photo of my tabby cat");
let img2 = await this.image("cat.jpg", "photo of my tabby cat", "(min-width: 30em) 50vw, 100vw");
return `${img1}
${img2}`;
};
This image
shortcode example requires an async-friendly template language and is not available in Handlebars.
Synchronous Shortcode Jump to heading
Expand to see an example of Synchronous usage.
Use Image.statsSync
to get the metadata of a source even if the image generation is not finished yet:
const Image = require("@11ty/eleventy-img");
function imageShortcode(src, cls, alt, sizes, widths) {
let options = {
widths: widths,
formats: ['jpeg'],
};
// generate images, while this is async we don’t wait
Image(src, options);
let imageAttributes = {
class: cls,
alt,
sizes,
loading: "lazy",
decoding: "async",
};
// get metadata even if the images are not fully generated yet
let metadata = Image.statsSync(src, options);
return Image.generateHTML(metadata, imageAttributes);
}
module.exports = function(eleventyConfig) {
eleventyConfig.addNunjucksShortcode("myImage", imageShortcode);
}
Make your own Markup Jump to heading
If you have an advanced use case and don’t want to use our methods to generate the image markup, you can do it yourself!
const Image = require("@11ty/eleventy-img");
// Only one module.exports per configuration file, please!
module.exports = function(eleventyConfig) {
eleventyConfig.addShortcode("image", async function(src, alt) {
if(alt === undefined) {
// You bet we throw an error on missing alt (alt="" works okay)
throw new Error(`Missing \`alt\` on myImage from: ${src}`);
}
let metadata = await Image(src, {
widths: [600],
formats: ["jpeg"]
});
let data = metadata.jpeg[metadata.jpeg.length - 1];
return `<img src="${data.url}" width="${data.width}" height="${data.height}" alt="${alt}" loading="lazy" decoding="async">`;
});
};
const Image = require("@11ty/eleventy-img");
// Only one module.exports per configuration file, please!
module.exports = function(eleventyConfig) {
eleventyConfig.addShortcode("image", async function(src, alt, sizes = "100vw") {
if(alt === undefined) {
// You bet we throw an error on missing alt (alt="" works okay)
throw new Error(`Missing \`alt\` on responsiveimage from: ${src}`);
}
let metadata = await Image(src, {
widths: [300, 600],
formats: ['webp', 'jpeg']
});
let lowsrc = metadata.jpeg[0];
let highsrc = metadata.jpeg[metadata.jpeg.length - 1];
return `<picture>
${Object.values(metadata).map(imageFormat => {
return ` <source type="${imageFormat[0].sourceType}" srcset="${imageFormat.map(entry => entry.srcset).join(", ")}" sizes="${sizes}">`;
}).join("\n")}
<img
src="${lowsrc.url}"
width="${highsrc.width}"
height="${highsrc.height}"
alt="${alt}"
loading="lazy"
decoding="async">
</picture>`;
});
};
Process images as a Custom Template Jump to heading
Use Eleventy’s Custom Template Language feature to process images. This one is not yet available on the docs: do you want to contribute it?
Process images as Data Files Jump to heading
Added in v2.0.0 Nontraditional use case. Eleventy’s Custom Data File Formats features an example of processing Images as data files to feed EXIF data into the Data Cascade. You can use the same feature to add the metadata stats returned from the Image utility directly to the Data Cascade for use in your templates.
- Benefits:
- Processing happens in the data cascade so this works in any template language.
- Images stored in the global data folder will be processed and available to all templates
- Drawbacks:
- You can’t customize the Image options (e.g.
widths
orformats
) from the template code. It is set globally in the config.
- You can’t customize the Image options (e.g.
- Both a benefit and a drawback:
- Beholden to Eleventy’s Data Cascade file name conventions when using with template/directory data files.
Show the code
const Image = require("@11ty/eleventy-img");
const path = require("path");
module.exports = function(eleventyConfig) {
eleventyConfig.addDataExtension("png,jpeg", {
read: false, // Don’t read the input file, argument is now a file path
parser: async imagePath => {
let stats = await Image(imagePath, {
widths: ["auto"],
formats: ["avif", "webp", "jpeg"],
outputDir: path.join(eleventyConfig.dir.output, "img", "built")
});
return {
image: {
stats
}
};
},
});
// This works sync or async: images were processed ahead of time in the data cascade
eleventyConfig.addShortcode("dataCascadeImage", (stats, alt, sizes) => {
let imageAttributes = {
alt,
sizes,
loading: "lazy",
decoding: "async",
};
return Image.generateHTML(stats, imageAttributes);
});
};
With a template my-blog-post.md
and an image file my-blog-post.jpeg
, you could use the above configuration code in your template like this:
{% dataCascadeImage image.stats, "My alt text" %}
Note this also means that folder/folder.jpeg
would be processed for all templates in folder/*
and any images stored in your global _data
would also be populated into the data cascade based on their folder structure.
Advanced Usage Jump to heading
Caching Jump to heading
In-Memory Cache Jump to heading
To prevent duplicate work and improve build performance, repeated calls to the same source image (remote or local) with the same options will return a cached results object. If a request in-progress, the pending promise will be returned. This in-memory cache is maintained across builds in watch/serve mode. If you quit Eleventy, the in-memory cache will be lost.
Images will be regenerated (and the cache ignored) if:
- The source image file size changes (on local image files)
- The cache asset duration expires (for remote images).
You can disable this behavior by using the useCache
boolean option:
useCache: true
(default)useCache: false
to bypass the cache and generate a new image every time.
Examples
Example of in-memory cache reuse (returns the same promise)
const Image = require("@11ty/eleventy-img");
(async () => {
let stats1 = Image("./test/bio-2017.jpg");
let stats2 = Image("./test/bio-2017.jpg");
console.assert(stats1 === stats2, "The same promise");
})();
Example of in-memory cache (returns a new promise with different options)
const Image = require("@11ty/eleventy-img");
(async () => {
let stats1 = Image("./test/bio-2017.jpg");
let stats2 = Image("./test/bio-2017.jpg", { widths: [300] });
console.assert(stats1 !== stats2, "A different promise");
})();
Disk Cache Jump to heading
Added in Image 1.0.0 Eleventy will skip processing files that are unchanged and already exist in the output directory. This requires the built-in hashing algorithm and is not yet supported with custom filenames. More background at Issue #51.
New tip: Re-use and persist the disk cache across Netlify builds
Dry-Run Jump to heading
If you want to try it out and not write any files (useful for testing), use the dryRun
option.
dryRun: false
(default)dryRun: true
Change Global Plugin Concurrency Jump to heading
const Image = require("@11ty/eleventy-img");
Image.concurrency = 4; // default is 10
Advanced control of Sharp image processor Jump to heading
Extra options to pass to the Sharp constructor or the Sharp image format converter for webp, png, jpeg, or avif.
sharpOptions: {}
sharpWebpOptions: {}
sharpPngOptions: {}
sharpJpegOptions: {}
sharpAvifOptions: {}
Output animated GIF or WebP Jump to heading
Added in Image 1.1.0 To process and output animated gif
or webp
images, use the animated
option for the Sharp constructor.
const Image = require("@11ty/eleventy-img");
await Image("./test/bio-2017.jpg", {
formats: ['webp', 'gif'],
sharpOptions: {
animated: true
}
})
Change the default Hash length Jump to heading
Added in v1.0.0 You can customize the length of the default filename format hash by using the hashLength
property.
const Image = require("@11ty/eleventy-img");
await Image("./test/bio-2017.jpg", {
hashLength: 8 // careful, don’t make it _too_ short!
});
Advanced Caching Options for Remote Images Jump to heading
For any full URL first argument to this plugin, the full-size remote image will be downloaded and cached locally. See all relevant eleventy-fetch
options.
{
cacheOptions: {
// if a remote image URL, this is the amount of time before it fetches a fresh copy
duration: "1d",
// project-relative path to the cache directory
directory: ".cache",
removeUrlQueryParams: false,
},
}
When caching remote images, you may want to check the processed image output into your git
(et al) repository to avoid refetches in the future. If remote images are not checked in, they may be refetched every time on your CI server unless you preserve the .cache
folder between builds.
Using a Hosted Image Service Jump to heading
Custom URLs Jump to heading
Want to use a hosted image service instead? You can override the entire URL. Takes precedence over filenameFormat
option. Useful with statsSync
or statsByDimensionsSync
.
When you use this, returned data will not include filename
or outputPath
.
{
urlFormat: function ({
hash, // not included for `statsOnly` images
src,
width,
format,
}) {
return `https://sample-image-service.11ty.dev/${encodeURIComponent(src)}/${width}/${format}/`;
}
}
Stats Only Jump to heading
Added in Image 1.1.0 Skips all image processing to return metadata. Doesn’t read files, doesn’t write files. Use this as an alternative to the separate statsSync*
functions—this will use in-memory cache and de-duplicate requests.
statsOnly: false
(default)statsOnly: true
With remotely hosted images, you may also need to supply the dimensions when using statsOnly
:
{
statsOnly: true,
remoteImageMetadata: {
width,
height,
format, // optional
}
}
From the Community Jump to heading
×49 resources courtesy of 11tybundle.dev curated by Bob Monsour