QGIS 4 is Here. Plugin Developers Have Two Things to Fix.

Key Takeaways 

  • QGIS 4.0 “Norrköping” shipped on March 6, 2026, and it brings two significant changes for anyone who maintains a QGIS plugin. 
  • The first is a switch from Qt5 to Qt6 – the GUI framework QGIS is built on – which breaks compatibility with most existing plugins. 
  • The second is a new security scanning system that reviews every plugin before it gets published to the repository. 
  • Both changes require that you actually run your plugin and verify its behavior – not just pass the automated checks. 
  • QGIS DevTools connects VS Code to a live, running QGIS session so you can do exactly that: pause execution at any point, look at what’s happening inside your plugin, and catch problems before your users do. 

Introduction

QGIS 4.0 “Norrköping” was released on March 6, 2026 – the first major version jump in roughly eight years, since QGIS 3.0 “Girona” in 2018. For most users, it looks nearly identical. For plugin developers, it arrives with two distinct sets of requirements landing at the same time.

This article walks through both, and explains where QGIS DevTools fits in.

Change One: Qt6

QGIS is built on top of a software framework called Qt (pronounced “cute”), which handles everything from the window layout and buttons to how the application talks to Python. QGIS has been running on Qt version 5 since 2016. QGIS 4 moves to Qt version 6.

Versions 5 and 6 are not fully compatible. Plugins that were written for Qt5 are highly unlikely to run in QGIS 4. This is the headline change for plugin developers – and old news for many.

The QGIS project has done a lot to soften the transition. The QGIS 3 LTR release was extended to give developers extra time. An official migration guide and a conversion script – pyqt5_to_pyqt6.py – are available to handle the bulk of the mechanical updates automatically. The next Long Term Release, QGIS 4.2, is scheduled for October 2026. That is the practical window: the version most organisations and institutions will adopt for production use.

What actually needs to change in your plugin


If you open a Python plugin that was written for QGIS 3, you’ll typically see lines at the top of each file that look something like this:

Example

from PyQt5.QtCore import Qt, QTimer

from PyQt5.QtWidgets import QAction, QDialog
  

These lines load the tools your plugin needs from Qt5. In Qt6, they need to reference Qt6 instead – or better yet, use a version-neutral path that QGIS provides:

Example

from qgis.PyQt.QtCore import Qt, QTimer

from qgis.PyQt.QtWidgets import QDialog
  

The migration script rewrites most of these automatically. Run it, and it will scan your plugin directory and update the import lines it recognises.

A few other things change beyond the imports:

Named option values. Qt uses something called “enums” – essentially, named values that represent options. Think of them like named settings: instead of passing the number 1 to mean “align left,” you write Qt.AlignLeft. In Qt6, these need to be written more specifically: Qt.AlignmentFlag.AlignLeft. The migration script catches many of these, but not all, especially when they appear in more complex or conditional code.

Moved components. Some Qt tools moved to different locations between versions. QAction, for example, moved from QtWidgets to QtGui. These are straightforward to fix once you know about them, but they surface as errors only when you actually run that part of the plugin.

Older QGIS API patterns. QGIS 4 currently keeps compatibility with some older patterns from the QGIS 2.x era, but this is not guaranteed to last throughout the 4.x lifecycle. Plugins relying on the old Processing API in particular should be updated.

Limitations of the migration script

The script is a good starting point. It handles the mechanical, predictable changes. What it cannot do is verify that your plugin actually behaves correctly after those changes. The QGIS project’s own migration guide puts it plainly: test your plugin thoroughly. That is easy advice to give. In practice, it means you need to exercise every code path in a real, running QGIS 4 session – and when something goes wrong, you need a way to understand what happened.

Change Two: The New Security Scanner

Separately from the Qt6 migration, the QGIS Plugin Repository introduced a security scanning system earlier this year. This one affects anyone who publishes a plugin, regardless of whether they’ve migrated to Qt6 yet.

Why this is happening

QGIS plugins run with Python and with the same permissions as the user running QGIS on their computer. That is a lot of access. Until now, the repository has operated largely on trust: once a plugin was approved, it could be republished freely with relatively little scrutiny. The new system changes that in two ways.

First, trust now attaches to the person, not the plugin. Previously, trust was granted to a plugin and stayed there regardless of what was uploaded later. Now the repository tracks authors – if a developer is found to be acting in bad faith, their entire portfolio of plugins can be addressed at once.

Second, every plugin now goes through automated security scanning before it can be published.

What the scanner looks at

The scanning uses a tool called Bearer. It looks for the kinds of problems that are easy to introduce accidentally and hard to spot by eye:

  • Credentials left in code. API keys, passwords, or access tokens that got hardcoded into a plugin and shouldn’t be there. This happens more often than you’d expect, especially with plugins that were built quickly or with AI assistance.
  • Overly permissive file system access. Code that reads or writes to locations on the user’s computer in ways that could cause harm or expose sensitive data.
  • Other known security risk patterns. Practices that security tools flag as potential vulnerabilities.

There is also a separate, non-blocking layer of checks – a tool called flake8 – that flags style and quality issues like unused imports, inconsistent formatting, and similar things. These do not block publication; they’re advisory.

What the badges mean

Every plugin in the repository now displays a badge. A red badge means the scanner found issues that need attention. A green badge means the plugin passed all the blocking checks. A small “i” icon means there are non-blocking advisories to look at.

If you are the owner of a plugin and it has a red badge, you can log in at plugins.qgis.org and see the full detail report for each flagged item.

What the scanner currently blocks – and what it doesn’t

For plugins being uploaded fresh, passing the security scan is required. Existing plugins that are already published are not being removed – they get the badge, and developers are expected to address the flagged issues in their next update.

There are known cases where a flagged item is actually intentional. A plugin that needs to embed an API key for a legitimate service, for example, will be flagged – but developers can mark those specific lines with an override flag in their code to tell the scanner that the issue has been considered and accepted. The goal is not automatic enforcement but conscious review: the QGIS project wants developers to have looked at each flagged issue and made a deliberate decision about it.

The team has acknowledged some teething problems. Some standard Python libraries – the XML parser, certain hashing functions – were triggering false positives, and the issue count reported in the badge didn’t always match the number of items listed in the detail report. These are being fixed. If you believe something is being flagged incorrectly, you can file an issue at github.com/qgis/QGIS-Plugins-Website.

For now, the badges are only visible on the plugins website. They do not yet appear inside QGIS Desktop’s own plugin manager – though that is on the roadmap.

What Both Changes Have in Common

The Qt6 migration and the security scanner are different in nature, but they share a key requirement: at some point, you have to run your plugin and check that it actually works.

The migration script rewrites your import lines. Static analysis tools – think of them as a spell-checker for code – can flag known patterns. But neither will tell you whether a variable contains the value you expect at a critical point, or why the QGIS interface freezes when a user triggers a particular action. The same is true after fixing security flags: code that passes the scanner still needs to work correctly in practice.

For most of QGIS plugin development history, the only tool available for this was printing messages to the console and hoping – a slow and frustrating process, especially in complex plugins. There was no clean way to attach a proper debugger to a running QGIS session.

That is the gap QGIS DevTools was built to close.

QGIS DevTools: A Debugger for a Live QGIS Session

QGIS DevTools is a QGIS plugin – free, open-source under GPL-2.0, available from the standard QGIS Plugin Repository – that starts a debugging server inside the running QGIS application and connects it to VS Code. It is already compatible with Qt6 and was updated to version 1.3.2 just days before QGIS 4.0 launched.

Once the connection is active, you can interact with your plugin through QGIS normally, but now you have full visibility into what is happening inside the code as it runs.

What this looks like in practice

Breakpoints. You place a marker on any line in your plugin’s code. When execution reaches that line – triggered by whatever action you perform in QGIS – it pauses. The interface freezes (intentionally), and VS Code shows you exactly where you are in the code.

Variable inspection. At the moment of pause, every variable that is currently in use is visible in the Variables panel in VS Code. For Qt6 migration work, this is particularly valuable: you can verify that the values you’re working with are what Qt6 actually produces, rather than what you assumed the migration script would give you. For security fixes, you can confirm that sensitive values are being handled the way you intended.

The debug console. While paused, you can type expressions and evaluate them against the live session. Ask for the coordinates of the last mouse click, inspect a geometry object, check the state of any variable – all without modifying your code.

Step-through. Instead of jumping to the next breakpoint, you can advance one line at a time and watch exactly how execution flows through a section of code.

Multiple QGIS instances. DevTools supports running several QGIS instances simultaneously by configuring a range of port numbers instead of a single one. This is useful when you want to compare behavior between a QGIS 3.x build and a QGIS 4 build side by side.

The plugin also works with the QGIS Python Console script editor – there’s a dedicated Debug Script button that starts the same debugging session for standalone scripts.

Setup

Full instructions are in the documentation. The short version:

  1. Install debugpy, the underlying debugging library, for your operating system:
    • Windows (OSGeo4W installation): add it via the OSGeo4W installer in the Libs category
    • Linux: apt install python3-debugpy
    • macOS: /Applications/QGIS.app/Contents/MacOS/bin/python3 -m pip install debugpy
  2. Install QGIS DevTools from the Plugin Repository (Plugins → Manage and Install Plugins → search “QGIS DevTools”)
  3. Install the Python Debugger extension in VS Code (Extensions → search “Python debugger”)
  4. In QGIS, open your plugin folder in VS Code, then press Start in the DevTools panel
  5. Copy the launch.json template that appears and paste it into a .vscode folder inside your plugin directory
  6. In VS Code, go to Run & Debug (Ctrl+Shift+D) and run “Attach to QGIS”

When the session is live, the DevTools icon in the QGIS status bar turns green and shows “client connected.”

A Practical Workflow for QGIS 4 Migration

Putting both the Qt6 migration and the security scanner together, here is a practical sequence:

  1. Run pyqt5_to_pyqt6.py on your plugin directory
  2. Fix the import errors and named-value issues it flags
  3. Address any blocking items from the security scanner report (log in at plugins.qgis.org to see yours)
  4. Load the updated plugin in QGIS 4
  5. Attach DevTools
  6. Set breakpoints in the code paths you changed – particularly anywhere the migration script rewrote something, and anywhere you modified code to address a security flag
  7. Trigger those actions in QGIS through normal use
  8. Inspect what’s in the variables at each pause point – confirm the behavior matches what you expect
  9. Step through any sections where something looks wrong

Steps 6–9 are what the automated tools cannot do for you, and where the time investment in a proper debugging setup pays off.

Quick Summary

  • QGIS 4.0 “Norrköping” shipped March 6, 2026. Plugins built for Qt5 will not run in it without updates.
  • The QGIS project provides a migration script (pyqt5_to_pyqt6.py) and a migration guide. The script handles the predictable changes. Runtime testing is still required.
  • A new security scanning system now reviews all plugins before publication. Blocking issues must be resolved before a new version can be uploaded. Existing published plugins get a badge and time to update.
  • Both changes require you to exercise your plugin in a real QGIS session to verify the results – not just check the code.
  • QGIS DevTools provides the connection between VS Code and a live QGIS 4 session: breakpoints, variable inspection, step-through execution.
  • QGIS 3 LTR has been extended to give plugin developers extra time. QGIS 4.2 LTR is expected in October 2026 – that is when most production environments will move, and the practical deadline for both the Qt6 update and security compliance.

FAQ

Does QGIS DevTools work with QGIS 4.0? Yes. The plugin is Qt6 compatible and was updated just before QGIS 4.0 launched.

Does it work with QGIS 3.x? Yes. You can start using DevTools today in QGIS 3.x to get comfortable with the workflow before you need it for migration testing.

I didn’t write my plugin myself – I used an AI assistant or adapted someone else’s code. Does this still apply to me? Yes, and arguably it matters even more. Automated tools are good at making changes that appear syntactically correct. The only way to know whether the result actually runs correctly is to test it in a real session. DevTools makes that testing practical.

Does using DevTools change my plugin code in any way? No. DevTools connects to the running QGIS application externally. Your plugin is untouched.

Which IDEs are supported? VS Code and Visual Studio, via debugpy. Support for additional environments – PyCharm, Eclipse – is planned.

My plugin has a red security badge. What should I do? Log in at plugins.qgis.org and open the detail report for your plugin. Work through the flagged items one at a time. For items that are genuinely intentional features (an embedded API key that is meant to be there, for example), you can add an override marker in your code. The QGIS team’s guidance is: visit each flagged issue, decide whether to fix it or accept it, and document that decision in the code. Full documentation on the scanning rules is at plugins.qgis.org/docs/security-scanning.

Is DevTools free? Yes. Open-source under GPL-2.0, free to install from the Plugin Repository. NextGIS also offers commercial support and custom development if you need it.

Resources

Comments are closed.