Distribute a Python GUI App in 5 Minutes

March 15, 2025

Read on Medium
  • software-development
  • coding
  • python
  • gui
  • apps

In this quick guide, I will show you how to build your own Python app with a GUI using Tkinter or PyQt, and distribute it as an executable file. Currently, this approach has only been tested on Windows, but similar steps can be applied to macOS or Linux with some adjustments. I’ll update this post once I confirm those details

Create Your Python Project in a Dedicated Environment

You can create your Python project however you prefer. I tend to use PyCharm because it makes it easy to manage environments. I will also be using command prompt, PowerShell acts a bit different. After creating your project, you can set up the environment by running:

python -m venv myenv

Now activate it using:

.\myenv\Scripts\activate

Install PyInstaller and Necessary Packages

PyInstaller is one of the most popular and recommended tools for packaging Python apps into executables, which is what we’ll use in this guide. For more information, check out the documentation here.

Make sure you have activated your environment, and then install PyInstaller using:

pip install pyinstaller

For GUIs in Python, you have several options, including Tkinter and PyQt. Tkinter is already included in Python, so no installation is needed. However, I prefer using PyQt6 or PySide6, as it offers more features and a more modern aesthetic. To install PyQt6, run:

pip install PyQt6

Basic GUI Application with PyQt

Now let’s create a simple GUI application using PyQt. Create a main.py file in your project’s root directory with the following code:

# main.py
import sys
from PyQt6.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout, QLabel

class GUI(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle('Simple PyQt6 App')
self.setGeometry(200, 200, 300, 200)
layout = QVBoxLayout()
self.label = QLabel('Hello, PyQt6!', self)
self.button = QPushButton('Click Button', self)
layout.addWidget(self.label)
layout.addWidget(self.button)
self.button.clicked.connect(self.change_text)
self.setLayout(layout)
def change_text(self):
self.label.setText("Button Clicked!")
if __name__ == '__main__':
app = QApplication(sys.argv)
window = GUI()
window.show()
sys.exit(app.exec())

Build Executable for Application

Now, let’s bundle the application into an executable using PyInstaller. Run the following command:

pyinstaller --onefile --windowed main.py

This targets the main.py file you created and will begin bundling the code, creating a build and a dist directory once completed.

  • --onefile packages the code into a single executable file.
  • --windowed removes the terminal window, so only the application window appears when running the .exe.

At this point, you might encounter errors with your antivirus software, marking the files as Trojan horse malware. I’ve seen this happen with Windows Defender and Bitdefender before. You have a few options:

  • Temporarily disable your antivirus shield while bundling the application.
  • Add an exception to your antivirus software for the path containing your project.
  • You can also check the file using VirusTotal to confirm whether it’s falsely flagged.

If everything runs smoothly, you should now see a .exe file in your dist directory, which will launch your application when run.

Simple PyQt6 demonstration

Rebuild Using a Spec File

After bundling your application, PyInstaller will create a main.spec file that references your main.py file. The spec file allows you to customize the build process and includes instructions for how to build your application. This can be useful for adding additional files or excluding packages, for example. To rebuild the application, run:

pyinstaller main.spec

This makes it easy to rebuild your app after making changes.

Track Dependencies & Clean Up

It’s highly recommended that you add a requirements.txt file to track the dependencies in your project. You can generate the file with:

pip freeze > requirements.txt

Additionally, it’s a good idea to update your .gitignore to exclude build artifacts from your repository. Here's a sample .gitignore:

# Ignore build directories
build/
dist/

# Ignore virtual environment
.venv/

# Ignore other IDE files
.idea/
.vscode/

Conclusion

You’ve now created your own distributable GUI application in Python. PyInstaller is great at automatically bundling your code, so you likely won’t need to modify the main.spec file unless necessary. For example, I was able to package an application with an SQLite database without additional configuration.

Python directory app made with PyQt and bundled with PyInstaller

Thanks for reading! I’m a full-stack developer specializing in React, TypeScript, and Web3 technologies.

Check out more of my work at mrmendoza.dev
Find my open-source projects on GitHub
Connect with me on LinkedIn

Let me know if this article was helpful or anything you’d like to see next.

Contact Me

Let's bring your web project to life

Thank you for taking the time to visit my website! If you're looking for a skilled and innovative developer to work with, don't hesitate to reach out. Whether you have a job opportunity or a freelance project in mind, let's connect and see how we can work together.

You can send me a message below or email me at mrmendoza171@gmail.com