Build standalone executable with PyApp
PyApp is a tool for distributing Python applications to end users who have no Python experience. In this topic, we are going to build a standalone executable of Mahoraga with PyApp, utilizing a running Mahoraga instance. The Mahoraga executable can be copied to another machine, and will help you set up Python development environment efficiently.
Note
Mahoraga serves on http://127.0.0.1:3450 by default. Replace it with the actual URL exposed to your clients.
Prerequisites
- A running Mahoraga server which we have set up in the previous tutorial.
- Pixi should be available in your
PATHand should have been configured according to the tutorial. - Xcode/MSVC toolchain if you are using macOS/Windows. If you don't need the Xcode/VS IDE, just install Xcode Command Line Tools or Microsoft C++ Build Tools.
- Other dependencies (for example Rust) are managed by Pixi, so they don't require explicit installation here.
Build steps
PyApp itself cannot pack a Python environment, but we can create a Python environment by executing an online bootstrapper.
Make an empty directory, cd to it, and then build the online version of PyApp:
export PYAPP_PROJECT_NAME=mahoraga
export PYAPP_PROJECT_VERSION=0.5.0
export PYAPP_PROJECT_FEATURES=granian
export PYAPP_DISTRIBUTION_SOURCE=http://127.0.0.1:3450/python-build-standalone/20260114/cpython-3.14.2+20260114-x86_64_v3-unknown-linux-gnu-install_only_stripped.tar.gz
export PYAPP_FULL_ISOLATION=1
export PYAPP_UV_ENABLED=1
export PYAPP_UV_SOURCE=http://127.0.0.1:3450/uv/uv-x86_64-unknown-linux-gnu.tar.gz
pixi exec -s gcc_linux-64 -s rust \
cargo install --locked --no-track --root . pyapp
PYAPP_INSTALL_DIR_MAHORAGA=temp \
UV_DEFAULT_INDEX=http://127.0.0.1:3450/pypi/simple \
UV_PYTHON=temp/python/bin/python3 \
bin/pyapp
Note
You may want to replace the v3 in PYAPP_DISTRIBUTION_SOURCE with v2 or v4 if the CPU of the target machine is already known.
export PYAPP_PROJECT_NAME=mahoraga
export PYAPP_PROJECT_VERSION=0.5.0
export PYAPP_PROJECT_FEATURES=granian
export PYAPP_DISTRIBUTION_SOURCE=http://127.0.0.1:3450/python-build-standalone/20260114/cpython-3.14.2+20260114-aarch64-apple-darwin-install_only_stripped.tar.gz
export PYAPP_FULL_ISOLATION=1
export PYAPP_UV_ENABLED=1
export PYAPP_UV_SOURCE=http://127.0.0.1:3450/uv/uv-aarch64-apple-darwin.tar.gz
pixi exec -s rust cargo install --locked --no-track --root . pyapp
PYAPP_INSTALL_DIR_MAHORAGA=temp \
UV_DEFAULT_INDEX=http://127.0.0.1:3450/pypi/simple \
UV_PYTHON=temp/python/bin/python3 \
bin/pyapp
export PYAPP_PROJECT_NAME=mahoraga
export PYAPP_PROJECT_VERSION=0.5.0
export PYAPP_PROJECT_FEATURES=granian
export PYAPP_DISTRIBUTION_SOURCE=http://127.0.0.1:3450/python-build-standalone/20260114/cpython-3.14.2+20260114-x86_64-apple-darwin-install_only_stripped.tar.gz
export PYAPP_FULL_ISOLATION=1
export PYAPP_UV_ENABLED=1
export PYAPP_UV_SOURCE=http://127.0.0.1:3450/uv/uv-x86_64-apple-darwin.tar.gz
pixi exec -s rust cargo install --locked --no-track --root . pyapp
PYAPP_INSTALL_DIR_MAHORAGA=temp \
UV_DEFAULT_INDEX=http://127.0.0.1:3450/pypi/simple \
UV_PYTHON=temp/python/bin/python3 \
bin/pyapp
$Env:PYAPP_PROJECT_NAME = "mahoraga"
$Env:PYAPP_PROJECT_VERSION = "0.5.0"
$Env:PYAPP_PROJECT_FEATURES = "granian"
$Env:PYAPP_DISTRIBUTION_SOURCE = "http://127.0.0.1:3450/python/3.14.2/python-3.14.2-embed-amd64.zip"
$Env:PYAPP_FULL_ISOLATION = "1"
$Env:PYAPP_UV_ENABLED = "1"
$Env:PYAPP_UV_SOURCE = "http://127.0.0.1:3450/uv/uv-x86_64-pc-windows-msvc.zip"
pixi exec -s rust cargo install --locked --no-track --root . pyapp
$Env:PYAPP_INSTALL_DIR_MAHORAGA = "temp"
$Env:UV_DEFAULT_INDEX = "http://127.0.0.1:3450/pypi/simple"
bin/pyapp
pyapp will fail to run since we didn't set PYAPP_DISTRIBUTION_PATH_PREFIX on Unix and didn't remove python314._pth on Windows. That doesn't matter since we have already get the Python environment. Pack it with maximum compression rate:
pixi exec -s tar -s zstd tar -cf temp.tar.zst -C temp/python \
--use-compress-program "zstd -T0 --ultra -22" .
pixi exec -s zstd tar -cf temp.tar.zst -C temp/python \
--use-compress-program "zstd -T0 --ultra -22" .
pixi exec -s zstd tar -cf temp.tar.zst -C temp/python \
--use-compress-program "zstd -T0 --ultra -22" .
rm temp/python314._pth
pixi exec -s zstd tar -cf temp.tar.zst -C temp `
--use-compress-program "zstd -T0 --ultra -22" .
Pass the tarball to PyApp again, and we will finally get the desired offline executable:
export PYAPP_PROJECT_NAME=mahoraga
export PYAPP_PROJECT_VERSION=0.5.0
export -n PYAPP_DISTRIBUTION_SOURCE
export PYAPP_DISTRIBUTION_PYTHON_PATH=bin/python3
export PYAPP_DISTRIBUTION_PATH=~+/temp.tar.zst
export PYAPP_FULL_ISOLATION=1
export PYAPP_SKIP_INSTALL=1
pixi exec -s gcc_linux-64 -s rust \
cargo install --frozen --no-track --root offline pyapp
mv offline/bin/pyapp mahoraga
export PYAPP_PROJECT_NAME=mahoraga
export PYAPP_PROJECT_VERSION=0.5.0
unset PYAPP_DISTRIBUTION_SOURCE
export PYAPP_DISTRIBUTION_PYTHON_PATH=bin/python3
export PYAPP_DISTRIBUTION_PATH=~+/temp.tar.zst
export PYAPP_FULL_ISOLATION=1
export PYAPP_SKIP_INSTALL=1
pixi exec -s rust cargo install --frozen --no-track --root offline pyapp
mv offline/bin/pyapp mahoraga
export PYAPP_PROJECT_NAME=mahoraga
export PYAPP_PROJECT_VERSION=0.5.0
unset PYAPP_DISTRIBUTION_SOURCE
export PYAPP_DISTRIBUTION_PYTHON_PATH=bin/python3
export PYAPP_DISTRIBUTION_PATH=~+/temp.tar.zst
export PYAPP_FULL_ISOLATION=1
export PYAPP_SKIP_INSTALL=1
pixi exec -s rust cargo install --frozen --no-track --root offline pyapp
mv offline/bin/pyapp mahoraga
$Env:PYAPP_PROJECT_NAME = "mahoraga"
$Env:PYAPP_PROJECT_VERSION = "0.5.0"
$Env:PYAPP_DISTRIBUTION_SOURCE = ""
$Env:PYAPP_DISTRIBUTION_PYTHON_PATH = "python.exe"
$Env:PYAPP_DISTRIBUTION_PATH = Convert-Path temp.tar.zst
$Env:PYAPP_FULL_ISOLATION = "1"
$Env:PYAPP_SKIP_INSTALL = "1"
pixi exec -s rust cargo install --frozen --no-track --root offline pyapp
mv offline/bin/pyapp.exe mahoraga.exe
That's it. You can run this mahoraga on either the same machine or another one, and it will work as expected.