Blog / Open Source
How to Write Your First Pull Request to an Open Source Project
Your first pull request doesn't need to fix a hard bug. It needs to be small, correct, and reviewable in under five minutes — a maintainer's-eye guide to finding, scoping, and shipping it, start to finish.
Most people's first attempt at an open source contribution dies at the same stage: they find a hard, unassigned, six-month-old issue with a vague title, spend a weekend on it, open a 600-line pull request touching files across the whole codebase — and it sits unreviewed for three weeks, because no maintainer has an hour free to untangle a stranger's first-ever PR to their project. The problem was never their code quality. It was the size and shape of the ask.
A maintainer reviewing your PR is doing unpaid, volunteer work, usually squeezed between a day job and everything else in their life, and every pull request is a small tax on their attention whether it gets merged or not. Your job on a first contribution isn't to prove you can solve the project's hardest open problem. It's to prove you can move through the project's process cleanly, in a way that costs the maintainer as little time as possible to say yes to.
Choosing which project to contribute to in the first place
Before you even get to picking an issue, the project itself matters more than beginners usually credit. A project with a recent commit in the last week, a handful of merged PRs from people who aren't the original maintainer, and open issues that actually get responses is a healthy, living project — your contribution has somewhere to land. A project whose last commit was fourteen months ago, no matter how famous or how many stars it has, is often effectively unmaintained, and a PR there can sit forever with nobody able to review it, through no fault of your own.
Check the repo's insights or commit history before investing real time. A project with an active maintainer who responds to issues within a few days is worth far more to a first-time contributor than a bigger, flashier project that's gone quiet — the size of the project matters much less than whether anyone's actually there to say yes.
Finding an issue that's actually a good first one
Skip anything that's been open for months with no comments — that silence usually means it's harder or more ambiguous than it looks, not that it's been overlooked. The labels `good first issue` and `help wanted` exist on most actively maintained repos specifically because maintainers have already done the work of identifying which problems are genuinely small and well-scoped; use that filtering instead of guessing.
Documentation is underrated as a first contribution and shouldn't be. A broken link, a code example that no longer matches the current API, a setup step that's missing from the README — these are real, useful, low-risk fixes that teach you the entire contribution workflow (fork, branch, commit, PR, review, merge) without the added risk of also being wrong about the code. Plenty of people treat "just docs" as a lesser contribution; maintainers, who deal with outdated docs constantly, generally do not.
And the best source of all might be a project you already use as a normal person, not as a contributor. You'll notice rough edges naturally — the error message that didn't make sense, the flag that behaved differently than the docs implied — because you hit them living your life, not because you went hunting for something to fix.
Before you write a single line of code
Read the project's `CONTRIBUTING.md` if one exists. This sounds obvious and gets skipped constantly, and it's the single highest-leverage five minutes in the whole process — it usually tells you exactly what a maintainer wants (which branch to target, whether they want a linked issue first, what their commit message format is), which means you skip an entire round of review comments just by reading it before you start instead of after.
Comment on the issue saying you'd like to take it, and actually wait for a response before starting. This feels like it slows you down, and it does, by maybe a day — but it prevents the genuinely demoralizing outcome where you spend a weekend on a fix and discover someone else's PR for the same issue merged yesterday. Get the repo running locally before touching anything. A pull request that breaks the build because your own environment wasn't configured right is a specific, avoidable, bad first impression.
A complete walkthrough, from fork to merged commit
Concretely, the git side of a first contribution looks like this. Fork the repository into your own GitHub account, then clone your fork locally — not the original repo, your copy of it, since you don't have write access to the original and don't need it. Add the original repository as a second remote, conventionally called `upstream`, so you can pull in new changes from the real project as it moves without losing your own fork's history.
git clone https://github.com/YOUR-USERNAME/project.git
cd project
git remote add upstream https://github.com/ORIGINAL-OWNER/project.git
git checkout -b fix-settings-page-crash
# make your change
git add .
git commit -m "Fix crash on settings page when user.email is missing"
git push origin fix-settings-page-crashCreate a new branch for the specific fix — never commit directly to your fork's `main`, since that makes it much harder to keep your fork in sync with upstream later and to work on a second, unrelated fix at the same time. Name the branch after what it does, not after you or the issue number alone; `fix-settings-page-crash` tells a reviewer more at a glance than `patch-1` does.
Once you've pushed the branch, GitHub will offer to open a pull request from it directly, comparing your fork's branch against the original project's default branch. If a maintainer asks for a change after you've opened it, don't close the PR and open a new one — just make the change locally, commit again, and push to the same branch. The existing pull request updates itself automatically.
Keeping the change itself small on purpose
There's a real temptation, once you're in the code, to also fix the thing next to the thing you were fixing, and the thing next to that. Resist it on a first PR specifically. A twelve-line diff that does exactly one thing gets reviewed in a couple of minutes; a 400-line diff that fixes a bug and reformats three unrelated files and renames a variable you didn't like gets set aside for "when I have time to really look at this," which in practice means never.
Match the existing code style exactly, even in places you'd personally write it differently — tabs versus spaces, quote style, where the braces go. This isn't about your style being wrong; it's that consistency inside someone else's codebase matters more than any individual preference, yours included. And if the project has tests, add or update one covering exactly what you changed. A bug fix with no regression test is a bug that's allowed to come back.
The description is doing more work than the diff
A maintainer opening your PR is trying to answer three questions as fast as possible: what changed, why, and how do I know it actually works. A description that answers all three up front is the difference between a same-day review and a two-week wait, because you've done the maintainer's triage work for them instead of making them reconstruct it from a diff and a one-line title.
## What
Fixes a crash when `user.email` is missing on the settings page.
## Why
Fixes #142 — accounts created before email verification became
required have no email on file, and the settings page assumed one
always exists.
## How I tested it
Added a test case for a user with no email set, and manually loaded
the settings page against a seeded account without one.After you've opened it — including the parts nobody warns you about
Review feedback on a first pull request is, almost always, about the project's conventions rather than a judgment on your ability — respond to it as information, not as criticism, and push new commits onto the same branch rather than opening a fresh PR every time something needs adjusting. If it goes quiet for a week or two, a polite check-in comment is normal and expected, not pushy.
It's also worth preparing yourself for the outcome nobody talks about as much: sometimes a PR gets closed without merging, or a maintainer explains that the project is going a different direction than your fix assumed. This isn't a referendum on you, and it happens to experienced contributors constantly, not just beginners — the fix for how it feels is the same as the fix for most things in this list: pick another small issue and go again. The skill you were actually building — moving through a real project's process — is unaffected by any one PR's outcome.
Becoming a repeat contributor, not a one-time one
The gap between "contributed once" and "is a contributor" is usually just doing it a second and third time, and it gets meaningfully easier each time, because you already know the project's conventions, you already have `upstream` configured, and the maintainer already recognizes your name from a past PR that went well. That recognition compounds — a maintainer who's merged three small, clean PRs from you is far more willing to trust a fourth, larger one, which is genuinely how people end up with real ongoing responsibility on projects they didn't start.
A merged first pull request is a permanent line in a real project's commit history with your name on it. That's worth more, concretely, on a resume than most people give it credit for — and it took one small, well-scoped fix, not a heroic one.
Once you've done this once, the entire process stops being a mystery, and every contribution after it gets easier — not because the code gets easier to write, but because you've already learned the part that actually trips up most people: how to be a stranger a maintainer can say yes to quickly.