The one-sentence version
Every "endpoint" is a pre-generated file on GitHub Pages, served over
HTTPS from a global CDN with permissive CORS โ so any client can GET it
directly, forever, for free.
The stack
- Data โ plain Python modules, one per dataset, each a list of records.
- Build โ a small Python generator turns those into JSON files, an OpenAPI spec and a sitemap.
- Host โ GitHub Pages serves the files from a CDN; a custom domain (
gratisapi.com) sits in front via aCNAME. - CI/CD โ GitHub Actions regenerates and deploys on every push.
- Front end โ a few hand-written HTML/CSS/JS pages, no build step, no dependencies.
Why static?
A traditional API needs a server that is always running, always patched, always paid for โ and that server is a single point of failure, a rate-limiter, a tracker, and a bill. A static API has none of that. Because every possible response is computed ahead of time and written to disk, there is nothing to run at request time. That yields some remarkable properties:
- It can't go down under load. Serving a file is what CDNs do best; there is no application to crash.
- It can't rate-limit you. There is no server keeping count.
- It can't track you. A static file can't run code, set cookies, or log who you are.
- It costs almost nothing to host โ which is why it can be free forever rather than free-for-now.
Clean, extension-less URLs
The API is addressed with human-friendly paths and no query strings:
# the catalog of every API GET /api/index # one collection GET /api/animals/index # one record GET /api/animals/lion GET /api/elements/79 GET /api/quotes/42
GitHub Pages can't serve a directory as JSON, so the generator writes each response
twice: once as an extension-less file (the advertised URL, e.g.
/api/animals/lion) and once with a .json extension (handy for
browsers, which then display it as JSON). The two files are byte-identical, and Git stores
identical content only once, so the mirror is effectively free. fetch(...).json()
and curl work against the clean URLs regardless of content type.
The response shape
Every collection returns metadata plus the full result set โ there is no pagination to page through, because the whole dataset is already one cache-friendly file:
{
"api": "animals",
"count": 71,
"endpoints": { "list": ".../api/animals/index", "item": ".../api/animals/{id}" },
"fields": ["class", "common_name", "..."],
"results": [ { "id": "lion", "url": ".../api/animals/lion", "...": "..." } ]
}
The build pipeline
Data lives as Python, not JSON, so it's easy to review, comment and compute. Each
dataset is a module exposing a META dict and an ITEMS list:
# scripts/data/planets.py META = {"name": "planets", "title": "Planets", "emoji": "๐ช", "description": "..."} ITEMS = [{"id": "earth", "order_from_sun": 3}, "..."]
Running python3 -m scripts.generate discovers every module, validates that
ids are unique, normalises each slug to lowercase-hyphen, and writes the whole
/api tree plus openapi.json and sitemap.xml. Adding
a dataset is one file; nothing else changes. Even this site's articles are generated the
same way and served at /api/articles/index.
How hosting fits in
GitHub is the source of truth: the generated files are committed to the
gh-pages branch and two GitHub Actions workflows keep everything honest. The
public front door is Cloudflare Pages, which serves the static assets from
a global edge with unlimited bandwidth and lets a small _headers
file return clean application/json with open CORS. (We began on GitHub Pages;
the story of why we moved is worth a read.) The two workflows:
- CI re-runs the generator on every push and fails if the committed output is stale or any JSON is invalid โ so the repo can never drift from its data.
- Deploy rebuilds and publishes the site to Pages automatically.
Open source & free
GratisAPI is licensed GPL-2.0-or-later. That makes it free in both senses: free of charge (gratis) and free as in freedom (libre). You may run it, study it, modify it and redistribute it, and copyleft guarantees those freedoms survive in anyone's fork. The reasoning โ and the story of Richard Stallman, the FSF and the four freedoms โ is on the philosophy page.
Fork it or self-host it
Because it's just files and a build script, standing up your own copy takes a couple of minutes:
# clone, build, serve git clone https://github.com/DomTheDeveloper/GratisAPI cd GratisAPI python3 -m scripts.generate python3 -m http.server # now browse http://localhost:8000
Point a fork's Pages at your own domain, add datasets under scripts/data/,
keep the GPL, and you have your own permanent, free API.
FAQ
Is there really no rate limit?
Correct. There is no server counting requests. Be kind to GitHub's CDN, cache responses where you can, and you're set.
Can I use it in production / commercially?
Yes. It's public data under the GPL. For mission-critical use, the safest move is the one the license enables anyway: mirror the data yourself so you never depend on us.
How fresh is the data?
Datasets are curated reference data (taxonomy, the periodic table, country capitals, and so on) โ the kind of information that rarely changes. Nothing here is a live feed of prices or other volatile values.
How do I add or fix data?
Open a pull request on GitHub. Datasets are small Python files; corrections and new datasets are very welcome.
Go deeper
Our story
The vision, GitHub Pages, and the move to Cloudflare for unlimited bandwidth.
Read the story โThe technicals
How static works, the limitations we know exist, and the two APIs we offer.
Get technical โWhat it costs
An itemised bill: $0 hosting, a cheap domain, donations, and the dynamic API.
See the numbers โ