electron-builder packages your application code and resources into distributable formats. Understanding how files are organized and what gets included is crucial for optimizing your app’s size and performance.
Default File Inclusion
By default, electron-builder includes:
Your application code (from the app directory)
node_modules dependencies
package.json
All required runtime files
The default behavior automatically excludes development dependencies, test files, and common non-runtime files.
ASAR Archives
What is ASAR?
ASAR (Atom Shell Archive) is a simple archive format that concatenates files into a single file. Electron can read files from ASAR archives without unpacking them, which provides:
Faster loading : Single file reads are faster than many small file reads
Reduced file count : Improves performance on Windows
Basic obfuscation : Source code is not immediately visible (but not encrypted)
Default ASAR Configuration
By default, your application code is packaged into app.asar:
{
"build" : {
"asar" : true
}
}
ASAR Integrity Validation
electron-builder supports ASAR integrity validation to prevent tampering:
{
"build" : {
"electronFuses" : {
"enableEmbeddedAsarIntegrityValidation" : true ,
"onlyLoadAppFromAsar" : true
}
}
}
ASAR integrity checking is supported on:
macOS as of Electron 16.0.0+
Windows as of Electron 30.0.0+
When enabling onlyLoadAppFromAsar, Electron will only load code from app.asar, not from unpacked app directories. Combine this with integrity validation for maximum security.
Unpacking Files from ASAR
Some files need to be unpacked from ASAR:
Native Node.js addons (.node files)
Files accessed by external processes
Files that need to be executable
{
"build" : {
"asar" : true ,
"asarUnpack" : [
"**/node_modules/sharp/**/*" ,
"**/node_modules/sqlite3/**/*" ,
"**/node_modules/**/*.node"
]
}
}
electron-builder automatically unpacks .node files by default. You only need to explicitly specify asarUnpack for special cases.
Disabling ASAR
For development or specific use cases, you can disable ASAR:
{
"build" : {
"asar" : false
}
}
Disabling ASAR increases the number of files in your package, which can slow down application startup, especially on Windows.
File Configuration Options
files
Specifies which files to include in the application:
{
"build" : {
"files" : [
"dist/**/*" ,
"node_modules/**/*" ,
"package.json" ,
"!**/node_modules/*/{CHANGELOG.md,README.md,README,readme.md,readme}" ,
"!**/node_modules/.bin" ,
"!**/*.{iml,o,hprof,orig,pyc,pyo,rbc,swp,csproj,sln,xproj}" ,
"!**/{.DS_Store,.git,.hg,.svn,CVS,RCS,SCCS,__pycache__,thumbs.db,.gitignore}"
]
}
}
See File Patterns for detailed information on glob pattern syntax.
Files to copy to the app’s resources directory (outside ASAR):
{
"build" : {
"extraResources" : [
{
"from" : "assets/" ,
"to" : "." ,
"filter" : [ "**/*" ]
},
"LICENSE.txt" ,
"bin/helper"
]
}
}
Location in packaged app:
macOS: Contents/Resources/
Windows: resources/
Linux: resources/
Accessing in code:
import path from 'path'
import { app } from 'electron'
const resourcesPath = process . resourcesPath
const assetPath = path . join ( resourcesPath , 'assets' , 'icon.png' )
Files to copy to the app’s output directory (outside ASAR and resources):
{
"build" : {
"extraFiles" : [
{
"from" : "bin/${os}/" ,
"to" : "." ,
"filter" : [ "**/*" ]
},
"README.md"
]
}
}
Location in packaged app:
macOS: Contents/ (app contents root)
Windows: App directory root
Linux: App directory root
FileSet Configuration
Both extraResources and extraFiles support FileSet configuration:
package.json
electron-builder.yml
{
"build" : {
"extraResources" : [
{
"from" : "build/assets/" ,
"to" : "assets" ,
"filter" : [
"**/*" ,
"!**/*.map"
]
}
]
}
}
FileSet interface:
interface FileSet {
/**
* The source path relative to the project directory.
*/
from ?: string
/**
* The destination path relative to the app's resources/output directory.
*/
to ?: string
/**
* The glob patterns to filter files.
*/
filter ?: Array < string > | string
}
Application Directory Structure
Packaged App Structure
MyApp.app/
├── Contents/
│ ├── MacOS/
│ │ └── MyApp # Executable
│ ├── Resources/
│ │ ├── app.asar # Your application
│ │ ├── app.asar.unpacked/ # Unpacked files
│ │ └── ... # Extra resources
│ ├── Frameworks/ # Electron framework
│ └── Info.plist
MyApp/
├── MyApp.exe # Executable
├── resources/
│ ├── app.asar # Your application
│ ├── app.asar.unpacked/ # Unpacked files
│ └── ... # Extra resources
├── locales/
└── ... # Electron files
myapp/
├── myapp # Executable
├── resources/
│ ├── app.asar # Your application
│ ├── app.asar.unpacked/ # Unpacked files
│ └── ... # Extra resources
├── locales/
└── ... # Electron files
Optimizing Application Size
1. Remove Unnecessary Dependencies
Move development dependencies to devDependencies:
{
"dependencies" : {
"electron-store" : "^8.0.0"
},
"devDependencies" : {
"electron" : "^28.0.0" ,
"electron-builder" : "^24.0.0" ,
"webpack" : "^5.0.0"
}
}
2. Exclude Development Files
{
"build" : {
"files" : [
"**/*" ,
"!src${/*}" ,
"!**/*.ts" ,
"!**/*.map" ,
"!**/{.eslintrc,.prettierrc,tsconfig.json}" ,
"!**/node_modules/**/{test,__tests__,tests}${/*}"
]
}
}
3. Use Compression
{
"build" : {
"compression" : "maximum" ,
"asar" : true
}
}
Compression levels: store (no compression), normal (default), maximum
{
"build" : {
"removePackageScripts" : true ,
"removePackageKeywords" : true
}
}
Accessing Packaged Resources
From Main Process
import { app } from 'electron'
import path from 'path'
import fs from 'fs'
// App directory (inside asar)
const appPath = app . getAppPath ()
const configPath = path . join ( appPath , 'config' , 'settings.json' )
// Resources directory (outside asar)
const resourcesPath = process . resourcesPath
const assetPath = path . join ( resourcesPath , 'assets' , 'icon.png' )
// Read from asar
const config = fs . readFileSync ( configPath , 'utf8' )
// Read from resources
const icon = fs . readFileSync ( assetPath )
From Renderer Process
const path = require ( 'path' )
const fs = require ( 'fs' )
// Using preload script (recommended)
const { getResourcePath } = require ( 'electron' ). ipcRenderer
// Or direct access (if nodeIntegration is enabled)
const isDev = process . env . NODE_ENV === 'development'
const basePath = isDev
? process . cwd ()
: process . resourcesPath
const assetPath = path . join ( basePath , 'assets' , 'data.json' )
Build Hooks for File Processing
Use hooks to process files during the build:
electron-builder.config.js
export default {
// ... other config
hooks: {
onNodeModuleFile : async ( file ) => {
// Return true to force include, false to exclude
if ( file . endsWith ( '.d.ts' )) {
return false // Exclude TypeScript definition files
}
}
}
}
Development vs Production
Development Configuration
{
"build" : {
"asar" : false ,
"compression" : "store" ,
"directories" : {
"output" : "dist-dev"
}
}
}
Production Configuration
{
"build" : {
"asar" : true ,
"compression" : "maximum" ,
"directories" : {
"output" : "dist"
},
"electronFuses" : {
"enableEmbeddedAsarIntegrityValidation" : true ,
"onlyLoadAppFromAsar" : true
}
}
}