Skip to content

PyInstaller

PyInstaller is a Python application bundler that freezes a Python program, the CPython interpreter it was built against, and every imported dependency into a single distributable. The output runs on end-user machines without a pre-installed Python interpreter and without a virtual environment. PyInstaller supports CPython on macOS, Linux, and Windows; there is no iOS, Android, or tvOS target. Install it with uv tool install pyinstaller or pipx install pyinstaller.

Key Features

  • One-folder bundles via --onedir and self-extracting single-file executables via --onefile
  • Hook system that declares hidden imports, data files, and runtime patches for third-party packages
  • Community hook repository (pyinstaller-hooks-contrib) installed alongside PyInstaller, covering packages such as NumPy, SciPy, PyQt, and Matplotlib
  • Spec file workflow for declarative builds (pyinstaller my.spec) in addition to CLI flags
  • --exclude-module flag for trimming unused transitive dependencies out of a bundle
  • Optional UPX compression for smaller executables

Build Process

A PyInstaller spec file orchestrates four stages: Analysis walks the entry-point script’s imports to produce a dependency graph and applies hooks for packages that need special handling. PYZ compiles pure-Python modules to bytecode and packs them into a ZlibArchive. EXE concatenates the PYZ, extension modules, shared libraries, and data files (wrapped internally in a PKG CArchive) onto a precompiled native bootloader and writes the executable. COLLECT copies the executable plus any external dependencies into the output folder for one-folder builds; one-file builds skip COLLECT and emit the self-extracting executable directly.

The bootloader is a small C program that, at runtime, extracts or memory-maps the PYZ archive, initializes the embedded Python interpreter, and executes the frozen entry point. PyInstaller ships precompiled bootloaders for supported platforms; the bootloader source is available in the project repository for teams that need to recompile it.

Distribution Modes

The --onedir mode produces a folder containing the executable, the Python interpreter shared library, and every dependency file. Startup is fast because no archive extraction happens at launch.

The --onefile mode concatenates the same contents into a self-extracting archive. At launch, the bootloader extracts the payload into a temporary directory, runs the program, and cleans up on exit. Startup is slower than --onedir and the temporary directory can be inspected by anyone with filesystem access.

Pros

  • Extensive third-party hook coverage via pyinstaller-hooks-contrib, reducing manual work for packages with C extensions or data files
  • Cross-platform support across macOS, Linux, and Windows from the same spec file
  • Active maintenance with regular releases
  • Licensed GPLv2-or-later with a documented exception that permits distributing bundled applications under any license, including proprietary ones
  • Works with any CPython installation; does not require a specific build backend or project layout

Cons

  • Bundle sizes for ML workloads are large. Community reports for PyTorch and TensorFlow --onefile executables range from roughly 500 MB to 1.5 GB before manual --exclude-module tuning.
  • No built-in code signing. Windows distributions require signtool with a code-signing certificate; macOS distributions require codesign and notarytool with an Apple Developer ID.
  • Antivirus false positives are a known issue. PyInstaller documents rebuilding the bootloader from source and signing the result as a mitigation, which requires a C toolchain on each target platform.
  • --onefile startup is slower than --onedir because the payload is extracted on every launch.
  • No mobile target support. Projects shipping to iOS or Android need a different tool such as Briefcase.
  • Bundles the interpreter at build time, so the build machine’s OS and architecture must match the target. Cross-compilation is not supported.

Alternatives

Nuitka compiles Python source to C and produces a native binary instead of freezing bytecode. cx_Freeze provides a lighter-weight freezing workflow for pure-Python programs without heavy third-party dependencies. Briefcase targets native installer formats and app stores on desktop and mobile platforms.

auto-py-to-exe is a third-party GUI wrapper around PyInstaller. It exposes the PyInstaller CLI flags as form inputs and is maintained independently of PyInstaller itself.

Learn More

Last updated on