Flutter

Migrating Flutter Plugins to Pigeon: Lessons Learned

After two years using Pigeon for Firebase plugins, we weigh its benefits for type safety against frequent breaking changes. Read our experience and insights.

5 min readMigrating Flutter Plugins to Pigeon: Lessons Learned

In June 2022, the FlutterFire team at Invertase and Google decided to migrate to Pigeon—a new method for writing plugins aimed at enhancing type safety within the Flutter ecosystem.

At the time, most native bridges were manually implemented. Transitioning to Pigeon felt like a great opportunity to automate this process, reducing the potential for errors when parsing or extending platform interfaces.

I had previously used Pigeon successfully when migrating my location plugin. Encouraged by this positive experience, I wanted to explore using it at a larger scale. Given that the objects sent to native platforms can become quite large and challenging to thoroughly review, adopting Pigeon seemed like an ideal solution to avoid oversights and enhance accuracy.

Now, in April 2025, it's time to reflect on this technical decision.

The Good

One significant improvement since adopting Pigeon—particularly noticeable after migrating large plugins like Firebase Firestore—has been the substantial boost in type safety. It helped streamline our implementations, ensuring consistent approaches across iOS and Android.

Another benefit is the reduction of boilerplate parsing code. Now that explicit types are expected, we can better focus our efforts on maintaining meaningful logic rather than tedious parsing tasks.

Additionally, since the initial migration, we've introduced Firestore support for Windows. In this context, Pigeon’s ability to generate typing directly was incredibly valuable.

Overall, Pigeon has significantly contributed to our code quality and allowed us to dedicate more resources to value-adding functionalities.

The Bad

Despite these advantages, our experience wasn’t without hurdles. A notable issue was the lack of native support for EventChannels. To address this, we leveraged parsers generated for MethodChannels as a workaround, achieving type generation indirectly. While functional, it was clearly not ideal.

Another challenge is how difficult it is to contribute or add new features to Pigeon. Early on, we attempted to make Encoders and Decoders public, enabling their reuse elsewhere in our codebase, but despite offering PRs and clearly defined use-cases, we faced significant resistance. It seemed Pigeon maintained a rigid vision aligned tightly with Flutter’s internal roadmap, rather than broader community needs. EventChannel support finally arrived two years later, in December 2024, but it still lacks C++ support, limiting its utility for us.

We also struggled with the lack of built-in support for CustomCodecs. Again, a workaround was required to enable their use with Firestore.

Perhaps the most disruptive aspect has been the sheer frequency of breaking changes. At the time of writing, Pigeon stands at version 25.2.0, meaning we've experienced 25 major breaking updates. Currently, FlutterFire is pinned at version 11.0.1. The constant migration pressure reduces confidence and commitment—why adopt a solution intended to save time when much of that gain is lost maintaining compatibility with the latest version?

Community Adoption

More than five years after version 0.1.0 of Pigeon was released, how widely has it been adopted?

A quick GitHub search reveals usage by notable companies and packages including Alibaba, AWS, and popular Flutter packages like camera and image_picker. It's also extensively used within Google's official packages, such as in_app_purchase and video_player.

Clearly, Pigeon has gained traction. However, a deeper dive shows that many projects, even official Flutter ones, aren’t always using the latest version. Packages like url_launcher remain on version 21, while camera_android is still on version 9.1.0. Is this cause for concern? Not necessarily. Given Pigeon's role—simply facilitating message passing between native platforms—it might not be critical to frequently update. The mantra "if it ain’t broke, don’t fix it" likely applies here.

Nevertheless, the frequency of breaking changes makes upgrading an unnecessarily time-consuming task.

Conclusion

If given the chance to make this decision again, would I still migrate everything to Pigeon? Honestly, despite its drawbacks, it continues to save significant time when dealing with large, complex objects exchanged between platforms. For simpler packages, sticking with a straightforward MethodChannel might be simpler and more efficient.

If Pigeon slows down the frequency of breaking changes, its value proposition becomes much stronger. For now, the maintenance overhead of keeping up with frequent updates might overshadow the advantages it brings.

Curious about Flutter development? Check out our Flutter open-source projects here to learn more and get involved!