For years I told myself I would contribute to open source "when I had time". I use Angular and Laravel every day, so I was reading their code and docs all the time, and I never sent anything back. In September I stopped waiting.
Most of this happened after my day job: between college classes, or late at night after them, looking for bugs I could fix. My first pull requests went out on September 11, to super-productivity, Symfony and Swashbuckle.AspNetCore, and the next day I sent one to Laravel. The Angular docs PRs came at the end of the month.
From September 11 to October 21, 46 of my pull requests were merged across 10 projects:
- angular/angular: 7 (docs)
- ng-native: 6
- voidzero-dev/oxc-angular-compiler: 2
- super-productivity: 8
- laravel/framework: 2
- laravel/docs: 12
- symfony/symfony: 5
- symfony/symfony-docs: 2
- filamentphp/filament: 1
- Swashbuckle.AspNetCore: 1
A few of those are one-line docs fixes. Others needed real debugging on an Android emulator. This is what I took from it.
1. Docs are the easiest way in
My merged Angular PRs had no code in them. I read the guides and checked whether the examples still matched what the framework does. A lot of them didn't.
On angular.dev I found a guide that still talked about fullTemplateTypeCheck, an afterRenderEffect example using the wrong phase, and Signal Forms pages that still called the feature experimental. In the Laravel docs I ran into examples with syntax errors, wrong method names, and default values that had changed in 13.x.
My process was simple: when something in the docs looked wrong, I tested it against the code. If the code did something different, I had a PR.
Docs PRs are small and quick to review, and they make you read the framework closely.
2. Real bugs come from real work
My laravel/framework fix came from a freelance project. My code threw an error, I opened the framework source to see why, and found the bug: appendToPriorityList() broke when the middleware you pointed at was the first item in the list.
I sent a PR with a regression test. While I was messaging my coworkers that I had just sent a fix to Laravel itself, the notification arrived: Taylor Otwell had merged it, about two and a half hours after I opened it.
The PR was easy to merge because it asked for very little: one test that failed before the fix and passed after it.
3. Prove the fix the way the project does
Each project has its own way of showing that a change works, and following it is half of the job.
- For ng-native (Angular running on React Native), I needed to see the bug on a real Android emulator. I run it in Docker, so the Android SDK never gets installed on my machine. I let Claude Code do that setup for me. For installing and configuring tools, AI saves a lot of time.
- For oxc-angular-compiler (a Rust port of the Angular compiler), I compared its output with the official compiler,
ngtsc, on the same templates. Every difference is a possible bug, and that is how I discovered that incremental hydration never switched on its runtime. - For super-productivity, the first full test run froze my machine: not enough RAM and no swap. Now I cap memory before running heavy test suites.
4. Maintainers may change your code, and that's fine
I started contributing to oxc-angular-compiler because I admire Ashley Hunter, the main maintainer of ng-native, who also works on it.
In #592 I made @defer blocks lazy-load the imports used only inside them. Before merging, the maintainer pushed four more commits on top of mine: exact selector matching like the Angular compiler does, keeping the imports that other code still needs, and a few other things.
In ng-native #935 (the Android keyboard following the screen while it moves), the maintainer added two commits and merged it in under an hour.
A maintainer adding commits to your PR is not a rejection. It means they wanted the change in.
5. Every project merges differently
My first Symfony PR shows up as "Closed" on GitHub, not "Merged", but it did get in: the maintainer applied it as a commit on the 6.4 branch and left a comment with the hash. When a PR is closed, read the last comment before assuming it was turned down.
What's next
In upcoming posts I'll take one PR at a time and explain the bug, why it happened, and how it was fixed. The next one covers how @defer decides which imports become lazy.
If you are just starting, my advice is to begin with the docs, read the contribution guide before anything else, and send one small thing at a time.
You can find me on GitHub and LinkedIn.
Drafted with AI assistance; the experiences and facts are mine.
Top comments (0)