<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Oleksii Fischer</title>
    <description>The latest articles on DEV Community by Oleksii Fischer (@weisshufer).</description>
    <link>https://dev.to/weisshufer</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F899651%2F3787d184-a6f7-4a10-be4c-622236e2cbf1.jpg</url>
      <title>DEV Community: Oleksii Fischer</title>
      <link>https://dev.to/weisshufer</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/weisshufer"/>
    <language>en</language>
    <item>
      <title>From PyInstaller to Nuitka: Convert Python to EXE Without False Positives</title>
      <dc:creator>Oleksii Fischer</dc:creator>
      <pubDate>Tue, 02 Dec 2025 09:13:29 +0000</pubDate>
      <link>https://dev.to/weisshufer/from-pyinstaller-to-nuitka-convert-python-to-exe-without-false-positives-19jf</link>
      <guid>https://dev.to/weisshufer/from-pyinstaller-to-nuitka-convert-python-to-exe-without-false-positives-19jf</guid>
      <description>&lt;p&gt;As a Python developer, I ran into an annoying problem: my PyInstaller-compiled executables kept getting flagged as viruses by Windows Defender. After hours of research and frustrating whitelist attempts, I discovered Nuitka – and it changed everything.&lt;/p&gt;

&lt;p&gt;In this article, I'll show you how to convert Python projects into clean, performant EXE files using Nuitka that won't get blocked by antivirus software.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem with PyInstaller
&lt;/h2&gt;

&lt;p&gt;PyInstaller has been the go-to tool for creating Python executables for years. But there's a massive problem: &lt;strong&gt;false positives from antivirus software&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Why does this happen?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PyInstaller uses a bootstrapping mechanism that looks similar to malware behavior&lt;/li&gt;
&lt;li&gt;The EXE unpacks itself at runtime into temporary folders&lt;/li&gt;
&lt;li&gt;This behavior triggers heuristic virus scanners&lt;/li&gt;
&lt;li&gt;Microsoft Defender is particularly aggressive about flagging these files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result? Your legitimate business software gets reported as a trojan. Not exactly what you want when trying to impress clients.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution: Nuitka
&lt;/h2&gt;

&lt;p&gt;Nuitka is a true Python compiler (not a packer like PyInstaller). The key difference:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nuitka compiles Python → C/C++ → Machine Code&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No self-extraction mechanism&lt;/li&gt;
&lt;li&gt;No suspicious runtime behavior&lt;/li&gt;
&lt;li&gt;Real native binaries&lt;/li&gt;
&lt;li&gt;Bonus: Better performance (10-20% faster than regular Python)&lt;/li&gt;
&lt;li&gt;Superior source code protection&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The false positive rate is &lt;strong&gt;drastically lower&lt;/strong&gt; than PyInstaller.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step-by-Step Tutorial
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Prerequisites and Setup
&lt;/h3&gt;

&lt;p&gt;Before we start compiling, let's talk about Python environment management. Your choice here affects how smoothly the Nuitka compilation will go.&lt;/p&gt;

&lt;p&gt;If you're using vanilla Python with pip, the installation is straightforward. However, if you're working with modern tools like Poetry or uv, there are some considerations to keep in mind. Poetry creates virtual environments and manages dependencies through pyproject.toml files, which is excellent for development but requires a different approach when compiling. The tool uv, on the other hand, is Rust-based and incredibly fast for package installation, making it ideal for CI/CD pipelines where compilation speed matters.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;

&lt;p&gt;The basic installation depends on your package manager. With pip, you simply install Nuitka globally or in your virtual environment. With Poetry, you add it as a dev dependency to keep your project dependencies clean. And with uv, you get the speed benefits during both installation and subsequent package operations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Using pip (traditional approach):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create a virtual environment first (recommended)&lt;/span&gt;
python &lt;span class="nt"&gt;-m&lt;/span&gt; venv venv
&lt;span class="nb"&gt;source &lt;/span&gt;venv/bin/activate  &lt;span class="c"&gt;# On Windows: venv\Scripts\activate&lt;/span&gt;

&lt;span class="c"&gt;# Install Nuitka and optimization tools&lt;/span&gt;
pip &lt;span class="nb"&gt;install &lt;/span&gt;nuitka
pip &lt;span class="nb"&gt;install &lt;/span&gt;ordered-set  &lt;span class="c"&gt;# Speeds up compilation significantly&lt;/span&gt;
pip &lt;span class="nb"&gt;install &lt;/span&gt;zstandard    &lt;span class="c"&gt;# Reduces final EXE size by 30-50%&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Using Poetry (modern Python projects):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Add Nuitka as a development dependency&lt;/span&gt;
poetry add &lt;span class="nt"&gt;--group&lt;/span&gt; dev nuitka ordered-set zstandard

&lt;span class="c"&gt;# Activate Poetry's virtual environment&lt;/span&gt;
poetry shell

&lt;span class="c"&gt;# Now you can use Nuitka within the Poetry environment&lt;/span&gt;
python &lt;span class="nt"&gt;-m&lt;/span&gt; nuitka &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Poetry approach is particularly valuable because it keeps Nuitka separate from your production dependencies. This means your pyproject.toml file clearly distinguishes between what your application needs to run versus what you need to build it. This separation becomes crucial when you're managing multiple projects or working in a team where not everyone needs the compilation toolchain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Using uv (fastest option, great for CI/CD):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install uv (if not already installed)&lt;/span&gt;
curl &lt;span class="nt"&gt;-LsSf&lt;/span&gt; https://astral.sh/uv/install.sh | sh

&lt;span class="c"&gt;# Create a virtual environment with uv (much faster than venv)&lt;/span&gt;
uv venv

&lt;span class="c"&gt;# Activate the environment&lt;/span&gt;
&lt;span class="nb"&gt;source&lt;/span&gt; .venv/bin/activate  &lt;span class="c"&gt;# On Windows: .venv\Scripts\activate&lt;/span&gt;

&lt;span class="c"&gt;# Install dependencies blazingly fast&lt;/span&gt;
uv pip &lt;span class="nb"&gt;install &lt;/span&gt;nuitka ordered-set zstandard

&lt;span class="c"&gt;# Install your project dependencies&lt;/span&gt;
uv pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;span class="c"&gt;# Or if you have pyproject.toml: uv pip install -e .&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The speed difference with uv is remarkable. Where pip might take 30 seconds to install Nuitka and its dependencies, uv can do it in under 5 seconds. This matters a lot in CI/CD pipelines where you're compiling regularly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating Your First EXE
&lt;/h3&gt;

&lt;p&gt;Let's start with the simplest case and build up to more complex scenarios. The key is understanding what each flag does and why you need it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Basic standalone executable:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; nuitka &lt;span class="nt"&gt;--standalone&lt;/span&gt; your_script.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a folder with your executable and all necessary dependencies. The standalone mode means Nuitka bundles Python itself along with your script, so the target machine doesn't need Python installed. However, this creates a folder structure rather than a single file, which can be inconvenient for distribution.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Single-file executable (most common for distribution):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; nuitka &lt;span class="nt"&gt;--standalone&lt;/span&gt; &lt;span class="nt"&gt;--onefile&lt;/span&gt; your_script.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The onefile mode takes that folder of dependencies and packages everything into a single executable. When you run this EXE, it temporarily unpacks itself to a cache directory, runs your program, and cleans up afterward. This is perfect for sharing with clients or deploying to end users who just want to double-click and run.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GUI application without console window:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; nuitka &lt;span class="nt"&gt;--standalone&lt;/span&gt; &lt;span class="nt"&gt;--onefile&lt;/span&gt; &lt;span class="nt"&gt;--windows-disable-console&lt;/span&gt; your_app.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're building a GUI application with Tkinter, PyQt, or similar frameworks, you don't want a console window popping up behind your GUI. The windows-disable-console flag prevents that. This only works on Windows and should not be used for CLI tools or scripts that need to print output.&lt;/p&gt;

&lt;h3&gt;
  
  
  Working with Dependencies and Poetry Projects
&lt;/h3&gt;

&lt;p&gt;Here's where things get interesting. If you have a Poetry project with a pyproject.toml file, you need to ensure Nuitka can find all your dependencies. Poetry installs packages in its own virtual environment, which Nuitka needs to access.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Compiling a Poetry project:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# First, make sure you're in the Poetry environment&lt;/span&gt;
poetry shell

&lt;span class="c"&gt;# Compile with plugin support for common packages&lt;/span&gt;
python &lt;span class="nt"&gt;-m&lt;/span&gt; nuitka &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--standalone&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--onefile&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--enable-plugin&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;numpy &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--enable-plugin&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;tk-inter &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--follow-imports&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  your_script.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The follow-imports flag is crucial here. It tells Nuitka to recursively include all imported modules, even if they're dynamically imported. Poetry projects often have complex dependency trees, and this flag ensures nothing gets missed.&lt;/p&gt;

&lt;p&gt;If you're using specific packages that need special handling, Nuitka provides plugins. For example, numpy requires the numpy plugin because it has compiled C extensions. Similarly, matplotlib needs the matplotlib plugin. You can check which plugins are available with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; nuitka &lt;span class="nt"&gt;--plugin-list&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Embedding Resources and Assets
&lt;/h3&gt;

&lt;p&gt;Many applications need to include images, configuration files, or data files. This is where people often struggle because the file paths change when your code is compiled into an executable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Including data directories:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; nuitka &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--standalone&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--onefile&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--include-data-dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;./assets&lt;span class="o"&gt;=&lt;/span&gt;assets &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--include-data-dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;./config&lt;span class="o"&gt;=&lt;/span&gt;config &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--windows-icon-from-ico&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;icon.ico &lt;span class="se"&gt;\&lt;/span&gt;
  your_script.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The syntax for include-data-dir is important to understand. The format is source=destination, where source is the folder on your development machine and destination is where it will be placed in the compiled executable. So ./assets=assets means "take my assets folder and make it available as 'assets' in the compiled version."&lt;/p&gt;

&lt;p&gt;However, there's a catch. When running as a onefile executable, your script doesn't run from the same directory as the EXE file. Nuitka unpacks everything to a temporary directory. You need to adjust your code to handle this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_resource_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;relative_path&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Get the absolute path to a resource, works for dev and compiled.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="c1"&gt;# If running as a Nuitka onefile, __file__ points to the temp directory
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;frozen&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Running as compiled executable
&lt;/span&gt;        &lt;span class="n"&gt;base_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Running as script
&lt;/span&gt;        &lt;span class="n"&gt;base_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__file__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;relative_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Usage
&lt;/span&gt;&lt;span class="n"&gt;config_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_resource_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;config/settings.json&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;image_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_resource_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;assets/logo.png&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This helper function ensures your resource paths work correctly both during development and when running as a compiled executable. The sys.frozen attribute is set by Nuitka when your code is compiled, allowing you to detect the runtime environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Advanced Optimization with UPX
&lt;/h3&gt;

&lt;p&gt;After Nuitka creates your executable, you can compress it further using UPX. This is particularly valuable if you're distributing your application over the internet or need to fit it on limited storage.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install UPX first&lt;/span&gt;
&lt;span class="c"&gt;# Windows with Scoop: scoop install upx&lt;/span&gt;
&lt;span class="c"&gt;# macOS with Homebrew: brew install upx&lt;/span&gt;
&lt;span class="c"&gt;# Linux: apt install upx-ucl&lt;/span&gt;

&lt;span class="c"&gt;# Compress your executable (can take several minutes)&lt;/span&gt;
upx &lt;span class="nt"&gt;--ultra-brute&lt;/span&gt; your_script.exe

&lt;span class="c"&gt;# For faster compression with slightly less compression ratio:&lt;/span&gt;
upx &lt;span class="nt"&gt;--best&lt;/span&gt; your_script.exe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The ultra-brute option uses maximum compression, which can reduce file size by 50-70% but takes significantly longer. The best option gives you about 40-50% reduction in just a fraction of the time. For CI/CD pipelines, I recommend using --best to keep build times reasonable.&lt;/p&gt;

&lt;p&gt;One important note: some antivirus software doesn't like UPX-compressed executables because malware authors also use UPX. So if you're using Nuitka specifically to avoid false positives, you might want to skip UPX compression or test thoroughly with your target antivirus software.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using uv in CI/CD Pipelines
&lt;/h3&gt;

&lt;p&gt;If you're building executables in a CI/CD environment like GitHub Actions or GitLab CI, uv can dramatically speed up your build times. Here's a complete example workflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .github/workflows/build.yml&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build EXE with Nuitka&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;windows-latest&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install uv&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;curl -LsSf https://astral.sh/uv/install.sh | sh&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Create venv and install dependencies&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;uv venv&lt;/span&gt;
        &lt;span class="s"&gt;.venv\Scripts\activate&lt;/span&gt;
        &lt;span class="s"&gt;uv pip install nuitka ordered-set zstandard&lt;/span&gt;
        &lt;span class="s"&gt;uv pip install -r requirements.txt&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Compile with Nuitka&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;.venv\Scripts\activate&lt;/span&gt;
        &lt;span class="s"&gt;python -m nuitka --standalone --onefile --windows-disable-console app.py&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Upload artifact&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/upload-artifact@v3&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;windows-executable&lt;/span&gt;
        &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app.exe&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The beauty of uv in CI/CD is its speed. Traditional pip-based workflows might take 2-3 minutes just for dependency installation. With uv, that drops to 15-30 seconds, which adds up significantly if you're building frequently.&lt;/p&gt;

&lt;h3&gt;
  
  
  Troubleshooting Common Issues
&lt;/h3&gt;

&lt;p&gt;When compiling complex projects, you'll inevitably run into issues. Here are the most common problems and their solutions.&lt;/p&gt;

&lt;p&gt;If Nuitka can't find a module even though it's installed, the issue is usually that the module is imported dynamically or conditionally. Use the --include-package flag to force inclusion:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; nuitka &lt;span class="nt"&gt;--standalone&lt;/span&gt; &lt;span class="nt"&gt;--onefile&lt;/span&gt; &lt;span class="nt"&gt;--include-package&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;my_module your_script.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your compiled executable crashes with import errors at runtime, check if you're using packages that need plugins. Run python -m nuitka --plugin-list and look for your package. Then enable it with --enable-plugin=package-name.&lt;/p&gt;

&lt;p&gt;For Poetry projects, if Nuitka complains about missing dependencies, make sure you're running the compilation from within the Poetry shell. You can verify this by checking which python shows you the Poetry environment's Python interpreter.&lt;/p&gt;

&lt;p&gt;If the compilation takes forever or uses too much memory, try reducing the optimization level with --python-flag=no_asserts or compiling without optimizations first using --python-flag=-O0. Once it works, you can gradually increase optimization.&lt;/p&gt;

&lt;h2&gt;
  
  
  PyInstaller vs Nuitka
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;PyInstaller&lt;/th&gt;
&lt;th&gt;Nuitka&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Method&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Packer (bundles files)&lt;/td&gt;
&lt;td&gt;Compiler (C/C++ → Binary)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;False Positives&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;⚠️ Very common&lt;/td&gt;
&lt;td&gt;✅ Rare&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Performance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;= Python Interpreter&lt;/td&gt;
&lt;td&gt;🚀 10-20% faster&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;EXE Size&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;15-30 MB (smaller)&lt;/td&gt;
&lt;td&gt;25-50 MB (larger)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Compilation Time&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;⚡ Fast (seconds)&lt;/td&gt;
&lt;td&gt;🐌 Slower (minutes)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Setup&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Easy&lt;/td&gt;
&lt;td&gt;Requires C compiler&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Source Protection&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Excellent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Best For&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Quick &amp;amp; Dirty&lt;/td&gt;
&lt;td&gt;Production Deployments&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  My Recommendation
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Development/Prototyping&lt;/strong&gt;: PyInstaller (if false positives don't matter)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Production/Client Projects&lt;/strong&gt;: Nuitka (more reliable, safer)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance-Critical&lt;/strong&gt;: Nuitka (noticeably faster)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Switching from PyInstaller to Nuitka was a game changer for me. Yes, compilation takes longer. Yes, the setup is more complex. But:&lt;/p&gt;

&lt;p&gt;✅ No more false positives&lt;br&gt;
✅ Better performance&lt;br&gt;
✅ More professional solution for production environments&lt;/p&gt;

&lt;p&gt;For internal tools or prototypes, PyInstaller is perfectly fine. But as soon as you're distributing software to clients or deploying at scale, I'd always recommend Nuitka.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Have you had similar experiences? Which solution do you prefer?&lt;/strong&gt; Drop a comment below! 👇&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Like this article? Follow me for more Python tips and automation content!&lt;/em&gt; 🐍&lt;/p&gt;

</description>
      <category>python</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
