Key takeaways
- Start with a modular monolith: it is the choice that costs the least to change your mind about.
- Microservices solve an organisational problem, not a load problem.
- A properly indexed relational database goes much further than people think.
- Serverless is excellent for irregular workloads, expensive for constant traffic.
- Split when a separate team needs to ship independently, not before.
“We’re going with microservices, so we’ll be ready to scale.” That sentence has cost more young companies more money than any market mistake.
It comes from a good intention and rests on a confusion: microservices do not solve a load problem, they solve an organisational problem. As long as you do not have that organisational problem, they bring you nothing but their cost.
The three architectures, honestly
| Modular monolith | Microservices | Serverless | |
|---|---|---|---|
| Start-up cost | Low | High | Low |
| Operational complexity | Low | High | Medium |
| Development speed at the start | Fast | Slow | Fast |
| Cost at constant traffic | Predictable | Predictable | High |
| Cost at irregular traffic | Medium | Medium | Very low |
| Debugging | Simple | Difficult | Medium |
| Number of teams supported | 1 to 3 | Several | 1 to 3 |
Why the modular monolith wins at the start
A modular monolith is a single application deployed as one block, but organised into modules with clean boundaries: each module owns its data, exposes an explicit interface, and never directly accesses another’s tables.
It is the best compromise for three reasons.
It costs the least to change your mind about. A well-isolated module can be extracted into a microservice in a few weeks when the need genuinely appears. The reverse — gluing back together three premature microservices — is far more painful.
It can be debugged. A complete execution trace in a single process, versus a distributed investigation across five services and a message queue. On a young product that changes every day, this difference is counted in weeks per quarter.
It can be deployed. One pipeline, one artefact, one database. The operational load of a distributed system is a part-time job that nobody has budgeted for.
The real signal for splitting: two separate teams can no longer ship without coordinating, or a specific component needs to be scaled independently (video processing, heavy computation, massive ingestion). As long as neither is true, splitting costs without paying back.
The decisions that really matter
The architecture debate often hides the choices that actually determine your ability to hold up under load.
The database
A single relational database, with indexes on the right fields and monitored queries, goes much further than its reputation suggests. The performance problems we come across almost always come from three causes, never from the choice of engine:
- looped queries that make hundreds of round trips where one would do;
- missing indexes on columns filtered in every query;
- large columns loaded systematically when they are rarely read.
The boundaries between modules
This is the most structuring decision and the cheapest to get right from day one. If the “billing” module reads the “users” module’s tables directly, you have a spaghetti monolith, and no architecture will save you later.
What happens when an external call fails
Maximum timeout, number of retries, behaviour in the event of prolonged unavailability. It is what distinguishes a system that slows down from a system that collapses — and it has nothing to do with the number of services.
When serverless is the right choice
It genuinely is in three situations:
- Very irregular load: a short daily peak, long quiet periods. You pay only for actual use.
- One-off processing: document generation, image resizing, scheduled tasks, reacting to events.
- A team with no operational skills: nobody to administer a server, and no budget for it.
It is much less so for an API in constant demand: at constant traffic, the bill quickly exceeds that of a correctly sized server, and cold-start times degrade the experience.
The right architecture is not the one that will support ten million users. It is the one that will let you serve a thousand properly, while remaining changeable when you discover what the next ten million really want.
Our default recommendation
For a young product, with a team of one to five developers:
- A modular monolith in a language the team masters, with explicit module boundaries checked in code review.
- A single relational database, with versioned migrations and slow queries logged from day one.
- Serverless for asynchronous tasks: sending emails, image processing, exports.
- Automated deployment in one command, from the first week — the subject of our article on setting up CI/CD.
This boring stack has an immense advantage: it leaves you all your energy for the only problem that will decide your fate, which is whether anyone wants your product.
Sources
- PostgreSQL: Documentation: Chapter 11. Indexes — PostgreSQL Global Development Group
- Understanding the Lambda execution environment lifecycle — AWS
- Tarification AWS Lambda (in French) — AWS



