I spent a year building AI features and shipped nothing
What over-engineering burnout actually looks like from the inside, and the ordering mistake that caused it.
I want to tell you about the most productive year of my life in which nothing shipped.
I wrote thousands of commits. I ran coding agents around the clock. I redesigned the same dashboard so many times that I have folders of screenshots that look like a design agency’s entire portfolio. At one point I had four separate repositories that were all, if you squinted, the same product. And at the end of that year, the number of people who could visit a URL and pay me money was zero.
This is a story about burnout, but probably a different kind than you’re picturing. The exhaustion came from motion. There’s a specific fatigue that comes from being busy every single day while a quiet voice in the back of your head keeps asking why nothing is actually done, and it compounds worse than any crunch I ever worked in a real job.
How it actually happens
Nobody decides to over-engineer. It arrives in small, individually reasonable steps.
Mine looked like this. I started building an AI content-checking product. Sensible scope, real users waiting, an actual scoring engine that worked. Then I decided the database layer needed to be right before I went further, so I evaluated ORMs. I ended up with one ORM on the main branch and a different one on the development branch, with a decision document explaining which one would win. The document was well written. It was never executed. For months, every feature had to be mentally reconciled against two database layers, and so most features quietly didn’t happen.
Meanwhile the dependency count crept up. One app hit 72 packages. Every one of them had a justification at the time it went in, and collectively they meant that any security alert, any major version bump, any tooling change turned into an afternoon of archaeology.
Then came the copies. When a codebase starts feeling heavy, there’s a powerful temptation to start fresh, and I gave in to it repeatedly. Fresh repo, better stack, lessons learned this time. Except the old repo never died, so now there were two. Then a prototype for a rebrand. Then a shell generated with one of the AI app builders to explore a new information architecture. Four codebases, each holding some fraction of the product, none of them deployable.
Here’s the part that took me longest to admit: all of that work felt great while I was doing it. Evaluating ORMs feels like engineering. Restructuring repos feels like leadership. Watching agents refactor code overnight feels like the future. The feeling of progress and the fact of progress had completely detached from each other, and I couldn’t tell, day to day, which one I was experiencing.
The ordering mistake underneath all of it
When I finally sat down and audited the wreckage, the root cause turned out to be ordering rather than any single technical decision. I built the product before the launch.
The unglamorous artifacts that let a product actually take money, the landing page with real pricing on it, the terms of service, the privacy policy, the refund policy, the payment account, the domain wired to production, all of that sat at the bottom of every to-do list for a year. It was always “after the next feature.” And because the finish line was never wired up, no amount of feature work could ever reach it. I had built most of a paid product, including auth and a working billing spine, and I had never once been in a position where one more day of work would have produced a customer.
Flipping the order changed everything about how the work feels. Site first, legal pages, real prices in real currency, payment approval, and only then the feature lane. The day I made that flip, I discovered something uncomfortable and liberating at the same time: my first revenue required zero feature building. Everything the first paying customer needed already existed. It had existed for months, buried under work that only I would ever see.
What I actually changed
Nothing fancy: three rules, enforced by writing them down where my tools and my future self would keep seeing them.
One lane. One repository is the product. Every other copy got archived or demoted to a reference I can read for design ideas. The decision took an afternoon and removed a background hum of guilt I’d been carrying for a year.
Deletion before improvement. When a dependency has a vulnerability, the first question is no longer “what version fixes this.” It’s “is this package even used.” An unused package doesn’t get patched; it gets deleted. Around a third of the time, that’s the answer, and the same test works on features, branches, and entire repos.
Ship order is law. Landing page, legal, pricing, payments, then features. I wrote it down as a sequence with no branches, because the branches are where I lose years.
I still feel the pull. This week, while shipping the very site you’re reading, I caught myself wanting to build a contact-form backend before the site had a domain pointed at it. The instinct doesn’t go away. What changes is having something outside your own head that says: that’s not the next step, and you already know what the next step is.
If you’re a year into building and no stranger can pay you yet, I doubt your problem is velocity, and more effort will make it worse. Put the boring launch artifacts first. The relief on the other side is enormous.