Application Contents
This page covers how electron-builder determines which files are included in the packaged app and how to customize file inclusion.
How electron-builder Collects Files
electron-builder uses a two-phase approach to build the app bundle:
- App files — your application source code and assets, placed inside the ASAR archive (or directly in the app folder if ASAR is disabled)
- Extra files/resources — additional files copied into specific locations in the output package, outside the ASAR archive
Default File Inclusion
By default, electron-builder includes all files matching **/* from the app directory, minus a comprehensive set of automatically-excluded files:
Always excluded:
node_modulesdev dependencies (only production dependencies are included)- The extensions of
fileOptions.excludedExts("default":*.iml,*.hprof,*.orig,*.pyc,*.pyo,*.rbc,*.swp,*.csproj,*.sln,*.slnx,*.suo,*.xproj,*.cc,*.d.ts,*.mk,*.a,*.o,*.obj,*.forge-meta,*.pdb), also innode_modules .editorconfig,._*,.DS_Store,.git,.hg,.svn,.gitignore,.gitattributes__pycache__,.flowconfig,.idea,.vs,.nyc_outputappveyor.yml,.travis.yml,circle.ymlnpm-debug.log,yarn.lock,.yarn-integrity,.yarn-metadata.json- Test directories:
{test,__tests__,tests,powered-test,example,examples}inside node_modules *.d.tsfiles inside node_modulesnode_modules/.bin
These exclusions are applied even when you define custom patterns. To keep an excluded file, name it in a fileOptions.files pattern (one that names an excluded extension includes only the files it matches: **/*.obj every .obj file outside node_modules and the build resources and output directories, models/teapot.obj only that file), or change the excluded extensions with fileOptions.excludedExts.
The file options are nested under fileOptions (fileOptions.files, fileOptions.extraResources, fileOptions.extraFiles), at the configuration root and in the platform sections (e.g. mac.fileOptions). A platform's lists are added to the root ones. Run electron-builder migrate-schema to move files, extraResources and extraFiles keys set directly on the configuration into fileOptions; see file options.
The files Option
Override which files are included using the fileOptions.files option. Patterns are glob expressions relative to the app directory:
fileOptions:
files:
- "**/*"
- "!src/**" # exclude source files
- "!tests/**" # exclude test directory
- "!**/*.map" # exclude source maps
- "dist/**" # include dist directory
Important behavior:
- If any pattern does NOT start with
!(i.e., it's an include pattern), the default**/*pattern is NOT automatically prepended. You must include it explicitly if you want to start from all files. package.jsonandnode_modules/**/*(production only) are always included regardless of patterns.- All default ignores (listed above) are always applied.
Simple Include Example
fileOptions:
files:
- "**/*"
- "!src/**"
- "!*.ts"
- "!tsconfig*.json"
Only Include Specific Directories
fileOptions:
files:
- dist/**
- assets/**
- node_modules/** # production node_modules (already automatic)
- package.json # always included, but can be explicit
Exclude Large Unused Files
fileOptions:
files:
- "**/*"
- "!node_modules/**/README*"
- "!node_modules/**/*.md"
- "!node_modules/**/*.map"
- "!**/test/**"
- "!**/__tests__/**"
FileSet Objects
For advanced scenarios, use FileSet objects instead of (or alongside) glob strings. FileSets let you copy files from a different source directory:
fileOptions:
files:
- from: dist
to: .
filter:
- "**/*"
- "!**/*.map"
- from: assets
to: assets
| Field | Description |
|---|---|
from | Source path. Relative to the app directory for files; relative to project dir for extraResources/extraFiles. Defaults to the app directory. |
to | Destination path. Relative to the ASAR root for files; relative to content dir for extraFiles; relative to resources dir for extraResources. |
filter | Glob patterns relative to from. Defaults to **/*. |
Renaming a File
fileOptions:
files:
- from: dist/main.js
to: app.js
Copying from Outside the App Directory
fileOptions:
files:
- "**/*"
- from: ../shared/assets
to: shared-assets
Extra Files and Resources
Copy files into the packaged app outside the ASAR archive:
extraResources
Copies into the resources/ directory:
- macOS:
MyApp.app/Contents/Resources/ - Windows/Linux:
resources/
fileOptions:
extraResources:
- from: native-binaries/
to: bin
filter:
- "**/*"
- "assets/icon.png" # string shorthand — copies to resources/assets/icon.png
extraFiles
Copies into the app content directory:
- macOS:
MyApp.app/Contents/ - Windows/Linux: the install directory root
fileOptions:
extraFiles:
- from: config/
to: config
- "LICENSE"
Use extraResources for native binaries, CLI tools, or data files that need to be accessible at runtime. Access them in your app via process.resourcesPath.
Symbolic Links
Only the build configuration is trusted. The files electron-builder copies (the app directory, node_modules, and the extraResources / extraFiles / extraDistFiles sources) and the symlinks among them are not: a symlink planted in a dependency or a copied directory could otherwise make the build package files from elsewhere on the build machine (SSH keys, credentials), or write outside the output directory. electron-builder therefore checks packaged files, copied symlinks and write destinations by their real path.
Linked files must resolve inside the workspace
A file of the app (packed into app.asar or copied with asar: false) that is a symlink, or is reached through one (a linked package in node_modules, a symlinked directory in the app directory), is packaged only when its real path is inside:
- the workspace root (the project directory when there is no workspace), the project directory or the app directory, or
- the package-manager store (pnpm's
storeDirandvirtualStoreDir, read fromnode_modules/.modules.yaml, which coversenableGlobalVirtualStore).
Packages linked by pnpm, yarn, npm or bun workspaces are inside the workspace. A file that resolves anywhere else (an npm link, a file:../lib dependency outside the repository, a symlink into the home or temp directory) fails the build with InvalidConfigurationError (code ERR_ELECTRON_BUILDER_FILE_OUTSIDE_WORKSPACE):
Cannot copy file [node_modules/lib/src/index.js] symlinked to file [/home/me/src/lib/src/index.js] outside the package: electron-builder only packages files whose real path is inside the workspace root (/home/me/src/app) or the package-manager store. ...
To fix it, add the linked package to the workspace (pnpm-workspace.yaml, workspaces in package.json), install it from a tarball (npm pack) or the registry instead of linking it, or replace the symlink with a copy. If packaging it from where it is is intended, allow it.
Symlinks that leave the app are refused
Destinations are checked by real path when they are written. The build fails with InvalidConfigurationError (code ERR_ELECTRON_BUILDER_PATH_OUTSIDE_ROOT) when:
- a copy would be written through a symlink that leads out of the app output directory, e.g. the app directory (
asar: false) puts aresources/data -> /somewheresymlink in place andextraResourcesthen copies intodata/. The same applies to the files electron-builder writes itself after the copies (app-update.yml,package-type,apparmor-profile, NSISelevate.exe, the snapcommand.sh, Squirrel'sSquirrel.exeand execution stub). A symlink at such a file name is replaced, never followed. - a copied symlink would lead outside the output.
extraResources/extraFileskeep a symlink as it is, but only when it stays inside the app output directory or leads into the workspace or the package-manager store. In that last case it is dangling on other machines, and the build warns once. Withasar: false, a symlink in the app directory that leaves it is copied as the file it points to (see Linked files must resolve inside the workspace), and one that is kept must stay inside the app, including through other symlinks (x/a -> up/..wherex/up -> ..). - a Windows archive or installer would store files from outside the app. The Windows
zip/7ztargets, the NSIS app package, AppX/MSIX and Squirrel.Windows store what a symlink points to rather than the symlink, so a symlink in the app output directory that leads outside it fails these targets.
To fix it, replace the symlink with a copy of what it points to (or point it at a path inside the app), or exclude it from the copy with a "!" pattern. The error names the symlink, where it resolves to and, when the symlink can be allowed, the entry that allows it.
Allowing external links
fileOptions.allowExternalLinks allows symlinks that are intended to lead outside the app, the workspace and the package-manager store. It is false by default.
trueallows any such symlink.- A list of paths, relative to the project directory or absolute, allows a symlink only when the real path of what it points to is inside (the real path of) one of them. A listed path that does not exist fails the build.
fileOptions:
allowExternalLinks:
- ../shared-lib
linux:
fileOptions:
allowExternalLinks: true # any link, for Linux builds only
Set it at the configuration root or per platform (mac.fileOptions, win.fileOptions, linux.fileOptions). A platform's value replaces the root one rather than being added to it, so false there turns the root list off for that platform.
An allowed symlink is packaged: what it points to is copied (or stored by the archive), and a copied symlink is kept as it is. The build warns once when this option allows a symlink. A refusal suggests the entry to add, e.g. To allow it, set "fileOptions": { "allowExternalLinks": ["../shared-lib"] } (or { "allowExternalLinks": true }) in your build configuration.
allowExternalLinks only allows what is packaged. A copy, or a file electron-builder writes (app-update.yml, ...), whose destination leads out of the output directory through a symlink is always refused.
ASAR Packaging
ASAR is Electron's archive format — it bundles all app files into a single app.asar file for faster loading and to prevent casual file inspection.
asar: {} # ASAR is enabled by default — pass an object to configure, or set asar: false to disable
Set asar: false to disable ASAR packaging (all files are placed in the app directory directly). Useful for debugging or if you have unusual file access patterns.
Unpacking Files from ASAR
Some files cannot be inside an ASAR archive:
- Native modules (
.nodefiles) - Large binary assets that need random-access reads
- Files that need to be executed directly
Use asar.unpack to unpack specific files into app.asar.unpacked/:
asar:
unpack:
- "**/*.node" # all native modules
- "resources/ffmpeg" # large binary
- "**/**/node_modules/sharp/**" # specific module
Files in app.asar.unpacked/ are accessible via the same paths as if they were in the ASAR — Electron transparently redirects reads.
Smart Unpack
asar:
smartUnpack: true # Default: true
When enabled, electron-builder automatically detects executables and native modules and unpacks them from ASAR. You generally don't need to configure asar.unpack manually unless you have unusual cases.
ASAR Ordering
Optimize app startup time by specifying file ordering within the ASAR archive. Files listed first are packed first, enabling faster sequential reads at startup:
asar:
ordering: build/asar-ordering.txt
index.js
renderer.js
node_modules/some-dependency/lib/index.js
- Where the file is found: the
orderingpath is resolved like other build resources, relative to the build resources directory (directories.buildResources, defaultbuild) first, then the project directory. A missing file fails the build. - Line syntax: one file per line, relative to the app directory (where the app's
package.jsonsits, i.e. the root ofapp.asar). A leading/and a<count>:prefix (as written by load counters) are accepted,\separators are treated as/, and blank lines are ignored. There is no comment syntax: a#line is read as a path and never matches. Lines naming a directory are ignored, and listed files that are not packaged (for examplenode_modules/electron, which is never in the archive) are skipped. The build log reportsmatched N/M; run withDEBUG=electron-builderto see the first unmatched lines. - Resulting layout: directory entries first (they hold no data), then the listed files in the order of the file, then everything else in its default order.
Without an ordering file, electron-builder packs dependencies first and your app files last, so the files that change most often sit at the end of the archive and differential updates download less. An ordering file moves the listed files to the front, so a change to any of them shifts the offsets of everything packed after it, which can increase differential update download size. Measure startup gains against update size before adopting it.
Practical Examples
Electron App with Native Modules
fileOptions:
files:
- "**/*"
- "!src/**"
- "!**/*.ts"
- "!**/*.map"
asar:
unpack:
- "**/*.node"
App with Large Video Assets
fileOptions:
files:
- "**/*"
- "!src/**"
- "!videos/**" # exclude from ASAR
extraResources:
- from: videos/
to: videos # place outside ASAR, accessible via process.resourcesPath
Monorepo Setup (Two-Package Structure)
directories:
app: packages/app # app directory is not the project root
fileOptions:
files:
- "**/*"
- "!src/**"
See Two package.json Structure for the full monorepo setup.
Including Default-Excluded Files
electron-builder excludes a set of development-only file extensions and names by default — for example
build artifacts such as .obj, .o, .a, and .d.ts, lockfiles such as yarn.lock and
package-lock.json, and VCS/tooling metadata such as .git, .idea, and .github.
To ship a file that would otherwise be excluded, add an explicit fileOptions.files glob that targets it. An
explicit include overrides the matching default exclusion:
fileOptions:
files:
- "**/*"
- "**/*.obj" # keep Wavefront .obj 3D models that are excluded by default
The same applies to default-excluded names — reference the name in a pattern segment, e.g.:
fileOptions:
files:
- "**/*"
- "**/.github/**" # keep the .github directory that is excluded by default
A pattern that names an excluded extension includes only the files it matches: **/*.obj includes every .obj file outside node_modules and the build resources and output directories, models/teapot.obj only that file. A pattern with a default-excluded name as a path segment opts that name back in. Broad patterns such as **/* continue to honor the defaults.
Troubleshooting
File is missing from packaged app: Check if the file is being excluded by a pattern. Run DEBUG=electron-builder electron-builder build to see detailed file collection output.
Native module crashes at runtime: The module likely needs to be outside the ASAR archive. Add it to asar.unpack:
asar:
unpack:
- "node_modules/better-sqlite3/**"
App directory is too large: Profile what's included by examining the app bundle after building. Common culprits: source maps (*.map), TypeScript source files (*.ts), and large test fixtures.
FileSet from path not found: Remember that from in files is relative to the app directory. For extraResources/extraFiles, it's relative to the project root.
File Contents Configuration
Interface: FilesBuildOptions
Which files are copied into the packaged app, which file extensions are excluded from it, and which symlinks among them may lead outside it,
set under fileOptions at the configuration root or per platform (e.g. mac.fileOptions). A platform's file lists are added to the root
ones; a platform's excludedExts and allowExternalLinks replace the root ones.
See file options.
Properties
allowExternalLinks?
optionalallowExternalLinks?:boolean|string[] |null
Whether symlinks among the packaged files may lead outside the app, the workspace and the package-manager store.
Only the build configuration is trusted, not the files it packages: by default (false) electron-builder refuses
- a file of the app (
app.asarorasar: false) that is a symlink, or is reached through one, whose real path is outside the workspace root, the project and app directories and the package-manager store (npm link, afile:../libdependency outside the repository, a symlink into the home or temp directory), - a copied symlink that resolves outside the app: one in
extraResources/extraFiles(other than into the workspace or the store), one kept by anasar: falsecopy, and any symlink leaving the app in a target that stores what symlinks point to (Windowszip/7z, the NSIS app package, AppX/MSIX, Squirrel.Windows).
Without these checks, a symlink planted in a dependency or a copied directory could package files from elsewhere on the build machine (SSH keys, credentials) into the artifact, which is why this is off by default.
trueallows any such symlink.- A list of paths, relative to the project directory or absolute, allows a symlink only when the real path of what it points to is
inside the real path of one of them (e.g.
["../shared-lib"]). A listed path that does not exist fails the build.
An allowed symlink is packaged: what it points to is copied (or stored by the archive), and a copied symlink is kept as it is. A warning is logged once when this allows a symlink.
Set it under fileOptions, at the configuration root or per platform; a platform's value (false included) replaces the root one
rather than being added to it:
{ "fileOptions": { "allowExternalLinks": ["../shared-lib"] }, "linux": { "fileOptions": { "allowExternalLinks": true } } }
This does not allow writing through a symlink: a copy or a file written by electron-builder whose destination leads outside the output directory through a symlink is always refused, and a symlink at such a file name is replaced, never followed. See Symbolic links.
Default
false
excludedExts?
optionalexcludedExts?:string|string[] |null
File extensions (without the leading dot) excluded from the packaged app files and the copied node_modules.
"default"expands to the built-in list of excluded extensions (see the table below).- Any other entry adds that extension, e.g.
"map". - An entry starting with
!removes that extension from the others listed, e.g.["default", "!pdb"]to keep.pdb(Program Database) symbol files for Windows crash-dump analysis..pdbfiles contain symbol names and the source paths of the build machine: keep them only in internal builds or builds for a symbol server, or upload them to a symbol server instead of shipping them. A list of removals only, such as["!pdb"], is rejected because it would exclude no extension at all: write["default", "!pdb"]. A"!ext"in a list that does not otherwise list that extension (e.g.["map", "!pdb"]) has no effect and logs a warning.
The built-in list ("default"):
| Extension | Typically used for |
| --- | --- |
| .iml | IntelliJ IDEA / WebStorm module file |
| .hprof | Java heap dump |
| .orig | Original copy of a file, left behind by merge tools and patch |
| .pyc | Compiled Python bytecode |
| .pyo | Optimized compiled Python bytecode (Python 2) |
| .rbc | Compiled Ruby bytecode (Rubinius) |
| .swp | Vim swap file |
| .csproj | C# (MSBuild) project file |
| .sln | Visual Studio solution file |
| .slnx | Visual Studio XML solution file |
| .suo | Visual Studio solution user options |
| .xproj | .NET Core project file (Visual Studio 2015) |
| .cc | C++ source file, e.g. of a native module |
| .d.ts | TypeScript declaration file |
| .mk | Makefile fragment generated by node-gyp |
| .a | Static library archive from a native build |
| .o | Object file from a native build |
| .obj | Object file from an MSVC native build; also used for Wavefront 3D models, which a files pattern can re-include |
| .forge-meta | Metadata @electron/rebuild writes next to a rebuilt native module |
| .pdb | Program Database: Windows debug symbols, with symbol names and the build machine's source paths |
The list replaces the defaults: list "default" to extend them rather than replace them. null (or omitting it) is ["default"],
and an empty array [] excludes no extension.
An invalid list (an entry that is not a file extension, "!default", or removals only) fails the build when the configuration is validated, at the root and in every platform section, before anything is packed.
{ "fileOptions": { "excludedExts": ["default", "!pdb", "map"] } }
Set it under fileOptions, at the configuration root or per platform. Unlike the other lists, a later list replaces an earlier one rather
than being merged with it. For the root and for each platform section, the last layer that sets the list wins: the extends parents in
order, then the configuration file, then the programmatic or -c configuration. For the mas and mas-dev targets, a mas list then
replaces the mac one, and a masDev list (for mas-dev) replaces both. A platform's list then replaces the root one, whichever layer
set either. A null value keeps the earlier list.
A files pattern that names an excluded extension includes only the app files it matches: **/*.obj every .obj file outside
node_modules and the build resources and output directories, models/teapot.obj only that file.
A single entry may be given as a string, e.g. on the command line: -c.fileOptions.excludedExts=default. For several entries, repeat the flag:
-c.fileOptions.excludedExts=default -c.fileOptions.excludedExts=!pdb (in an interactive bash or zsh, write the second one as '-c.fileOptions.excludedExts=!pdb', single-quoted, so that !pdb is not expanded).
Default
["default"]
extraFiles?
optionalextraFiles?:string|FileSet| (string|FileSet)[] |null
The same as extraResources but copy into the app's content directory (Contents for MacOS, root directory for Linux and Windows).
extraResources?
optionalextraResources?:string|FileSet| (string|FileSet)[] |null
A glob patterns relative to the project directory, when specified, copy the file or directory with matching names directly into the app's resources directory (Contents/Resources for MacOS, resources for Linux and Windows).
File patterns (and support for from and to fields) the same as for files.
files?
optionalfiles?:string|FileSet| (string|FileSet)[] |null
A glob patterns relative to the app directory, which specifies which files to include when copying files to create the package.
Defaults to:
[
"**/*",
"!**/node_modules/*/{CHANGELOG.md,README.md,README,readme.md,readme}",
"!**/node_modules/*/{test,__tests__,tests,powered-test,example,examples}",
"!**/node_modules/*.d.ts",
"!**/node_modules/.bin",
"!**/*.{iml,o,hprof,orig,pyc,pyo,rbc,swp,csproj,sln,slnx,xproj}",
"!.editorconfig",
"!**/._*",
"!**/{.DS_Store,.git,.hg,.svn,CVS,RCS,SCCS,.gitignore,.gitattributes}",
"!**/{__pycache__,thumbs.db,.flowconfig,.idea,.vs,.nyc_output}",
"!**/{appveyor.yml,.travis.yml,circle.yml}",
"!**/{npm-debug.log,yarn.lock,.yarn-integrity,.yarn-metadata.json}"
]
Development dependencies are never copied in any case. You don't need to ignore it explicitly. Hidden files are not ignored by default, but all files that should be ignored, are ignored by default.
Default pattern **/* is not added to your custom if some of your patterns is not ignore (i.e. not starts with !). package.json and **/node_modules/**/* (only production dependencies will be copied) is added to your custom in any case. All default ignores are added in any case — you don't need to repeat it if you configure own patterns.
May be specified in the platform options as well (e.g. mac.fileOptions.files, see mac).
You may also specify custom source and destination directories by using FileSet objects instead of simple glob patterns.
[
{
"from": "path/to/source",
"to": "path/to/destination",
"filter": ["**/*", "!foo/*.js"]
}
]
You can use file macros in the from and to fields as well. from and to can be files and you can use this to rename a file while packaging.
FileSet Configuration
Interface: FileSet
Properties
filter?
optionalfilter?:string|string[]
The glob patterns. Defaults to "**/*"
from?
optionalfrom?:string
The source path relative to and defaults to:
- the app directory for
files, - the project directory for
extraResourcesandextraFiles. If you don't use two-package.json structure and don't set custom app directory, app directory equals to project directory.
to?
optionalto?:string
The destination path relative to and defaults to:
- the asar archive root for
files, - the app's content directory for
extraFiles, - the app's resource directory for
extraResources.