Open Source Contribution Guide

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.

Getting Started: Finding and Claiming Work

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.

Setting Up the Development Environment

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.

Running Tests and Linting

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

Making Your Change: Code, Commit, Push

Now write your code. Suppose you’re fixing a bug where a user’s email is not being validated on registration.

Writing the Patch

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);
}

Committing with a Conventional Message

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.

Pushing to Your Fork

Push your branch to your forked repository:

git push origin feature/user-email-validation

You can now open a pull request.

Submitting Your 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.

Review Process and Feedback

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.

Handling CI and Build Failures

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.

Resolving Merge Conflicts

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

Merging and Maintaining Your Contribution

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 Merging: The Lifespan of a Contribution

After your change lands, the next phase begins.

git checkout v1.1.0
git cherry-pick <commit-hash>
git push origin v1.1.0

Handling Long-Term Involvement

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.

Common Pitfalls and Sharp Edges

Confusing npm run build and npm run dev

Running npm run build but not deploying the dist/ directory leads to a missing index.html or broken assets.

The Forgotten package-lock.json

After 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.

Misunderstanding merge vs rebase

When merging a PR, maintainers often choose between:

Use rebase and merge when you want a linear history with no extra merge commits.

Silent Failures in Test Environments

Tests may pass locally but fail in CI due to:

Always check the CI logs for console.log output or error stack traces.

The ci:build Job That Skips Tests

A 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.

Final Checklist Before Submitting

Before pushing your PR:

  1. Run npm run lint
  2. Run npm run test
  3. Run npm run build
  4. Commit all changes, including package-lock.json
  5. Push to your fork
  6. Open the PR with a clear title and description
  7. Link to the issue and include relevant context

After the PR is open:

  1. Add a help wanted label if you need more feedback
  2. Add a good first issue label for future contributors
  3. Update the project’s CONTRIBUTING.md with your experience if you learned something new

This 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.