stevex.us

How stevex.us is put together

Reference · updated 2026-08-16

This page documents the domain it is served from. If the setup drifts, fix this page.

#The split

The domain is a hybrid: cheap content lives at paths on one worker, real apps get their own subdomain.

Thing Where Why
Reference pages, notes stevex.us/ref/*, stevex.us/learn/* A markdown file shouldn't need its own deploy
Anything with state, a build, or its own stack thing.stevex.us Independent deploy, independent blast radius

The rule of thumb: if it's markdown, it's a path. If it's an app, it's a subdomain.

There is no gateway proxying paths to backends — the apex worker serves paths itself, so it can never take a subdomain project down with it, and a subdomain project can never take the hub down.

#Adding a page

# 1. write it
content/ref/my-thing.md

# 2. build + deploy
npm run deploy

That's the whole loop. Frontmatter is optional; without it the title is derived from the filename and the description from the first paragraph.

---
title: My Thing
description: One line for the section index and the meta tag.
updated: 2026-08-16
order: 10
index: false
---

#Adding a section

Make a folder under content/ and drop a _section.md in it:

---
title: Recipes
description: Shows up under the card on the hub.
order: 30
hidden: false
---

The hub, the header nav, and the router all pick it up from the filesystem — there is no registry to update. _section.md is metadata only; it never renders as a page.

#Adding a subdomain project

  1. Build it wherever (default: a new Cloudflare Worker, same as everything else).
  2. Bind thing.stevex.us in that project's wrangler.toml:
    [[routes]]
    pattern = "thing.stevex.us"
    custom_domain = true
    
  3. Add one object to PROJECTS[] in src/index.js so the hub links it.

⚠️ Never mix dashboard-attached custom domains with declarative [[routes]] on the same worker — a deploy detaches the dashboard ones. Learned the hard way during the stevexsports.com apex cutover.

A subdomain doesn't have to be a Worker. It's a CNAME; point it at Vercel, Pages, a container, whatever the project wants. Workers is the default because it's the fastest path, not a rule.

#Why markdown compiles at build time

build.js walks content/, renders each file with marked, and writes src/content.gen.js — a plain JS module of pre-rendered HTML strings.

The tradeoff: content changes require a deploy. For a handful of reference pages that's the right trade — and it means the site cannot break from bad data, only from bad code.

#Routes

Path Serves
/ Hub — section cards + project cards
/<section> Section index
/<section>/<slug> A page
/healthz ok
/robots.txt Allow-all; per-page meta tags do the real gating
anything else 404

www.stevex.us 301s to the apex, path and query preserved. Trailing slashes 301 to the bare form.

#Commands

npm run build    # markdown -> src/content.gen.js
npm run dev      # build, then wrangler dev on localhost
npm run deploy   # build, then wrangler deploy