Comprehensive reference for open source contribution guide covering essential concepts, practical examples, and production best practices.
Contributing to open source projects is essential for engineers who want to ship code that reaches thousands, collaborate across time zones, and build visible, lasting impact. This guide is your step-by-step map from first-time contributor to regular maintainer, covering the full lifecycle of a contribution—from finding an issue, setting up a local environment, making a change, and submitting a pull request to landing that change in production.
Before writing a single line of code, you must find a problem that matters. Start with a search on GitHub, GitLab, or a project’s issue tracker. Use the is:issue and label:good-first-issue filters. For example:
https://github.com/org/project/issues?q=is:issue+label:good-first-issue+sort:updated-desc
Once you’ve picked an issue, comment on it to claim it: “I’d like to work on this. Please assign me.” This signals your intent and prevents duplicate work.
Most open source projects use git for version control and package.json for dependency management. Clone the repository, then install dependencies:
git clone https://github.com/org/project.git
cd project
npm install
Many projects use package.json scripts. Run the development server with:
npm run dev
If the project uses a Dockerfile, you can also use docker-compose up to run the full stack:
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
depends_on:
- db
db:
image: postgres:15
environment:
POSTGRES_DB: project_dev
POSTGRES_USER: devuser
POSTGRES_PASSWORD: devpass
Run it with:
docker-compose up -d
Check that the app is running at http://localhost:3000.
Before making a change, run the test suite:
npm test
If tests fail, examine the output. A common failure is a test that expects a specific JSON response:
{
"error": "User not found",
"status": 404
}
If your code returns {"error": "User not found", "code": 404}, the test fails because the key status is expected but code is provided.
Use npm run lint to catch style issues. The linter might complain about trailing whitespace or missing semicolons:
src/userService.js
15:1 error Missing semicolon semi
22:3 warning Trailing whitespace no-trailing-spaces
Fix all issues with:
npm run lint:fix
Now write your code. Suppose you’re fixing a bug where a user’s email is not being validated on registration.
Edit src/controllers/userController.js:
// Before
async function createUser(req, res) {
const { name, email } = req.body;
const user = await User.create({ name, email });
return res.status(201).json(user);
}
// After
async function createUser(req, res) {
const { name, email } = req.body;
if (!email || !/^\S+@\S+\.\S+$/.test(email)) {
return res.status(400).json({
error: 'Invalid email format',
details: { email }
});
}
const user = await User.create({ name, email });
return res.status(201).json(user);
}
Use git commit with a standard message format:
git add src/controllers/userController.js
git commit -m "feat(user): validate email format on registration
- Add regex validation for email field
- Return 400 with error details if invalid
- Update test to expect error object with `error` and `details` keys
Closes #123"
The commit message follows the format: <type>(<scope>): <subject> and includes a body with details. The Closes #123 line automatically closes the issue with number 123 when the PR is merged.
Push your branch to your forked repository:
git push origin feature/user-email-validation
You can now open a pull request.
Go to the project’s GitHub page, and click “Compare & pull request.” Fill in the PR template, which may include:
Use the Fixes #123 syntax in the PR body to link related issues.
After submitting, the maintainers will review your PR. They may request changes. Common feedback includes:
Respond to feedback by pushing new commits to the same branch:
git commit -m "docs: update README with example of email validation"
git push origin feature/user-email-validation
The PR automatically updates with the new commits.
Most projects use GitHub Actions, GitLab CI, or Travis CI. A PR triggers a CI pipeline. Look at the logs to diagnose failures.
A common failure is a test that times out:
1) User registration with invalid email
should return 400 on invalid email:
AssertionError: expected 400 to equal 201
at Context.<anonymous> (test/user.test.js:45:18)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
✕ 1 passing (4.2s)
✕ 1 failing
1) User registration with invalid email:
AssertionError: expected 400 to equal 201
The test expects a 201 Created status but gets 400 Bad Request. This usually means the createUser function is not returning the correct status.
Check the actions tab in GitHub. Click on a job, then on a step. You’ll see the exact command run:
npm run test
Look at the output of npm run test to see what failed.
If the main branch has changed while your PR was open, you may need to merge the latest changes.
git fetch origin
git merge origin/main
If you get merge conflicts, edit the files with conflicting sections:
<<<<<<< HEAD
const user = await User.create({ name, email });
=======
const user = await User.create({ name, email });
await user.save();
>>>>>>> feature/user-email-validation
Edit the file, then resolve conflicts:
git add src/controllers/userController.js
git commit -m "Merge main into feature/user-email-validation"
git push origin feature/user-email-validation
When your PR is approved, the maintainer merges it. You can now remove your feature branch:
git branch -d feature/user-email-validation
git push origin --delete feature/user-email-validation
After your change lands, the next phase begins.
semantic versioning. A new v1.2.0 release includes your change.README.md, CONTRIBUTING.md, or docs/ directory.git cherry-pick:git checkout v1.1.0
git cherry-pick <commit-hash>
git push origin v1.1.0
As you contribute more, you may:
A common mistake is writing a PR with no test coverage. Always ask: “Does this change need a new test? Does it cover edge cases?”
Another silent failure: the PR is merged but the change is not released. After merging, the maintainer must create a release tag:
git tag -a v1.2.1 -m "Fix email validation and add test coverage"
git push origin v1.2.1
If the release is not published, users don’t get your change.
npm run build and npm run devnpm run dev starts a server in watch mode, recompiling on file changes.npm run build compiles the entire project into dist/, producing static files for deployment.Running npm run build but not deploying the dist/ directory leads to a missing index.html or broken assets.
package-lock.jsonAfter npm install, always commit package-lock.json. It pins exact versions of all dependencies. Without it, a contributor might use different versions of lodash, axios, or express, leading to subtle bugs.
merge vs rebaseWhen merging a PR, maintainers often choose between:
Use rebase and merge when you want a linear history with no extra merge commits.
Tests may pass locally but fail in CI due to:
DATABASE_URL, JWT_SECRET)users table missing email column)Always check the CI logs for console.log output or error stack traces.
ci:build Job That Skips TestsA common pattern: ci:build runs npm run build, but ci:test runs npm test. If ci:build is not triggered after ci:test, the build step may run on outdated code.
Ensure that the CI workflow triggers ci:test after ci:build.
Before pushing your PR:
npm run lintnpm run testnpm run buildpackage-lock.jsonAfter the PR is open:
help wanted label if you need more feedbackgood first issue label for future contributorsCONTRIBUTING.md with your experience if you learned something newThis guide is not a checklist. It’s a living document, shaped by the real friction of making code public, visible, and lasting.
This page was rewritten on 18 October 2026. It replaced a templated version that was not specific to its own title. How these pages are written and checked. If anything here is wrong, tell us at [email protected] and we will correct it.
We use cookies for analytics (Google Analytics) and advertising (Google AdSense) to improve your experience and support free content. Privacy Policy