Skip to main content

pyappdist

Ship your Python app as a native installer straight from pyproject.toml. If it installs with pip, it almost certainly ships with pyappdist.

📖 Documentation: https://pyappdist.readthedocs.io/

pyappdist bridges the Python packaging ecosystem and native application distribution. It reads your application's pyproject.toml and builds setup packages for Windows, macOS, and Linux:

  • Windows: MSI / MSIX
  • macOS: DMG / .app bundle, PKG installer, or a self-extracting installer
  • Linux: self-extracting installer

For example, to build a Windows MSI, configure pyproject.toml like this:

[tool.pyappdist]
name = "My App"
python = "3.12"

[[tool.pyappdist.launchers]]
name = "myapp"              # produces myapp.exe (or a shell wrapper on Linux/macOS)
entry = "myapp:main"        # module:callable
# gui = true                # use pythonw.exe (no console window) on Windows
# icon = { windows = "assets/app.ico" }   # per-OS launcher icon table
# args = "--serve"          # fixed leading arguments

[[tool.pyappdist.targets]]
name = "windows"
platform = "windows-x86_64"
format = "msi"
manufacturer = "Example Inc."
# scope = "user"            # "user" (default, no admin) or "machine" (Program Files)

Then build the MSI package (on Windows):

uvx pyappdist build

The result lands under appdist/<target>/dist/.

How it works

pyappdist creates a dedicated Python runtime directory and installs your application and its dependencies into it with pip. That runtime directory itself becomes the setup package. The Python runtime comes from python-build-standalone, the same distribution Astral's uv uses to build its environments.

With this approach, binary files such as a package's DLLs and related files such as images are placed in the proper directories according to the Python language specification and the PyPA specifications. Because this environment is used for the setup package as-is, most applications can be expected to run unmodified, with no per-application adjustments. If your app runs under uv run, it almost certainly runs after pyappdist build.

Why pyappdist

Tools such as PyInstaller and Nuitka analyze your code, select only the necessary files from the Python interpreter and dependency packages, and build an executable or a directory from that minimal set of files.

The problem is that the selection is not always correct. Static analysis cannot reliably find dynamically imported modules, data files, or plugins, so these tools often need per-application adjustments — hidden-import declarations, data-file lists, and library-specific hooks — and adding a new dependency can break the build again.

Those tools trade complexity for smaller distributions. A typical Python runtime adds roughly 100–150 MB. That used to matter more than it does today.

pyappdist makes the opposite trade-off: it builds a complete environment according to the Python and PyPA specifications and creates the distribution package from it. What your application and its dependencies contain does not matter — there is nothing to hunt down and nothing to adjust per application. It also does not build a one-binary executable — it only provides small launcher executables where needed. Through this design, pyappdist creates a stable application environment that end users can rely on.

What it produces

Each [[tool.pyappdist.targets]] entry describes one output package, selected by its platform and format:

format Platform Output
msi Windows .msi installer
msix Windows .msix package (Microsoft Store / sideloading)
linux Linux self-extracting .run installer
macos macOS self-extracting .run installer
macapp macOS .app bundle
dmg macOS .dmg disk image
pkg macOS .pkg installer
image any plain .zip / .tar.gz archive of the install tree

Supported platform values: windows-x86_64, windows-arm64, linux-x86_64, linux-aarch64, macos-x86_64, macos-aarch64. The macOS formats (macapp / dmg / pkg) support code-signing and notarization.

Samples

Runnable example apps live under samples/, each with its own [tool.pyappdist] config:

  • helloworld — smallest config, no dependencies; a good starting template
  • pandascli — pandas + numpy (C extensions)
  • datafiles — ships a bundled data file, located via sysconfig
  • multiprocessingdemo — multiprocessing with spawn works unmodified
  • pytorchdemo — CUDA PyTorch via a per-index pin (Windows/Linux)
  • matplotlibdemo — TkAgg GUI using the bundled tkinter
  • pygamedemo — pygame-ce GUI (C extensions)
  • pyside6demo — PySide6 (large abi3 wheel, Qt plugins)
  • niceguidemo — NiceGUI + pywebview, per-target extras for backend selection
  • pyvisionmarker — Gradio + pywebview object detection; environment markers pick the backend, MSI license dialog

Status

Beta: Core packaging workflows are ready for real-world use, although configuration details may still change before 1.0.

Metadata

Release files for pyappdist 0.12.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pyappdist 0.12.0
File Size Uploaded
pyappdist-0.12.0.tar.gz 405.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pyappdist 0.12.0
File Interpreter ABI Platform
pyappdist-0.12.0-py3-none-any.whl Python 3 none any Details

Total release size: 831.0 kB

Release files / pyappdist-0.12.0.tar.gz

Download URL pyappdist-0.12.0.tar.gz
Size 405.2 kB
Tags Source
SHA-256 checksum
How to use checksums
005def581bdc01ea4034c4441b22d5f61096496b427c81a72f801511f22b2ddb
BLAKE2b-256 checksum
How to use checksums
e482bf82ea8c7a5491562d8c5d4011c1e1ccf273c42edbd25814feddfb87901a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 12, 2026.

Transparency log

Release files / pyappdist-0.12.0-py3-none-any.whl

Download URL pyappdist-0.12.0-py3-none-any.whl
Size 425.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5408b2e0d4fdea70834026b30d012535a54edffbabe5d5a0adc84c727763314d
BLAKE2b-256 checksum
How to use checksums
aedbe174bb15313fd02be69cc3d45b6610411e283a3645d9c63e5645a20eadcf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 12, 2026.

Transparency log

Release history Release notifications | RSS feed

0.14.0

2 release files

0.13.0

2 release files

This release

0.12.0 This release

2 release files

0.10.0

2 release files

0.9.0

2 release files

0.8.0

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page