Server architecture basics: what actually happens between DNS and your code
You cannot debug what you cannot picture. This is the map of a production request, layer by layer.
Start with a modular monolith. Microservices become worthwhile when multiple teams need to deploy independently, when parts of the system have genuinely different scaling or availability requirements, or when a component needs a different technology stack. Splitting before those conditions exist buys network calls, distributed transactions and deployment complexity in exchange for nothing.
None of these are insurmountable. All of them require engineering time that is not going into your product, and they scale with the number of services rather than the size of your codebase.
One deployable application with strictly enforced internal module boundaries — separate domains, explicit interfaces, no reaching into another module's data.
src/
modules/
billing/ # owns billing tables; exposes a typed public API
index.ts # the only file other modules may import
internal/
catalog/
identity/
shared/ # genuinely cross-cutting: logging, config, errorsEnforce it with lint rules that forbid deep imports across modules. The discipline is the same as microservices — clear ownership, explicit contracts — without the network in between. And when a module genuinely needs to become a service, the boundary already exists, which makes the extraction mechanical.
Around data ownership. Each service owns its tables exclusively and exposes them only through its API. If two services read and write the same table, you have a distributed monolith — all the coupling of a monolith with all the failure modes of a distributed system.
Only for scaling components independently. A monolith scales horizontally very well — you run more copies. The advantage appears when one part needs ten times the resources of the rest.
It can, and it usually should not. With a small team, the operational overhead consumes the capacity that should be going into finding product-market fit.
Services that must be deployed together, share a database, or break when any one of them is down. It is the worst outcome of a premature split and unfortunately a common one.
With sagas — a sequence of local transactions plus compensating actions on failure. It is significantly more complex than a database transaction, which is itself an argument for keeping related data in one service.
Harshal Patel
Founder & Lead Engineer, ROVQIX
Harshal leads engineering at ROVQIX, where he has shipped production Next.js, Node.js and PostgreSQL systems for startups, SaaS teams and ecommerce brands. He writes about the trade-offs behind architecture decisions rather than the framework of the week.
ROVQIXdesigns and builds production web platforms — Next.js front ends, Node.js APIs and the infrastructure behind them. Tell us what you're building and we'll scope it with you.
You cannot debug what you cannot picture. This is the map of a production request, layer by layer.
Kubernetes is excellent at problems most teams do not have yet. The cost of adopting it early is paid in engineering hours you needed elsewhere.
Some decisions can be changed in an afternoon. These seven set the shape of the codebase for years, so they deserve an hour of thought each.
No spam. Just the occasional case study and craft breakdown.