Render local · push static · serve at the edge

DARE.CO.UK · ARCHITECTURE APPROACH · 2026-05-16

A declaration of how the dare portfolio renders, deploys, and serves. The shape compounds across dare.co.uk, dogwood.house, audreyinc.com, and any client engagement — different scripts, same rhythm.

The principle in one line

Render on the developer’s laptop. Push the rendered output as static files. Serve from Cloudflare’s edge. Reserve cloud compute (Cloud Run, Workers) for the narrow problems where local rendering genuinely can’t.

That’s the whole stack. It’s small on purpose. Each layer does one thing well and stays out of the others’ way.

The shape, by surface

Surface Render Source-of-truth Deploy → Serve
dashboard.dare.co.uk ~/bin/dare_cf_analytics.py — Python on Dan’s Mac, fetches Cloudflare Analytics GraphQL, renders one large HTML file rendered artefact at ~/Downloads/dare_dashboard.html; no git mirror — regenerated from source data each run wrangler pages deployCDN, security layer, and DNS provider sitting in front of dare.co.uk.">CF Pages project dare-dashboardCDN, security layer, and DNS provider sitting in front of dare.co.uk.">CF edge
devreports.dare.co.uk ~/bin/dare_dev_reports_publish.py — bundles markdown reports written by every other tool, renders to HTML git repo xlab-co/devreports-content — mirror of synced ~/Downloads/ reports, pushed every 30 min by dare_devreports_sync.sh (a) local wrangler pages deploy, OR (b) Cloud Run Job devreports-publish daily 06:00 ET as redundancy. CDN, security layer, and DNS provider sitting in front of dare.co.uk.">CF Pages project dare-dev-reportsCDN, security layer, and DNS provider sitting in front of dare.co.uk.">CF edge
dare.co.uk (main site) None — already-static HTML pre-built and committed git repo xlab-nyc/dare-co-uk on main CDN, security layer, and DNS provider sitting in front of dare.co.uk.">CF Pages auto-builds on push → CDN, security layer, and DNS provider sitting in front of dare.co.uk.">CF edge
dare-time-poc.pages.dev ~/bin/dare_time_page.py — static generator using Python’s zoneinfo stdlib, no external API none — generator output is ephemeral and regenerable from script wrangler pages deployCDN, security layer, and DNS provider sitting in front of dare.co.uk.">CF Pages → CDN, security layer, and DNS provider sitting in front of dare.co.uk.">CF edge
dare-dashboard-v2-poc.pages.dev Observable Framework via npm run build — local Node git repo (local-only commit while POC) wrangler pages deploy distCDN, security layer, and DNS provider sitting in front of dare.co.uk.">CF Pages → CDN, security layer, and DNS provider sitting in front of dare.co.uk.">CF edge

Why this shape

Rendering on your laptop means you have full debugger access. No log-export rituals when something breaks. Print statements are real-time. The headless-Chrome thumbnail capture runs against the same Chrome you have open. Iteration is seconds, not minutes.

Static files mean Cloudflare Pages can do the one thing it’s best at: global edge delivery. Cloudflare doesn’t try to be your build system; it’s a CDN with HTTPS, Brotli compression, and roughly free pricing at this traffic shape. The render layer and the serve layer are decoupled — change the renderer, the serve layer doesn’t notice.

Source-of-truth as git, not as the renderer’s working directory. When today’s session shipped 41 backlogged devreports in one wave, that worked because the markdown files are mirrored to xlab-co/devreports-content — a git repo any other render path (Cloud Run, a colleague’s laptop, a future CI worker) can clone and re-render against. The renderer becomes interchangeable; the data doesn’t.

Cloud compute reserved for the narrow case. GCP touches the pipeline at exactly one point: the daily 06:00 ET Cloud Run Job that re-renders devreports as a redundancy. It exists for the “Dan’s Mac is asleep” case, not as the primary path. Cost: dollars-per-month. Mental footprint: a single Job we can read end-to-end in one screen.

What compounds across the portfolio

The same shape works for every portfolio site:

The toolkit ships across surfaces because the rendering layer is just Python that writes HTML. No framework lock-in. No vendor lock-in beyond Cloudflare’s edge (and CDN, security layer, and DNS provider sitting in front of dare.co.uk.">CF is interchangeable with Vercel, Netlify, or any other static host in an afternoon).

What changes when a surface needs more

The architecture is honest about its boundaries:

The pattern: static by default, dynamic by exception, justified by the user-facing win, not by the engineering excitement.

Today’s session as a stress test

Eleven hours of iterations shipped through this pipeline today:

Each one was: edit local file → run a script that wrote new HTML → wrangler upload → live in <10 seconds. No CI queue. No build farm. No 30-minute pipeline wait. The friction surface — the place where iteration slows down — was the decision to ship, not the act of shipping.

What this tells us

Render-local + push-static + edge-serve is a compounding choice. Each tool we build here drops cleanly into every other portfolio surface. The cost of building a new tool against this pattern is the cost of writing the Python script — there’s no infra setup, no service to provision, no API gateway to configure. Every hour spent on a render-local tool is an hour of permanent capability across the portfolio.

The architecture isn’t aspirational; it’s load-bearing. Today shipped fixes for two narrator bugs (phantom 0% cache; HTML-tag leak), a new dashboard section, a new tool (time-poc), a daily-hygiene runner, a robots.txt fix, an A/B preview, and the matching dev-reports session report — all using exactly this pipeline. No friction in the shipping; the only constraint was design judgement.

Watch items

What’s next

The aphorism

The cheapest infrastructure is the kind your laptop already runs. The cheapest CDN is the kind that charges in tens of dollars a year. Build at the intersection and you spend your time on the thing that compounds — the design judgement — instead of on the plumbing.


Source: ~/Downloads/dare_strategy_render_pipeline_approach_2026-05-16.md. Companion to project_hygiene_toolkit.md (the generator pattern), feedback_upstream_fix_downstream_compounding.md (the compounding rule), feedback_stdlib_over_external_api.md (the “stdlib first” principle that keeps the local renderer light). Written 2026-05-16 in conversation with Dan, in the voice of dare.

Source: dare_strategy_render_pipeline_approach_2026-05-16.md · Rendered 2026-05-16 11:37