← Blog
Windows DevJune 10, 2026·12 min read

Compiling standalone Python executables with Nuitka to eliminate machine overhead.

The definitive guide to launching ultra-fast .exe files on Windows, without needing slow runtime packages like PyInstaller. This is exactly how ReelNox Studio and BackDrop_ ship to real users — including every mistake I made getting there.

Ça vous plaît ? Un ❤️ vous attend à la fin.

Why compile Python at all

If you're building a desktop app in Python and want a normal person to run it, "pip install" isn't an option. They don't have Python installed, they don't want to install it, and they shouldn't have to. You need a real .exe they can double-click. That means compiling — turning your interpreted Python code and its dependencies into something that runs without a Python installation on the target machine.

Why PyInstaller wasn't good enough

PyInstaller was my first attempt, and it works — technically. The problem is what it actually does: it bundles a Python interpreter and all your dependencies into a package, then unpacks them to a temp folder every time the app starts (in --onefile mode) or ships them as a folder full of loose files (in --onedir mode). Either way, you're still running interpreted bytecode through an embedded Python runtime at startup, not compiled machine code. Startup felt sluggish, the temp-extraction step added a visible delay on first launch, and antivirus software treats "unpacks itself to %TEMP% and starts executing" as a textbook heuristic for malware — which caused exactly the false-positive problem I was trying to avoid.

The right approach: Nuitka --standalone

Nuitka is a real Python-to-C compiler. It doesn't bundle an interpreter — it translates your Python code into C, compiles that with a real C compiler, and links it into an actual native executable. The result runs as compiled machine code, not interpreted bytecode inside an embedded runtime. Startup is close to instant, and — critically — it never extracts itself to a temp folder at runtime, which removes the single biggest trigger for antivirus heuristics. The flag that matters most is --standalone: it produces a self-contained folder with your .exe and its native dependencies sitting right next to it, ready to distribute as-is or wrap in an installer.

How to actually do it

1Install Nuitka: pip install nuitka (it needs a C compiler on the machine — MSVC on Windows, which the Nuitka installer can fetch for you if you don't already have Visual Studio Build Tools)
2Run the compile: python -m nuitka --standalone --enable-plugin=tk-inter --windows-console-mode=disable --output-dir=dist main.py
3Nuitka produces a dist/main.dist/ folder containing main.exe plus every native dependency it detected — this whole folder is what you distribute, not just the .exe
4Wrap that folder with an installer (I use Inno Setup) so users get a normal Windows install experience instead of a loose folder of files
5Test the installed app on a clean Windows VM with no Python installed, before you ship — this is the only way to catch a missing DLL or an asset path that only worked on your dev machine

The 3 mistakes that cost me hours

⚠️ Forgetting --enable-plugin=tk-inter

If your GUI uses Tkinter or CustomTkinter and you skip this flag, the compiled app doesn't error out loudly — it just fails to load the GUI toolkit and can crash silently or show a blank window. Nuitka doesn't include GUI framework support by default; you have to opt in per-framework.

⚠️ Using --onefile instead of --standalone

--onefile is tempting because it produces a single .exe instead of a folder. Don't use it for anything you plan to distribute publicly. Onefile builds still self-extract to a temp directory at runtime — the same behavior that made PyInstaller trigger false positives — and I've seen it flagged by Windows Defender as Wacatac or Sabsik purely from that extraction pattern, with completely clean code. --standalone avoids this entirely.

⚠️ Resolving asset paths with __file__ instead of sys.executable

In a normal Python script, __file__ points to your source file's location. In a compiled standalone build, that assumption breaks. Use Path(sys.executable).parent to find where your .exe actually lives on the user's machine, and load config files, icons, and bundled assets relative to that — not relative to where your source happened to sit during development.

What this actually gets you

Both ReelNox Studio and BackDrop_ ship as Nuitka --standalone builds, code-signed with a DigiCert EV certificate. Startup is instant, Windows Defender doesn't flag either installer, and neither app has ever needed a bundled Python runtime the user has to think about. The combination that matters is: --standalone (not --onefile) plus proper code signing — together they solve both the performance problem and the trust problem that come with distributing a Python app as a native Windows executable.

See it running → ReelNox StudioBuilt with Nuitka --standalone, GPU-accelerated, EV code signed

About

Patrick Chen — indie developer behind Sublimearts.io. I write about the exact build problems I actually hit shipping ReelNox Studio, BackDrop_ and TimePeek to real Windows users — not generic tutorials.

Did you find this helpful?