Python Shiv Zipapp — Core Concepts
What Shiv is
Shiv is a command-line tool from LinkedIn that creates self-contained Python applications using the zipapp format (PEP 441). It bundles your code and dependencies into a single .pyz file with a shebang line, making it directly executable on Unix systems.
The key difference from similar tools: Shiv fully extracts itself on first run rather than importing from a zip archive. This makes it more compatible with packages that expect to live on disk — compiled extensions, data files, and packages using __file__ all work without special handling.
How to build a Shiv
# Install shiv
pip install shiv
# Bundle a project with its dependencies
shiv -c myapp -o myapp.pyz myapp
# Bundle from requirements
shiv -r requirements.txt -e myapp.main:run -o myapp.pyz
# Run it
./myapp.pyz
The -c flag uses console_scripts entry points (from setup.py/pyproject.toml). The -e flag specifies a direct entry point as module:function.
The extraction model
This is Shiv’s defining feature. On first execution:
- Shiv reads the zip archive embedded in the
.pyzfile. - It extracts everything to
~/.shiv/<app-name>/<build-id>/. - The extracted directory contains a full site-packages layout.
- Python’s import system loads modules from the extracted directory normally.
Subsequent runs skip extraction — Shiv checks the build ID and reuses the existing extraction.
~/.shiv/
└── myapp/
└── a1b2c3d4_sha256/
├── site-packages/
│ ├── flask/
│ ├── requests/
│ └── myapp/
└── bin/
This “extract then run” model means compiled extensions (.so, .pyd files) work without any workarounds. Packages like NumPy, pandas, and cryptography — which are notoriously tricky with zip-based importers — work out of the box.
Build ID and cache invalidation
Each Shiv file contains a unique build ID based on the build timestamp. When you deploy a new version, the build ID changes, and Shiv extracts to a new directory. Old versions remain on disk until cleaned up.
# Set a custom build ID
shiv --build-id "v2.3.1" -e myapp:main -o myapp.pyz myapp
# Clean old extractions
rm -rf ~/.shiv/myapp/old_build_id/
This is intentional — keeping old extractions means rollback is instant (old .pyz files still find their cache).
When to use Shiv
Shiv fits a specific niche:
- Internal CLI tools — ship a single file to your team instead of writing install instructions.
- Server deployments — deploy one file per service, no
pip installon production servers. - Data science scripts — bundle analysis code with exact dependency versions.
Shiv is not the right choice for:
- Desktop applications for end users (they may not have Python — use PyInstaller instead).
- Environments where disk space for extraction is limited.
- Cases requiring multi-platform support from a single build.
Shiv vs PEX
| Aspect | Shiv | PEX |
|---|---|---|
| Import model | Extract to disk | Zip import + selective extraction |
| First-run cost | Higher (full extraction) | Lower (only compiled deps) |
| Compatibility | Higher (real filesystem) | Lower (zip import quirks) |
| Multi-platform | No | Yes (bundled platform wheels) |
| Configuration | Minimal | Extensive |
| Maintenance | Simple codebase | Complex, many features |
Choose Shiv when simplicity and compatibility matter more than advanced features. Choose PEX when you need multi-platform support or want to avoid disk extraction.
Common misconception
“Zipapps are slow because they’re zip files.”
Shiv sidesteps this entirely. It only uses the zip format for transport — the actual execution happens from extracted files on disk, running at normal Python speed. The extraction cost is paid once, then cached. A warm Shiv launch typically adds under 50ms to startup.
One thing to remember: Shiv’s “extract everything to disk” approach trades first-run speed for maximum compatibility — making it the pragmatic choice when you need zipapp simplicity without fighting zip import edge cases.
See Also
- Python Appimage Distribution An AppImage is like a portable app on a USB stick — download one file, double-click it, and your Python program runs on any Linux computer without installing anything.
- Python Briefcase Native Apps Imagine a travel agent who repacks your suitcase for each country's customs — Briefcase converts your Python app into proper native packages for every platform.
- Python Flatpak Packaging Flatpak wraps your Python app in a safe bubble that works on every Linux system — like a snow globe that keeps your program perfect inside.
- Python Mypyc Compilation Your type hints are not just for documentation — mypyc turns them into speed boosts by compiling typed Python into fast C extensions.
- Python Nuitka Compilation What if your Python code could run as fast as a race car instead of a bicycle? Nuitka translates Python into C to make that happen.