Passthrough File Copy
On this page
If we want to copy additional files that are not Eleventy templates, we use a feature called Passthrough File Copy to tell Eleventy to copy things to our output folder for us.
Configuration API Method
Use a configuration API method to specify files or directories for Eleventy to copy to the output folder.
export default function (eleventyConfig) {
// Output directory: _site
// Copy `img/` to `_site/img/`
eleventyConfig.addPassthroughCopy("img");
// Copy `css/fonts/` to `_site/css/fonts/`
// Keeps the same directory structure.
eleventyConfig.addPassthroughCopy("css/fonts");
// Copy any .jpg file to `_site`, via Glob pattern
// Keeps the same directory structure.
eleventyConfig.addPassthroughCopy("**/*.jpg");
};
module.exports = function (eleventyConfig) {
// Output directory: _site
// Copy `img/` to `_site/img/`
eleventyConfig.addPassthroughCopy("img");
// Copy `css/fonts/` to `_site/css/fonts/`
// Keeps the same directory structure.
eleventyConfig.addPassthroughCopy("css/fonts");
// Copy any .jpg file to `_site`, via Glob pattern
// Keeps the same directory structure.
eleventyConfig.addPassthroughCopy("**/*.jpg");
};
If you do not want to maintain the same directory structure, change the output directory.
How Input Directories are Handled
As stated above, passthrough file copy paths are relative to the project root and not the input directory. Because of this, if the passthrough file copy path is inside of your input directory, the input directory will be stripped from the output path.
For example:
input
directory issrc
output
directory is_site
.
If we copy src/img
using passthrough file copy, it will copy to _site/img
.
export default function (eleventyConfig) {
// Input directory: src
// Output directory: _site
// The following copies to `_site/img`
eleventyConfig.addPassthroughCopy("src/img");
};
module.exports = function (eleventyConfig) {
// Input directory: src
// Output directory: _site
// The following copies to `_site/img`
eleventyConfig.addPassthroughCopy("src/img");
};
Using Globs
In this example, we copy all jpg
image files to the output folder, maintaining their directory structure. If you do not want to maintain the same directory structure, change the output directory.
Note that this method is slower than non-glob methods, as it searches the entire directory structure and copies each file individually.
export default function (eleventyConfig) {
// Find and copy any `jpg` files, maintaining directory structure.
eleventyConfig.addPassthroughCopy("**/*.jpg");
};
module.exports = function (eleventyConfig) {
// Find and copy any `jpg` files, maintaining directory structure.
eleventyConfig.addPassthroughCopy("**/*.jpg");
};
With an output directory of _site
:
img/avatar.jpg
will copy to_site/img/avatar.jpg
subdir/img/avatar.jpg
will copy to_site/subdir/img/avatar.jpg
Copy a file alongside a Template Added in v3.1.0
Use the HTML Relative Passthrough Copy Mode to copy files referenced in any template syntax that outputs to .html
. Issue #3573
export default function(eleventyConfig) {
// Relative to the project root directory
eleventyConfig.addPassthroughCopy("content/**/*.mp4", {
mode: "html-relative"
});
}
module.exports = function(eleventyConfig) {
// Relative to the project root directory
eleventyConfig.addPassthroughCopy("content/**/*.mp4", {
mode: "html-relative"
});
}
Full options list
export default async function(eleventyConfig) {
// glob or Array of globs to match for copy
eleventyConfig.addPassthroughCopy("**/*.png", {
mode: "html-relative",
paths: [], // additional fallback directories to look for source files
failOnError: true, // throw an error when a path matches (via `match`) but not found on file system
copyOptions: { dot: false }, // `recursive-copy` copy options
});
}
module.exports = async function(eleventyConfig) {
// glob or Array of globs to match for copy
eleventyConfig.addPassthroughCopy("**/*.png", {
mode: "html-relative",
paths: [], // additional fallback directories to look for source files
failOnError: true, // throw an error when a path matches (via `match`) but not found on file system
copyOptions: { dot: false }, // `recursive-copy` copy options
});
}
Any references that match this glob in a[href]
, video[src]
, audio[src]
, source
, img[src]
, [srcset]
and a whole bunch more (via posthtml-urls) will colocate the file alongside your template (reusing any permalink
values correctly). If a passthrough copy file is not found to be referenced in an HTML output file, it will not be copied to the output directory.
As a few example paths, with an output directory of _site
:
<video src="video.mp4">
ontemplate.njk
will copy to_site/template/video.mp4
alongside_site/template/index.html
.<video src="assets/video.mp4">
ondir/template.njk
will copy to_site/dir/template/assets/video.mp4
alongside_site/dir/template/index.html
- dot files are filtered out by default (override by changing the
copyOptions.dot: false
default, consult the Full options list above) - Referenced files must be inside the project’s root directory.
- Absolute paths are ignored.
Change the Output Directory
Instead of a string, pass in an object of the following structure: { "input": "target" }
.
export default function (eleventyConfig) {
// Input directory: src
// Output directory: _site
// Copy `img/` to `_site/subfolder/img`
eleventyConfig.addPassthroughCopy({ img: "subfolder/img" });
// Copy `src/img/` to `_site/subfolder/img`
eleventyConfig.addPassthroughCopy({ "src/img": "subfolder/img" });
// Copy `random-folder/img/` to `_site/subfolder/img`
eleventyConfig.addPassthroughCopy({ "random-folder/img": "subfolder/img" });
};
module.exports = function (eleventyConfig) {
// Input directory: src
// Output directory: _site
// Copy `img/` to `_site/subfolder/img`
eleventyConfig.addPassthroughCopy({ img: "subfolder/img" });
// Copy `src/img/` to `_site/subfolder/img`
eleventyConfig.addPassthroughCopy({ "src/img": "subfolder/img" });
// Copy `random-folder/img/` to `_site/subfolder/img`
eleventyConfig.addPassthroughCopy({ "random-folder/img": "subfolder/img" });
};
Using Globs and Output Directories
Note that this method is slower than non-glob methods, as it is searching the entire directory structure and copies each file in Eleventy individually.
export default function (eleventyConfig) {
// Output directory: _site
// Find and copy any `jpg` files in any folder to _site/img
// Does not keep the same directory structure.
eleventyConfig.addPassthroughCopy({ "**/*.jpg": "img" });
};
module.exports = function (eleventyConfig) {
// Output directory: _site
// Find and copy any `jpg` files in any folder to _site/img
// Does not keep the same directory structure.
eleventyConfig.addPassthroughCopy({ "**/*.jpg": "img" });
};
With an output directory of _site
:
img/avatar.jpg
would copy to_site/img/avatar.jpg
subdir/img/avatar.jpg
would copy to_site/img/avatar.jpg
Emulate Passthrough Copy During --serve
Added in v2.0.0
The Eleventy Dev Server includes a great build-performance feature that will emulate passthrough file copy.
Practically speaking, this means that (during --serve
only!) files are referenced directly and will not be copied to your output folder. Changes to passthrough file copies will not trigger an Eleventy build but will live reload appropriately in the dev server.
You can enable this behavior in your project using this configuration API method:
export default function (eleventyConfig) {
// the default is "copy"
eleventyConfig.setServerPassthroughCopyBehavior("passthrough");
};
module.exports = function (eleventyConfig) {
// the default is "copy"
eleventyConfig.setServerPassthroughCopyBehavior("passthrough");
};
This behavior will revert to "copy"
in your project automatically if:
- If you are running Eleventy without
--serve
(a standard build or via--watch
) - You change from the default development server: Eleventy Dev Server (e.g. swap back to Browsersync)
2.0.0-canary.12
through 2.0.0-canary.30
. It was changed to opt-in in 2.0.0-canary.31
.Passthrough by File Extension
Eleventy, by default, searches for any file in the input directory with a file extension listed in your templateFormats
configuration. That means if you’ve listed njk
in your templateFormats
, we’ll look for any Nunjucks templates (files with the .njk
file extension).
If a file format is not recognized by Eleventy as a template file extension, Eleventy will ignore the file. You can modify this behavior by adding supported template formats:
export default function (eleventyConfig) {
eleventyConfig.setTemplateFormats([
"md",
"css", // `css` is not a registered template syntax file extension
]);
};
module.exports = function (eleventyConfig) {
eleventyConfig.setTemplateFormats([
"md",
"css", // `css` is not a registered template syntax file extension
]);
};
In the above code sample css
is not currently a recognized Eleventy template, but Eleventy will search for any *.css
files inside of the input directory and copy them to output (maintaining the same directory structure).
You might use this for images by adding "jpg"
, "png"
, or even "webp"
.
addPassthroughCopy
configuration API method above, especially if your project is large and has lots of files.Advanced Options Added in v2.0.0
Additionally, you can pass additional configuration options to the recursive-copy
package. This unlocks the use passthrough file copy with symlinks, transforming or renaming copied files. Here are just a few examples:
export default function (eleventyConfig) {
eleventyConfig.addPassthroughCopy("img", {
expand: true, // expand symbolic links
});
eleventyConfig.addPassthroughCopy({ img: "subfolder/img" }, {
debug: true, // log debug information
});
};
module.exports = function (eleventyConfig) {
eleventyConfig.addPassthroughCopy("img", {
expand: true, // expand symbolic links
});
eleventyConfig.addPassthroughCopy({ img: "subfolder/img" }, {
debug: true, // log debug information
});
};
Review the full list of options on the recursive-copy
GitHub repository.