---
title: Releasing an Open Source Project
description: Everything to do before, during, and after publishing a project as open source.
category: software
tags: [software, open-source]
version: "1.0"
updated: 2026-07-07
sources:
  - name: GitHub — Open Source Guides
    url: https://opensource.guide/
  - name: Choose a License
    url: https://choosealicense.com/
  - name: Keep a Changelog
    url: https://keepachangelog.com/
---

For making a repository public for the first time — a new project or
a formerly private one. Ordered so that nothing sensitive is exposed
before the scan, and nothing is announced before it's usable.

## Before anything is public

- [ ] Scan the entire git history for secrets, not just the current tree `{essential}`
  Use gitleaks or trufflehog. A key deleted in commit 50 is still
  sitting in commit 49, and bots scan newly public repos within
  minutes of creation.
- [ ] Rotate every credential the scan finds `{essential}`
  Treat found as compromised. Rewriting history is not enough — you
  cannot prove no one has a clone.
- [ ] Purge private data from history `{when: previously-private-repo}` `{essential}`
  Internal hostnames, customer data, colleagues' emails, embarrassing
  commit messages. `git filter-repo` does this; note it rewrites every
  commit hash, so do it before anyone else has cloned.
- [ ] Choose a license and add a LICENSE file `{essential}`
  No license means all rights reserved — nobody can legally use the
  code. MIT and Apache-2.0 for permissive (Apache adds an explicit
  patent grant), GPL for copyleft.
- [ ] Verify your dependencies' licenses are compatible with yours `{essential}`
  You cannot ship GPL code inside an MIT project. Check transitive
  dependencies too — license checkers exist for every ecosystem.
- [ ] Confirm you have the right to publish `{when: employed}` `{essential}`
  Many employment contracts claim IP created on company time or
  equipment. Get written approval or use your employer's open source
  release process — retroactive permission is much harder.

## Make it usable

- [ ] Write a README with what it does, how to install it, and a working example — all in the first screenful
  A visitor decides in about thirty seconds. A copy-pasteable example
  above the fold beats three paragraphs of philosophy.
- [ ] Verify the install instructions on a clean machine or container
  Your dev machine has invisible dependencies the README doesn't
  mention. A fresh container is the only honest test.
- [ ] Add a CONTRIBUTING guide: how to run the tests, what PRs are welcome
  The second half matters most — saying what you *won't* merge saves
  contributors wasted evenings and you awkward rejections.
- [ ] Add a SECURITY.md with a private reporting channel
  You want vulnerability reports in your inbox, not in a public issue
  with a proof of concept attached.
- [ ] Adopt a code of conduct `{when: expecting-contributors}`
  The Contributor Covenant is the de facto default; adopting it takes
  five minutes and deciding disputes without one takes much longer.
- [ ] Set up CI running the tests on every pull request
  Contributors can't run your private test setup. Public CI is what
  lets you review a stranger's PR without pulling it down first.
- [ ] Enable branch protection on the main branch
  Require the CI check to pass; block force-pushes. Cheap insurance
  the day a second maintainer arrives.

## Version and publish

- [ ] Adopt semantic versioning and start at 0.1.0
  0.x tells users the API may still change; 1.0.0 is a compatibility
  promise — don't make it before you mean it.
- [ ] Start a CHANGELOG in Keep a Changelog format
  Written for humans deciding whether to upgrade, not a dump of
  commit messages.
- [ ] Tag the release in git with a version tag matching the package version
  `v0.1.0` — tags are what let users and tooling map an installed
  version back to source.
- [ ] Check the package name is available on the registry `{when: publishing-package}`
  Check npm/PyPI/crates.io before the name is in your README, docs,
  and announcement. Avoid names one typo away from popular packages.
- [ ] Build the package and inspect exactly what's inside `{when: publishing-package}` `{essential}`
  `npm pack --dry-run` or `python -m build`, then list the contents.
  Packages routinely ship `.env` files, test fixtures, and junk —
  use an explicit include list, not excludes.
- [ ] Enable 2FA on the registry account before publishing `{when: publishing-package}` `{essential}`
  A hijacked publisher account is a supply-chain attack on everyone
  who installs your package.

## Announce

- [ ] Write the announcement around the problem it solves, not the implementation
  "I kept needing X, so I built..." travels; "a Rust library that
  uses..." doesn't, except to people who already wanted it.
- [ ] Post where your users already are, then stay for the first few hours
  Show HN, the relevant subreddit, the ecosystem's forum or Discord.
  Answering early questions in the thread is half the launch.
- [ ] Respond to the first issues and PRs within a day
  The first week sets the community's expectations permanently. A
  fast "thanks, looking at it" costs nothing and keeps contributors.
- [ ] Add repository topics and a one-line description
  It's how GitHub search and topic pages find you after the
  announcement traffic fades.
