The last abstraction

May 26, 2026

This site is intentionally over-engineered. I built it to learn a handful of web concepts and tools firsthand. I wrote about that initial journey here.

Shortly after launching this site, I grew frustrated with the framework I used to build it: Gatsby. The team behind Gatsby released v4 weeks after I finished the site, and migrating from v3 didn’t look simple. When I built the site, Gatsby and Next.js were the obvious choices for a pre-rendered React static site with blog posts in Markdown. Next.js also had SSR[1], and according to NPM Trends, it had roughly four times the daily downloads of Gatsby. I didn’t view that as a decisive difference; since Gatsby felt slightly more geared toward pure static sites, I went with it. You can see the rest in the chart below. By today's numbers, Next.js is on another planet. That matters because code that gets used gets maintained. Gatsby's plugins eventually drifted out of sync with each other and with the core. Next.js was the better bet.

NPM download trends: Gatsby vs Next.js
NPM download trends: Gatsby vs Next.js

I kept telling myself I would migrate off Gatsby, or at least upgrade to v4, but I never got around to it. A few weeks ago, I transferred my domain’s DNS management to Cloudflare and decided to move from Netlify to Cloudflare Pages in the process. Cloudflare Pages requires Node.js v22. Gatsby v3 doesn't run on it. Claude upgraded the project to v5 (the latest version of Gatsby) and all its dependencies to Node.js v22 compatible versions in about 15 minutes.

Fast forward a couple of weeks, and I read A Desktop Made For One, in which the author notes that coding agents have enabled him to build custom software for nearly all of his personal computing needs. That got me thinking. Although I should have initially chosen Next.js over Gatsby for this site, Next.js is by no means the perfect fit for this site. It’s excellent for getting projects off the ground, but it does far more than most projects actually need. I didn’t just migrate my site from Gatsby to Next.js. Instead, I custom-built the specific functionality this site actually uses.

Here's what I did, roughly in order:

  • Replaced miscellaneous Gatsby plugins (fonts, analytics, tweet embedding, SEO) with direct implementations.
  • Replaced Gatsby image plugins with a custom pre-bundle pipeline built on sharp (the library behind the image plugins in Gatsby, Next.js, Vite, and Webpack), plus a custom React component to replace Gatsby's lazy-loading image component
  • Swapped Gatsby's internal routing logic with React Router
  • Migrated off Gatsby's GraphQL build-time queries with custom content injection
  • Replaced Gatsby's MDX (Markdown w/ JSX) parsing with a custom script
  • Decoupled entirely from Gatsby by migrating to Vite, which handles TypeScript transpilation, bundling, and the dev/build server

But then I asked myself: why stop there? Sure, Vite is popular, but do I really need it just for its "lightning fast HMR" dev server? If I were building an enterprise application, perhaps. But for a personal blog? No.

So I kept going:

  • I replaced Vite with esbuild for transpilation and bundling, plus custom pipelines for CSS and MDX.
  • Set up a custom Static Site Generation (SSG) script to run after the bundle (formerly handled by Gatsby)
  • Set up code-splitting and link prefetching (formerly handled by Gatsby)
  • Added caching for the image and content pre-bundle steps
  • Simplified the project's linting and formatting config
  • Ditched Bootstrap in favor of plain CSS
  • Dropped the react-icons dependency and inlined the handful of icon SVGs the site needs.

Here's what my dependencies looked like before and after this project:[2]

Dependencies before the project
Dependencies after the project
Dependencies before the project
Before
Dependencies after the project
After
Left: Before
Right: After

And here's what my scripts look like:

Scripts before the project
Scripts after the project
Scripts before the project
Before
Scripts after the project
After
Left: Before
Right: After

The net result is that I have more ownership over my site. Literally, it depends on less code that I don't own.

This project reminded me that coding agents are the ultimate abstraction. You no longer write the code; you simply define what you want the code to be. In the past, we reached for all kinds of abstractions because they reduced the cognitive load required to ship features. Now, we have coding agents. They render many other abstractions obsolete. The path of least resistance is no longer a thick wrapper around React. It's a spec — and an agent that implements it.

This project barely scratches what coding agents can do. Yet, it may be a preview of what is to come: more custom-tailored code that's resilient to the drift of dependencies that reinvent themselves or go unmaintained. On the other hand, none of us know what the future holds. In coming months, we may find that this kind of work is merely tinkering. Junior engineers and non-technical builders are having great success shipping fast with coding agents. Unencumbered by mental models of how things ought to be, they simply trust the LLM. That may matter more than the stack.



Notes:

  1. Gatsby supports SSR now as well, since v4.

  2. The one thing I dropped in the process is the site's PWA setup for offline reading, formerly handled by gatsby-plugin-offline.