← Back to Writing
Building Systems

How I Rebuilt This Site (and Why It Took Deleting 90% of the Code)

7 min read

Reading note

Essays for people who want the pattern behind the pattern.

This page is designed to read like a quiet, deliberate argument rather than a feed item.

My portfolio site had 84 dependencies, 47 UI components, an Express backend, a database ORM configured but never connected, an authentication system with a password field but no login page, and a contact form that stored messages in memory and lost them every time the server restarted.

It served seven pieces of content.

I’m an architect. I should have known better. But overengineering is sneaky — it doesn’t announce itself. It arrives one reasonable decision at a time.

How it happened

I built the original site on Replit using a full-stack template. React frontend, Express backend, TypeScript everywhere. It was the kind of stack you’d use for a SaaS product with user accounts, dynamic content, and real-time features.

I was building a blog.

But each addition felt justified in isolation. I added shadcn/ui because I wanted nice-looking components. That pulled in 27 Radix UI packages as dependencies. I configured Tailwind, then added a component library on top of Tailwind. I set up Drizzle ORM because I thought I might eventually want a database. I installed Passport.js because maybe I’d add authentication later. I added React Query for data fetching, even though every piece of content was hardcoded in a TypeScript file.

At no point did I sit down and decide to build something absurdly complex. It just accumulated. Every tool I added was good. The stack was clean, well-typed, properly structured. The code had zero TODOs, zero hacks, zero TypeScript suppressions. It was, by conventional measures, well-engineered.

It was also completely wrong for the problem.

The audit that made it obvious

I ran an architectural review and the numbers were hard to argue with. Of the 47 UI components installed, I was using 14. The ten largest files in the codebase included four unused components. The Express server existed solely to handle a contact form that didn’t actually send emails. The security audit flagged critical vulnerabilities — an unprotected API endpoint, a plaintext password schema — that were only dangerous because the code shouldn’t have existed in the first place.

The most telling detail: the “what’s good” section of the audit praised the type safety, the clean separation of concerns, the lack of technical debt indicators. All true. But good engineering applied to the wrong problem is still the wrong problem.

The rebuild

I replaced everything with Astro. Static site generation. Markdown files for content. Tailwind for styling. No backend. No database. No API. No component library.

The dependency count went from 84 to 7. The file count went from 95 to 20. The build time dropped to about one second. The entire site compiles to 14 static HTML files that deploy to Vercel.

The content — blog posts, field notes, project descriptions — moved from hardcoded TypeScript arrays into markdown files with YAML frontmatter. This means publishing a new post is creating a .md file, not touching application code.

The contact form became a mailto link.

What I learned

Complexity is a one-way door if you’re not paying attention. Every dependency you add is easy to justify and hard to remove. The shadcn/ui components I installed took seconds to add and would have taken hours to individually evaluate and remove. The path of least resistance is always toward more, not less.

Good engineering can mask bad decisions. My original codebase had excellent type safety, clean architecture, and zero code smells. None of that mattered because the fundamental decision — building a full-stack application for a static site — was wrong. Quality within the wrong frame is still the wrong frame.

The right question is “what does this need?” not “what can I use?” I started with tools and found uses for them. I should have started with requirements and found tools to match. A blog needs pages, content, and styling. It does not need a server, a database, or an ORM.

Deletion is a skill. The rebuild wasn’t about writing new code. It was about having the judgment to throw away working code that didn’t need to exist. That’s harder than it sounds, because working code feels like an asset. Sometimes it’s a liability.

The simplest version is usually the most honest one. My over-engineered site was, in a way, performative. Look at all this technology I can use. The static site says something different: I know what this needs, and I built exactly that. For a site whose purpose is to demonstrate technical judgment, the restraint is the demonstration.

The irony

I’m an architect. I help organizations move from overcomplicated systems to ones that are appropriately scoped, maintainable, and operationally sound. And my personal site was the exact kind of mess I’d flag in a client review.

The cobbler’s shoes, as they say.

I’m not embarrassed by it. It’s a common trap, and recognizing it is most of the work. But it’s a useful reminder that the instinct to build with the best tools available is different from the instinct to build the right thing. The first instinct is about capability. The second is about judgment.

This site now runs on seven dependencies and does exactly what it needs to do. That’s the portfolio piece.