Data refreshed 5 October 2026, 22:59 UTC
Methodology: how the top 100 GitHub repositories are collected
Everything on this site is the output of one script, one workflow and one API endpoint. This page documents exactly what happens, so that any number here can be reproduced or challenged.
The query
Every list on this site is the result of a single GitHub Search API request per language:
GET https://api.github.com/search/repositories
?q=language:Python
&sort=stars
&order=desc
&per_page=100
&page=1
GitHub returns at most 100 results per page for this endpoint, so
per_page=100 is exactly what makes a "top 100" list possible in one
call. sort=stars&order=desc ranks by
stargazers_count; no other ordering is applied anywhere on the site.
One API request per language
There are no per-repository follow-up calls. A naive implementation would call
GET /repos/{owner}/{repo} for every row to "complete" the data, which
would multiply API usage by roughly 100×. The search-result item already contains
almost everything GitHub knows about a repository — owner, licence, topics, every
count, all timestamps — so the script keeps it as-is and stays at
one request per language per run.
For the default list of 30 languages that is 30 requests per refresh, comfortably inside the authenticated Search API limit of 30 requests per minute.
The data is never reshaped
Each line of data/JSONL/<language>.jsonl is the full JSON
object GitHub returned, serialised back to JSON with no fields dropped, renamed,
rounded or reordered. If GitHub adds a field tomorrow, it appears in the next
refresh automatically. The field reference documents
what is in there and what is not.
Refresh cadence and automation
A scheduled GitHub Actions workflow runs at minute zero of every hour
(cron: "0 0/1 * * *"), re-fetches all 30 languages, rebuilds the
Markdown tables, rebuilds this website and commits everything back to the
repository. The job needs permissions: contents: write so the bot can
commit, and the resulting commit does not re-trigger the Pages deployment, so the
deploy job is wired to the data workflow's completion instead.
You can also trigger a run by hand from the Actions tab and pass any comma-separated list of languages.
Rate limits and back-off
Authenticated requests get 30 Search API requests per minute; unauthenticated
requests get 10. The script reads X-RateLimit-Remaining after each
language and, when it is nearly exhausted, sleeps until
X-RateLimit-Reset. HTTP 403 and 429 responses are retried with
exponential back-off using Retry-After when GitHub sends it.
What the Search API does not return
A handful of fields exist only on the single-repository endpoint:
subscribers_count, network_count, the
parent/source objects for forks,
code_of_conduct and security_and_analysis. The script can
optionally merge them by calling
GET /repos/{owner}/{repo} for every result — set
ENRICH_WITH_REPO_DETAILS = True in
scripts/fetch_top_repos.py — but that turns one request per language
into about 101, so it is off by default.
Known limitations
- Language is a single label. GitHub assigns each repository one detected primary language. A project written half in Python and half in C appears in only one list.
- Forks are excluded by default. GitHub's repository search leaves
forks out unless the query adds
fork:trueorfork:only, so a fork never displaces the repository it was copied from, however many stars it has. Archived repositories, by contrast, are included: they are read-only but public, and a few of them rank highly. total_countis approximate for very broad queries. GitHub reports a number that can be much larger than the 1,000 results it will actually page through, and occasionally answers withincomplete_results: true. The site reports the number GitHub returned rather than pretending it is exact.- No history. This is a snapshot refreshed hourly, not a time series. For star trends over time use Star History or OSS Insight; for event-level history use GH Archive or BigQuery.
- Ranking by stars only. Stars are a popularity signal, not a quality signal, and they accumulate forever — which is why a 2014 tutorial can outrank a better 2026 tool.
Run it yourself
# locally (needs a token with public_repo / no scope for public data)
GH_TOKEN=ghp_xxx LANGUAGES=Python,Rust python scripts/fetch_top_repos.py
# or let GitHub do it: Actions → "Top Repos by Language" → Run workflow
# and pass the languages you want as a comma-separated input.
The workflow is self-contained: actions/checkout, Python 3.12, the
script, and a commit step. Fork the repository and it will refresh your own copy
every hour.
Every number on this site is reproducible: the workflow, the script and the resulting data all live in the same repository, and the commit history is the changelog.