After building well over 50 web applications across industries — from tiny SaaS tools to enterprise platforms — we’ve seen the same architectural decisions cause the same downstream disasters.
These aren’t exotic edge cases. They’re predictable traps that smart teams fall into because they’re optimizing for the wrong thing at the wrong time.
Mistake 1: Starting with a Microservices Architecture
Everyone’s read about microservices. Netflix uses them. Uber uses them. Your 6-week-old startup should not.
The overhead of distributed systems — network latency, service discovery, deployment complexity, observability — is appropriate for teams with hundreds of engineers managing services that genuinely need independent scaling.
For most web apps, start as a monolith. You can extract services later, when you actually understand which parts of your system need independent scaling. The companies that started with microservices and had to merge them back together quietly don’t write Medium posts about it.
What to do instead: Build a well-structured monolith with clear module boundaries. When (if) you need to extract a service, the seams are already defined.
Mistake 2: Using Your Database as a Message Queue
We’ve seen it more times than we can count: a jobs table, a pending_emails table, a notifications_to_process table. Polling loops that hit the database every 5 seconds. Rows that get locked, processed, and deleted.
It works. Until your database load spikes at 2am because 40,000 tasks all became ready at the same time and you have 12 workers pounding the same table.
What to do instead: Use an actual message queue — Redis with BullMQ, AWS SQS, or even Postgres with pg_notify if you want to stay in the DB ecosystem without polling. These tools are purpose-built for this problem.
Mistake 3: Skipping the Audit Log
We know. It sounds like unnecessary overhead. You’re moving fast. You’ll add it later.
Later never comes, and then six months into production a client asks “what happened to that order?” and the only honest answer is “we have no idea.”
Audit logs — immutable records of every meaningful state change — are vastly cheaper to add from day one than to retrofit into a production system with years of mutations in it.
What to do instead: Add a simple audit_log table on day one. Every important model gets a trigger or service-level hook that writes a record of who did what and when. Don’t regret this later.
Mistake 4: Ignoring Multi-Tenancy Until Customers Demand It
If there’s any chance your app will serve multiple organizations, think about multi-tenancy early. Not at the code level, necessarily — but at the data model level.
We’ve seen apps that launched as single-tenant tools, then added org_id columns in a mad scramble when enterprise customers came calling. They never quite got the row-level security right. One bug served User A’s data to User B. It’s a startup-ending incident.
What to do instead: Even if you only have one tenant today, model your data with tenant isolation in mind. Add org_id or tenant_id to every relevant table. Use row-level security policies (Postgres RLS is excellent for this). Do it before you have data you can’t afford to leak.
Mistake 5: Not Treating Your API Contract as a Public Interface
If you control the client and the server, it’s tempting to change API responses freely. Then you add a mobile app. Or a partner integration. Or someone builds a public integration based on your docs.
Suddenly every API change is a breaking change that you only discover when something silently stops working in production.
What to do instead: Version your APIs from day one (/v1/, /v2/). Treat the schema as a contract. Use tools like TypeSpec or OpenAPI to define your API before implementing it. Never remove fields — deprecate them.
The Underlying Pattern
Notice what all five of these have in common? They’re all shortcuts that feel sensible in the short term and create compounding pain over time.
The best architectures aren’t the most sophisticated ones — they’re the ones that remain comprehensible and modifiable as the team and requirements evolve. That takes discipline, not cleverness.
If you’re building something new and want a second opinion on your architecture before you commit to it, reach out. We offer architecture review sessions and we’ll tell you the truth even if it’s not what you wanted to hear.