Open Source Your Side Project the Right Way
Turn a personal repo into a contributor-ready GitHub project with a license, README badge, templates, and CI.
What you'll build / learn
You'll take an existing local git repo and turn it into a public, contributor-ready GitHub project: an MIT license, a README with a live CI badge, a CONTRIBUTING guide, a structured bug-report issue form, a pull request template, and a GitHub Actions workflow that runs your tests on every push and PR — all from the terminal.
Prerequisites
Verified on macOS 26 with:
- git 2.50 — any 2.x works.
- GitHub CLI (
gh) 2.86, authenticated: rungh auth loginonce ifgh auth statusdoesn't show "Logged in". - A GitHub account and a local project with at least one commit. The CI step assumes a Node project with an
npm testscript; swap that one line for your stack (pytest,go test ./..., etc.). - Action versions verified:
actions/checkout@v7,actions/setup-node@v7.
Commands are POSIX shell; on Windows use Git Bash or WSL.
1. Pick a license and add it
No license means nobody can legally use or contribute to your code. For a side project, MIT is the safe default — it lets people do almost anything, including ship closed-source forks; pick GPLv3 if you want derivatives to stay open. Compare options at choosealicense.com, which GitHub maintains.
gh can print any of GitHub's license templates. Write it to LICENSE (that exact filename is what GitHub's license detection looks for) and fill in the placeholders:
cd ~/code/my-project # your repo
gh repo license view mit > LICENSE
sed -i '' 's/\[year\]/2026/; s/\[fullname\]/Your Name/' LICENSE # macOS sed; on Linux drop the ''
head -3 LICENSE
gh repo license list shows the other keys (apache-2.0, gpl-3.0, …).
2. Write a README that answers three questions
A contributor-ready README says what the project does, how to run it, and how to help. The badge line goes live after step 6 — replace OWNER/my-project with your GitHub handle and repo name here and in every later snippet:
# my-project
[](https://github.com/OWNER/my-project/actions/workflows/ci.yml)
One sentence on what this does and who it's for.
## Install
npm install my-project
## Usage
my-project --help
## Contributing
See [CONTRIBUTING.md](CONTRIBUTING.md). Bug reports and PRs welcome.
## License
MIT — see [LICENSE](LICENSE).
Save that as README.md.
3. Add a CONTRIBUTING guide
GitHub links this file whenever someone opens an issue or PR and adds a "Contributing" tab to the repo overview. It can live in the root, .github/, or docs/; root is most discoverable.
cat > CONTRIBUTING.md <<'MD'
# Contributing
Thanks for helping out. Here's the short version.
## Setup
1. Fork and clone the repo.
2. `npm install`
3. `npm test` — make sure it's green before you start.
## Making changes
- Open an issue first for anything bigger than a bug fix, so we can agree on the approach.
- Create a branch from `main`: `git switch -c fix/short-description`.
- Add or update tests for what you changed.
- Keep PRs focused: one change per PR.
## Submitting
Push your branch and open a pull request against `main`. CI must pass. I usually review within a few days.
MD
4. Add an issue form and a PR template
Issue forms are YAML files in .github/ISSUE_TEMPLATE/ that GitHub renders as structured web forms, so bug reports arrive with repro steps instead of "it doesn't work". name, description, and body are required; body needs at least one non-markdown field.
mkdir -p .github/ISSUE_TEMPLATE
cat > .github/ISSUE_TEMPLATE/bug_report.yml <<'YML'
name: Bug report
description: Something isn't working as expected.
title: "[Bug]: "
labels: ["bug"]
body:
- type: textarea
id: what-happened
attributes:
label: What happened?
description: What did you expect to happen instead?
validations:
required: true
- type: textarea
id: repro
attributes:
label: Steps to reproduce
placeholder: "1. Run ...\n2. See error ..."
validations:
required: true
- type: input
id: version
attributes:
label: Version
placeholder: e.g. 1.2.0
- type: textarea
id: logs
attributes:
label: Relevant log output
render: shell
YML
labels only applies if the label already exists — bug is one of GitHub's defaults. Now discourage blank issues and point questions elsewhere:
cat > .github/ISSUE_TEMPLATE/config.yml <<'YML'
blank_issues_enabled: false
contact_links:
- name: Question
url: https://github.com/OWNER/my-project/discussions
about: Ask usage questions here instead of opening an issue.
YML
The PR template is plain Markdown at .github/pull_request_template.md (lowercase filename matters):
cat > .github/pull_request_template.md <<'MD'
## What does this PR do?
## How was it tested?
- [ ] Added/updated tests
- [ ] `npm test` passes locally
MD
5. Add a CI workflow
mkdir -p .github/workflows
cat > .github/workflows/ci.yml <<'YML'
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: 22
- run: npm ci
- run: npm test
YML
The workflow's name: CI is what the badge displays; the filename ci.yml is what the badge URL references.
6. Publish the repo
Commit everything, then create the GitHub repo from the local directory and push in one command (--license can't be combined with --source, which is why step 1 wrote LICENSE by hand):
git add -A
git commit -m "Add license, README, contributing guide, templates, and CI"
gh repo create my-project --public --source=. --remote=origin --push
Expected output:
✓ Created repository OWNER/my-project on github.com
https://github.com/OWNER/my-project
✓ Added remote https://github.com/OWNER/my-project.git
✓ Pushed commits to https://github.com/OWNER/my-project.git
The push triggers the first CI run, which populates the badge.
Verify it works
Give the push a minute, then check the run from the terminal:
gh run list --workflow ci.yml --limit 1 --json workflowName,status,conclusion --jq '.[0]'
Expected output:
{"conclusion":"success","status":"completed","workflowName":"CI"}
If status is still in_progress, re-run in a few seconds. Then open the repo in a browser (gh repo view --web). Confirm:
- The README badge reads CI passing (green).
- The MIT license appears in the About sidebar.
- Insights → Community Standards shows green checks for README, License, Contributing, and Issue templates.
- Issues → New issue shows your "Bug report" form and the "Question" contact link. You'll still see Blank issue marked Maintainers only — that's expected; contributors with read access won't.
Troubleshooting
the --source option is not supported with --clone, --template, --license, or --gitignore — you passed --license alongside --source=.. Drop --license; the local LICENSE file from step 1 is all GitHub needs.
--push enabled but no commits found in /path/to/my-project — the directory is a git repo but has nothing committed. Run git add -A && git commit -m "Initial commit" and re-run gh repo create.
error: remote origin already exists. — the repo already has an origin (for example from an earlier private remote). Either git remote remove origin first, or pass a different name such as --remote=github and push with git push -u github main.
Badge is a broken image (URL returns 404) — the badge URL is built from the workflow filename, not its name:. Check it's .../actions/workflows/ci.yml/badge.svg and that the file is actually at .github/workflows/ci.yml on main. The badge only exists once GitHub has registered the workflow, i.e. after the first push.
Issue form doesn't appear, or the chooser says Body must contain at least one non-markdown field — YAML validation failed. GitHub shows the exact message (Required top level key name is missing, Body must have unique ids, …) when you open the file on github.com. Fix the key it names; id values may only contain letters, numbers, - and _.
Next steps
- Finish the Community Standards checklist: Add file → Create new file →
CODE_OF_CONDUCT.md→ Choose a code of conduct template, and Security → Security policy → Start setup forSECURITY.md. - Protect
main: Settings → Rules → Rulesets, require thetestcheck to pass before merging. - Tag good starter issues with
good first issue— GitHub surfaces those to newcomers. - Cut a first release with
gh release create v0.1.0 --generate-notesso people have something versioned to depend on.
Sources & further reading
- gh repo create - GitHub CLI manual — cli.github.com
- Syntax for issue forms — docs.github.com
- Configuring issue templates for your repository — docs.github.com
- Setting guidelines for repository contributors — docs.github.com
- Adding a workflow status badge — docs.github.com
- Choose an open source license — choosealicense.com
Lenn writes about cloud platforms, Kubernetes internals, and the infrastructure decisions that quietly make or break engineering organizations. Based in Berlin's vibrant tech scene, they have a talent for turning dense platform-engineering topics into prose that people actually finish reading.
Discussion 0
No comments yet
Be the first to weigh in.