/writing
Designing URLs for a Printed QR Code
· 2 min read
I built the companion site for a book that is going to print. Every chapter carries a QR code linking to that chapter’s song.
That one sentence contains the hardest constraint of the project. Once the book ships, the URL behind every code is frozen. You cannot patch paper. URL stability stops being a preference and becomes a contract with objects you will never be able to reach again.
Two ways a URL dies
The first threat is the host. The site deploys to a GitHub Pages project page under a repo path, which would tie every printed code to a vendor and a path prefix. The answer is a domain I own. If the host ever changes, that is one DNS update, and the printed codes never notice.
The second threat is the path. The obvious route shape comes from the song title, and titles get edited. What does not change is the track number, so each song lives at /t/01 through /t/10. Nothing anyone might rename appears in the path.
Short paths help on paper too. Fewer characters means a sparser QR code, and a sparser code scans better on a smudged page.
Print before deploy
The subtle decision was in how the codes get generated. They are built at build time as SVGs, and they encode a hardcoded permanent origin rather than reading the framework’s site config.
Reading the config would bake whatever it happened to say into every physical copy, and for most of the project it said a temporary GitHub Pages URL. Instead the codes point at the permanent domain from the start. They were correct on paper before that domain resolved at all, which felt wrong and was not. It means the book can go to print on its own schedule rather than waiting on the site.
The codes use error correction level H, which survives roughly thirty percent damage. Paper smudges and books get carried around.
What I learned
A printed QR code is an API with one consumer you can never migrate. Design the URL the way you would design a public contract: nothing mutable in the path, no coupling to a host, and pin the target to the value that has to be true in five years rather than the one that is true today.
More writing
Caching Sharp-Processed Images in Static Builds
How I cut documentation build times by hashing image inputs, committing the preprocessed webp outputs, and skipping image work on every CI run.
· 3 min read
Hybrid Next.js: Static Export and SSR from One Codebase
How I shipped a Next.js marketing site that builds as a static export for one host and as a server-rendered app on Vercel, without forking the codebase.
· 3 min read
What My Thesis Assumed About Hardware
Five years on from my paper about coordinating jobs across weak devices. The hardware assumption aged badly. The reliability assumption did not age at all.
· 3 min read