Copies existing individual files or entire directories to the build directory.
To begin, you'll need to installcopy-webpack-plugin
:
npm install copy-webpack-plugin --save-dev
or
yarn add -D copy-webpack-plugin
or
pnpm add -D copy-webpack-plugin
Then add the plugin to yourwebpack
configuration. For example:
webpack.config.js
const CopyPlugin=require("copy-webpack-plugin");module.exports={ plugins:[newCopyPlugin({ patterns:[{from:"source", to:"dest"},{from:"other", to:"public"},],}),],};
[!NOTE]
copy-webpack-plugin
is not designed to copy files generated during the build process. Instead, it is meant to copy files that already exist in the source tree, as part of the build process.
[!NOTE]
If you want
webpack-dev-server
to write files to the output directory during development, you can enable thewriteToDisk
option or use thewrite-file-webpack-plugin
.
[!NOTE]
You can get the original source filename from theAsset Objects in the webpack stats API.
The plugin's usage:
webpack.config.js
const CopyPlugin=require("copy-webpack-plugin");module.exports={ plugins:[newCopyPlugin({ patterns:[{from:"source", to:"dest"},"path/to/source",// Absolute or relative path, can be files, directories or globs. See examples below.], options:{ concurrency:100,},}),],};
Patterns
from
Type:
typefrom=string;
Default:undefined
Glob or path from where we copy files.Globs follow thefast-glob pattern-syntax.Note: Globs must be astring
.
[!WARNING]
Don't use directly
\\
infrom
option if it is aglob
(i.epath\to\file.ext
) option, as backslashes are treated as regular characters on UNIX systems(not as path separators).On Windows, both forward slashes and backslashes act as separators.Use/
instead, or use Node'spath
utilities to normalize paths.
webpack.config.js
module.exports={ plugins:[newCopyPlugin({ patterns:["relative/path/to/file.ext","relative/path/to/dir", path.resolve(__dirname,"src","file.ext"), path.resolve(__dirname,"src","dir"),"**/*",{from:"**/*",},// If absolute path is a `glob` we replace backslashes with forward slashes, because only forward slashes can be used in the `glob` path.posix.join( path.resolve(__dirname,"src").replace(/\\/g,"/"),"*.txt",),],}),],};
For windows
If you're using an absolute file or folder path in thefrom
option onWindows
, you can use windows path segment (\\
)
module.exports={ plugins:[newCopyPlugin({ patterns:[{from: path.resolve(__dirname,"file.txt"),},],}),],};
However, when writingglob
expressions, always use forward slashes.See thefast-glob manual for more details.
module.exports={ plugins:[newCopyPlugin({ patterns:[{// If absolute path is a `glob` we replace backslashes with forward slashes, because only forward slashes can be used in the `glob`from: path.posix.join( path.resolve(__dirname,"fixtures").replace(/\\/g,"/"),"*.txt",),},],}),],};
The behavior of thecontext
option varies depending on whether thefrom
value is aglob
,file
ordir
.See moreexamples
.
to
Type:
typeto=|string|((pathData:{ context:string; absoluteFilename?:string})=>string);
Default:compiler.options.output
string
Specifies the output path.
[!WARNING]
Don't use directly
\\
in theto
path (i.epath\to\dest
) option, as backslashes are treated as regular characters on UNIX systems(not as path separators).On Windows, both forward slashes and backslashes act as separators.Use/
instead, or use Node'spath
utilities to normalize paths.
webpack.config.js
module.exports={ plugins:[newCopyPlugin({ patterns:[{from:"**/*", to:"relative/path/to/dest/",},{from:"**/*", to:"/absolute/path/to/dest/",},{from:"**/*", to:"[path][name].[contenthash][ext]",},],}),],};
function
Allows to modify the writing path.
[!WARNING]
Don't use directly
\\
into
(i.epath\to\newFile
) option, as backslashes are treated as regular characters on UNIX systems(not as path separators).On Windows, both forward slashes and backslashes act as separators.Use/
instead, or use Node'spath
utilities to normalize paths.
webpack.config.js
module.exports={ plugins:[newCopyPlugin({ patterns:[{from:"src/*.png",to({ context, absoluteFilename}){return"dest/newPath/[name][ext]";},},],}),],};
webpack.config.js
module.exports={ plugins:[newCopyPlugin({ patterns:[{from:"src/*.png",to({ context, absoluteFilename}){return Promise.resolve("dest/newPath/[name][ext]");},},],}),],};
context
Type:
typecontext=string;
Default:options.context|compiler.options.context
Defines the base directory used for two purposes:
It is prepended to thefrom
path.
It is removed from the beginning of the result path(s).
[!WARNING]
Don't use directly
\\
into
(i.epath\to\newFile
) option, as backslashes are treated as regular characters on UNIX systems(not as path separators).On Windows, both forward slashes and backslashes act as separators.Use/
instead, or use Node'spath
utilities to normalize paths.
webpack.config.js
module.exports={ plugins:[newCopyPlugin({ patterns:[{from:"src/*.txt", to:"dest/", context:"app/",},],}),],};
Thecontext
can be an absolute or relative path. If it's relative, then it will be converted to an absolute path based oncompiler.options.context
.
You should explicitly definecontext
whenfrom
uses a glob pattern. Otherwise, the plugin sets it automatically based on the nature offrom
:
Iffrom
is a file, thencontext
defaults to the file’s directory. The result path will be just the filename alone.
Iffrom
is a directory,context
is set to the same directory. The result paths include the directory’s contents (including subdirectories), relative to it.
The use ofcontext
is illustrated by theseexamples
.
globOptions
[!WARNING]
TheonlyDirectories does not work because the plugin is designed to copy files, not directories alone.
Type:
typeglobOptions=import("tinyglobby").GlobOptions;
Default:undefined
Allows you to configure the glob pattern matching library used by the plugin.See the list of supported optionsTo exclude files from being copied, use theglobOptions.ignore option
webpack.config.js
module.exports={ plugins:[newCopyPlugin({ patterns:[{from:"public/**/*", globOptions:{ dot:true, gitignore:true, ignore:["**/file.*","**/ignored-directory/**"],},},],}),],};
filter
Type:
typefilter=(filepath:string)=>boolean;
Default:undefined
[!NOTE]
To ignore files by path (e.g., by extension or name), prefer using the [
globOptions.ignore
] option.
webpack.config.js
const fs=require("fs").promise;module.exports={ plugins:[newCopyPlugin({ patterns:[{from:"public/**/*",filter:async(resourcePath)=>{const data=await fs.promises.readFile(resourcePath);const content= data.toString();if(content==="my-custom-content"){returnfalse;}returntrue;},},],}),],};
toType
Type:
typetoType="dir"|"file"|"template";
Default:undefined
Determines the type of theto
option — whether it's a directory, file, or template.Sometimes it is hard to say what isto
, examplepath/to/dir-with.ext
.If you want to copy files in directory you should explicitly set the type todir
.In most cases, the plugin will automatically determine the correcttype
, so you typically don't need to set this option manually.
Name | Type | Default | Description |
---|---|---|---|
'dir' | string | undefined | Usedto has no extension or ends with a'/' . |
'file' | string | undefined | Used whento is a file path that is not a directory or template. |
'template' | string | undefined | Used whento containsa template pattern |
'dir'
webpack.config.js
module.exports={ plugins:[newCopyPlugin({ patterns:[{from:"path/to/file.txt", to:"directory/with/extension.ext", toType:"dir",},],}),],};
'file'
webpack.config.js
module.exports={ plugins:[newCopyPlugin({ patterns:[{from:"path/to/file.txt", to:"file/without/extension", toType:"file",},],}),],};
'template'
webpack.config.js
module.exports={ plugins:[newCopyPlugin({ patterns:[{from:"src/", to:"dest/[name].[contenthash][ext]", toType:"template",},],}),],};
force
Type:
typeforce=boolean;
Default:false
Overwrites files that already exist incompilation.assets
(typically added by other plugins or loaders).
webpack.config.js
module.exports={ plugins:[newCopyPlugin({ patterns:[{from:"src/**/*", to:"dest/", force:true,},],}),],};
priority
Type:
typepriority=number;
Default:0
Allows to specify the priority of copying files with the same destination name.Files for patterns with higher priority will be copied later.To enable overwriting, theforce
option must be set totrue
.webpack.config.js
module.exports={ plugins:[newCopyPlugin({ patterns:[// Copied second and will overwrite "dir_2/file.txt"{from:"dir_1/file.txt", to:"newfile.txt", force:true, priority:10,},// Copied first{from:"dir_2/file.txt", to:"newfile.txt", priority:5,},],}),],};
transform
Type:
typetransform=|{transformer:(input:string, absoluteFilename:string)=>string| Buffer; cache?:boolean| TransformerCacheObject|undefined;}|((input:string, absoluteFilename:string)=>string| Buffer);
Default:undefined
Allows you to modify the contents of a file before it is written to the output directory.
function
webpack.config.js
module.exports={ plugins:[newCopyPlugin({ patterns:[{from:"src/*.png", to:"dest/",// The `content` argument is a [`Buffer`](https://nodejs.org/api/buffer.html) object, it could be converted to a `String` to be processed using `content.toString()`// The `absoluteFrom` argument is a `String`, it is absolute path from where the file is being copiedtransform(content, absoluteFrom){returnoptimize(content);},},],}),],};
object
Name | Default | Description |
---|---|---|
transformer | undefined | Allows you to modify the contents of the file. |
cache | false | Enables caching fortransform . You can usetransform: { cache: { key: 'my-cache-key' } } to manually invalidate the cache when needed. |
transformer
Type:
typetransformer=(input:string, absoluteFilename:string)=>string;
Default:undefined
webpack.config.js
module.exports={ plugins:[newCopyPlugin({ patterns:[{from:"src/*.png", to:"dest/",// The `content` argument is a [`Buffer`](https://nodejs.org/api/buffer.html) object, it could be converted to a `String` to be processed using `content.toString()`// The `absoluteFrom` argument is a `String`, it is absolute path from where the file is being copied transform:{transformer(content, absoluteFrom){returnoptimize(content);},},},],}),],};
webpack.config.js
module.exports={ plugins:[newCopyPlugin({ patterns:[{from:"src/*.png", to:"dest/", transform:{transformer(content, path){return Promise.resolve(optimize(content));},},},],}),],};
cache
Type:
typecache=|boolean|{ keys:{[key:string]:any;};}|{keys:( defaultCacheKeys:{[key:string]:any;}, absoluteFilename:string,)=>Promise<{[key:string]:any;}>;}|undefined;
Default:false
webpack.config.js
Enable or disable caching and configure its behavior.By default, the cache directory is located at:node_modules/.cache/copy-webpack-plugin
.
boolean
Enables/Disabletransform
caching.
webpack.config.js
module.exports={ plugins:[newCopyPlugin({ patterns:[{from:"src/*.png", to:"dest/", transform:{transformer(content, path){returnoptimize(content);}, cache:true,},},],}),],};
object
Enablestransform
caching and setup invalidation keys.
webpack.config.js
module.exports={ plugins:[newCopyPlugin({ patterns:[{from:"src/*.png", to:"dest/", transform:{transformer(content, path){returnoptimize(content);}, cache:{ keys:{// May be useful for invalidating cache based on external values// For example, you can invalid cache based on `process.version` - { node: process.version } key:"value",},},},},],}),],};
You can setup invalidation keys using a function.
Simple function:
webpack.config.js
module.exports={ plugins:[newCopyPlugin({ patterns:[{from:"src/*.png", to:"dest/", transform:{transformer(content, path){returnoptimize(content);}, cache:{keys:(defaultCacheKeys, absoluteFrom)=>{const keys=getCustomCacheInvalidationKeysSync();return{...defaultCacheKeys, keys,};},},},},],}),],};
Async function:
webpack.config.js
module.exports={ plugins:[newCopyPlugin({ patterns:[{from:"src/*.png", to:"dest/", transform:{transformer(content, path){returnoptimize(content);}, cache:{keys:async(defaultCacheKeys, absoluteFrom)=>{const keys=awaitgetCustomCacheInvalidationKeysAsync();return{...defaultCacheKeys, keys,};},},},},],}),],};
transformAll
Type:
typetransformAll=( data:{ data: Buffer; sourceFilename:string; absoluteFilename:string;}[],)=>any;
Default:undefined
Allows you to modify the contents of multiple files and save the combined result into a single file.
[!NOTE]
The
to
option must be specified and point to a file. Only the[contenthash]
and[fullhash]
template strings are allowed in the filename.
webpack.config.js
module.exports={ plugins:[newCopyPlugin({ patterns:[{from:"src/**/*.txt", to:"dest/file.txt",// The `assets` argument is an array of assets matched by the pattern `from` ("src/**/*.txt")transformAll(assets){const result= assets.reduce((accumulator, asset)=>{// The asset content can be obtained from `asset.source` using `source` method.// The asset content is a [`Buffer`](https://nodejs.org/api/buffer.html) object, it could be converted to a `String` to be processed using `content.toString()`const content= asset.data; accumulator=`${accumulator}${content}\n`;return accumulator;},"");return result;},},],}),],};
noErrorOnMissing
Type:
typenoErrorOnMissing=boolean;
Default:false
Doesn't generate an error if file(s) are missing.
module.exports={ plugins:[newCopyPlugin({ patterns:[{from: path.resolve(__dirname,"missing-file.txt"), noErrorOnMissing:true,},],}),],};
info
Type:
typeinfo=| Record<string,any>|((item:{ absoluteFilename:string; sourceFilename:string; filename:string; toType: ToType;})=> Record<string,any>);
Default:undefined
Allows to add assets info.
webpack.config.js
module.exports={ plugins:[newCopyPlugin({ patterns:["relative/path/to/file.ext",{from:"**/*",// Terser skip this file for minification info:{ minimized:true},},],}),],};
webpack.config.js
module.exports={ plugins:[newCopyPlugin({ patterns:["relative/path/to/file.ext",{from:"**/*",// Terser skip this file for minimizationinfo:(file)=>({ minimized:true}),},],}),],};
concurrency
type:
typeconcurrency=number;
Default:100
Limits the number of simultaneous requests to fs.
webpack.config.js
module.exports={ plugins:[newCopyPlugin({ patterns:[...patterns], options:{ concurrency:50},}),],};
from
(glob
,file
ordir
).Consider the following file structure:
src/directory-nested/deep-nested/deepnested-file.txtsrc/directory-nested/nested-file.txt
Everything that you specify infrom
will be included in the result:
webpack.config.js
module.exports={ plugins:[newCopyPlugin({ patterns:[{from:"src/directory-nested/**/*",},],}),],};
Result:
src/directory-nested/deep-nested/deepnested-file.txt,src/directory-nested/nested-file.txt
If you don't want the result paths to start withsrc/directory-nested/
, then you should movesrc/directory-nested/
tocontext
, such that only the glob pattern**/*
remains infrom
:
webpack.config.js
module.exports={ plugins:[newCopyPlugin({ patterns:[{from:"**/*", context: path.resolve(__dirname,"src","directory-nested"),},],}),],};
Result:
deep-nested/deepnested-file.txt,nested-file.txt
webpack.config.js
module.exports={ plugins:[newCopyPlugin({ patterns:[{from: path.resolve(__dirname,"src","directory-nested"),},],}),],};
Result:
deep-nested/deepnested-file.txt,nested-file.txt
Technically, this is equivalent to using**/*
with a predefined context set to the specified directory
webpack.config.js
module.exports={ plugins:[newCopyPlugin({ patterns:[{from:"**/*", context: path.resolve(__dirname,"src","directory-nested"),},],}),],};
Result:
deep-nested/deepnested-file.txt,nested-file.txt
module.exports={ plugins:[newCopyPlugin({ patterns:[{from: path.resolve( __dirname,"src","directory-nested","nested-file.txt",),},],}),],};
Result:
nested-file.txt
Technically, this is a filename with a predefined context equal to the file's directorypath.dirname(pathToFile)
.
webpack.config.js
module.exports={ plugins:[newCopyPlugin({ patterns:[{from:"nested-file.txt", context: path.resolve(__dirname,"src","directory-nested"),},],}),],};
Result:
nested-file.txt
webpack.config.js
module.exports={ plugins:[newCopyPlugin({ patterns:[{from: path.posix.join( path.resolve(__dirname,"src").replace(/\\/g,"/"),"**/*",), globOptions:{ ignore:[// Ignore all `txt` files"**/*.txt",// Ignore all files in all subdirectories"**/subdir/**",],},},],}),],};
Removes all directory references and copies only file names.
[!WARNING]
If files have the same name, the result is non-deterministic.
webpack.config.js
module.exports={ plugins:[newCopyPlugin({ patterns:[{from:"src/**/*", to:"[name][ext]",},],}),],};
Result:
file-1.txtfile-2.txtnested-file.txt
webpack.config.js
module.exports={ plugins:[newCopyPlugin({ patterns:[{// When copying files starting with a dot, must specify the toType option// toType: "file",to({ context, absoluteFilename}){return`newdirectory/${path.relative(context, absoluteFilename)}`;},from:"directory",},],}),],};
Result:
"newdirectory/file-1.txt","newdirectory/nestedfile.txt","newdirectory/nested/deep-nested/deepnested.txt","newdirectory/nested/nestedfile.txt",
Useful if you need to simply copy*.js
files to destination "as is" without evaluating and minimizing them using Terser.
webpack.config.js
module.exports={ plugins:[newCopyPlugin({ patterns:["relative/path/to/file.ext",{from:"**/*",// Terser skip this file for minimization info:{ minimized:true},},],}),],};
yarn workspaces
andmonorepos
When usingyarn workspaces
or monorepos
, relative copy paths fromnode_modules
can be broken due to the way packages are hoisting.To avoid this, you should explicitly specify where to copy the files from; by usingrequire.resolve
.
webpack.config.js
module.exports={ plugins:[newCopyPlugin({ patterns:[{from:`${path.dirname( require.resolve(`${moduleName}/package.json`),)}/target`, to:"target",},],}),],};
We welcome all contributions!
If you are new here, please take a moment to review our contributing guidelines before submitting issues or pull requests.