Packaging PySide6 and PyQt6 Apps with PyInstaller

Solving the missing Qt platform plugin error when building executables
Heads up! You've already completed this tutorial.

I'm trying to package a PySide6 application with PyInstaller, but when I run the resulting executable I get the error: qt.qpa.plugin: Could not find the Qt platform plugin "xcb" in "". The packaging itself seems to work, but the app won't start. How can I fix this?

When you package a PySide6 or PyQt6 application with PyInstaller, the resulting executable sometimes can't find the Qt platform plugins it needs to run. This is a well-known issue that happens because PyInstaller doesn't always know where to find (or how to bundle) the plugin files that Qt depends on at runtime.

In this article, we'll look at why this happens and walk through the solution: telling PyInstaller exactly where to find those files so it can include them in your build.

Why Does This Happen?

Qt applications need platform plugins to interact with the operating system's display system. On Linux, the required plugin is called xcb. On Windows, it's qwindows. On macOS, it's qcocoa. These plugins live inside your Python environment's site-packages directory, typically under PySide6/plugins/platforms/ or PyQt6/Qt6/plugins/platforms/.

When PyInstaller bundles your app, it tries to detect and include all the necessary files automatically. For PySide6 and PyQt6, this automatic detection has historically been incomplete. The plugins folder gets left out, and when you run the packaged app, Qt can't find the platform plugin it needs — resulting in the error you see.

The Fix: Manually Including Qt Files

The workaround is to tell PyInstaller to include the missing files using the --add-data flag. This flag copies additional files or directories into the packaged application.

For PySide6

You need to include the plugins directory from your PySide6 installation. The command looks like this:

sh
pyinstaller --add-data "PYTHON_DIRECTORY/Lib/site-packages/PySide6/plugins:PySide6/plugins/" your_app.py

Replace PYTHON_DIRECTORY with the path to your Python installation. For example, if you're using a virtual environment at /home/user/myenv, the path would be /home/user/myenv/lib/python3.9/site-packages/PySide6/plugins.

For PyQt6

PyQt6 organizes its files a bit differently. You'll need to include the Qt6 directory and the sip module:

sh
pyinstaller --add-data "PYTHON_DIRECTORY/Lib/site-packages/PyQt6/Qt6:PyQt6/Qt6" your_app.py

Again, replace PYTHON_DIRECTORY with the actual path to your Python installation.

Finding Your Python Directory

If you're not sure where your Python packages are installed, you can find out by running this in a terminal:

sh
python -c "import sysconfig; print(sysconfig.get_path('purelib'))"

Or, to find the specific package location:

sh
python -c "import PySide6; print(PySide6.__path__[0])"

Replace PySide6 with PyQt6 if you're using that instead.

Linux vs. Windows: Watch the Separator

The --add-data flag uses a separator character between the source path and the destination path inside the bundle. This separator is different depending on your operating system:

  • On Windows, use a semicolon: ;
  • On Linux and macOS, use a colon: :

So on Windows, the PySide6 command would look like:

sh
pyinstaller --add-data "C:\Python39\Lib\site-packages\PySide6\plugins;PySide6/plugins/" your_app.py

And on Linux:

sh
pyinstaller --add-data "/home/user/myenv/lib/python3.9/site-packages/PySide6/plugins:PySide6/plugins/" your_app.py

Getting the separator wrong is a common source of confusion, so double-check this if things aren't working.

Using a Spec File

If you prefer to use a PyInstaller .spec file (which is helpful for more complex projects), you can add the data files there instead. First, generate a spec file:

sh
pyinstaller --name myapp your_app.py

This creates a file called myapp.spec. Open it in a text editor and find the Analysis section. You'll see a datas parameter — this is where you add your extra files:

python
a = Analysis(
    ['your_app.py'],
    pathex=[],
    binaries=[],
    datas=[
        ('/home/user/myenv/lib/python3.9/site-packages/PySide6/plugins',
         'PySide6/plugins'),
    ],
    hiddenimports=[],
    # ... rest of the options
)

Then build using the spec file:

sh
pyinstaller myapp.spec

This approach is easier to manage than long command-line arguments, especially as your project grows.

A Complete Example

Let's walk through the entire process with a simple PySide6 application. First, here's a small app to package:

python
import sys
from PySide6.QtWidgets import QApplication, QMainWindow, QLabel


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("My Packaged App")
        label = QLabel("Hello from PySide6!")
        label.setContentsMargins(20, 20, 20, 20)
        self.setCentralWidget(label)


app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())

Save this as my_app.py. Now, find your PySide6 plugins path:

sh
python -c "import PySide6; print(PySide6.__path__[0])"

Let's say this prints /home/user/myenv/lib/python3.9/site-packages/PySide6. Now package the app (on Linux):

sh
pyinstaller --add-data "/home/user/myenv/lib/python3.9/site-packages/PySide6/plugins:PySide6/plugins/" --windowed my_app.py

The --windowed flag prevents a console window from appearing alongside your GUI app (on Windows and macOS; on Linux it has no effect but doesn't hurt).

Your packaged application will be in the dist/my_app/ directory. Run it with:

sh
./dist/my_app/my_app

If It Still Doesn't Work

If you've added the plugins directory and still see errors, here are a few things to check:

  • PyInstaller version: Make sure you're using a recent version of PyInstaller. Support for PySide6 and PyQt6 has improved significantly over time. Upgrade with pip install --upgrade pyinstaller.
  • Virtual environment: If you're working in a virtual environment (which is recommended), make sure the paths you provide to --add-data point to files inside that environment, not your system Python.
  • Additional Qt libraries: Some applications may need more than just the plugins directory. If you see errors about missing Qt libraries at runtime, you may need to include additional directories from the PySide6 or PyQt6 package, such as the Qt/lib folder.
  • Consider alternatives: If PyInstaller continues to cause problems, other packaging tools like cx_Freeze or fbs may have better support for your particular setup. That said, PyInstaller's Qt6 support continues to improve with each release, so it's worth revisiting if you hit a wall.

Summary

The "Could not find the Qt platform plugin" error when packaging PySide6 or PyQt6 apps with PyInstaller happens because PyInstaller doesn't always bundle the Qt plugin files automatically. The fix is to manually specify these files using --add-data on the command line or in your .spec file. Remember to use : as the path separator on Linux/macOS and ; on Windows, and make sure you're pointing to the correct paths inside your Python environment.

Well done, you've finished this tutorial! Mark As Complete
[[ user.completed.length ]] completed [[ user.streak+1 ]] day streak

Create GUI Applications with Python & Qt6 by Martin Fitzpatrick

(PySide6 Edition) The hands-on guide to making apps with Python — Over 15,000 copies sold!

More info Get the book

Martin Fitzpatrick

Packaging PySide6 and PyQt6 Apps with PyInstaller was written by Martin Fitzpatrick.

Martin Fitzpatrick has been developing Python/Qt apps for 8 years. Building desktop applications to make data-analysis tools more user-friendly, Python was the obvious choice. Starting with Tk, later moving to wxWidgets and finally adopting PyQt. Martin founded PythonGUIs to provide easy to follow GUI programming tutorials to the Python community. He has written a number of popular Python books on the subject.