In this guide
On this page ⌄
Most first open source contributions fail for reasons that have nothing to do with coding ability. The contributor picks a project that is too big or too quiet, grabs an issue that is vaguer than it looks, spends a weekend on a change the maintainers did not want, and opens a pull request that ignores the project's conventions. The PR sits for weeks, then gets closed. The contributor decides open source is not for them.
Landing a first contribution is mostly about choosing well and communicating early. This guide covers how to pick a project, find an issue you can finish, get oriented in the repository quickly, make a change that fits, and write a pull request that is easy to say yes to. The orientation part leans on the same method as reading any unfamiliar codebase, adapted for a project where you do not have teammates down the hall.
Key takeaways
- Choose a project you use, that is actively maintained, and that responds to newcomers. Activity and responsiveness matter more than fame.
- Pick an issue that is small, clearly specified and recently confirmed by a maintainer. Comment before you start.
- Read CONTRIBUTING.md, the PR template and a few recently merged PRs before writing code. They tell you how this project wants work done.
- Get the project building and its tests passing locally before you change anything.
- Keep the PR small and focused, with a test and a clear description linking the issue.
- Respond to review quickly and politely. Most first PRs need a round or two of changes; that is normal.
Step 1: Choose a project
The best first project is one you already use. You understand what it does from the outside, you may have hit its bugs, and you will care about the result. Beyond that, check a few signals on the repository page:
| Signal | Where to look | Good sign |
|---|---|---|
| Recent activity | Commits and merged PRs tab | Merges in the last few weeks |
| Responsiveness | Recent issues and PRs from non-maintainers | Replies within days, not months |
| Newcomer friendliness | Labels like good first issue, help wanted | Labels exist and are recent |
| Contribution docs | CONTRIBUTING.md, CODE_OF_CONDUCT.md | Present, specific setup steps |
| CI | Checks on PRs | Automated tests run on every PR |
| Size | Lines of code, number of packages | Small to medium for a first PR |
Very large projects (major frameworks, operating systems, browsers) can be great places to contribute, but their processes are heavier: contributor license agreements, long review queues, strict release cycles. A mid-sized library or tool with a few active maintainers is often a gentler start.
GitHub's issue search helps find candidates across projects:
is:issue is:open label:"good first issue" language:python no:assignee
is:issue is:open label:"help wanted" language:typescript comments:<5
Step 2: Pick an issue you can finish
A good first issue has four properties:
- Small. A change you can make in an evening or two.
- Specified. It describes the current behavior, the expected behavior, and ideally where in the code the fix belongs.
- Confirmed. A maintainer has acknowledged it, labeled it, or said they would accept a fix. Unconfirmed feature requests are risky.
- Unclaimed. Nobody has said "I'm working on this" recently, and there is no linked open PR.
Documentation fixes, error message improvements, small bugs with a reproduction, and missing tests are all good first contributions. They are real work that maintainers value, and they teach you the project's process without requiring deep knowledge of its internals.
Before you write code, comment on the issue:
I'd like to work on this. My plan is to add a check in `parseConfig` so that
an empty `include` array raises the same error as a missing one, plus a test
in `tests/test_config.py`. Does that approach sound right?
This one comment prevents the most common failure: building something the maintainers did not want. It also shows you have read the code, which makes a maintainer more likely to answer.
Step 3: Read how the project works
Before touching code, read the project's process documents. They save you a review round.
[ ] CONTRIBUTING.md: setup, branch naming, commit style, how to run tests
[ ] PR template (.github/pull_request_template.md): what the description must include
[ ] CODE_OF_CONDUCT.md
[ ] Issue templates: how bugs are expected to be reported
[ ] Changelog conventions: does every PR add an entry? (CHANGELOG.md, changesets, towncrier fragments)
[ ] Commit message style: Conventional Commits? Sign-off (DCO) required?
[ ] Three to five recently merged PRs from outside contributors
The recently merged PRs are the most useful item. They show you what a successful PR looks like here: its size, how tests are written, how the description is phrased, what reviewers ask for. Copy those patterns.
If the project requires a Developer Certificate of Origin sign-off, commit with -s:
git commit -s -m "fix(config): treat empty include list as missing"
Step 4: Set up and get oriented
Fork the repository, clone your fork, and add the original as upstream:
git clone git@github.com:<you>/<project>.git
cd <project>
git remote add upstream https://github.com/<owner>/<project>.git
git checkout -b fix-empty-include
Follow the setup steps in CONTRIBUTING.md and run the full test suite before changing anything. If tests fail on a clean checkout, you need to know that now, not after your change.
Then orient yourself around your issue, not the whole project:
- Find the entry point for your change. If the issue is about a CLI flag, find where flags are parsed. If it is an error message, search for the message text. The string search usually lands you within a few lines of the fix.
- Read the surrounding code and its tests. Tests show how the module is meant to be used and give you a template for your own test.
- Check who calls what you will change. In a library, public functions may be used by every downstream project; changing their behavior is a bigger deal than it looks.
- Look at history for that file.
git log --oneline -- path/to/fileshows recent changes and who reviewed them.
rg -n "include must not be empty|include" src/ | head
git log --oneline -10 -- src/project/config.py
For deeper orientation on an unfamiliar repo, the techniques in finding the entry point of any repository apply directly.
Step 5: Make a change that fits
Maintainers merge changes that look like the rest of the project. Some rules that hold almost everywhere:
- Stay in scope. Fix the issue and only the issue. Do not reformat the file, rename unrelated variables or fix three other things you noticed. Open separate issues for those.
- Match the style. Run the project's formatter and linter (
npm run lint,ruff check,cargo fmt && cargo clippy,gofmt). Follow naming and structure patterns from nearby code even if you would do it differently. - Add a test. A bug fix with a test that fails before the fix and passes after is the easiest kind of PR to approve.
- Update docs and changelog if the project expects it.
- Keep commits tidy. Some projects squash on merge, some want a clean history. Follow what merged PRs do.
Before pushing, sync with upstream so your branch is current:
git fetch upstream
git rebase upstream/main
# run tests again
git push -u origin fix-empty-include
Step 6: Write a PR description maintainers can review fast
Maintainers review a lot of PRs, often in their spare time. Make yours fast to evaluate:
Fixes #1234
## What
An empty `include` list in the config now raises `ConfigError("include must
not be empty")`, the same as a missing `include`. Previously it silently
matched no files.
## How
Added a length check in `parse_config` (src/project/config.py) next to the
existing missing-key check.
## Testing
- Added `test_empty_include_raises` in tests/test_config.py
- Ran the full suite locally: all passing
Link the issue with a closing keyword (Fixes #1234) so it closes on merge. Fill in every section of the PR template, even if it feels redundant. If CI fails, look at the logs and fix it before asking for review.
Step 7: Handle review well
Expect feedback. A first PR often goes through one or two rounds of changes, and that is a sign the maintainers care, not that you did badly.
- Respond within a day or two if you can. Momentum matters; a PR that goes quiet gets forgotten.
- Address every comment, either with a change or a short reply explaining why not. Mark conversations resolved only if the project expects contributors to do so.
- Ask when unclear. "Do you mean move the check into the validator class, or call the validator from here?" is a perfectly good reply.
- Push follow-up commits rather than force-pushing a rewritten history, unless the project asks otherwise. It makes re-review easier.
- Be patient. If a week passes without a response, a single polite ping is fine: "Friendly bump, happy to make any changes needed."
If the PR is declined, ask what would have made it acceptable. The answer is useful for the next one.
After the first merge
The second contribution is much easier than the first. You have a working setup, you know the conventions, and the maintainers know your name. Look for a slightly larger issue in the same area, review someone else's PR, or help triage new issues by reproducing them. Many long-term maintainers started exactly this way.
Getting oriented faster
The slowest part of a first contribution is usually orientation: understanding enough of an unfamiliar repo to know where your change belongs and what it might affect. A guided overview can shorten that. OpenVisio's Tour works on public GitHub repos: paste the URL and it indexes the code in your browser, then walks through the main parts of the project stop by stop. For a pointed question like "where is the config file parsed?", Ask returns an answer with the relevant code beside it, which you can then confirm by reading and running the tests.
Pick a project you use, pick a small confirmed issue, comment first, follow the project's conventions, and keep the PR small. That combination gets first contributions merged far more often than talent alone.

