pyinstaller
Bundle Python applications into stand-alone executables
TLDR
SYNOPSIS
pyinstaller [options] script [script ...] | specfile
DESCRIPTION
pyinstaller packages a Python program together with its interpreter and every imported module into a self-contained bundle that runs on machines without Python installed. It works by tracing imports starting from the entry script, copying the resulting set of modules, shared libraries, and data files into a build directory, and producing either a one-folder layout (--onedir, default) or a single executable file (--onefile) extracted to a temporary location at runtime.The build runs in two phases. First, PyInstaller writes a _script_.spec file that captures the script paths, options, and analyzer hints for the project. Second, it processes that spec file to assemble the actual bundle in dist/. Editing the spec file directly is the recommended way to handle non-trivial projects, since spec files are plain Python and let you control hooks, binaries, data trees, and runtime options that the CLI flags cannot fully express.PyInstaller is cross-platform but not cross-compiling: a bundle built on Linux runs on Linux, a Windows bundle must be built on Windows, and a macOS bundle on macOS. It supports CPython 3.8 and later, and integrates hooks for hundreds of popular packages (NumPy, PyQt, Django, TensorFlow) so they bundle correctly out of the box.
PARAMETERS
-F, --onefile
Produce a single executable file. At launch the binary self-extracts into a temporary directory and runs from there.-D, --onedir
Produce a folder containing the executable and its dependencies. This is the default and the fastest to start.-n NAME, --name NAME
Assign a name to the bundled app and to the generated .spec file. Defaults to the script's base name.-w, --windowed, --noconsole
On Windows and macOS, do not attach a console window. Use for GUI applications.-c, --console, --nowindowed
Force a console window (the default on most platforms).--icon FILE
Apply a custom icon: .ico on Windows, .icns on macOS. Use NONE to suppress the default.--add-data SOURCE:DEST
Bundle additional data files or directories under DEST inside the bundle. Use ; instead of : as the separator on Windows.--add-binary SOURCE:DEST
Same as --add-data but for shared libraries that need binary handling.--hidden-import MODULE
Force a module to be included even when the static analyzer cannot see the import (typical for plugin systems or dynamic imports).-p DIR, --paths DIR
Prepend DIR to the module search path, like adding to PYTHONPATH for analysis only.--clean
Wipe PyInstaller's cache and temporary build artifacts before starting.-y, --noconfirm
Replace the output directory without asking for confirmation.--log-level LEVEL
Set verbosity: TRACE, DEBUG, INFO (default), WARN, ERROR, FATAL.--specpath DIR
Place the generated .spec file in DIR instead of the current directory.--distpath DIR, --workpath DIR
Override the dist/ and build/ output directories.--upx-dir DIR
Use the UPX executable packer from DIR to compress the bundled binaries.
SPEC FILE WORKFLOW
The first invocation generates myscript.spec, a Python file describing the Analysis, PYZ, EXE, and COLLECT steps. For anything beyond a trivial script, edit the spec to add data files, runtime hooks, version info, or splash screens, then rebuild with:
CAVEATS
Cross-compilation is not supported. Build on the target operating system (and ideally the oldest supported version) to maximize compatibility.Antivirus false positives are common with --onefile binaries on Windows, because the self-extracting stub pattern resembles malware packers. Code-signing the executable usually resolves this.Dynamic imports break analysis. Plugins loaded via importlib, \_\_import\_\_, or string-based discovery must be declared with --hidden-import or a custom hook, or they will be missing at runtime.Startup is slower with --onefile because the runtime self-extracts to a temporary directory on every launch. Prefer --onedir for latency-sensitive applications.Bundles are large. A minimal "hello world" produces a tens-of-megabytes binary because the entire CPython runtime is embedded. Use --exclude-module to drop unused stdlib modules.
HISTORY
PyInstaller began life in 2005 as a fork of Gordon McMillan's Installer project, with the goal of producing portable Python executables on Linux, Windows, and macOS from a single codebase. The 2.x and 3.x series consolidated platform support and added the spec-file workflow; PyInstaller 4 (2020) dropped Python 2; PyInstaller 5 (2022) reworked bootloader handling; PyInstaller 6 (2023) introduced the SOURCE:DEST syntax for --add-data that replaced the older platform-specific separators.
SEE ALSO
python(1)
