There's a pattern we see with painful regularity. A startup builds fast, ships fast, raises a Series A on strong traction. Then they hire engineering leadership, who opens the codebase and finds a collection of architectural decisions that made sense in month three but are now actively preventing the company from scaling.

The rewrite that follows costs six to twelve months of engineering velocity. Sometimes it costs more than that. Here are the five decisions we see most often behind this outcome.

1. The Monolith That Was Never Meant to Be a Monolith

Starting with a monolith is fine. Most successful companies start with a monolith. The problem is a monolith with no internal boundaries - where every module can call every other module directly, database tables are accessed from anywhere in the codebase, and business logic is scattered across multiple layers.

A well-structured monolith can scale much further than people think and can be extracted into services when the time is right. An unstructured monolith becomes unmaintainable quickly and requires a ground-up rewrite to move past. The effort required to impose boundaries later is much greater than the effort to establish them upfront.

2. Relational Databases Used as Document Stores

We regularly inherit codebases where PostgreSQL tables contain JSON blob columns holding 60-70% of the meaningful data. This is almost always a sign that the schema was designed before the domain was fully understood, and JSON columns were used as an escape hatch for evolving data shapes.

The problem is that you lose the benefits of both approaches. You can't efficiently query inside the JSON at scale. You can't enforce constraints on the stored data. Your ORM doesn't know how to work with it. And you can't migrate the structure without writing custom scripts for every change. Pick an approach and commit to it.

3. Authentication and Authorization Bolted On After the Fact

Auth is boring to build and easy to defer. Many early codebases have authentication as an afterthought - a simple JWT check at the API gateway level with no fine-grained authorization model. When multi-tenant requirements, role-based access, or resource-level permissions appear (and they always appear), retrofitting them into a codebase that wasn't designed for them is painful and error-prone.

Design your authorization model in week one, even if the initial implementation is simple. The model is what's hard to change later; the implementation is relatively easy.

4. Synchronous Processing for Everything

Every web request that does more than read and return data from a database is a candidate for async processing. Sending emails, generating reports, processing payments, syncing with external systems, resizing images - these should all be jobs in a queue, not blocking operations in the request/response cycle.

Codebases that don't draw this boundary end up with slow API responses, unreliable external service integrations, and no good way to handle partial failures. Adding a queue-based system to an existing synchronous codebase is a significant refactor. Building it in from the start is a few days of work.

5. No Observability Strategy

Logging console.log statements is not an observability strategy. Structured logging, distributed tracing, error tracking, and performance metrics need to be in place before you go to production - not because something has gone wrong, but because something will go wrong, and when it does at 2am with production traffic, you need to understand what happened.

The cost of adding good observability to an existing system that wasn't built with it in mind is high. The cost of building it in from the start is low. This is one of the areas where experienced engineering judgment pays for itself many times over.

The best architecture is the simplest one that addresses your current needs while leaving the door open for where you'll need to go. Over-engineering kills early-stage startups. Under-engineering kills growth-stage ones.

The Common Thread

All five of these mistakes share a root cause: decisions made under time pressure, without the benefit of experience that's seen where each shortcut leads. This isn't a criticism of the engineers who made them - it's an argument for making sure you have experienced technical leadership involved in the earliest architectural decisions, not just in the execution.