
Monolith to Microservices, No Rewrite
The rewrite is the failure mode, not the plan. Here is how to extract services one seam at a time while the thing stays live.

An MVP that nobody uses never breaks. The systems we get called about are the ones that worked — the launch went well, a campaign landed, a partner sent traffic, and the thing that comfortably served forty users fell over at four hundred.
It is almost always the same five things, in roughly the same order.
The first thing to go is nearly always a query that was fine against a thousand rows and is catastrophic against a million. Usually it is an N+1: a list page that runs one query for the list and then one more per row. At ten rows nobody notices. At ten thousand, the page times out.
Close behind: missing indexes on the columns you filter and sort by. These are cheap to fix and easy to find — turn on slow query logging before you need it, not during the incident.
Sending the email, generating the PDF, calling the third-party API, resizing the image — all done inline, while the user waits. It is the fastest thing to build and the first thing to collapse, because your response time is now the sum of everyone else's.
When the payment provider has a slow afternoon, your checkout has a slow afternoon. When their API is down, your requests pile up until the connection pool is exhausted and the whole app stops, including the parts that had nothing to do with payments.
The fix is a queue and a worker. Accept the request, enqueue the job, return. It is an afternoon of work before launch and a fortnight of firefighting after.
Most early systems have logs nobody reads and no metrics at all. When it slows down, the honest answer to "what's slow?" is a guess, and the debugging method is redeploying things until it stops.
The minimum worth having before you have users:
Sessions in local memory. Uploads on the local disk. A cache in a process variable. Everything works perfectly on one server, and the moment you add a second, users get logged out at random and half the uploads 404 depending on which box answered.
This is the shortcut that most reliably blocks scaling horizontally, and it is genuinely cheap to avoid up front: sessions in Redis, files in object storage, cache somewhere shared. Retrofitting it means touching auth and uploads under load, which is exactly when you least want to.
If shipping means SSHing to a box and running commands in the right order, you will ship less as risk rises — which is precisely backwards, because when things are breaking is when you most need to ship fixes quickly.
You do not need sophisticated tooling. You need a deploy that is one command, a way back that is also one command, and migrations that run automatically. Anything more is optimisation; anything less is a liability.
Not every shortcut is debt worth avoiding. These are usually fine to take and cheap to undo later:
The distinction is whether undoing the shortcut later touches one layer or every layer. Adding a read replica is one change. Pulling session state out of memory once you have real users is a migration with a risk of logging everyone out.
Do not rewrite. In order: turn on query logging and fix the top three queries; move the slowest inline work to a queue; add request and error metrics so you can see the next problem coming; then move state off local disk and memory.
That sequence is roughly two weeks for most systems and buys a very large multiple of headroom — usually enough that the architecture question can wait until you actually have the traffic to justify it.
Most often an N+1 query pattern or a missing index — queries that are fine against a thousand rows and catastrophic against a million. Enable slow query logging with a 100ms threshold and look at the top offenders before assuming you need more servers or a new architecture.
In order: fix the three slowest database queries, move slow inline work like emails and third-party API calls to a background queue, add request-duration and error-rate metrics, then move sessions and uploads off local memory and disk. That sequence is about two weeks and usually buys a large multiple of headroom.
A single database, a monolith, server-rendered pages and platform hosting are all fine — each is one change to undo later. The costly ones are storing sessions in memory or files on local disk, because undoing those touches auth and uploads while you are under load.
Usually not. Most scaling problems at this stage are query performance, work done inside the request, and state tied to one machine — all fixable inside a monolith. Split services only when you have a named operational reason, such as one component needing to scale independently.