Skip to main content

Fast, cross-platform Python application packager with uv and Go

Project description

UVBOX

Fast, simple and cross-platform Python application packaging

Package your Python apps as self-boostrapping executables for every platforms.

Go Python

Linux MacOS Windows

FeaturesComparisonQuick StartConfigurationHow It WorksAdvanced UsageExamples


What is uvbox?

uvbox generates standalone executables that bootstrap an embedded uv installation to automatically setup and run your Python application in a fully isolated environment — for any platform, from any platform.

No Python required on the target system. The binary handles everything: downloads the right Python version, creates a virtual environment, installs dependencies, and runs your app.

uvbox demo

Features

  • 📦 Package from PyPI or Wheels — Install your application from package indexes or choose to bundle local wheel files
  • 🚀 True Cross-Compilation — Build binaries for Linux, macOS, and Windows (AMD64/ARM64) from any platform in seconds
  • 🔄 Auto-Updates — Built-in version checking and self-update/fallback capabilities for your binaries
  • 🔒 Dependency Freezing — Use constraints files to ensure reproducible installations
  • 🌍 Enterprise-Friendly — Support for custom registries, mirrors, and CA certificates
  • ⚡ Fast — Powered by Go, builds complete in very few seconds
  • 📝 Simple Integration — Add as a dev dependency to your Python project

Comparison

Feature uvbox pyapp PyInstaller
Build Time ~1s ~30s ~1-5min
Cross-Compilation ✅ All platforms from any platform ⚠️ Requires target toolchains ❌ Native only
macOS from Linux/Windows ✅ Out of the box ❌ Forbidden by Apple license ❌ Forbidden by Apple license
Updates ✅ Built-in ✅ Built-in ❌ Manual
Fallbacks ✅ Version fallback support ❌ Not supported ❌ Not supported
Distribution Downloads at first run Downloads at first run Bundles everything (offline-ready)

🎯 Choosing the right tool:

uvbox excels at fast, cross-platform builds with minimal setup, built-in automatic updates, and version fallback mechanisms. It downloads dependencies at first run, making binaries small but requiring internet connectivity initially.

PyInstaller bundles everything into the binary, creating larger files but ensuring complete offline functionality and maximum stability (no runtime network dependencies). However, it requires native builds per platform and lacks built-in update mechanisms.

💡 Use uvbox when: You want fast builds, easy cross-compilation, or when enforced updates/fallbacks may be required, and don't mind first-run downloads.

💡 Use PyInstaller when: You need guaranteed offline functionality, distribute in air-gapped environments, or only target a single platform (especially Linux-only deployments).

Quick Start

Installation

Add uvbox to your project from PyPI:

# With uv
uv add --dev uvbox

# With pip
pip install uvbox

[!NOTE] Installing from PyPI automatically includes Go and nfpm as dependencies, so you don't need to install them separately.

Basic Usage

Create a simple configuration and build:

# Create a minimal config file
cat > uvbox.toml <<EOF
[package]
name = "cowsay"
script = "cowsay"
EOF

# Build for all platforms
uvbox pypi --config uvbox.toml

# Output:
# ✓ DARWIN/AMD64 → cowsay-x86_64-apple-darwin.tar.gz
# ✓ DARWIN/ARM64 → cowsay-aarch64-apple-darwin.tar.gz
# ✓ LINUX/AMD64 → cowsay-x86_64-unknown-linux-gnu.tar.gz
# ✓ LINUX/ARM64 → cowsay-aarch64-unknown-linux-gnu.tar.gz
# ✓ WINDOWS/AMD64 → cowsay-x86_64-pc-windows-msvc.zip

Your executables are now in the dist/ directory!

Build from Wheels

Package local wheel files instead of installing from PyPI:

uvbox wheel --config uvbox.toml ./my-app.whl

Configuration

Using pyproject.toml

Embed configuration directly in your Python project:

[tool.uvbox.package]
name = "my-awesome-app"
script = "main"  # Entry point from your package

[tool.uvbox.package.version]
dynamic = "https://example.com/my-app/version.txt"  # Fetch version from URL
static = "1.0.0"  # Fallback version if dynamic fetch fails
auto-update = true

# Optional: Constrain dependencies
[tool.uvbox.package.constraints]
dynamic = "https://example.com/my-app/<VERSION>/constraints.txt"

# uv index and mirror configuration will be automatically be used
[[tool.uv.index]]
name = "company-pypi"
url = "https://my.artifactory.com/artifactory/api/pypi/pypi-mirror/simple"
default = true

[tool.uv]
python-install-mirror = "https://my.github.remote/astral-sh/python-build-standalone/releases/download"

Then build directly from your project directory:

# uvbox automatically detects pyproject.toml
uvbox pypi

Using Standalone Config Files

Create a dedicated uvbox.toml file:

[package]
name = "my-app"
script = "my_entrypoint"

[package.version]
# Pin to specific version
static = "2.1.0"
# Or use dynamic version from URL
dynamic = "https://example.com/my-app/version.txt"
# Enable automatic updates before each run
auto-update = true

[package.constraints]
# Freeze dependencies with a constraints file
# <VERSION> placeholder is automatically replaced
dynamic = "https://example.com/my-app/<VERSION>/constraints.txt"

# Or use a static constraints file
static = "./constraints.txt"

[certificates]
# Bundle custom CA certificates (useful behind corporate firewalls)
path = "./ca-bundle.crt"

[uv]
# Optional: Specify which uv version to use
version = "0.4.20"
# Optional: Use a mirror for downloading uv itself
mirror = "https://mirror.example.com/uv/releases/download"
# Configure uv runtime behavior with environment variables
environment = [
    "UV_INDEX_URL=https://pypi.example.com/simple",
    "UV_PYTHON=3.12",
    "UV_PYTHON_INSTALL_MIRROR=https://mirror.example.com/python-builds"
]

Configuration Reference

[package]

Core package configuration.

  • name (required) — Package name to install from PyPI
  • script (required) — Entry point script to run (from [project.scripts] in your package)

[package.version]

Version management and updates.

  • static — Pin to a specific version (e.g., "1.2.3")
  • dynamic — URL to a text file containing the version to install
  • auto-update — Check for updates before each run (may slow startup)

[package.constraints]

Dependency freezing for reproducible installs.

  • static — Path to local constraints file
  • dynamic — URL to remote constraints file (supports <VERSION> placeholder)

[certificates]

Bundle custom CA certificates.

  • path — Path to certificate bundle (relative to working directory)

The binary automatically sets REQUESTS_CA_BUNDLE and SSL_CERT_FILE environment variables.

[uv]

Configure uv installation and behavior.

  • version — Specific uv version to download and use (e.g., "0.4.20")
  • mirror — Alternative download URL for uv releases (e.g., "https://mirror.example.com/uv/releases/download")
  • environment — Array of environment variables to set for uv runtime behavior

See uv's documentation for available environment variables.

Config File Discovery

uvbox automatically searches for configuration files:

  1. Explicit path via --config flag
  2. uvbox.toml in current directory or parents
  3. pyproject.toml with [tool.uvbox] section in current directory or parents

How It Works

uvbox leverages Go's powerful cross-compilation to create lightweight executables that:

  1. Embed uv — Each binary contains the uv installation URL and configuration
  2. Bootstrap on First Run — Downloads and extracts uv to an isolated XDG-compliant directory
  3. Install Your App — Uses uv tool install to set up your package and dependencies in complete isolation
  4. Run — Executes your application's entry point with the configured environment

All files are stored in XDG-compliant directories ($XDG_DATA_HOME/uvbox/ or ~/.local/share/uvbox/ by default), ensuring a clean and standardized file system layout.

Why Go?

  • ⚡ Blazing Fast Compilation — ~1 second vs ~30 seconds for Rust-based alternatives
  • 🌍 True Cross-Compilation — Build macOS binaries from Linux/Windows without licenses or complex toolchains
  • 📦 Zero Dependencies — Just set GOOS and GOARCH environment variables
  • 🎯 Simple Deployment — Single static binary, no runtime dependencies

Runtime Behavior

When a user runs your binary:

./my-app --help

The first run automatically:

  1. Extracts embedded uv to $XDG_DATA_HOME/uvbox/<identifier>/uv/ (defaults to ~/.local/share/uvbox/<identifier>/uv/)
  2. Downloads Python if needed to $XDG_DATA_HOME/uvbox/<identifier>/python/ (defaults to ~/.local/share/uvbox/<identifier>/python/)
  3. Installs your package in an isolated environment at $XDG_DATA_HOME/uvbox/<identifier>/tools/ (defaults to ~/.local/share/uvbox/<identifier>/tools/)
  4. Runs your script

Subsequent runs skip straight to execution (unless updates are configured).

[!NOTE] The <identifier> is a hash computed from your package name, script, and configuration to ensure complete isolation between different applications.

Built-in Commands

Every generated binary includes these self commands:

  • <app> self update — Update the package to the latest available version
  • <app> self remove — Remove installation (clean up installed files and virtual environment)
  • <app> self path — Display paths related to the installation
  • <app> self cache — Manage cache
  • <app> self uv — Run installation uv executable inside the isolated environment

Advanced Usage

Linux Package Generation

Generate .deb and .rpm packages alongside binaries:

# Create nfpm.yaml configuration
cat > nfpm.yaml <<EOF
name: my-app
maintainer: "Your Name <you@example.com>"
description: "My awesome application"
homepage: "https://github.com/you/my-app"
license: "MIT"

# Template variables
arch: ${UVBOX_ARCH}
platform: ${UVBOX_PLATFORM}
version: ${UVBOX_VERSION}

# Copy executable to target folder
contents:
  - src: ${UVBOX_BUILT_EXECUTABLE}
    dst: /usr/bin/my-app

# Built-in pre-remove script that ensures application data are removed
scripts:
  preremove: ./pre_remove.sh
EOF

# Build with packaging
uvbox pypi --nfpm nfpm.yaml --release-version 1.0.0

Available Template Variables:

uvbox provides environment variables for use in your nfpm configuration:

  • UVBOX_BUILT_EXECUTABLE — Absolute path to the compiled executable
  • UVBOX_NAME — Executable name (from script configuration)
  • UVBOX_PLATFORM — Target platform (linux, darwin, windows)
  • UVBOX_ARCH — Target architecture (amd64, arm64)
  • UVBOX_VERSION — Version from --release-version flag

Use them with ${VARIABLE_NAME} syntax in your nfpm.yaml.

[!TIP] The preremove: ./pre_remove.sh script is optional. If you include it in your nfpm configuration, uvbox automatically generates it to call <executable> self remove, which cleans up application data (virtual environments, cached Python installations) when the package is uninstalled.

Custom Registry Example

[package]
name = "internal-tool"
script = "tool"

[uv]
environment = [
    "UV_INDEX_URL=https://artifactory.company.com/api/pypi/pypi-mirror/simple",
    "UV_EXTRA_INDEX_URL=https://artifactory.company.com/api/pypi/internal-packages/simple",
    "UV_PYTHON_INSTALL_MIRROR=https://internal-mirror.company.com/python-builds"
]

[certificates]
path = "./company-ca-bundle.crt"

Version Fallback Strategy

Use dynamic versioning with fallback:

[package.version]
# Try to fetch latest version from URL
dynamic = "https://cdn.example.com/my-app/latest.txt"
# Fallback to this version if URL is unreachable
static = "1.0.0"
# Check for updates before each run
auto-update = true

Examples

See the examples/ directory for complete working examples:

Requirements

Build Time

  • Go 1.21+ (automatically fetched if installed via PyPI package)
  • nfpm (optional, only if generating .deb/.rpm packages)

Runtime (Generated Binaries)

  • libc (standard C library, required by Python itself)

License

MIT © 2025 Amadeus

Contributing

We welcome contributions!

Acknowledgments

Heavily inspired by the excellent pyapp project. Built with:

  • uv — Blazing fast Python package installer
  • Go — Enabling true cross-compilation magic
  • pyapp — Inspiration and reference implementation

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

uvbox-1.0.2-py3-none-win_arm64.whl (3.4 MB view details)

Uploaded Python 3Windows ARM64

uvbox-1.0.2-py3-none-win_amd64.whl (3.8 MB view details)

Uploaded Python 3Windows x86-64

uvbox-1.0.2-py3-none-manylinux2014_x86_64.whl (3.7 MB view details)

Uploaded Python 3

uvbox-1.0.2-py3-none-manylinux2014_aarch64.whl (3.4 MB view details)

Uploaded Python 3

uvbox-1.0.2-py3-none-macosx_11_0_arm64.whl (3.5 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

uvbox-1.0.2-py3-none-macosx_10_9_x86_64.whl (3.7 MB view details)

Uploaded Python 3macOS 10.9+ x86-64

File details

Details for the file uvbox-1.0.2-py3-none-win_arm64.whl.

File metadata

  • Download URL: uvbox-1.0.2-py3-none-win_arm64.whl
  • Upload date:
  • Size: 3.4 MB
  • Tags: Python 3, Windows ARM64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for uvbox-1.0.2-py3-none-win_arm64.whl
Algorithm Hash digest
SHA256 61941276baace69c496442e686365802287a80e77c7d9fabdc3b28fb0f4d620e
MD5 2d171c10f5fd47803f16af4e7f376ca7
BLAKE2b-256 90f88e42a0391cb1c3d749548d072134c1d271c45c7b6054c7dab140278a10de

See more details on using hashes here.

Provenance

The following attestation bundles were made for uvbox-1.0.2-py3-none-win_arm64.whl:

Publisher: release.yml on AmadeusITGroup/uvbox

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file uvbox-1.0.2-py3-none-win_amd64.whl.

File metadata

  • Download URL: uvbox-1.0.2-py3-none-win_amd64.whl
  • Upload date:
  • Size: 3.8 MB
  • Tags: Python 3, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for uvbox-1.0.2-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 62f5456ebf0608504c6b840154d66556e8193b40cb3fb76ebf2df0e8408ef27b
MD5 f6f9ffc7aa52c2f18a26c5aaaf480cc9
BLAKE2b-256 1bdb672256b57d9f8bcc7f9787ea12bd8d3fa5ea6ddc2059a148c2dc40a4c880

See more details on using hashes here.

Provenance

The following attestation bundles were made for uvbox-1.0.2-py3-none-win_amd64.whl:

Publisher: release.yml on AmadeusITGroup/uvbox

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file uvbox-1.0.2-py3-none-manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for uvbox-1.0.2-py3-none-manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 c24f38a41a2a2d55cdc838c233c2e9ddce8e42e392021153d4954e957c3e07e9
MD5 9206ac5d75ee6e3009190d1e316a667b
BLAKE2b-256 428e72f00afd463ba0a3f093d47d47e9bfab3e3647a2a4be7bbd1f44ee730e2f

See more details on using hashes here.

Provenance

The following attestation bundles were made for uvbox-1.0.2-py3-none-manylinux2014_x86_64.whl:

Publisher: release.yml on AmadeusITGroup/uvbox

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file uvbox-1.0.2-py3-none-manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for uvbox-1.0.2-py3-none-manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 04f0fb7ecd5f02b2ffcafe5b9d1c31f99f3591dc0e94853084d45781e9161c08
MD5 482d1957c0fba6af605759de7a6999be
BLAKE2b-256 9f012dd1f4b9e9f4e0feab75f8d97acc77b3e63ce523f3af7177f2227ffd97fd

See more details on using hashes here.

Provenance

The following attestation bundles were made for uvbox-1.0.2-py3-none-manylinux2014_aarch64.whl:

Publisher: release.yml on AmadeusITGroup/uvbox

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file uvbox-1.0.2-py3-none-macosx_11_0_arm64.whl.

File metadata

  • Download URL: uvbox-1.0.2-py3-none-macosx_11_0_arm64.whl
  • Upload date:
  • Size: 3.5 MB
  • Tags: Python 3, macOS 11.0+ ARM64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for uvbox-1.0.2-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 0f42d6a405a18bfe44a8b26f71e6509fe392b3e3fb358c1f36e8e55a89d4f6e6
MD5 ac27576564b45bf2829954eeb08c8ad5
BLAKE2b-256 10bacf7cd609eb8de69a750346ceaa39212f17f84deee2f716b060d1ffb7bbc7

See more details on using hashes here.

Provenance

The following attestation bundles were made for uvbox-1.0.2-py3-none-macosx_11_0_arm64.whl:

Publisher: release.yml on AmadeusITGroup/uvbox

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file uvbox-1.0.2-py3-none-macosx_10_9_x86_64.whl.

File metadata

File hashes

Hashes for uvbox-1.0.2-py3-none-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 aa6e29f62e070e7234f9da9043828a3c9bd8e0d4769b7b723b2da37ad413665c
MD5 157447e87c7d7748e9b95a15ef7f6373
BLAKE2b-256 fd09dda33fd097d61b28be9263674a1afd206dd25ccad49f1dcfb2c7faa389e5

See more details on using hashes here.

Provenance

The following attestation bundles were made for uvbox-1.0.2-py3-none-macosx_10_9_x86_64.whl:

Publisher: release.yml on AmadeusITGroup/uvbox

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page