Hosting your .rete
A .rete file needs no special server — the whole promise of the format is
that any HTTP host can serve it queryably. This page says exactly what a host
must support, how to check it in ten seconds, and gives working recipes for the
hosts this project uses in production.
What a host must support
- HTTP range requests. A
Range: bytes=…request must get back206 Partial Contentwith exactly those bytes. A host that ignoresRangeand replies200with the whole file is rejected loudly by every rete client — never silently mis-read. - CORS — for browser clients only. The CLI (
rete query-url,sparql-url, …) needs nothing else. But the playground / any web page fetches cross-origin, so the host must sendAccess-Control-Allow-Origin(*is fine for public data). - A way to learn the file's length (browser clients). The reader first
tries a
HEADrequest —Content-Lengthis CORS-safelisted, so this works almost everywhere. If the host rejectsHEAD, it falls back to a one-byte rangedGETand reads the total fromContent-Range— which is not safelisted, so that fallback additionally needsAccess-Control-Expose-Headers: Content-Range. Satisfy either one.
The ten-second check
# 206 + a content-range header = ranges work:
curl -sI -r 0-1023 https://host/path/data.rete | grep -iE "^HTTP|content-range"
# HTTP/2 206
# content-range: bytes 0-1023/104857600
# CORS for browsers — expect access-control-allow-origin in the answer:
curl -sI -r 0-1023 -H "Origin: https://example.org" https://host/path/data.rete \
| grep -i access-control
If both pass, rete card-url https://host/path/data.rete should print the
dataset card in two range requests — and the same URL pasted into the
playground's + Add source → Connect (lazy) queries it
live.
Recipes
Cloudflare R2 (what the playground uses)
All the playground's datasets are served from an R2 bucket behind a custom
domain (data.graphplaza.com): direct 206 responses, free egress, CORS-open.
Two things to configure once on the bucket:
- A public hostname (custom domain or the
r2.devsubdomain). - A CORS policy that exposes what the readers need:
[{
"AllowedOrigins": ["*"],
"AllowedMethods": ["GET", "HEAD"],
"AllowedHeaders": ["*"],
"ExposeHeaders": ["Content-Range", "Content-Length", "ETag"],
"MaxAgeSeconds": 86400
}]
Upload over the S3 API (aws s3 cp, rclone, or the repo's small helper):
# env: S3_API_ENDPOINT, ACCESS_KEY_ID, SECRET_ACCESS_KEY
python3 dev/r2_s3.py put <bucket> data.rete datasets/mygraph/data.rete
One sizing note: Cloudflare's cache handles objects up to ~512 MB, so files at or below that stay CDN-cacheable. A bigger graph is better published as several shards queried as one — see Federated queries.
Zenodo (free, permanent, citable)
An academic repository works as a live query host: Zenodo serves uploads with
206 ranges and CORS, and gives the deposit a DOI — so a paper's data
citation can point at a file that is directly queryable in the browser. No
account tier, no server, and takedown-resistant persistence. Zenodo doesn't
expose Content-Range cross-origin, which is exactly why the readers probe
length with HEAD first (requirement 3 above) — it just works. The
playground's wikidata-zenodo dataset is a 1 GB .rete served straight from
a Zenodo DOI, and it benchmarks on par with R2 (~4 s to first answer).
Upload through the normal Zenodo web UI or REST API; the file URL under
https://zenodo.org/records/<id>/files/<name> is the query URL.
GitHub Pages / raw.githubusercontent.com
Both serve ranges and send Access-Control-Allow-Origin: *, so a small .rete
can live right next to your project site (this repo's own docs site hosts demo
files that way). The constraint is GitHub's 100 MB per-file limit — fine
for demos and small graphs, not for the big ones.
S3 / GCS / any static host
Standard object stores work out of the box for the CLI; for browsers, attach
the same kind of CORS policy as the R2 recipe (S3 and GCS both take a JSON CORS
configuration; make sure GET + HEAD are allowed and Content-Range is
exposed). For local development, the bundled dev server speaks ranges:
python3 scripts/range_server.py 8000 .
rete card-url http://127.0.0.1:8000/data.rete
Hosts that do not work (from the browser)
A host can serve the CLI fine and still fail in a browser. The known offender:
Hugging Face's buckets/…/resolve endpoint answers 405 to a cross-origin
browser GET (the CLI sends no Origin, so it never notices). If a host
can't be made CORS-friendly, put a CORS-open front (a proxy, or R2) in front of
the bytes.
After hosting: publish it properly
- Embed a Dataset Card at build time (
rete build --card) so anyone who finds the URL gets the title, license, counts, and runnable starter queries from two range requests —rete card-url <url>. - Register it in the playground catalog to give it a browsable home with examples, media rendering, and SQL companions — see Media & SQL companions.
- For a living dataset,
rete serve(see the CLI reference) runs a live SPARQL endpoint — updates journal beside the immutable base file, andGET /snapshot.reteemits a fresh publishable snapshot at any time.