cx_Freeze
cx_Freeze is a Python application freezer that packages a Python program and its dependencies into a self-contained directory or executable. It targets Windows, macOS, and Linux from the same configuration and ships native commands for producing each platform’s preferred installer format. Recent releases add experimental support for freezing free-threaded CPython builds. Install it with uv tool install cx_Freeze or pipx install cx_Freeze.
When to Use cx_Freeze
cx_Freeze fits projects whose deliverable is an installer rather than a raw binary. Its bdist_msi, bdist_dmg, bdist_appimage, and bdist_deb commands produce platform-native installers in one step, without a second packaging tool like WiX, dmgbuild, or dpkg-deb. Most other freezers stop at a folder or single executable and leave installer generation to the user.
For a single static binary with heavy optimization, Nuitka compiles Python to C and produces smaller, faster executables. For the largest plugin and hook ecosystem covering obscure scientific libraries, PyInstaller has the deepest catalog. cx_Freeze sits between them: fewer hooks than PyInstaller, no C compilation like Nuitka, but the only one of the three that treats installer generation as a first-class feature.
Key Features
- Native installer commands:
bdist_msion Windows,bdist_dmgandbdist_macon macOS,bdist_appimage,bdist_deb, andbdist_rpmon Linux - Cross-platform from one config: The same
[tool.cxfreeze]table in pyproject.toml drives freezes on every supported OS - Free-threaded Python support: Experimental support for freezing free-threaded CPython (3.13t) builds
- Dependency discovery: A static module finder walks the program’s imports and copies the required pure-Python modules, extension modules, and shared libraries into the output
- Explicit include/exclude lists:
includes,include_files,excludes,packages, andzip_include_packagesgive direct control over what ends up in the frozen build - Hooks for common libraries: Ships hooks for PySide6, PyQt6, numpy, scipy, matplotlib, pandas, PyTorch, tkinter, and others that need special handling for data files or dynamic imports
- Multiple configuration formats: Reads
pyproject.toml,setup.py,setup.cfg, or CLI flags; acxfreeze-quickstartcommand generates a starter script
How cx_Freeze Works
cx_Freeze runs the project’s setup, walks the import graph starting from each entry-point script, and copies every detected module into a build directory alongside a bootstrap executable. The bootstrap executable embeds a C launcher that initializes CPython using PEP 587 Python Initialization Configuration and then runs the frozen script.
The output is a folder containing the launcher, a shared python3x.dll/libpython3.x.so/Python binary, a zip file of pure-Python modules, and any extension modules or data files the application needs. Running the launcher on a machine without Python installed loads the bundled interpreter and executes the frozen code with no additional install step.
Configuration lives in [tool.cxfreeze] in pyproject.toml:
[project]
name = "guifoo"
version = "0.1"
[tool.cxfreeze]
executables = [
{script = "guifoo.py", base = "gui"}
]
[tool.cxfreeze.build_exe]
excludes = ["tkinter", "unittest"]
zip_include_packages = ["encodings", "PySide6", "shiboken6"]Running cxfreeze build_exe then produces the frozen folder, and cxfreeze bdist_msi (or bdist_dmg, bdist_appimage, bdist_deb) wraps that folder in a native installer.
Installer Formats
cx_Freeze provides six bdist_* commands that other freezers leave to separate tooling:
| Command | Output | Platform |
|---|---|---|
bdist_msi |
Windows Installer .msi |
Windows |
bdist_mac |
macOS .app bundle |
macOS |
bdist_dmg |
macOS disk image .dmg |
macOS |
bdist_appimage |
Linux AppImage (single-file executable) | Linux |
bdist_deb |
Debian/Ubuntu .deb package |
Linux |
bdist_rpm |
Red Hat .rpm package |
Linux |
On Python 3.13 and 3.14, bdist_msi depends on the python-msilib backport (msilib was removed from the standard library in 3.13), pulled in automatically as a dependency.
Package Split
Recent releases split the project into two PyPI packages: cx_Freeze (the user-facing CLI, setup-script API, and hooks) and freeze-core (the platform-specific freezing internals). Installing cx_Freeze still pulls in freeze-core automatically. The split let the project add free-threaded Python support without churning the main package.
Pros
- Only mainstream Python freezer with first-class
bdist_msi,bdist_dmg,bdist_appimage, andbdist_debcommands - Configuration lives in
pyproject.tomlunder[tool.cxfreeze], matching the standard Python project layout - Supports recent CPython releases, with experimental free-threaded (3.13t) support
- Active maintenance by Marcelo Duarte with regular releases
- Hooks for GUI and scientific packages (PySide6, PyQt6, numpy, scipy, matplotlib, pandas, PyTorch) are maintained in-tree
Cons
- Smaller hook ecosystem than PyInstaller; obscure libraries may need manual
includes/include_filesentries - No compilation step: the bundle carries the full Python interpreter and source bytecode, so output size tracks the source plus CPython (Nuitka’s compile-to-C output can be smaller and faster)
- Antivirus false positives happen to any freezer that bundles a Python interpreter; code signing with a real certificate is the usual fix
bdist_dmgneeds a macOS host,bdist_msineeds Windows, andbdist_deb/bdist_appimageneed Linux: cross-building installers across OSes is not supported- Smaller community and fewer Stack Overflow answers than PyInstaller when something goes wrong
Learn More
- cx_Freeze documentation
- cx_Freeze GitHub repository
- cx_Freeze on PyPI
- freeze-core on PyPI
- PyInstaller is the bundler alternative with the largest hook ecosystem
- Nuitka compiles Python to C instead of freezing bytecode
- Briefcase targets mobile and also produces native installers
- How do I ship a Python application to end users? frames when installers are the right deliverable
- pyproject.toml
- What is a Python application?