The source of goceleris.dev: the documentation, architecture deep-dives and benchmark dashboard for celeris, the HTTP engine for Go.
Documentation · Benchmark dashboard · Methodology · Run it locally
This repository builds goceleris.dev: the landing page, the user documentation, the methodology page and the benchmark dashboard. It is a fully static Astro site with no server: every page is plain HTML generated at build time, and the dashboard is a single client-only Preact island that loads the per-version JSON the build emitted.
The benchmark data lives in this repository. Each published run is a set of committed files under
results/; the build reads that tree directly and derives every dashboard asset from it,
so there is no database. probatorium measures the runs and
publishes them here.
Requires Bun at the version engines.bun in package.json sets
(the badge above reads it).
bun install --frozen-lockfile
bun run dev # build:data, then astro dev at http://localhost:4321
bun run demo # the same, against a synthesized demo dataset for a richer preview/is the landing page with the headline benchmark stats./docsis the documentation./benchmarksis the dashboard./methodologyexplains how the numbers are made.
bun run dev builds the dashboard data from the committed results/ tree, so it shows the published
runs out of the box. bun run demo synthesizes a broader multi-version fixture tree under
.dev-results/ (gitignored) when you want to exercise more of the dashboard.
Every task is a Bun script (see package.json):
| Script | What it does |
|---|---|
bun run dev |
build:data, then astro dev (localhost:4321) |
bun run demo |
Synthesize demo fixtures, build data from them, then astro dev |
bun run build |
build:data → astro build → pagefind --site dist → dist/ |
bun run preview |
Serve the built dist/ locally |
bun test |
Data-layer tests |
bun run validate |
Validate results/ without emitting anything: the publish gate |
bun run check |
astro check (types and content schema); run build:data first |
bun run build:data |
Rebuild the dashboard assets from results/ |
bun run demo:data |
Synthesize fixtures, then build data from them |
bun run fixtures |
Synthesize the demo fixture tree only |
bun run start |
Alias for bun run dev |
validate runs build-data --validate-only. It walks every cell and emits nothing. It exits non-zero
when a cell's summary.json or env.json fails validation, and with status 2 if it examined no cells
at all, so a gate that inspected nothing can never report success. Problems in timeseries.json.gz
are reported as warnings. Unlike build, it also scans the versions listed in DEACTIVATED_VERSIONS:
hiding a version from the dashboard is a presentation decision, not a licence for its committed data
to rot.
It runs in two places: the build job of ci.yml on every pull request
and push to main, and sync-benchmarks.yml on every publish.
bun run build deliberately does not fail on a bad cell: when a cell's summary.json is missing,
unreadable or invalid, it warns, marks the cell excluded:invalid and carries on, so one corrupt cell
cannot take the whole deploy down. That is why the separate gate exists.
The versions live in package.json and bun.lock; the Astro and Bun
badges above read package.json on main.
- Astro with
output: 'static', built with Bun: no SSR and no runtime server. - Integrations: @astrojs/mdx, @astrojs/preact (
compat: false) and @astrojs/sitemap. - Dashboard: one Preact + @preact/signals island under
src/dashboard/, mounted withclient:only="preact"on the benchmarks page. It ships six views inviews/:HeadToHead,Leaderboard,Matrix,OverTime,ResourcesandVersions. The over-time view draws with uPlot (charts/UplotChart.tsx). - Search: full-text search over the documentation pages with Pagefind,
indexed against the built site (
pagefind --site dist); it degrades silently in dev. - Fonts: self-hosted, subset Inter and JetBrains Mono through Astro's Fonts API (the
top-level
fontskey inastro.config.mjs), emitted at build time with metric-override fallbacks, so there is no runtime font JavaScript and no third-party request. - Code: Shiki highlights at build time with dual themes
(
github-dark-default/github-light-default), so highlighted code ships as plain HTML.
The canonical URL comes from SITE_URL in astro.config.mjs (default
https://goceleris.dev), which drives the sitemap, canonical links and Open Graph URLs.
The documentation is an Astro content collection
(src/content/docs/**/*.{md,mdx}). Each page's frontmatter is validated against
the schema in src/content.config.ts:
---
title: Routing # required
description: ... # optional
group: Routing & Handlers # sidebar section (default "Guides")
order: 1 # sort order within the group (default 100)
draft: false # default false
---The sidebar groups appear in this order:
- Getting Started: install Celeris, learn the mental model, serve a request
- Routing & Handlers: routes, params, binding, responses, errors, files
- Middleware: the chain and ordering, plus the in-tree catalog
- Real-Time: streaming, Server-Sent Events, WebSocket fan-out
- Data & Integration: database and cache drivers on the event loop, net/http interop
- Reference: every
Configfield, the four I/O engines, the fullContextAPI - Operations: deploy behind TLS, shut down cleanly, observe, tune, test
Pages beyond the docs collection live in src/pages/: the landing page (index), the
docs index and article routes (docs/index, docs/[...slug]), the benchmarks dashboard,
methodology, a branded 404, and generated llms.txt / llms-full.txt
maps.
results/ is the single source of truth. A cell is laid out as:
results/<version>/<yyyymmdd>/<arch>/
summary.json # per-(scenario × server) aggregates: rps, latency percentiles, RSS, CPU
timeseries.json.gz # per-second rps / p99 / errors over the run
histograms.json.gz # merged HdrHistograms (base64), kept for provenance; the site does not read them yet
env.json # run provenance: version, arch, date, run, git ref, celeris and loadgen versions,
# run config and the test fabric
scripts/build-data.ts walks that tree (override the root with
RESULTS_ROOT), validates and loads each cell, averages all runs per (version, arch), and excludes
smoke runs (anything shorter than 30 s) unless BUILD_INCLUDE_SMOKE=1. It never crashes on empty or
malformed data: bad cells are skipped with a warning, and an empty tree yields valid empty assets.
Versions in its DEACTIVATED_VERSIONS set are left out of the dashboard.
It emits two sets of assets, both gitignored and rebuilt on every build:
src/data/generated/{manifest,competitors,scenarios}.json: the versions, the adapter registry and the scenario taxonomypublic/data/v/<version>/<arch>.json: one aggregated payload per version and arch
The landing page's headline stats are computed from those assets by src/lib/site.ts.
The typed data layer that walks, validates and aggregates cells lives in
src/lib/results/ and is covered by bun test.
- On the cluster, probatorium's
mage Publishwrites the four files of a cell intoresults/<version>/<yyyymmdd>/<arch>/of this repository and pushes them tomain(one commit by default; withPUBLISH_VIA=contentsit writes each file through the GitHub contents API instead). It then fires arepository_dispatchevent of typebenchmark-published(a small pointer payload:{ version, arch, date, run_id, path, commit }). - That push to
mainis what triggers Cloudflare Workers Builds, which rebuilds and redeploys the site; the build reads the newresults/tree. sync-benchmarks.ymllistens for that dispatch (it can also be run by hand) and verifies the publish withcontents: readand no deploy: it checks that the cell the pointer describes is committed, retrying a few times whilemaincatches up, fails the job if it never lands, and then runsbun run validateover the tree. It does not trigger the deploy; the push tomainalready did.
The site is a Cloudflare Workers static-assets deployment: an assets-only Worker (no SSR, no
Worker script), configured in wrangler.jsonc:
name: "goceleris-docs", with assets served from./distnot_found_handling: "404-page", so the brandeddist/404.htmlis served (with a 404 status) on unknown routes
Cloudflare Workers Builds rebuilds and deploys on every push to main (bun run build → dist/),
so a merged publish ships automatically. The only build setting is SITE_URL (default
https://goceleris.dev); there is no deploy hook.
Caching and crawling are static config:
public/_headers: content-hashed/_astro/*isimmutable;/brand,/og,/favicon.svg,/pagefindand/datacache for a day; HTML keeps Cloudflare's default of always revalidating, so a deploy shows up immediately.public/robots.txt: allows everything except/data/, and points crawlers athttps://goceleris.dev/sitemap-index.xml.
src/
content/docs/ # the docs content collection
dashboard/ # the Preact + uPlot dashboard island (views, charts, state)
lib/results/ # typed data layer: walk, validate, aggregate, taxonomy
lib/site.ts # landing-page headline stats
pages/ # index, docs, benchmarks, methodology, 404, llms(.full).txt
layouts/ components/ styles/
scripts/ # build-data and helper CLIs (see below)
results/ # committed benchmark cells: the single source of truth
public/ # static assets, _headers, robots.txt
test/fixtures/ # cell fixtures; sample-cell feeds the data-layer tests (scripts/build-data.test.ts)
build-data.ts: the pipeline above (build:data/validate).import-run.ts: reshape a raw probatorium run into aresults/cell (a manual bridge; the canonical source stays the probatorium run).regroup-docs.ts: rewrite each doc'sgroup/orderfrontmatter to the curated information architecture (idempotent).dev-fixtures.ts: synthesize the demo tree under.dev-results/from the preserved sample cell.gen-og.ts/gen-logo.ts: render the Open Graph image and the brand mark as static assets.
| Project | What it is |
|---|---|
| celeris | The HTTP engine for Go that this site documents |
| loadgen | The HTTP/1.1 and HTTP/2 load generator behind the published benchmarks |
| probatorium | The benchmark and validation harness that measures celeris and publishes runs here |
See CONTRIBUTING.md for the local checks CI runs, and SECURITY.md to report a vulnerability.
Apache-2.0. Package name: celeris-site.
