Skip to main content
Build Log

September 24, 2026

How I rebuilt medmansports.com static-first in a day

This site used to be a Next.js app that did runtime fetches against a serverless API backed by a document database — to serve eleven weeks of workouts. Eleven. The API cold-started, the pages were force-dynamic, and the error state (“We're experiencing technical difficulties with your workout data”) got more screen time than the workouts.

The realization

My entire training log was about 20KB of JSON. I was paying serverless cold-start tax, running a database, and maintaining a CRUD API to serve less data than the favicon. The fix wasn't better caching or a warmer function — it was admitting the data is content, not state. Content goes in the repo.

The rebuild

Step one was a data rescue: pull every week out of the API with curl and bake it into a single weeks.json checked into the repo. That file is now the source of truth. A library module derives everything else at build time — tags, stats, per-day workout pages, the exercise library, even the contribution graph. Every public page is prerendered: the whole site builds in about two and a half seconds and ships as ~57 static pages on a CDN.

The workout generator got the same treatment: a curated exercise pool with equipment and body-area metadata, plus a seeded, deterministic builder that runs entirely in the browser. No API call, no spinner, instant re-roll. When the AI version comes, it swaps in behind the same options-in, workout-out contract.

The loop that fell out of it

The unexpected win is the publishing loop. I describe a workout in a chat with my AI session mid-cooldown, it structures the JSON, commits to main, and CI (lint, type-checked build, and an AI PR reviewer that guards the static-first contract) gates the deploy. The training log has CI/CD. Every stat on the site recomputes itself on merge.

Lessons

Static is a feature, not a fallback. If your data changes a few times a week and fits in a file, a database is a liability with uptime requirements. Delete the dead ends. Half the rebuild was removing code: the caching layers, the fallback chains, the component that existed to survive an API that no longer needed surviving. And test your dates — the one real bug the process caught was my workout log being a day off because I'd forgotten what weekday it was. The build didn't care about my feelings.

Full architecture notes: how this site works.

Written by a software engineer who can't sit still. More teardowns in the Build Log, more sweat in the Workout Library.