Why I hand-wrote this site

I wrote this site from scratch. No Astro, no Next.js, no node_modules. The build is a handful of .mjs files with zero dependencies.

This is not retro affectation. It follows from one thing I worked out first: a personal site's SEO ceiling is set by the HTML it ships, not by the framework that produced it.

What a crawler actually sees#

A crawler receives a blob of HTML text. The things it cares about are a short list:

  • whether <title> and <meta name="description"> are accurate and unique
  • whether <link rel="canonical"> collapses duplicate URLs onto one address
  • whether hreflang is reciprocal, self-referential, and has exactly one x-default
  • whether the structured data is internally consistent and its @ids are stable
  • how fast the first readable content arrives
  • whether internal links reach every page

Nothing on that list says which framework generated the file. Static HTML from Astro and static HTML I wrote by hand are indistinguishable to a crawler — provided the contents are the same.

So where is the framework's value#

Authoring experience. That value is real and I am not dismissing it.

Astro's content collections are type-checked. Change a component and it propagates. Hot reload, automatic image optimisation. At a few hundred posts these stop being conveniences and become requirements.

But those gains accrue to me, not to the ranking. The decision I was actually making: is a full toolchain worth it for the authoring experience alone?

The trade-off I made#

For this site, no. Three reasons.

One: I want to own the SEO logic. A framework's sitemap plugin and SEO component are convenient, and the price is not knowing exactly what they emit. A wrong hreflang, a canonical pointing at the wrong URL, hundreds of tag pages indexed as near-duplicates — none of these throw an error. They show up six months later as traffic that never grew. I would rather that layer be code I wrote and can read.

As it stands the whole SEO surface sits in four files: the route table decides every URL, head.mjs emits every meta tag, schema.mjs emits every JSON-LD block, feeds.mjs emits the sitemap and robots. To audit the canonical logic I read one function.

Two: dependencies are a long-term cost. A fresh Astro project installs roughly 300 packages. They expire, collect security advisories, and eventually cost an evening to a breaking change. I expect this site to outlive a decade of framework churn, and I do not want to service a toolchain annually to keep it alive.

The flip side of zero dependencies: git clone this in two years, run node src/build.mjs, and it will still work.

Hand-written is not the same as doing less#

To be clear, skipping the framework did not mean skipping the work. This site ships:

CapabilityHow
Bilingual hreflangGenerated from one route table, guaranteed reciprocal and self-referential
Structured dataA single @graph with stable @ids, so the Person merges into one entity site-wide
SitemapGenerated from the route table, with xhtml:link language alternates
RSS / Atom / JSON FeedOne set per locale, full content plus summary
Markdown mirrorsA .md twin of every page, for AI assistants
TOC, footnotes, code blocksA small Markdown renderer, all resolved at build time
Content validationOver-long titles, missing descriptions, inverted dates all fail the build

That last row is the one a framework usually does not hand me: SEO validation at build time. A description over 160 characters warns; a post with no date fails outright. These are precisely the defects that are invisible locally and only surface once Search Console gets around to telling you.

What would change my mind#

I would migrate to Astro when:

  • the archive passes ~200 posts and manual index management starts producing mistakes
  • I need a real image pipeline (multiple sizes, AVIF, blurred placeholders)
  • I want comments, a subscribe form, or anything else genuinely dynamic
  • someone else starts maintaining this with me and stronger conventions pay off

None of those hold today, so today I do not migrate. Migration stays cheap regardless, because the content is ordinary Markdown either way.

The conclusion#

A framework does not make a site easier to find. Correct HTML does. A framework makes writing correct HTML less laborious — a real benefit, but a developer-experience benefit, not an SEO one.

Once those two are separated, the choice comes down to your actual scale rather than to whatever is currently fashionable.