Step 2 — Zenodo DOI
Get a DOI for your code, in one afternoon
Zenodo is a free, CERN-hosted long-term archive that mints DOIs for research artifacts — data, code, slides, anything. It’s the standard way to make a GitHub repo citable in academic writing.
Once you wire Zenodo to your GitHub repo, every future GitHub Release automatically produces an archived snapshot with its own DOI. You do this setup once and then never touch it again.
This is the single highest-return step in the entire handbook: it takes ~30 minutes and it turns your code into a permanently citable artifact.
Concept DOI vs. version DOI
Zenodo gives you two flavours of DOI, and it’s worth understanding the distinction before you cite them anywhere.
- Concept DOI — always resolves to the latest version of your repo. Use this in your README (“Cite
yourthing”) and in apaper.mdwhen you want a stable reference that doesn’t age. If you release v0.2 next year, papers that cite the concept DOI still work. - Version DOI — resolves to one specific release. Use this when you need pinned reproducibility (“we used
yourthingv0.1.0”). Every GitHub Release gets its own version DOI automatically.
In practice you’ll refer to both:
Software: yourthing (concept DOI: 10.5281/zenodo.1234500)
Version used: v0.1.0 (version DOI: 10.5281/zenodo.1234567)
The one-time setup (about 15 minutes)
You need a GitHub repo that already has a README.md, LICENSE, and CITATION.cff — see Step 1 — Repo hygiene.
1. Create a Zenodo account
Go to https://zenodo.org/signup and sign in with your GitHub account (this is the important part — the OAuth link is what lets Zenodo see your repos).
2. Add your ORCID
Under your Zenodo profile, link your ORCID if you have one (and get one now if you don’t — it takes 3 minutes and every author on your JOSS paper will need one eventually).
3. Enable Zenodo for your repository
Go to https://zenodo.org/account/settings/github/ — you’ll see a list of your GitHub repositories with a toggle next to each. Flip the switch on for your repo.
Zenodo is now watching. Nothing happens yet — you need a GitHub Release to trigger the first archive.
4. Create your first GitHub Release
On your repo’s GitHub page:
- Go to the Releases tab.
- Click Draft a new release.
- Create a new tag —
v0.1.0is a fine first release (see semantic versioning). - Give the release a title (e.g.,
yourthing 0.1.0 — initial release). - Add release notes describing what’s in this version.
- Click Publish release.
Within a minute or two, Zenodo receives the webhook, downloads the tagged snapshot, mints the DOIs, and creates a Zenodo record. Refresh https://zenodo.org/account/settings/github/ — you’ll see the new record with its DOI.
5. Add the badge to your README
Zenodo generates a Markdown badge you can paste into your README. It looks like:
[](https://doi.org/10.5281/zenodo.1234500)Put this near the top of your README. The badge shows the concept DOI, always resolves to the latest release, and looks professional in five seconds.
What Zenodo actually archives
For each GitHub Release, Zenodo:
- Downloads a zipball of your repo at the tagged commit.
- Stores it permanently in CERN’s archival infrastructure.
- Mints a DOI for that snapshot.
- Reads your
CITATION.cffand pre-fills the record’s title, authors, license, and description.
The Zenodo record page is publicly visible. Anyone can download the zipball, cite the DOI, or view the metadata. The record’s contents are immutable — future releases create new records with new version DOIs; they do not modify old ones.
CITATION.cff is good, your Zenodo record will be good
Zenodo reads CITATION.cff on each new release, so keep it current. In particular: add every author you want credited, with correct ORCIDs and affiliations. Editing a Zenodo record after the fact is possible but annoying.
Beyond the first release
Once the setup is done, the workflow for every future release is:
- Push commits to
main. - Tag a release (
git tag v0.2.0 && git push --tags) or click “Draft a new release” on GitHub. - Zenodo archives it automatically within a minute.
- Update the concept-DOI badge is not needed — it stays the same.
- Reference the new version DOI in your changelog / release notes.
The Zenodo Sandbox (for testing)
If you want to try Zenodo without permanently minting DOIs, use the Zenodo Sandbox — a full clone of Zenodo where DOIs are throwaway (they don’t resolve outside the sandbox). Useful if you’re nervous about your first release or want to test the webhook flow.
Common issues
“Zenodo says my repo is empty.” — You have Zenodo enabled but no releases yet. Create a GitHub Release; Zenodo won’t archive main-branch commits, only tagged releases.
“The wrong authors appear on the Zenodo record.” — Zenodo reads CITATION.cff at release time. Fix CITATION.cff on main, then either edit the Zenodo record manually or create a new release.
“I want to change the license retroactively.” — You can edit the license on the concept-DOI Zenodo record from the record’s edit page, but the immutable zipball still contains the old license. Future releases pick up the new one.
“I want to remove Zenodo entirely from my repo.” — Flip the switch back off at https://zenodo.org/account/settings/github/. Existing records remain (they have to — DOIs are permanent), but no new releases will be archived.
Checklist
Once your DOI is live, you have reached Level 0. If you plan to stop here, congratulations — your code is now permanently citable. If you want to go further, on to Step 3 — Make it pip-installable.