Blog post cover image

At Development Seed, we've worked on everything from cloud-native geospatial pipelines to interactive Earth observation platforms. But until recently, we hadn’t worked directly inside the QGIS plugin ecosystem.

That changed when we took on a major revamp of the QGIS Earth Engine plugin. Along the way, we gained a lot of knowledge on how to set up CI/CD for QGIS plugins, structure them with a modular architecture, and write meaningful tests.

We quickly learned that while the ecosystem is vibrant, advanced plugin development guidance is scattered. Tutorials often cover the “Hello World” stage, but not the patterns that make a plugin maintainable, testable, and future-proof. That’s where the Processing framework comes in.

Why The Processing Framework Should Be Your First Stop

The QGIS Processing framework provides a solid foundation for building plugins. It automatically validates parameters, handles logging, integrates with the Model Designer, and generates user interfaces for your algorithms. When you implement your plugin’s functionality as Processing algorithms, you also gain built-in documentation and the ability for users to combine your tools with others in larger workflows.

In the Earth Engine plugin, even the menu actions launch Processing algorithms using execAlgorithmDialog(). This approach keeps the interface consistent and eliminates the need to maintain duplicate logic—every time we make a change to the algorithm, it is instantly reflected in every place it’s used.

When you hit a wall with the Processing framework for its UI limitations, keep using it!

But the Default UI Has Limits

The Processing framework's auto-generated dialogs are static, built entirely from the parameter definitions you provide. That works well for straightforward tools, but it quickly becomes restrictive when you need more interaction. You can’t dynamically update a field—for instance, populating a dropdown after a user enters an asset name. You can’t easily show or hide inputs based on earlier selections. And you can’t handle more complex data entry, such as nested filters.

In our case, one algorithm needed a percentile slider to appear only when the “Percentile” compositing method was selected. In another, we wanted the dialog to reach out to Earth Engine, fetch metadata for a given dataset, and use that information to populate dropdown menus in real time.

Custom Dialogs Backed by the Processing Framework

Instead of abandoning the Processing framework and writing custom logic from scratch, we extended it.

We subclassed QgsProcessingAlgorithmDialogBase to create interactive dialogs that still invoke the underlying QgsProcessingAlgorithm. This gave us the benefits of Processing—logging, validation, and integration with other tools—while allowing for a responsive UI with conditional visibility, smart defaults, and dynamically populated fields. We kept the UI and algorithm logic separate, which made both easier to test and maintain.

Image

The Add Image Collection dialog.

The dialog itself acts only as a front-end wrapper. It gathers and validates inputs, then passes them to the algorithm’s processAlgorithm() method. This means the algorithm can still be run headlessly from the Processing toolbox, in a model, or from the Python console—without relying on the custom dialog.

Examples from the Earth Engine Plugin

Custom dialogs gave us room to make the plugin more responsive to the user’s workflow. Two examples from the Earth Engine plugin show how this works in practice.

In one case, we wanted to simplify the interface for compositing methods. The plugin offers several options—Mosaic, Mean, Max, Min, Median, and Percentile—but the percentile slider is only relevant when “Percentile” is selected. By wiring the compositing dropdown to show or hide the slider automatically, we kept the interface clean and reduced the chance of confusion.

Compositing method selection with dynamic percentile slider
Image

The percentile slider from the Add Image Collection dialog.

In another case, we wanted the plugin to guide users through filtering an Earth Engine dataset. When a user enters an Image Collection ID, the plugin fetches metadata for that dataset—such as available properties and bands—and uses it to populate the filtering and visualization dropdowns. This prevents typos, reduces trial-and-error, and makes it easier to explore unfamiliar datasets.

Earth Engine Image Collection ID input
Image

Dynamic filter selection in the Add Image Collection dialog.

Both of these behaviors are possible because the dialog still runs the underlying Processing algorithm, but with the added flexibility of custom interaction logic.

Other Lessons Learned

While the custom dialog pattern was our main takeaway, several other practices made a big difference to the stability and maintainability of the Earth Engine plugin. We set up a headless testing environment using pytest and pytest-qgis, which allowed us to run algorithms without launching the full QGIS GUI. This meant we could automate testing in continuous integration and catch regressions before they reached users.

We also implemented structured logging by integrating Python’s logging library with QGIS’s message log. This ensured that both developers and end users saw meaningful, actionable feedback—whether in the form of detailed logs during development or clear error messages in the QGIS interface.

Finally, we kept the plugin lightweight by avoiding unnecessary external libraries and relying on QGIS’s built-in capabilities wherever possible. This approach reduced the risk of dependency conflicts, kept the plugin well under the QGIS repository size limit, and made installation smoother for users.

Continuing the Conversation

The QGIS plugin ecosystem is thriving, but development practices are uneven. Many plugins are maintained by GIS experts who bring deep domain knowledge but may not have the time or background to apply modern engineering practices. Approaches like building custom dialogs on top of the Processing framework make it possible to create powerful, maintainable tools without unnecessary complexity.

We’d like to see these kinds of patterns collected in a shared QGIS Plugin Development Guide—covering architecture, testing, UI design, and integration with core features—so they’re easier to find and reuse. We’ve contributed our custom dialog approach to the official QGIS documentation.

If you want to see it in action, explore the Earth Engine plugin, run its Processing algorithms from both the toolbox and the menu, and check out how the custom dialogs work. If you’ve built similar patterns—or see ways to improve ours—we’d love to hear from you. QGIS keeps evolving, Earth Engine keeps growing, and the more we share what works, the stronger these tools become for everyone.

I’ll be at Geo4Good in New York later this month and would be glad to connect with Earth Engine users and developers.

What we're doing.

Latest