How this blog was built
A series on the technical and design decisions behind Sourcier
When I launched this blog last week I wrote a post called I Should Start a Blog — the short version of why I’d stopped putting it off. Part of what I mentioned there was that building the site itself had been an enjoyable project: a proper excuse to use Astro in earnest, deploy serverless functions on Netlify, wire up email delivery through Resend.
What I didn’t write about was how any of that actually works.
The series
I’ve decided to fix that. Starting today, I’m publishing a series of posts that document how this blog was built — the technical decisions, the design choices, the problems that needed solving and how I solved them.
It is, admittedly, a slightly self-referential thing to write a blog about the blog. But I think there’s genuine value in it. These are patterns and decisions that come up on almost any content-driven site. The answers I landed on aren’t unique to this project — they’re worth writing up properly.
The series covers:
- Choosing the tech stack — Live — the full stack decision: Astro for static output and content collections, Bulma for a no-runtime CSS foundation, Netlify for hosting and serverless functions, Font Awesome, Resend, and the other tools that hold it together.
- Typed content collections — Live — Zod schemas, build-time validation, the
draftflag pattern, and what typed frontmatter actually buys you. - Dark/light theme toggle — 7 April — CSS custom properties,
localStoragepersistence, and why not getting this right causes the flash of wrong theme. - Blog card and post hero design — 9 April — typography hierarchy, cover image pipeline, the draft overlay.
- A tag system with weighted clouds — 14 April — slug normalisation, the three-tier cloud, a concentric ring layout, paginated tag pages.
- OpenGraph and SEO metadata — 16 April — OG tags, Twitter Cards, canonical URLs, article metadata — all centralised in one place.
- RSS in Astro — 21 April — the
@astrojs/rsspackage, draft filtering, autodiscovery. - Breadcrumb navigation with Schema.org markup — 23 April — auto-generated crumbs,
BreadcrumbListstructured data, accessiblearia-current. - A share widget with the Clipboard API — 28 April — LinkedIn, email, copy-link with in-place feedback.
- Page history and credits — 30 April — transparent revision logs and why attribution is a first-class concern.
- Deploying to Netlify — 5 May —
netlify.toml, functions, environment variables, deploy previews. - Post notification emails with Resend — 7 May — a Node.js script that reads frontmatter, builds an HTML email, and sends a broadcast to subscribers.
- Scheduled publishing — 12 May — a
isPublished()helper that gates on both draft status and pubDate, a Netlify scheduled function, and a daily build hook so future-dated posts go live automatically. - Adding a mailing list — 14 May — Resend’s Segments API, a serverless subscribe function, honeypot spam protection.
- Comments on a static site — 19 May — Netlify Forms as a queue, HMAC-signed approve/delete links, three serverless functions, no database.
- Mermaid diagrams — 21 May — bypassing Expressive Code, client-side rendering, theme-aware SVGs, a fullscreen lightbox.
- Better code blocks — 26 May — syntax highlighting with Expressive Code, dual themes, line numbers, frames, and markers.
- Sticky table of contents — 28 May — build-time heading extraction, IntersectionObserver active state.
- Pagination — 2 June — clean URLs, skeleton placeholder cards, no client-side JavaScript.
- A custom 404 page — 4 June — outlined text, a ghost effect, and why a dead end is worth designing properly.
- Web analytics on a static Astro blog — 9 June — picking PostHog from the free options, loading the snippet only in production, and wiring up credentials with Netlify environment variables.
- Moving blog content to a private repository — 11 June — splitting Markdown content into a private GitHub repo, a build-time clone with a fine-grained token, and a GitHub Actions workflow to trigger deploys on content changes.
- Adding search — 12 June — Pagefind for static site search, a command-palette header modal with keyboard navigation, and the non-obvious problems with meta elements, asset hashing, and scoped styles.
- Emoji reactions with Netlify Blobs — 16 June — serverless key-value storage, a Netlify Function API, and an optimistic UI with pop animations and localStorage deduplication.
- Automating Dev.to cross-posting — 19 June — a Node.js script that reads your frontmatter, normalises tags, makes image URLs absolute, sets the canonical URL, and publishes in one command.
That’s twenty-five posts rolling out through to late June. Some are short — a single technique worth documenting cleanly. Others go deeper. All of them are grounded in code that actually runs on this site right now. Subscribe below and you’ll get each one the morning it drops — no noise, just the article.
Why write this at all
Two reasons.
The first is that documenting things properly forces me to understand them better. When I built the comment system I had a rough sense of how the HMAC signing worked. Writing it up properly — in a way that another engineer could follow — required me to be precise about the details. Every single post in this series has taught me something about my own implementation.
The second is that I genuinely couldn’t find a comprehensive write-up for most of these patterns when I was building them. There are fragments — a hint in the Astro docs, a Stack Overflow answer that’s half-right, a GitHub issue with a workaround. Writing them up in one place, with enough context to be useful, seems worth doing.
Working on something similar?
If you’re building a content site, a developer blog, or anything along these lines and would rather not figure it all out from scratch — I’m available for consulting. I can help with architecture decisions, implementation, or a straightforward code review.
Get in touch via the contact page and tell me what you’re working on.
Support this blog
If you found this useful, a small tip keeps the writing going.
Free · No spam · Unsubscribe any time
Get new posts in your inbox
When the next article drops, I'll send a short note — a link and a summary, nothing else. One email per post.
Did you find this useful?
Comments
Loading comments…
Leave a comment