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:

  1. Shiv reads the zip archive embedded in the .pyz file.
  2. It extracts everything to ~/.shiv/<app-name>/<build-id>/.
  3. The extracted directory contains a full site-packages layout.
  4. 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 install on 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

AspectShivPEX
Import modelExtract to diskZip import + selective extraction
First-run costHigher (full extraction)Lower (only compiled deps)
CompatibilityHigher (real filesystem)Lower (zip import quirks)
Multi-platformNoYes (bundled platform wheels)
ConfigurationMinimalExtensive
MaintenanceSimple codebaseComplex, 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.

pythonshivzipapppackagingdeployment

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.