Skip to content

Package your app

Your app works on your machine. Now you want to send it to someone who does not have Python, does not know what pip is, and should be able to double-click it. This tutorial takes an app from a project folder to a file you can share, and then to an automatic build for all three systems.

Goal Time Level You need
A double-clickable app for Windows, macOS and Linux 30 minutes (plus build time) Advanced · command line uv installed, a GitHub account for the last part
  • Create (or convert to) a Pyzed project: the layout pyzed build expects.
  • Build a standalone executable for the system you are on.
  • Add an icon, data files and a name, and read bundled files from your code.
  • Build all platforms at once with GitHub Actions, and why signing matters.
  1. Start from a project. pyzed build packages a uv project whose main form or script is set in pyproject.toml. Create one (or open New project in Pyzed Design’s welcome window):

    Windows, macOS and Linux
    uvx --from pyzed-ui pyzed new my-app
    cd my-app
    uv run pyzed run # try it

    Already have a uv project? Run pyzed init inside it. The UI lives in ui/ (forms and their handlers), the backend in src/my_app/.

  2. Build for this computer. From the project folder:

    Windows, macOS and Linux
    uv run pyzed build

    The first build takes a minute or two. The result goes to dist/:

    Built on You get Share it as
    Windows dist\my-app\my-app.exe A zip of the folder, or an installer (Inno Setup, WiX)
    macOS dist/my-app.app A zip or a .dmg, signed and notarized
    Linux dist/my-app/my-app A tarball, AppImage, .deb or Flatpak
  3. Try it like a user would. Copy the folder somewhere else (or to another machine without Python) and open the executable. If it closes at once, build with --console to see the error.

  4. Name, icon and data files. Add a [tool.pyzed.build] table to pyproject.toml:

    pyproject.toml
    [tool.pyzed.build]
    name = "Notes" # the executable's name
    icon = "assets/icon.ico" # .ico on Windows, .icns on macOS
    include = ["assets", "data/help.md"] # files your app reads at run time

    Inside the bundle, find those files from the bundle’s root:

    import sys
    from pathlib import Path
    ROOT = Path(getattr(sys, "_MEIPASS", Path(__file__).resolve().parents[1]))
    help_text = (ROOT / "data" / "help.md").read_text()
  5. One file or a folder? pyzed build --onefile makes a single file, handy to send, but slower to start (it unpacks itself every time) and more often flagged by antivirus software. A folder plus an installer is the safer choice for a real release.

  6. Every platform from CI. A build only runs on the system it was made on, so you need Windows, macOS and Linux machines. GitHub has them:

    Terminal window
    uv run pyzed build --workflow # writes .github/workflows/build.yml
    git add .github && git commit -m "Build on every platform" && git push
    git tag v1.0.0 && git push --tags # a v* tag starts the build

    Each run keeps the three dist/ folders as downloadable artifacts.