Skip to content
El escritorio de Jorge Saurina, con tres monitores y uno vertical arriba
El escritorio en ángulo, con la planta y la estantería iluminada
El estudio de noche, visto desde el sillón
Websites

I removed the CMS from my site, and now the content is text files

My personal site ran on Strapi with a database to serve five pages that hardly ever changed. Here is what I found when I opened it after two years, and what I did about it.

Monograma JS de Jorge Saurinaby Jorge Saurina
La portada de jopsa.me tras la reconstrucción, con la foto del escritorio a la izquierda

I opened my personal site's project after two years without touching it. The first thing I saw was not the code: it was the server's process list. Two applications running, a MySQL database, a subdomain for the admin panel, and a main domain that, depending on how you arrived, answered with a 500 error.

All of it to serve five pages that had not changed since 2023.

What was there

The previous version was a Next.js 13 front end consuming a Strapi API. The CMS lived at strapi.jopsa.me with its own database, and the front end ran in a separate process. On paper, the right architecture: a panel to edit content without touching code.

In practice, I logged into that panel about three times in two years.

I found the 500 by accident, opening the site from a tool that does not send the Accept-Language header. The middleware assumed it was always there, and without it the request blew up. It had been like that for months, failing for any bot or client that skipped the header. Nobody told me, of course: nobody reports the errors on a personal site.

The question

Before rewriting anything I asked myself one thing: what is the CMS giving me that a text file would not?

The honest answer was nothing. There is no newsroom, no approval workflow, no twenty editors. There is one person writing, and that person knows how to use git. What the CMS was giving me was a database to back up, one more process to watch, a version to upgrade and an extra attack surface.

What I did

I rewrote the site with the content in files: YAML for pages and Markdown for articles, one per language. Every file is validated against a schema at startup, so a mistyped field breaks the build on my machine instead of in production.

Pages are composed of blocks. Each block is a type declared in the schema and a component in the code; content never invokes an arbitrary component. Adding a new section is two things: describing its shape and drawing it.

The result is 22 routes generated at build time. No database, no CMS, no queries while someone waits for a page.

The two stumbles that cost me an afternoon

The server could not compile. The VPS runs Rocky Linux 8, with a glibc from 2018, and Next 16's compiler wants a newer one. Rather than fight the system, I moved the build to GitHub Actions: it compiles a self-contained bundle there, rsyncs it and restarts the process. Every push to the main branch deploys on its own, after passing lint, types, tests and content validation.

A redirect loop that did not exist locally. In production the home page bounced forever between / and /es. The cause was an environment variable: with HOSTNAME=127.0.0.1 set, Next compared the origin of its internal rewrite against the boot origin, they did not match, it treated the rewrite as external and sent it back through the proxy. Removing that line fixed it. I left the reason in a comment so I do not fall for it twice.

What is left

One process instead of two. No database. A deployment that takes two minutes and starts with git push. And, as a side effect of retiring the old stack, seven gigabytes back on the server.

The lesson is not that content management systems are bad. It is that I was paying maintenance for flexibility I never used. When I write, I open the editor and commit; the site publishes itself. For what I need, that is faster than any panel.