Mastering the Python ZipApp Module
Python's zipapp module bundles a directory of Python code into a single executable .pyz file. Learn how to create, run, and distribute Python apps without a full installer.
zipapp lets you package a Python application into a single .pyz file that runs with a plain python command. No installer, no virtualenv setup, no external build tools — just python myapp.pyz. It's the lightest-weight way to distribute a command-line tool or utility script.
How It Works
Python can execute a ZIP archive that contains a __main__.py as if it were a directory. zipapp formalizes this: it wraps your source directory into a ZIP and optionally embeds a shebang so users can run it directly.
Requirement: Your application directory must contain a __main__.py file — this is the entry point Python calls when you run python myapp.pyz.
Creating an Executable Archive
Project layout:
myapp/
├── __main__.py
└── utils.py
Build from the command line:
python -m zipapp myapp -o myapp.pyz
Run it:
python myapp.pyz
Specifying an Entry Point
Instead of relying on __main__.py, you can specify the entry point with -m:
python -m zipapp myapp -m "myapp:main"
This calls the main() function inside myapp/__init__.py (or any module named myapp). Useful when your code structure doesn't have a top-level __main__.py.
Specifying the Python Interpreter (Shebang)
Add a shebang with -p to make the archive directly executable on Unix systems:
python -m zipapp myapp -p "/usr/bin/env python3" -o myapp.pyz
chmod +x myapp.pyz
./myapp.pyz
The shebang is embedded in the file before the ZIP data, making myapp.pyz a self-contained executable.
Creating Archives Programmatically
import zipapp
zipapp.create_archive(
source="myapp",
target="myapp.pyz",
interpreter="/usr/bin/env python3",
main="myapp:main",
compressed=True, # Python 3.7+: compress the archive
)
Including Third-Party Dependencies
zipapp doesn't bundle dependencies automatically. Vendor them into your project directory first:
# Install dependencies into a subdirectory
pip install requests --target myapp/vendor
# Update sys.path in __main__.py to include vendor/
myapp/__main__.py:
import sys
import os
# Add vendor directory to path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "vendor"))
import requests # now available
# ... rest of your app ...
Then build normally:
python -m zipapp myapp -o myapp.pyz
zipapp vs PyInstaller
| | zipapp | PyInstaller | |---|---|---| | Output size | Small (source only) | Large (bundles Python runtime) | | Python required | Yes, on target machine | No | | Setup complexity | Zero | Moderate | | Best for | Utilities, internal tools | End-user apps without Python |
Use zipapp when distributing to developers or systems where Python is already installed. Use PyInstaller when your users won't have Python.
Conclusion
zipapp is the simplest way to ship a Python command-line tool as a single file. It requires no build system and works with any Python installation. For applications with complex dependencies or users who don't have Python, look at PyInstaller or shiv instead.