I have written a lot of posts complaining about Flutter.
"I Love Flutter, But Sometimes It Feels Like We're In A Toxic Relationship." "The Silent Struggle of a Flutter Developer." "Android Studio: Stockholm Syndrome Disguised as an IDE." You get the idea. Complaining is fun, it is easy, and people upvote it, which is a terrible incentive structure if you think about it too long.
Then one day I hit a small stupid thing and instead of writing about it, I fixed it.
Since then I have had 8 pull requests merged — five into Flutter itself and its official packages, one into the Supabase Dart SDK, and two into Sentry's. All reviewed by the teams that maintain them. All public. All boring in the best possible way.
Nobody tells you what that process is actually like, so here it is.
It started with dart format
You run flutter create my_app. You get a fresh project. You run dart format . before your first commit, because you are a reasonable person.
The formatter reformats the code Flutter just generated for you.
That is it. That is the bug. Brand new project, zero lines written by a human, and it already fails its own formatter. It is a tiny thing. It does not break anything. It just sits there being slightly wrong forever, for every single person who runs that command.
So I fixed the template. That was flutter/flutter#187443. Later I found the plugin example template had the same problem and fixed that too — #188382.
Here is the part that surprised me: nobody told me I was not allowed to. There is no gate. There is no "senior enough" checkbox. The repository is right there and the contributing guide is genuinely good.
What the other six were
I want to be honest about the size of these, because "I contributed to Flutter" sounds much more heroic than what actually happened.
flutter/packages#11793 — path_provider docs. getDownloadsDirectory() returns null on some platforms and throws UnsupportedError on others, and the documentation did not make it clear which was which. If you guess wrong you get a crash in production on one platform and a silent null on another. I documented the actual behaviour.
flutter/packages#11880 — Pigeon and enhanced enums. Pigeon is Flutter's code generator for platform channels. If you handed it a Dart enhanced enum, it did not say "I don't support that." It failed in a way that made you think you had done something wrong. Now it tells you plainly.
flutter/packages#11894 — Pigeon event channel docs. Generated code with no usage documentation, so you had to read the generator's source to figure out how to use its output.
supabase/supabase-flutter#1365. This one was a real bug. A realtime channel would try to rejoin using a cached JWT that had already expired, and the resulting InvalidJWTToken would surface as a failure even though the rejoin itself was fine. Your app just quietly loses realtime updates and you have no idea why.
getsentry/sentry-dart#3697. sentryOnError was not synchronous inside runZonedGuarded, which meant errors could be swallowed. Think about that for a second: an error reporting SDK, silently dropping errors. That is the worst possible thing for that specific library to do.
getsentry/sentry-dart#3698. Sentry's own diagnostic logs were not reaching the browser console on web, so when the SDK misbehaved you could not see why.
Three of those eight are documentation. One is an error message. None of them are clever. That is kind of the point.
What nobody tells you
Most of it is not code. Signing the CLA, matching the existing style, writing the test, filling out the PR template properly, linking the issue. The actual fix is often the smallest part of the work.
Reviewers are busy, not hostile. I braced myself for the legendary open source rudeness and it never came. What I got instead was silence, sometimes for a while, and then precise, specific feedback. Silence is not rejection. It is a queue.
The tests are the real barrier. Not writing them — figuring out where they go and how the existing harness works in a repository with tens of thousands of files. Budget more time for "where does this test live" than for the fix.
Small and correct beats large and ambitious. Nobody wants a drive-by refactor from a stranger. Everyone wants a two-line fix with a test that clearly explains why.
It is slow. Some of these took weeks from open to merge. If you need the dopamine hit today, this is the wrong hobby.
The honest part
I did not do this out of pure open source idealism. I did it partly because I am a developer in Bangladesh trying to prove I am good at this to people who have never met me, and "trust me, I'm experienced" does not travel well across borders.
A merged PR travels. It is a permanent, public, third-party-verified statement that a team of people who maintain a very large codebase looked at your work and decided it was correct. You cannot fake it and you cannot buy it. Anyone can check it in about thirty seconds.
That turned out to matter more than any line on my CV.
But there is a second thing that I did not expect and value more. Reading the Flutter source to fix one formatting template taught me more about how the framework actually works than two years of using it did. You stop treating it as magic. It is just code, written by people, with the same tradeoffs and leftover TODOs as yours.
How to find your first one
Not "solve a hard problem." Do this instead:
- Write down the next small thing that annoys you. Confusing error message, wrong documentation, example that does not compile. You hit these weekly and you scroll past them.
- Search the repo's issues for it. Usually someone has already reported it and it is sitting there because nobody had a spare afternoon.
-
Check
good first issue— but honestly, the annoyance you found yourself is better, because you already understand the context. - Read the contributing guide properly. Actually read it. Most rejected PRs fail on process, not on code.
- Open the PR and then go do something else. Do not refresh the tab. It will take as long as it takes.
Your first one does not need to be impressive. Mine was reformatting a template file.
If you use Flutter every day, you are already qualified to improve it. You know where it hurts, because it hurts you specifically. The gap between the people who complain about a framework and the people who fix it is not talent. It is mostly just opening the tab.
I have written a lot of posts complaining about software. The 8 pull requests did more for me than all of them combined.
I build Flutter and React Native apps, plus the backends behind them. My apps are on Google Play and the App Store. If you are dealing with something in the Flutter ecosystem that keeps not working, I am reachable at pranta.dev or github.com/theprantadutta.
Top comments (1)
Great advice. Here's my hotkey on this:
If you're new to open source, you might consider submitting fixes for the packages that you use from pub as a first step. Basically, find an issue, comment on it expressing interest in fixing it, and see if you get responses. Responses will range from "already being worked on, so coordinate with X" to [crickets], with the latter suggesting that you likely won't get a PR merged, so move on.