Project Setup
The Minimum Viable Open Source Project
An open source project needs more than source code. Without a README, nobody knows what your project does. Without a LICENSE, nobody can legally use it. Without a CONTRIBUTING.md, nobody knows how to help. Without CI, you cannot trust that contributions work.
This is the minimum viable setup for an open source project. Skip any of these and you are publishing code, not launching a project.
README: The Front Door
The README is the first thing anyone sees when they visit your repository. It has about 30 seconds to answer three questions: What does this do? How do I install it? How do I use it? If it fails to answer any of these, the visitor moves on.
What It Does
Start with one or two sentences that explain the project's purpose. Not what it is technically, but what problem it solves for the user.
BAD: "A Rust library implementing asynchronous I/O multiplexing
with epoll, kqueue, and IOCP backends."
GOOD: "Mio is a fast, low-level I/O library for Rust that works
on every major OS. It powers Tokio and Hyper."
The bad version describes the implementation. The good version tells you what it does, who uses it, and why you should care.
How to Install
Give the exact command to install the project. Do not make the user figure it out:
INSTALLATION
# Rust (add to Cargo.toml)
[dependencies]
my-library = "1.0"
# JavaScript
npm install my-library
# Python
pip install my-library
# Binary (macOS)
brew install my-tool
If there are prerequisites (a specific runtime version, system dependencies, environment variables), list them explicitly. "Requires Python 3.10+" is better than letting users discover the requirement through a cryptic error message.
How to Use It
Include a complete, working example. Not a snippet — a full example that someone can copy, paste, and run. This is the most important part of the README for adoption.
QUICK START EXAMPLE
IMPORT my_library
// Create a client with default settings
client ← my_library.NEW_CLIENT()
// Fetch data and print results
result ← client.FETCH("https://api.example.com/data")
FOR item IN result.items
PRINT item.name, item.value
The example should demonstrate the core value proposition, not a trivial hello world. If your library simplifies HTTP requests, show an HTTP request. If it parses CSV files, show a CSV being parsed. If it manages state, show state being managed.
Additional README Sections
Beyond the essentials, mature projects include:
- Badges: Build status, version, license, downloads. These provide quick quality signals.
- Features: A bulleted list of key capabilities
- Comparison: How this project differs from alternatives (use a table if there are many alternatives)
- API overview: High-level summary of the main types and functions
- Links: Documentation site, changelog, discussion forum
LICENSE: Choose Before Publishing
A public repository without a license file is not open source. Under default copyright law in most jurisdictions, the author retains all rights. Nobody can legally copy, modify, or distribute the code, even though they can read it on GitHub.
How to Choose
For most projects, the decision is straightforward:
- Want maximum adoption? MIT or Apache 2.0. Both are permissive. Apache 2.0 adds patent protection.
- Want modifications to stay open source? GPL v3 or AGPL v3. Copyleft.
- Building a library that might be embedded in proprietary code? MIT, Apache 2.0, or LGPL.
If you are unsure, MIT is the safe default. It is short, widely understood, and maximally permissive. More than 40% of GitHub repositories with a license use MIT.
Where to Put It
Create a file called LICENSE (no extension) in the root of the repository. Copy the full license text — do not paraphrase or summarize. Fill in the copyright year and name.
GitHub will automatically detect the license and display it in the repository sidebar. Package registries (npm, crates.io, PyPI) read the license from your project metadata.
Do Not Change the License Later
Changing a license after people depend on your project is legally and socially fraught. You can only relicense code you own — if others have contributed, you need their permission or a CLA that grants you relicensing rights. The Terraform license change (MPL to BSL) and the Elasticsearch license change (Apache 2.0 to SSPL) both triggered community forks and significant backlash.
Choose carefully the first time.
CONTRIBUTING.md: How to Contribute
A CONTRIBUTING.md file tells potential contributors how to participate. Without it, contributors guess at your expectations, submit PRs that violate your conventions, and waste both their time and yours.
What to Include
Development setup. How to clone, install dependencies, and run the project locally:
DEVELOPMENT SETUP
1. Fork and clone the repository
2. Install dependencies: npm install
3. Run tests: npm test
4. Run the linter: npm run lint
5. Start the dev server: npm run dev
Coding conventions. Formatting rules, naming conventions, architecture patterns. If the project uses a formatter, say which one. If commits should follow Conventional Commits, say so. If PRs should be small and focused, say so.
PR process. How to submit a PR, what to include in the description, what the review process looks like. Set expectations about response time: "We aim to review PRs within one week. If you haven't heard back after two weeks, please ping the PR."
Issue guidelines. How to file a bug report (include reproduction steps, environment details, expected vs actual behavior). How to request a feature (describe the problem, not just the solution). What to do before opening an issue (search existing issues, check the FAQ).
CLA requirements. If contributors need to sign a Contributor License Agreement, explain why and link to the signing process.
CODE_OF_CONDUCT.md: Setting Expectations
A code of conduct establishes behavioral expectations for the community. It signals that the project takes inclusivity seriously and provides a framework for handling violations.
Most projects adopt the Contributor Covenant, which is used by over 100,000 projects including Kubernetes, Rails, and Swift. It covers expected behavior (welcoming, inclusive language), unacceptable behavior (harassment, trolling, personal attacks), and enforcement (how violations are reported and handled).
Place the code of conduct in CODE_OF_CONDUCT.md in the repository root. Include an email address or other contact method for reporting violations. The enforcement process should be clear: who receives reports, how they are investigated, what consequences are possible.
A code of conduct without enforcement is theater. If you adopt one, be prepared to enforce it.
Issue Templates & PR Templates
Issue Templates
GitHub and GitLab support issue templates that pre-fill the issue form with sections the reporter should complete. This dramatically improves issue quality.
A bug report template:
BUG REPORT TEMPLATE
**Describe the bug**
A clear description of what the bug is.
**To reproduce**
Steps to reproduce the behavior:
1. ...
2. ...
3. ...
**Expected behavior**
What you expected to happen.
**Actual behavior**
What actually happened.
**Environment**
- OS: [e.g., Ubuntu 22.04]
- Version: [e.g., 2.3.1]
- Runtime: [e.g., Node.js 18.12]
**Additional context**
Logs, screenshots, or configuration files.
A feature request template:
FEATURE REQUEST TEMPLATE
**Problem**
Describe the problem this feature would solve.
**Proposed solution**
Describe your proposed solution.
**Alternatives considered**
What alternatives have you considered?
**Additional context**
Any other information.
PR Templates
A PR template ensures contributors provide the information reviewers need:
PR TEMPLATE
**What does this PR do?**
**Why is this change needed?**
Link to issue: #
**How was this tested?**
**Checklist**
- [ ] Tests pass locally
- [ ] Documentation updated (if applicable)
- [ ] Changelog entry added (if applicable)
CI: Tests Run on Every PR
Continuous integration is non-negotiable for an open source project. Without it, you have to manually check out every PR, run the tests, and verify the code works. With CI, this happens automatically.
The Minimum CI Pipeline
At minimum, CI should:
- Run the test suite. Every PR must pass all tests before it can be merged.
- Run the linter/formatter. Enforce coding style automatically rather than nitpicking in reviews.
- Build the project. Verify that the code compiles on all supported platforms.
GitHub Actions is the most common CI platform for open source because it is free for public repositories and tightly integrated with GitHub.
CI PIPELINE (simplified)
ON: Pull Request to main branch
STEPS:
1. Check out code
2. Install dependencies
3. Run formatter check (fail if code is not formatted)
4. Run linter (fail on warnings)
5. Run test suite
6. Build the project
7. Report results
Advanced CI
Mature projects add:
- Multiple OS testing (Ubuntu, macOS, Windows)
- Multiple runtime version testing (Node 18, 20, 22; Python 3.10, 3.11, 3.12)
- Security scanning (dependency audit, SAST)
- Coverage reporting (track test coverage trends)
- Documentation build (verify docs compile without errors)
The Rust project tests the compiler on every supported platform and architecture for every PR. Kubernetes runs thousands of tests across multiple configurations. You do not need this level of testing on day one, but plan for it as the project grows.
Putting It All Together
The minimum viable file structure for an open source project:
my-project/
README.md What it does, how to install, how to use
LICENSE Full license text
CONTRIBUTING.md How to contribute
CODE_OF_CONDUCT.md Behavioral expectations
.github/
ISSUE_TEMPLATE/
bug_report.md
feature_request.md
pull_request_template.md
workflows/
ci.yml CI pipeline definition
src/ Source code
tests/ Test suite
This is the foundation. Everything else — documentation sites, changelogs, release automation, benchmarks — is built on top of this base.
Common Pitfalls
No README or a README With Only the Project Name
A repository with no README or a README that says only "my-project" attracts zero users. Write the README before you write the code. It forces you to articulate what the project does and who it is for, which clarifies your own thinking.
Choosing a License After People Depend on You
If you publish without a license and gain users, adding a license later creates ambiguity about whether the earlier versions were covered. Even worse, some users may have already used the unlicensed code, putting both parties in a legally unclear position. License first.
Overly Complex Contribution Requirements
Requiring contributors to sign a CLA, set up Docker, install five dependencies, and run a 30-minute test suite before submitting a typo fix discourages contributions. Make the contribution process proportional to the contribution size. A documentation fix should not require the full development environment.
No CI or Broken CI
If CI is broken and has been for weeks, contributors do not know whether their changes are correct. If there is no CI at all, every PR is a gamble. Fix CI issues immediately — they block all development.
Writing Issue Templates That Are Too Long
An issue template with 20 required fields discourages reporting. Keep it short: what happened, how to reproduce, what was expected. You can always ask for more details in the comments.
Key Takeaways
- The minimum viable open source project needs five files: README, LICENSE, CONTRIBUTING.md, CODE_OF_CONDUCT.md, and a CI configuration.
- The README must answer three questions immediately: what does this do, how do I install it, and how do I use it. Include a complete, working example.
- Choose a license before publishing. No license means no rights for users.
- CONTRIBUTING.md sets expectations for contributors and reduces wasted effort on both sides.
- Issue and PR templates improve the quality of reports and submissions by guiding contributors to provide the right information.
- CI that runs tests, linting, and builds on every PR is non-negotiable. It protects the codebase and saves maintainer time.