---
title: "Why I hand-wrote this site"
description: "A personal site's SEO ceiling is set by its HTML, not by its framework. Here is the full reasoning behind dropping the build tooling."
canonical: https://yonnia.com/en/blog/hand-written-static-site
language: en
date: 2026-08-26
updated: 2026-08-26
tags: ["Web","SEO","Engineering"]
reading_minutes: 3
words: 754
---
# 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 `@id`s 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:

| Capability | How |
|---|---|
| Bilingual hreflang | Generated from one route table, guaranteed reciprocal and self-referential |
| Structured data | A single `@graph` with stable `@id`s, so the Person merges into one entity site-wide |
| Sitemap | Generated from the route table, with `xhtml:link` language alternates |
| RSS / Atom / JSON Feed | One set per locale, full content plus summary |
| Markdown mirrors | A `.md` twin of every page, for AI assistants |
| TOC, footnotes, code blocks | A small Markdown renderer, all resolved at build time |
| Content validation | Over-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.
