Common Architecture Mistakes in Web Projects
Insights/ Web Architecture & Platforms / Architecture Decisions
08 Feb 2024 - 07 min read

Most architecture failures are not novel
Most architecture mistakes that destroy web projects are not new. They show up in roughly the same shape, year after year, in projects of every size and every domain. The expensive part is rarely the mistake itself; it is how long it takes the team to recognise it for what it is and how late the cost shows up. By the time the symptom is visible (the platform is slow, the deploys are scary, the team is rewriting things instead of building things), the original choice that caused it is often two years old and three engineers ago.
This article is a working catalogue of the recurring architecture mistakes I see most often in web projects. It is the "what to avoid" companion to the architecture-choice article. Each mistake below is named, described, and paired with the symptom that usually surfaces first, so a team can recognise itself before the cost compounds.
Mistake 1: Choosing the stack before understanding the project
The most common architecture mistake is to pick the technology stack first, often based on what the team enjoys or what is fashionable in the industry, and back the project's shape into it. The conversation starts with "we'll use Next.js and Postgres on Vercel" and only later reaches the question of what the project actually is, who maintains it, what the load looks like, and what the editorial workflow needs.
The symptom shows up around month four or five: features that should be straightforward require workarounds because the stack does not naturally fit the project, or the team is paying operational tax for capabilities the project does not use. The fix is to start architecture conversations with the project shape and to let the technology fall out of that, not the other way around.
Mistake 2: Decomposing before the project earns it
Splitting the system into multiple services, multiple databases, multiple deployables, on day one, because that is what "modern" architectures look like. The team has never run a distributed system before, the project has one team, and there is no evidence that decomposition is needed yet, but the slide deck has a microservices diagram on it.
The symptom shows up immediately: every change requires coordinating two or three deployments, the local development setup is hostile, and a release that would have taken an hour as a monolith takes a full day. The fix is to start as a monolith, ideally a modular monolith, and to extract services only when the team count, blast radius incidents or scaling needs actually justify it.
Mistake 3: Building for hypothetical scale instead of the next plausible step
Designing the system for a million users when the realistic ceiling is ten thousand. Adding a queue, a cache layer and a service mesh before there is any evidence that any of them are needed. Optimising for a load that exists in a slide deck, not in the access logs.
The symptom is operational complexity that the team cannot absorb: too many moving pieces, too many runtime dependencies, too many places where something can go wrong. The fix is to build for the next plausible step, with a clean upgrade path, and to leave the headroom for later as a deliberate choice rather than a paid-up-front investment. The honest version of capacity planning is in the scalable platform article.
Mistake 4: Treating hosting and operations as an afterthought
Architecture documents that go deep on framework choice and content model and stop at "we will deploy it somewhere". The hosting decision gets made in the last week of the project, often by whoever happens to be available, and the operational implications (who is on call, how rollbacks work, where logs go, how secrets are managed) get decided in week one of production.
The symptom is the deploy that goes sideways at 5pm on a Friday and nobody has the access or the runbook to recover it before Monday. The fix is to treat hosting and operations as part of the architecture from the first conversation: who runs it, how it gets deployed, how it gets monitored, how it gets rolled back, and who is paged when it breaks.
Mistake 5: Weak data ownership and shared mutable state
Multiple parts of the system writing to the same tables without a clear owner. Application code reading another module's data directly because "it's the same database anyway". Background jobs and user-facing requests touching the same rows without a documented contract. The data layer is treated as a shared spreadsheet rather than as a system with boundaries.
The symptom shows up under load or during a refactor: a small change to the data model requires updating five places nobody remembers, or two writes race and the data ends up inconsistent in a way that takes weeks to untangle. The fix is to give every table or document collection a single named owner module, to forbid cross-module reads and writes, and to make any cross-boundary access an explicit API call.
Mistake 6: Integration boundaries that are not really boundaries
The system depends on three external APIs, and the calls happen inline in user-facing requests, with no timeout, no retry policy, no circuit breaker, no fallback. The integration is treated as if the external service is a local function. When the third-party API has a bad afternoon, the user-facing site has a worse one.
The symptom is the incident report that traces back to a third-party slowdown that the platform amplified instead of absorbing. The fix is to design every integration as a real boundary: explicit timeouts, retry with backoff, idempotent calls, fallback paths for known failure modes, and monitoring that distinguishes the platform's own latency from the third-party latency in front of it.
Mistake 7: "We will fix it later"
The most expensive sentence in any architecture decision. The temporary CSS hack, the hard-coded credential, the missing migration, the schema change that needs a backfill, the test that was disabled to ship the launch. Each one was supposed to be a few days of cleanup. None of them get cleaned up, because there is always something more urgent, and the cleanup quietly becomes structural debt.
The symptom is the codebase that has thirty TODO and FIXME comments, none of which have a date or an owner, and the team that has stopped trusting any of them. The fix is to refuse the "we will fix it later" framing and to either fix it now, ticket it with a real owner and a real date, or accept that it is permanent and update the architecture documentation to say so. Fictitious cleanup is more expensive than honest debt.
Final takeaway
Architecture mistakes are predictable. The same handful of patterns recur in projects of every size, and recognising them early is what separates teams that build platforms that age well from teams that rewrite the same system every two years. The discipline is not to be perfect; it is to keep the catalogue of recurring mistakes in mind, to name them when they show up, and to treat each one as a real decision instead of a default.
The wider context, including the architecture-choice, decomposition, headless and scalability decisions that these mistakes most often distort, is collected in the web architecture and platforms insights cluster. And when the question moves from "are we making one of these mistakes" to "we recognise the symptom and we now need someone to design the fix without breaking what currently works", that is exactly what my API development and system integration practice is built around.
- Haja Faniry
Related services
Web Application Development
Custom web application development for companies, startups and international organisations.
Technical SEO & Web Performance
Technical SEO and web performance optimisation services to improve website visibility, speed and search engine ranking.
API Development & System Integration
API development and system integration services to connect platforms, automate workflows and enable seamless data exchange between applications.


