My first startup was a failure, and several neighboring startups failed, too. We had: $100K in GCP credits, a founding engineer who’d built systems in enterprise, and go-to-market. And we failed, not because we built it wrong, but because we built it well. That was the problem.
While we spent time wrestling with what felt like an “un-optimal” tech stack, we lost the most important thing: time, momentum, and strategically an opportunity.
This story isn’t about people without common sense. I had common sense, and we knew we should keep things simple. But when your mental model doesn’t fit the situation, all your common sense gets swept away. You make “correct” decisions that kill you.
This also isn’t a story about bad engineering. It’s about how good engineering kills startups. How the very experience that makes you senior becomes your biggest liability. How “doing it right” or even “doing it simple” is often doing it wrong.
This article presents mental models to help you make the right decisions and avoid the wrong ones I made.
:::tip Who this is for: senior engineers starting or joining early-stage startups. If you’ve spent 5+ years in enterprise or Big Tech, this is your warning.
:::
\
$100K in GCP credits seems like a gift, but it’s a trap. It pushes you toward over-engineering because “it’s already paid for.” You get compute instances, load balancers, container registries, and enterprise tools that require enterprise setup. What do you need to get? A “push to deploy” button.
Sure, you can build “deploy from GitHub to VM” workflows on GCP/AWS/Azure. Some products come close. But it requires extra steps: configuring Cloud Build, setting up IAM roles, writing deployment scripts, managing secrets, and configuring health checks. You burn time building deployment infrastructure before deploying actual products.
Meanwhile, platforms like Railway or Fly.io give you what startups actually need: a persistent VM with start-and-go deployment from GitHub. Easy as it can be: you push your code, and it deploys. Just ready to use VM with environment variables, SSL, load balancers, logs, etc. It’s not “free,” but it’s ready.
Free credits push you toward over-engineering because “it’s already paid for.” You convince yourself you’re saving money while spending your most valuable resource: time.
\
The traditional KISS principle tells us to keep our software simple. But in startups, that's the wrong target. You shouldn't keep your SOFTWARE simple; you should keep your SOLUTIONS simple.
Real simplicity should be measured by total effort, not code complexity:
Total Effort = Initial Build + Maintenance + Debugging + Feature Addition + Security Updates + Scaling Changes
When you build from scratch, you own all of these forever. When you use a service, most of these become zero. The "bloated" third-party service is actually the simple solution because it minimizes total effort.
Our founding engineer decided to build OAuth from scratch instead of using an "unknown library." One week later, he submitted a PR: clean OAuth implementation with JWT tokens, refresh token rotation, session management, and role-based access control. No dependencies, no vendor lock-in, just code we controlled.
I didn't deny the PR. And this was a mistake. Throwing away a week of work would crush morale. But it creates code complexity and puts it on the wrong rails. Plus, not discussing the approach beforehand was our real mistake. We let engineering pride make a strategic decision.
Then, a client needed Microsoft OAuth and Google OAuth. Custom implementation meant days of refactoring, refresh token rotation, edge cases, RBA, and other things. Each "simple" addition required a deep understanding of our custom auth. Every security update was ours to implement. Every new requirement was ours to code.
Classic senior engineer mistake: optimizing for control instead of outcomes. In startups, reality requires completely inverting how senior engineers think:
\
\
We chose Angular because our founding engineer knew it deeply. Smart decision, right? Use your strengths, ship quality code. The framework was fine, BUT the problem was its ecosystem.
Angular is excellent and our engineer could build anything with it.
But "anything" took time just to start. Setting up deployment, authentication, and basic UI components meant endless configuration before writing a single feature. While we debugged Angular Material themes, competitors can (and will) use Next.js + Vercel were already onboarding users.
Just compare that to the Next.js + Vercel path: deploy a skeleton app with npx create-next-app on day one, add Clerk authentication and shadcn/ui components on, ship actual features on day one. Same destination, completely different journey.
The difference isn't framework quality, it's ecosystem optimization. Next.js/React is surrounded by venture-backed startups building tools for other startups:
Angular's ecosystem serves enterprises: powerful, flexible, infinitely customizable. Perfect(?) for teams of 50 and a poison for teams of 3.
\
But even with the right tools, there's one final trap: the compulsion to build things because you can, not because you should. This trap kills technically strong teams and more startups than we can imagine: building things nobody asked for because you can, not because you should.
We spent at least a month in total on features nobody needed. Custom OAuth when Auth0 existed. A Postgres-based job queue when Redis + Celery existed. Terraform from day one, when the console worked fine. Each decision felt productive, but each was self-sabotage to face real challenges like talking to customers or doing other customer development.
The pattern is simple: if customers won't choose you for it, don't build it.
If a SaaS costs less than $50/month, you can't afford to build it. Your time is too expensive.
Building custom OAuth takes 1-2 weeks in total maintenance and adding different OAuth providers. At startup burn rates, that's $5,000-$15,000 in engineering time, or in a losing opportunity time. Auth0 is free for up to 25,000 active users, then $35/month. You could pay for Auth0 for 35 years with what it costs to build it once.
So, this isn't about money but about priorities and opportunity cost.
In my opinion, build only if you can't learn about users without it. A simple example is when you need to test whether users will pay for AI-generated reports. Build the simplest version that proves demand. And everything else tries to slip. Yes, skip infrastructure, skip "doing it right", skip best practices that don't ship features, skip tests. Again, be as lazy as possible in writing code.
These aren't endorsements but my own choices optimized for speed. I guess your stack will differ but this principle won't.
\
\
LLMs have commoditized building. Any junior with Claude can create that custom auth system you're so proud of. Your value isn't in what you can build anymore, BUT it's in knowing what not to build.
Leadership is the ability to separate signals from noise. True seniority means having the discipline to ignore 90% of what you know and to ship today's solution, not tomorrow's architecture.


