Architecture
This page describes how static.bio serves public profiles while keeping the public surface static, no-JS, and auditable.
The system is intentionally split into two surfaces:
- Public profile surface: static HTML + CSS, no JS.
- Dashboard surface: authenticated UI for editing profile data (may use JS).
High-level model
A public profile request resolves to:
- Profile lookup (by username or custom domain)
- Pure HTML render (deterministic function)
- Static asset delivery (base CSS + theme CSS + avatar)
The public renderer has no framework/runtime dependencies at request time and produces a complete HTML document.
Request lifecycle (public profiles)
Username URL
GET /<username>
- Resolve
username -> profile - Load profile + links
- Render HTML via the pure renderer
- Return HTML
- Browser fetches:
/css/base.<hash>.css/css/theme-<id>.<hash>.css- avatar image (if present)
Custom domain URL
GET https://<custom-domain>/
- Resolve
host -> profile(custom domain mapping) - Same render flow as username URL
Notes:
- Custom domains should be implemented as rewrite, not redirect, so the canonical URL remains the user's domain.
- The HTML is the same; only the origin differs.
Core components
1) Profile store
Stores:
- profile identity (username, displayName, bio, avatarUrl)
- theme selection (
themeId) and sparse theme options (themeOptions) - plan (
FREE|LIFETIME) - analytics flag (
analyticsEnabled) - ordered links
Theme options are sparse (absence means default). This avoids leaking false booleans into the model and keeps raw JSON clean.
2) Pure renderer (HTML)
A deterministic function:
- input:
{ profile, links, options } - output:
{ html, meta }
Properties:
- No I/O inside the render function
- Deterministic: same input => same HTML string
- Escaping: user content is HTML-escaped
- No JS: renderer never emits
<script>tags for public pages
3) CSS system (base + theme)
CSS is split into:
- base CSS: shared component styles (sb-* primitives)
- theme CSS: variables + deltas for a single theme
At build time:
- CSS files are fingerprinted by content hash
- a manifest maps theme id -> hashed path
At request time:
- renderer emits
<link rel="stylesheet">tags for the base file and selected theme file - files are served with immutable caching headers
This allows many themes without shipping all CSS to every profile.
4) Redirect tracking (optional analytics)
Link click tracking is implemented as a server-side redirect layer:
- Public profile links either point directly to
link.url(analytics off) - Or point to a same-origin redirect endpoint (analytics on), e.g.
/r/<linkId>
The redirect endpoint:
- records a click event (server-side)
- responds with an HTTP redirect to the final destination
No JS or third-party scripts are required.
HTML structure contract
Themes should not require per-theme markup. The renderer emits a stable skeleton:
.sb-card-shellwrapper.sb-cardmain container.sb-avatar(optionally wrapped, theme-specific only when needed for layout invariants).sb-name,.sb-handle,.sb-bio.sb-linkscontaining.sb-buttonlinks.sb-footer(optional branding)
Themes should primarily use:
- variables
- scoped overrides
- pseudo-elements
Avoid theme-specific DOM where possible; it increases renderer complexity and makes themes harder to evolve.
Caching strategy
Public HTML
You may choose one of two strategies (both compatible with this architecture):
- Short-lived caching (safer during rapid iteration)
- Conditional caching keyed by profile
updatedAt/ content hash
The renderer returns a content hash (meta.contentHash) which can be used as an ETag or cache key.
CSS and static assets
- Fingerprinted filenames:
base.<hash>.css,theme-<id>.<hash>.css - Serve with:
Cache-Control: public, max-age=31536000, immutable
This makes repeat profile loads extremely cheap, and avoids bloating HTML responses with inline CSS.
Environments
production / preview
- public profiles link CSS via
<link>tags (cacheable) - no JS on public pages
export
- can inline base + theme CSS into the HTML for a true single-file artifact
- still no JS
Known tradeoffs
- Two CSS requests is intentional. We prefer cacheability and long-lived immutability over "single-response pages."
- Theme count scales file count. You'll have more static assets, but each is shared and cached across all profiles using that theme.
- Deterministic rendering limits per-view personalization. This is a deliberate constraint for auditability and performance.
- Some themes may need minimal wrapper markup. Keep exceptions rare and documented; the default should be "same skeleton, different CSS."
Contract tests (architecture-level)
These invariants should be regression-tested:
- Public HTML contains 0
<script>tags. - Public HTML loads ≤ 2 CSS files (base + theme).
- All resource URLs are same-origin (static.bio or custom domain).
- Renderer output is deterministic for identical inputs.
- CSS manifest generation produces stable hashed filenames for stable content.