Writing

Why I stopped overengineering my side projects


My side projects used to have a phase problem. They’d start with a burst of energy, hit about 70% done, and then stall — not because the interesting part was over, but because the boring part was about to begin. Deployment. Docs. The ugly edge cases. The part where the project becomes a thing instead of an idea.

It took me an embarrassingly long time to notice that my architecture choices were causing the stall. Every side project got the same treatment: a monorepo, a queue, a config system, abstractions for abstractions. Enterprise scaffolding on a toy. I was building for scale I’d never reach, with users who didn’t exist.

Overengineering is procrastination with a resume

Here’s the uncomfortable version: complexity was how I avoided the scary part. Setting up Kubernetes feels like work. Writing the actual copy for the landing page feels like exposure. Guess which one I chose every time.

The tell was always the same — I’d be three layers deep in a plugin architecture for an app with zero users, and I’d call it “investing in the future.” The future never came. The app never shipped.

What I do now

Three rules, learned the hard way:

One file until it hurts. No folders-of-one-file. No premature modules. When the file genuinely hurts to scroll, split it. Not before.

Boring tech by default. My most reliable side project is a single Astro site on a static host. It has no runtime, no database, no ops. It has never been down. My most “impressive” stack spent more time being upgraded than being used.

Ship the ugly version. The jump from “works on my machine” to “publicly available” is where side projects go to die. I force myself to deploy before I feel ready — the deploy itself is usually an afternoon, and the relief is immediate.

The irony is that the simple versions got more users than the ambitious ones ever did. Not because simple is magic, but because finished is the only feature that matters.