Top100 ★ 1 on GitHub

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

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.