6.8 KiB
layout, title, description, date, image, tags, tagId, category, categoryId, readTime
| layout | title | description | date | image | tags | tagId | category | categoryId | readTime | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @/layouts/BlogPostLayout.astro | All This Tinkering... For What? Engineering Reflections from a Full-Stack Developer | An honest reflection on tech stack selection paralysis. One developer's journey from chasing 'best practices' to realizing that technology is a tool, not a totem—how to avoid over-engineering and find the right fit for your actual needs. | 2026-01-08 | https://images.unsplash.com/photo-1518770660439-4636190af475?q=80&w=1470&auto=format&fit=crop |
|
|
Engineering | engineering | 8 min read |
A log of the soul-crushing details I encountered during a recent project setup. This is a summary of my own internal tug-of-war—lessons learned the hard way through endless trial and error. It might not be the "correct" way, but every word was paid for in lost time.
I recently set out to build a simple bookmarking tool. It only needed about 30 endpoints, yet I spent nearly a month agonizing over the tech stack. I felt like I was wandering through a dark forest, sprinting toward every glimmer of light only to find a new pitfall waiting for me.
Step 1: Chasing the "Mainstream" and Feeling the Friction
It started because I wanted to build a side project. In my day job, I use Vue; it’s second nature to me. But everywhere I looked online, the consensus was: "Next.js + React + shadcn-ui" is the gold standard. Great ecosystem, endless components, future-proof.
I told myself: Don’t get stuck in your comfort zone. Try something new. So, I benched Vue and picked up React. I was immediately hit by choice paralysis.
It wasn't just a choice between A and B; it was a choice between five different ways to do everything. I spent more time reading docs and comparisons than writing logic:
- Do I fetch data with SWR or TanStack Query?
- Is global state better in Zustand, Redux, or Jotai?
- How do I bridge the gap between server and client data?
Instead of building features, I was researching "how to build." To make matters worse, I kept hitting those cryptic "Hydration Errors." One refresh, one error, and an hour gone trying to find the mismatch.
The most draining part was tagging everything with "use client". I felt less like a developer and more like a clerk labeling boxes. I kept thinking: "If most of this ends up running on the client anyway, why am I using a framework that splits the stack so aggressively and demands such high mental overhead?"
Step 2: Retreating to Comfort—and the Fear of Missing Out
I went back to my familiar Vue ecosystem and fired up Nuxt. Suddenly, I could breathe. My productivity skyrocketed.
But the peace didn't last. I’d see another post praising the Next.js ecosystem and start doubting myself: "Am I choosing the wrong path? Am I falling behind?" I gave Next.js another shot for a few days, and like clockwork, all those petty, nagging frustrations returned.
That’s when I realized: Tech isn't about "better" or "worse"; it’s about fit. Trust your "handfeel." That sense of flow (or lack thereof) doesn't lie.
Step 3: The "Professionalism" Trap
Once the frontend was settled, I moved to the backend. I chose NestJS because it’s billed as the most "Enterprise-grade" option. To make it even more "professional," I forced it into a Monorepo. I effectively built myself a prison:
- Immense Friction: Changing a single shared enum or type meant re-building, waiting for workspace syncs, and restarting services. A 10-second change turned into a 1-minute wait.
- Compatibility Hell: NestJS is still clinging to CommonJS. Trying to use a pure ESM library or running a TS Worker thread resulted in config errors that made me question my career choices.
- Ceremony Over Substance: For 30 endpoints, I was writing endless Controllers, Services, Modules, and DTOs. The lines of code tripled, but the core logic stayed exactly the same.
- The Swagger Tax: I wanted to use Zod for validation, but Swagger only recognizes decorators (class-validator). I ended up maintaining two nearly identical data definitions just to have an API doc.
I traded my immediate efficiency for the "advantages of a large team" that I don't actually have. I wanted speed; the framework demanded "maintainability" for a scale I'll likely never hit.
Step 4: Stripping it Down and Losing My Way
I ditched the heavy frameworks for Fastify, thinking I’d keep it lean. But I quickly discovered that the problem wasn't just "weight"—it was "the anxiety of absolute freedom."
Fastify is liberating, but for someone used to structure, freedom is a burden:
- "Where should this file go?"
- "How do I organize this into a plugin?"
- Logging, queues, auth—everything NestJS gave me for free now required me to find, integrate, and debug a third-party library.
I hated the rules of heavy frameworks, yet I craved their structure. My mindset was completely torn.
The Epiphany: Tech is a Tool, Not a Totem
One night, working late, I asked myself: "Why am I doing this? I just wanted to build a simple tool."
Everything clicked. I was applying "Long-term Enterprise Maintenance" standards to a "Solo Rapid Prototype." It was like trying to build an eight-lane highway just to go to the grocery store around the corner.
I set a new, simple rule for myself:
- For Prototypes & Small Tools: Use Nuxt (or a monolithic framework) exclusively. Frontend and backend in one repo, natural type synchronization, no CORS issues, no sync friction. The goal is to ship.
- For Complex Systems & Large Teams: Then consider Nuxt + NestJS + Monorepo. The complexity is a fair trade for the architectural guardrails.
A New Contender: AdonisJS
During this spiral, I stumbled upon AdonisJS. It’s often called the "Laravel of Node.js." From a quick look, it seems to hit the sweet spot: it has the structure I crave (ORM and Auth built-in) but feels modern and supports ESM natively. I might give it a spin next time.
Final Thoughts
- Don’t blind-follow the hype: What works for Vercel might not work for your weekend project.
- Trust your "handfeel": If a tool makes you feel productive, that's worth more than any "State of JS" ranking.
- Ship first, optimize later: For a solo project, an un-launched architecture is just expensive fan fiction.
- Watch out for "Config Friction": If you spend more time in
.jsonand.config.jsfiles than in your logic, your tools are failing you.
This was my journey through the weeds. My approach might be "wrong" or even a bit clumsy. I’d love to hear how you handle the "stack anxiety." Do you have a go-to setup that just works, or are you still searching for the "perfect" balance?