Publish Output Performance #1035

Open
opened 2026-01-29 16:56:03 +00:00 by claunia · 12 comments
Owner

Originally created by @AeonSake on GitHub (Dec 12, 2025).

I have a few questions regarding the publish output which I couldn't really find an answer to so far:

  • Why is the output so large? The .NET runtime should be around 80-100MB and the electron binary around 150MB. Yet my current output (from the example Blazor Web App project) is more than 500MB as compressed binary.
  • I think some content is also packaged twice. This can be observed either by unpacking the app.asar file (npx @electron/asar extract app.asar <dir>), or by setting asar to false in the electron-builder.json file. The archive content under app.asar/bin seems to exist twice?
  • Is there any way to reduce the bundle size of the electron package? I've seen some reports that claim they managed to reduce their electron apps to below 50MB (or even less in some cases). Is the node_modules directory even required?

Furthermore, the startup time from launching the app via the published .exe file seems rather large? Does it extract the content every time you open the app?

Originally created by @AeonSake on GitHub (Dec 12, 2025). I have a few questions regarding the publish output which I couldn't really find an answer to so far: - Why is the output so large? The .NET runtime should be around 80-100MB and the electron binary around 150MB. Yet my current output (from the example Blazor Web App project) is more than 500MB as compressed binary. - I _think_ some content is also packaged twice. This can be observed either by unpacking the `app.asar` file (`npx @electron/asar extract app.asar <dir>`), or by setting `asar` to `false` in the `electron-builder.json` file. The archive content under `app.asar/bin` seems to exist twice? - Is there any way to reduce the bundle size of the electron package? I've seen some reports that claim they managed to reduce their electron apps to [below 50MB](https://github.com/electron/electron/issues/2003) (or even less in some cases). Is the `node_modules` directory even required? Furthermore, the startup time from launching the app via the published .exe file seems rather large? Does it extract the content _every time_ you open the app?
claunia added the help wantedenhancement labels 2026-01-29 16:56:03 +00:00
Author
Owner

@FlorianRappl commented on GitHub (Dec 12, 2025):

Why is the output so large?

node_modules. I know the issue and I have proposed a solution (bundling) beforehand. I will most likely implement this soon (definitely before the v1).

I think some content is also packaged twice.

That can definitely be. I have observed something more drastic (recursive cascade), but that has been a bug and should have been solved. Nevertheless, I think its a possibility we need to look into.

Is there any way to reduce the bundle size of the electron package?

Yes - see above. Right now node_modules is required, but in the future that won't be the case any more.

Does it extract the content every time you open the app?

I don't think so, but the extraction part is not where most of the time is spend. In general exe files are slower if they are bigger. It's just that IIRC Windows reads them fully before running. Hence reducing the size will have beneficial initial load impact.

@FlorianRappl commented on GitHub (Dec 12, 2025): > Why is the output so large? `node_modules`. I know the issue and I have proposed a solution (bundling) beforehand. I will most likely implement this soon (definitely before the v1). > I think some content is also packaged twice. That can definitely be. I have observed something more drastic (recursive cascade), but that has been a bug and should have been solved. Nevertheless, I think its a possibility we need to look into. > Is there any way to reduce the bundle size of the electron package? Yes - see above. Right now `node_modules` is required, but in the future that won't be the case any more. > Does it extract the content every time you open the app? I don't think so, but the extraction part is not where most of the time is spend. In general exe files are slower if they are bigger. It's just that IIRC Windows reads them fully before running. Hence reducing the size will have beneficial initial load impact.
Author
Owner

@AeonSake commented on GitHub (Dec 12, 2025):

After more testing, I can now definitely say that the bin directory is duplicated:

  • One copy is at resources/app.asar/bin (or resources/app if asar is disabled), which is required to run
  • Another copy is at resources/bin as unpacked content; this can be deleted without affecting the app

I tested this in the following ways:

  • Running the app from within the unpacked directory (win-unpacked on Windows) while the second directory was renamed/deleted
  • Running the app from the compressed .exe file, inspecting the application via Task Manager to find the current temp folder, seeing that both folders definitely exist after the .exe is extracted

Removing the duplicate will already reduce the binary size by at least 100MB.

@AeonSake commented on GitHub (Dec 12, 2025): After more testing, I can now definitely say that the `bin` directory is duplicated: - One copy is at `resources/app.asar/bin` (or `resources/app` if `asar` is disabled), which is required to run - Another copy is at `resources/bin` as unpacked content; this can be deleted without affecting the app I tested this in the following ways: - Running the app from within the `unpacked` directory (`win-unpacked` on Windows) while the second directory was renamed/deleted - Running the app from the compressed .exe file, inspecting the application via Task Manager to find the current temp folder, seeing that both folders definitely exist after the .exe is extracted Removing the duplicate will already reduce the binary size by at least 100MB.
Author
Owner

@AeonSake commented on GitHub (Dec 12, 2025):

Also regarding the unpacking, from the testing above, it really seems the app is unpacked every time the .exe is called. The temp directory is then deleted after the app is closed.

@AeonSake commented on GitHub (Dec 12, 2025): Also regarding the unpacking, from the testing above, it really seems the app is unpacked every time the .exe is called. The temp directory is then deleted after the app is closed.
Author
Owner

@AeonSake commented on GitHub (Dec 12, 2025):

For anyone that is concerned about bundle size, adding <CompressionEnabled>false</CompressionEnabled> to the project configuration will disable the brotli and gz compression of static web assets that is turned on by default since net9.0. Compression serves no real benefit for local apps and unnecessarily duplicates static files in your wwwroot directory (even if they are smaller after compression).

Adding "electronLanguages": [ "en-US" ] to electron-builder.json will remove all other locales from the output. Useful if you only use the electron shell as host and not show any other UI (or only target a select few locales).

@AeonSake commented on GitHub (Dec 12, 2025): For anyone that is concerned about bundle size, adding `<CompressionEnabled>false</CompressionEnabled>` to the project configuration will disable the `brotli` and `gz` compression of static web assets that is turned on by default since `net9.0`. Compression serves no real benefit for local apps and unnecessarily duplicates static files in your `wwwroot` directory (even if they are smaller after compression). Adding `"electronLanguages": [ "en-US" ]` to `electron-builder.json` will remove all other locales from the output. Useful if you only use the electron shell as host and not show any other UI (or only target a select few locales).
Author
Owner

@softworkz commented on GitHub (Dec 12, 2025):

Why is the output so large?

node_modules. I know the issue and I have proposed a solution (bundling) beforehand. I will most likely implement this soon (definitely before the v1).

I don't see this. My app.asar file is <7 MB

Image

One copy is at resources/app.asar/bin (or resources/app if asar is disabled), which is required to run
Another copy is at resources/bin as unpacked content; this can be deleted without affecting the app

Really?

resources/bin is actually the place where the .net application lives. I've never seen it in resources/app.asar/bin

Also regarding the unpacking, from the testing above, it really seems the app is unpacked every time the .exe is called. The temp directory is then deleted after the app is closed.

This is only ONE specific kind of output. There are many others available. Start with .zip for further investigations.

Though! I should note that everything I say is based on Linux targets - but there, it's true for all (deb, rpm, pac, tar.gz, AppImage)

@softworkz commented on GitHub (Dec 12, 2025): > > Why is the output so large? > > `node_modules`. I know the issue and I have proposed a solution (bundling) beforehand. I will most likely implement this soon (definitely before the v1). I don't see this. My app.asar file is <7 MB <img width="806" height="224" alt="Image" src="https://github.com/user-attachments/assets/86d80313-dfef-4d0a-a082-98f64624671f" /> > One copy is at resources/app.asar/bin (or resources/app if asar is disabled), which is required to run > Another copy is at resources/bin as unpacked content; this can be deleted without affecting the app Really? `resources/bin` is actually the place where the .net application lives. I've never seen it in `resources/app.asar/bin` > Also regarding the unpacking, from the testing above, it really seems the app is unpacked every time the .exe is called. The temp directory is then deleted after the app is closed. This is only ONE specific kind of output. There are many others available. Start with `.zip` for further investigations. Though! I should note that everything I say is based on Linux targets - but there, it's true for all (deb, rpm, pac, tar.gz, AppImage)
Author
Owner

@softworkz commented on GitHub (Dec 12, 2025):

Also, don't look at the xxx-unpacked folder. That's not a regular output.

@softworkz commented on GitHub (Dec 12, 2025): Also, don't look at the `xxx-unpacked` folder. That's not a regular output.
Author
Owner

@AeonSake commented on GitHub (Dec 12, 2025):

Really?

Well, yes.

This is only ONE specific kind of output. There are many others available. Start with .zip for further investigations.

I'm currently using portable for the Windows build. I also tried zip as target, with the same result. app.asar is ~120MB in size, and next to it is the bin directory, also with roughly 120MB. Extracting the app.asar file reveals that the bin directory also exists within it.

Also, don't look at the xxx-unpacked folder. That's not a regular output.

I get that, but the extracted content mirrors the content of the win-unpacked directory. At least on Windows.

@AeonSake commented on GitHub (Dec 12, 2025): > Really? Well, yes. > This is only ONE specific kind of output. There are many others available. Start with .zip for further investigations. I'm currently using `portable` for the Windows build. I also tried `zip` as target, with the same result. `app.asar` is ~120MB in size, and next to it is the `bin` directory, also with roughly 120MB. Extracting the `app.asar` file reveals that the `bin` directory also exists within it. > Also, don't look at the `xxx-unpacked` folder. That's not a regular output. I get that, but the extracted content mirrors the content of the `win-unpacked` directory. At least on Windows.
Author
Owner

@softworkz commented on GitHub (Dec 12, 2025):

Can you show your electron builder json?

@softworkz commented on GitHub (Dec 12, 2025): Can you show your electron builder json?
Author
Owner

@AeonSake commented on GitHub (Dec 12, 2025):

Pretty much the default:

{
    "$schema": "https://raw.githubusercontent.com/electron-userland/electron-builder/refs/heads/master/packages/app-builder-lib/scheme.json",
    "electronLanguages": [ "en-US" ],
    "compression": "maximum",
    "linux": {
        "target": [ "AppImage", "snap", "tar.xz" ],
        "executableArgs": [ "--no-sandbox" ],
        "artifactName": "${name}-${arch}-${version}.${ext}"
    },
    "mac": {
        "target": [ "dmg" ]
    },
    "win": {
        "target": [ "portable" ]
    }
}
@AeonSake commented on GitHub (Dec 12, 2025): Pretty much the default: ```json { "$schema": "https://raw.githubusercontent.com/electron-userland/electron-builder/refs/heads/master/packages/app-builder-lib/scheme.json", "electronLanguages": [ "en-US" ], "compression": "maximum", "linux": { "target": [ "AppImage", "snap", "tar.xz" ], "executableArgs": [ "--no-sandbox" ], "artifactName": "${name}-${arch}-${version}.${ext}" }, "mac": { "target": [ "dmg" ] }, "win": { "target": [ "portable" ] } } ```
Author
Owner

@softworkz commented on GitHub (Dec 12, 2025):

Okay, I can confirm this duplication is happening - on Windows - not on Linux.

@softworkz commented on GitHub (Dec 12, 2025): Okay, I can confirm this duplication is happening - on Windows - not on Linux.
Author
Owner

@hillin commented on GitHub (Jan 21, 2026):

I also find it helps a lot to clean up the bin folder before publishing.

@hillin commented on GitHub (Jan 21, 2026): I also find it helps a lot to clean up the bin folder before publishing.
Author
Owner

@softworkz commented on GitHub (Jan 21, 2026):

I also find it helps a lot to clean up the bin folder before publishing.

The problem with Clean is that it only cleans the bin/xxx output for the current configuration, and doesn't always remove everything. Also it doesn't clean the obj/xxx trees - when something has gone wrong there, it doesn't help either.

What I'm using all the time is a VS extension named "Super Clean" (there are multiple similar ones, but that's the best). Other than the MSBuild "Clean" target, it also doesn't clean dependencies but just the project(s) you have selected (before right-clickl >> Super Clean).

In the context of Electron.NET, it often shows a message about not being able to clean something in node_modules (not the one in the project but the one in the build subtree). But the 2nd attempt usually succeeds. And when it succeeds (no message shown) you can be 100% sure that all bin and obj folders have been emptied (that's why I don't recommend the other extensions of that kind).

@softworkz commented on GitHub (Jan 21, 2026): > I also find it helps a lot to clean up the bin folder before publishing. The problem with Clean is that it only cleans the `bin/xxx` output for the current configuration, and doesn't always remove everything. Also it doesn't clean the `obj/xxx` trees - when something has gone wrong there, it doesn't help either. What I'm using all the time is a VS extension named "Super Clean" (there are multiple similar ones, but that's the best). Other than the MSBuild "Clean" target, it also doesn't clean dependencies but just the project(s) you have selected (before right-clickl >> Super Clean). In the context of Electron.NET, it often shows a message about not being able to clean something in `node_modules` (not the one in the project but the one in the build subtree). But the 2nd attempt usually succeeds. And when it succeeds (no message shown) you can be 100% sure that all bin and obj folders have been emptied (that's why I don't recommend the other extensions of that kind).
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/Electron.NET#1035