What a spec file does and when to use it
A spec file is a Python script that tells PyInstaller exactly how to bundle your program into a standalone executable. Instead of typing a long command with dozens of options every time you build, you write those settings once in a spec file, then run PyInstaller against that file. PyInstaller generates the spec file automatically the first time you run it, but you edit it when you need to add hidden imports, change the icon, exclude certain modules, or control other build details.
You use a spec file when your program needs the same build settings repeatedly, when you're working in a team and want consistent builds, or when your program imports modules in ways PyInstaller can't detect on its own. If you're building a simple script once and never touching it again, the command line is faster. If you're iterating or sharing the build process, the spec file saves time and prevents mistakes.
Key Takeaways
- PyInstaller creates a spec file automatically when you first run it, and you edit this file to control how your executable is built.
- Run PyInstaller against the spec file using pyinstaller yourfile.spec from the command line in the directory where the spec file sits.
- Common edits to the spec file include adding hidden imports that PyInstaller missed, changing the executable icon, and excluding modules you don't need.
- The spec file is a normal Python file that you can version control, share with teammates, and edit in any text editor.
- After you run PyInstaller with the spec file, your executable appears in the dist folder inside your project directory.
Generate your first spec file
Open a terminal or command prompt in the folder where your Python script lives. Run PyInstaller once with your script name to create the spec file:
pyinstaller yourscript.py
PyInstaller scans your code, creates three new folders (build, dist, and __pycache__), and writes a file called yourscript.spec in your project directory. This spec file is a Python script that contains all the settings PyInstaller used. You can now edit this file to change how the next build behaves, and you never have to type that long command again — just run pyinstaller yourscript.spec instead.
If you want to create a spec file without actually building the executable yet, use the --specpath flag to tell PyInstaller where to write it, or use pyi-makespec yourscript.py to generate the spec file only.
Edit the spec file to add hidden imports
The most common reason to edit a spec file is to add hidden imports — modules that your code uses but PyInstaller didn't detect. This happens when you import a module dynamically (using __import__() or importlib) instead of a regular import statement at the top of your file. PyInstaller's static analysis can't see these imports, so it leaves them out of the executable, and your program crashes when it tries to load them.
Open the spec file in any text editor. Find the line that starts with a = Analysis(. Inside that block, look for the parameter called hiddenimports. It looks like this:
hiddenimports=[],
Add the names of the modules you need as strings in that list. If your code dynamically imports requests and numpy, change it to:
hiddenimports=['requests', 'numpy'],
Save the file and run pyinstaller yourscript.spec. The next build will include those modules.
Change the executable icon and other visual settings
To add a custom icon to your executable, find the line that starts with exe = EXE( in the spec file. Look for the parameter called icon. By default it's empty or set to None. Point it to your icon file:
icon='path/to/youricon.ico',
Use a .ico file on Windows, a .icns file on macOS, or a .png file on Linux. The path can be relative (from the spec file's location) or absolute. If you don't have an icon file yet, you can convert an image using an online tool or use Python's PIL library to create one.
Other common settings in the EXE block include console=False to hide the command window on Windows, and target_arch to specify 32-bit or 64-bit. The spec file is heavily commented, so scroll through it to see what each parameter does.
Exclude modules you don't need
Sometimes PyInstaller includes modules your program doesn't actually use, making the executable larger than necessary. Find the Analysis block and look for the excludedimports parameter:
excludedimports=[],
Add module names as strings to exclude them from the build. For example, if PyInstaller included matplotlib but your program doesn't use it:
excludedimports=['matplotlib'],
This is less common than adding hidden imports, but it's useful when you're trying to shrink the executable size or when a module causes conflicts during bundling. Test your executable after excluding modules to make sure it still runs.
Run the spec file and find your executable
Once you've edited the spec file the way you want it, build the executable by running:
pyinstaller yourscript.spec
PyInstaller reads the spec file, bundles your code and all its dependencies, and writes the result to the dist folder. On Windows, you'll find yourscript.exe. On macOS, you'll find yourscript.app (a folder that looks like a single application). On Linux, you'll find an executable file with no extension.
The first build takes longer because PyInstaller has to analyze everything. Subsequent builds are faster because PyInstaller caches the analysis. If you change your Python code, run the spec file again to rebuild. If you only change settings in the spec file, you can rebuild without changing your Python code.
Version control and sharing your spec file
Commit the spec file to version control (Git, Subversion, or whatever your team uses). The spec file is a plain text Python script, so it diffs cleanly and teammates can see exactly what changed. Don't commit the build and dist folders — they're generated output and will be different on every machine.
When a teammate pulls your code, they run the same command to build: pyinstaller yourscript.spec. They get the same executable settings you used, without having to remember a dozen command-line flags. This is especially useful for CI/CD pipelines, where you want builds to be identical every time.
If you need different builds for different purposes (one with the console window, one without; one for Windows, one for macOS), create separate spec files: yourscript-console.spec and yourscript-gui.spec. Each one can have its own settings, and you run whichever one you need.
Frequently Asked Questions
What if I edit my Python code — do I need to regenerate the spec file?
No. The spec file tells PyInstaller how to build, not what to build. Edit your Python code normally, then run pyinstaller yourscript.spec again. PyInstaller will re-analyze your updated code and create a new executable with the same settings you specified in the spec file.
Can I use the same spec file on Windows and macOS?
Yes, but with caveats. The spec file itself is platform-independent, but some settings (like icon format and console window behavior) are platform-specific. If you're building for multiple platforms, test the executable on each one. For large projects, it's common to have one spec file per platform or to use conditional logic inside the spec file to change settings based on the operating system.
Where do I put the spec file in my project?
Put it in the root of your project, next to your main Python script. PyInstaller looks for imports relative to the spec file's location, so keeping it at the top level makes paths simpler. If you have multiple spec files, you can organize them in a build or specs subfolder, but then you'll need to run PyInstaller from that folder or use the full path to the spec file.
How do I know which modules are hidden imports?
Run your executable and watch for import errors. If it crashes with ModuleNotFoundError: No module named 'something', that's a hidden import. Add it to the spec file and rebuild. You can also use tools like pipdeptree or read your code to find dynamic imports, but the trial-and-error approach is often fastest for small projects.
Can I edit the spec file while PyInstaller is running?
No. Close any running build, edit the spec file, save it, then run PyInstaller again. If you try to edit while a build is in progress, you'll get file-locking errors or the changes won't take effect.