2

I would like to reduce the volume of my pyinstaller generated exe that I have to deploy every time.

I create my app using pyinstaller. when I use the onefile flag I get a ~750MB exe file. Without the onefile flag, the exe is ~50MB and the _internal folder ~1.6GB (650MB when as zipped). I cannot remove dependencies to reduce the volume.

Is it possible to direct the exe to take the _internal folder from a specified location (for example: C:\Program Files\MyAppDeps v3_internal) such that I can deploy the _internal folder only once in a while (~once per quarter, when there is a new 3rd party dependency) and then distribute only the small exe file every time?

Users cannot copy the _internal/exe each time to the same directory. Users cannot create symbolic links.

I want to do this because I update my app very frequently (several times per week) and deploy to machines that are not connected to the any network making the distribution process long and difficult, reducing the distribution volume will improve productivity greatly.

mkrieger1
24.2k7 gold badges69 silver badges85 bronze badges
asked Sep 15, 2025 at 19:07
11
  • this way you could install full Python only once and you wouldn't have to use PyInstaller at all Commented Sep 15, 2025 at 19:27
  • the environment to create the exe is 3.6GB, so that is not an option. the reduced env that PyInstaller generates is much better (1.6GB) Commented Sep 15, 2025 at 19:37
  • 1
    Why can't you use the 50MB exe and let users replace it but let them keep the 650MB _internal folder? Commented Sep 15, 2025 at 19:42
  • maybe first you should check if all elements in 3.6GB you really need. And after installing Python (only once) later you have to replace only few MB with changes. Python wasn't created to make .exe file so tools like PyInstaller may always makes problems. Commented Sep 15, 2025 at 20:05
  • @mkrieger1 the users are haev extremely low technical level (and are lazy), they simply won't do it Commented Sep 15, 2025 at 21:10

4 Answers 4

0
+50

My assumptions

I am answering this question without a clear understanding of your deployment method, but I'll assume that:

  • Your users get the update either by manually downloading the executable, or the executable updates itself using some kind of remote index.
  • I also assume you have access to some kind of index/repository (I may be using the wrong word) from which people in your organization can download the software (but may require technical expertise) . In any case I hope this answer is useful to you and anyone else in the same predicament.

Splitting the exe from the data.

As you mention in your question, it seems wise to separate the internal data from the program itself, and ideally work with 50MB executables, and a compressed 650MB internal data zip.

I would advise that when your executable runs for the first time: you check the existence of your internal data at a predefined location such as C:\Program Files\MyAppDeps v3_internal (as you pointed out in your question). If this data does not exist it is installed from an index to that specified location. Of course, you add version-checking logic that ensures the existing data is up to date, and if not, you let the use know they should update the data using your application when appropriate.

You could also have your executable check if it is up to date with version on the index and follow the same logic as above.

I hope this was useful, please let me know if I should expand on this solution.

answered Oct 1, 2025 at 21:24
Sign up to request clarification or add additional context in comments.

1 Comment

thank you for the reply, unfortunately, the exe has to "start itself" before running any of my code. Since some of the dll's required (python dll itself actually) is in the data folder (_internal) it cannot even start and I get an error: '[PYI-29216:DEBUG] DYLIB: loading Python DLL: C:\...\v1_internal\python38.dll [PYI-29216:ERROR] Failed to load Python DLL 'C:\...\v1_internal\python38.dll'. LoadLibrary: The specified module could not be found.'
0

I found a solution for this problem. Instead of a symbolic link, use a Junction: mklink src dst /J
Unlike a symbolic link, a junction doesn't require elevated permissions to create so I can run it on the customer station. I wrapped this in a .bat file to run the program. The only downside is that the users will have to get used to running a .bat file instead of an .exe

mklink "%~dp0bin\_internal" "C:\installation_dir\bin\_internal" /J
call "%~dp0bin\my_app.exe"`
answered Oct 9, 2025 at 10:07

1 Comment

Just seeing this now: If I understand correctly, you have a bat file that installs the internal data and exe separately, can install a new exe is necessary and then runs the exe?
-1

Approach 1: Python path manipulation

Put your third party libraries in a known location. In your program startup, before importing libraries, run something like this:

import sys
sys.path.append('C:\\path\\to\\packages')

Then tell PyInstaller to ignore all those dependencies.

Approach 2: Use a different deployment approach

If having the PyInstaller exe is not a requirement, there would be various possible ways to deploy third party libraries and Python itself, separately from your app code. If you haven't already, check out uv with its uv tool install command that might be able to meet your needs.

answered Sep 16, 2025 at 0:01

2 Comments

approach 1 didn't work for me, got an error Traceback (most recent call last): File "C:\envs\***\Lib\site-packages\PyInstaller\hooks\rthooks\pyi_rth_pkgutil.py", line 63, in <module> _pyi_rthook() File "C:\envs\***\Lib\site-packages\PyInstaller\hooks\rthooks\pyi_rth_pkgutil.py", line 58, in _pyi_rthook pyimod02_importers.PyiFrozenImporter, AttributeError: module 'pyimod02_importers' has no attribute 'PyiFrozenImporter'
PyInstaller is probably doing weird stuff with the import system, so that approach might be harder than I thought.
-1

Then you should first built an installer
Approach:
The installer doesn't need to use you're env since it only downloads your executable and resources while being lightweight at the same time
- on launch the installer checks directory if they is a old version it just proceed to upgrade it without redownloading it all over (you'll need to index changes between versions so the installer only download files it needs)
- but if nothing is present in directory it start a new installation from the most recent upgrade
the tradeoffs are indexing changes per upgrades and maintaining a server from which you're installer can download from

The installer becomes the only things a users needs to upgrade you're app and their can upgrade to a newer installer later or use the same to upgrade app so it works out well and users won't have to copy anything just download and run

answered Oct 2, 2025 at 23:40

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.