Button guide
PyInstaller alternatives in 2026 Nuitka, cx_Freeze, Briefcase, or not shipping an executable at all
If you're tired of fighting PyInstaller's antivirus warnings, huge bundle sizes, and per-OS builds, you can switch to another packager like Nuitka, cx_Freeze, or Briefcase, or stop shipping executables altogether. For internal scripts, Button (https://button.bitgate.dev) turns the Python script on your own computer into a web form your colleagues can run from a browser, so there is nothing to bundle or distribute. The Free plan is $0 for 1 tool, 3 people, and 100 runs per month, and Pro is $15/month for up to 50 tools and 250 people.
Why PyInstaller gets painful
PyInstaller bundles your Python interpreter, script, and dependencies into a folder or a single executable. It works, until you hand that file to someone else.
First, --onefile builds unpack themselves into a temporary _MEI folder every single time the program starts. Second, antivirus false positives are a known issue - the PyInstaller repo even has a dedicated issue template for them. Third, PyInstaller isn't a cross-compiler. If you need a Windows .exe, you have to build it on Windows; if you need a macOS app, you build it on a Mac. And on macOS, an unsigned app from an unidentified developer triggers a Gatekeeper warning; removing it means signing the app through the Apple Developer Program at $99 per year.
When you hit those walls, here are the actual alternatives and what each one fixes (and doesn't).
1. Nuitka
Nuitka takes a different approach: instead of just bundling Python and your .pyc files, it compiles your Python code to C and builds an executable from that.
If you want to distribute a compiled binary and move away from how PyInstaller unpacks --onefile builds, Nuitka is a strong option. What it doesn't fix is the build setup. Like PyInstaller, Nuitka does not cross-compile, so you still have to build on every target OS, and you still have to pay Apple $99 per year if you want to sign a macOS build to avoid Gatekeeper warnings.
2. cx_Freeze
cx_Freeze creates standalone executables from Python scripts and has been around for a long time. Its main draw for some teams is its PSF license, which is simpler on paper than PyInstaller's GPLv2+ with an exception. If your legal team objects to GPL terms of any kind, cx_Freeze is the better choice. It only builds for the platform it runs on, though, so you still freeze on Windows for Windows and on a Mac for Macs, and you still sign for macOS.
3. BeeWare Briefcase
Briefcase (BSD license) packages a Python project as a native app for macOS, Windows, Linux, iOS, and Android. If you're shipping a real desktop or mobile application to end users and need native app bundles across desktop and mobile platforms, Briefcase is the better choice here. You still have to deal with Apple's $99 per year developer program if you want to sign macOS apps so Gatekeeper lets them through without a warning.
4. Shipping a virtual environment with an install script
Sometimes you don't need an executable at all, just a folder with a batch file or shell script that sets up a virtual environment and runs the Python code. This avoids PyInstaller's _MEI unpacking and the antivirus false positives that hit bundled executables. It only makes sense when your recipients are comfortable enough with their machines to let an install script pull down Python and packages, or when everyone is on the same OS setup.
5. Hosting it as a web app
Instead of putting the code on your colleagues' machines, you can wrap the script in a web framework and host it on a server. Your users get a URL, you don't build executables, and macOS Gatekeeper and Windows antivirus never enter the picture. The catch is that you now have to write web code, deploy it, and maintain a server. If your tool needs to run 24/7 for external customers even when your own laptop is closed, hosting it yourself is the right move.
6. Button: don't ship an executable at all
If you're only trying to let a few coworkers run a script you wrote, packaging it is usually a detour. Button (https://button.bitgate.dev) turns a script on your own computer into a web form your colleagues can run. It works with Python, Node, R, PowerShell, shell scripts, and compiled binaries.
With Button, nothing gets installed on your colleagues' machines: jobs run on your computer, never in Button's cloud, and Button's servers relay the form values and files between your colleague's browser and your computer. Because there is no executable to hand out, there are no Windows or Mac builds to maintain, no antivirus false positives, and no $99/year macOS signing fee.
Colleagues open the link from their invite email, sign in with Google or a one-time email code, fill in the form, press Run, and download the results. They install nothing and never pay.
How to set up a Python script on Button
Before you connect your script, make sure it takes its inputs as command-line arguments instead of using hard-coded paths or input() prompts. In Python, use argparse (or commandArgs() in R, a param() block in PowerShell, or $1 and $2 in bash). Take each input file path as an argument, and write the results as files into an output folder that is also passed as an argument:
import argparse
import pathlib
parser = argparse.ArgumentParser()
parser.add_argument("--input-file", required=True)
parser.add_argument("--output-dir", required=True)
parser.add_argument("--currency", default="USD")
args = parser.parse_args()
out = pathlib.Path(args.output_dir) / "result.txt"
out.write_text(f"Processed {args.input_file} in {args.currency}\n")
Once the script takes arguments, setting it up takes a few minutes:
- Sign in at button.bitgate.dev.
- Install the Button runner on your computer (macOS, Linux, or Windows) using the one-line command the site shows you -
curlon macOS and Linux, or PowerShell on Windows. - Open the local setup page and pick your program.
- Describe its inputs (text, number, yes/no, choice, or files). Fixed flags like
--currencyare part of the command you approve, while colleagues only supply the values for the form fields. - Publish the tool. Button gives it its own page and you can invite your colleagues.
The runner only executes the exact command you approved on that computer, pinned by hash, passes every form value as its own argument with no shell, and rejects values that start with -. If you change a tool later, people have to confirm the new version before running it. Every run is logged with who ran it and when, and you can revoke access or set it to expire at any time.
Where Button isn't the right fit
Button is built for sharing tools with colleagues, not for selling software to the public or running heavy background jobs. Keep these limits in mind:
- Your computer has to be on and online for someone to run your tool (tool pages show Ready, Busy, or Offline).
- One run happens at a time per computer, with a maximum of 30 minutes per run and logs up to 1 MB per run.
- Files can be up to 25 MB each, with up to 8 files and 100 MB per run. Inputs are deleted 24 hours after a run ends, and outputs after 7 days.
- You get one computer (runner) per workspace on every plan; pairing a new computer replaces the previous one.
If you need to ship a standalone desktop app to customers who will run it offline on their own hardware, stick with PyInstaller, Nuitka, cx_Freeze, or Briefcase.
Comparison of PyInstaller alternatives
| Option | What colleagues get | Builds you maintain | License or price | Main catch |
|---|---|---|---|---|
| PyInstaller | Executable or folder | One per OS, each built on that OS | GPLv2+ with an exception | --onefile unpacks to _MEI on every start; antivirus false positives |
| Nuitka | Executable compiled via C | One per OS, each built on that OS | Free, open source | Same per-OS builds and macOS signing |
| cx_Freeze | Standalone executable | One per OS, each built on that OS | PSF license | Same per-OS builds and macOS signing |
| Briefcase | Native app | One package per platform | BSD license | Built for real apps, including iOS and Android |
| Button | A web form in the browser | None | Free ($0) or Pro ($15/mo or $144/yr) | Your computer must be on; 30 minutes and 100 MB per run |
FAQ
Does PyInstaller or Nuitka let me build a Windows exe from a Mac?
No, neither PyInstaller nor Nuitka is a cross-compiler. You have to build the Windows executable on a Windows machine and the macOS app on a Mac.
Why do macOS users get a warning when opening my packaged Python app?
On macOS, unsigned apps from an unidentified developer trigger a Gatekeeper warning. Getting rid of that warning requires signing the app through the Apple Developer Program, which costs $99 per year.
Does Button run my Python script in the cloud?
No, jobs run on your own computer, never in Button's cloud, so your computer has to be on and online when someone runs a tool. Button's servers relay the form values and files between your colleague's browser and your computer.
How much does Button cost for the people running my tool?
Recipients never pay and don't install anything. For you as the creator, Free is $0 (1 published tool, 3 invited people, 100 runs/month) and Pro is $15/month or $144/year (50 tools, 250 people, 5,000 runs/month). Your own runs count toward the monthly total, and downgrading deletes nothing.
Last updated
Put your script behind a form
Button turns a script on your computer into a web form. Colleagues sign in, fill it in, press Run and download the results. Free for 1 tool and 3 people.