skip to content

A 6-person startup is deciding whether to build their new product as a monolith or as a set of independently deployed services from day one. What concrete reasons would favor starting as a monolith, and what signals would later tell them it's time to reconsider?

level: seniorimportance: should knowfreq 60%

answer

  1. team-size economics: no coordination problem to solve yet
  2. domain seams unknown pre-product-market-fit
  3. wrong service boundary is expensive to undo, wrong class boundary is cheap
  4. extract on measured pressure: scaling, org, compliance, pipeline bottleneck
  5. Shopify: monolith past conventional wisdom, extract selectively

basics

~20 s

With a small team and an unproven product, a monolith is faster to build, deploy, and change, and there's no clear reason yet to split it up. You'd reconsider once specific parts need different scaling, release cadence, or separate teams.

solid answer

~40 s

A 6-person team building an unproven product benefits from a monolith because domain boundaries aren't known yet — splitting into services means guessing boundaries you're likely to get wrong, and a wrong service boundary is far more expensive to undo than a wrong class boundary. Operationally, six people don't need independent deployability or scaling; the distributed-systems tax (service discovery, network failure handling, cross-service transactions, multiplied pipelines) is pure overhead when the team can just talk to each other. The signals to reconsider are specific: a component needs to scale at a very different rate than the rest, distinct teams now own distinct areas and are blocked by a shared release train, or a component needs a different technology or compliance boundary.

go deeper

for a junior

Should be able to say a small team with an unclear product benefits from a monolith because it's simpler to build and change quickly.

for a middle

Should name at least one concrete cost of premature microservices (operational overhead, distributed-systems tax) and one concrete signal to reconsider (independent scaling need).

for a senior

Should articulate both the team-size economics argument and the domain-uncertainty argument distinctly, and give multiple concrete, measurable signals for when to extract services rather than a vague sense of codebase size.

for a principal

Should reference a real organization's trajectory, discuss selective extraction of specific components over full decomposition, and identify legitimate exceptions where starting monolithic is the wrong call even at small scale.

## Two independent arguments The case for a small, early-stage team starting with a monolith rests on two independent arguments: 1. **team-size economics**; 2. **domain uncertainty**. Both point the same direction for a 6-person startup with an unproven product. ## Team-size economics On team-size economics: microservices exist to let independent teams deploy, scale, and operate their piece of a system without coordinating with every other team, and to let each service scale to its own load pattern independently. Both of those benefits require the coordination cost they solve to already exist — you need multiple teams stepping on each other, or genuinely divergent scaling needs, for splitting into services to pay for itself. Six engineers sitting in one Slack channel (or one room) do not have a cross-team coordination problem; they can just talk to each other, agree on an interface inside the codebase, and merge. Meanwhile, choosing microservices from day one imposes real, immediate costs regardless of team size. You now need: - **service discovery**; - **network-failure handling** (timeouts, retries, circuit breakers) for calls that used to be simple function calls; - **distributed tracing** to debug a request that spans multiple services; - separate **CI/CD pipelines** and monitoring dashboards per service; - some strategy for **cross-service data consistency** (sagas, outbox patterns) in place of a single database transaction. For six people, standing up and maintaining that infrastructure is itself a significant fraction of the team's total capacity — capacity that, pre-product-market-fit, is far better spent building and testing the actual product. ## Domain uncertainty On domain uncertainty: service boundaries are supposed to track real, stable seams in the business domain — the places where two areas of the system genuinely change for different reasons and at different rates. An early-stage startup, by definition, doesn't yet know where those seams are; the product is still being discovered through customer feedback, and what looks like a natural 'billing service' boundary in week one may turn out to be tangled up with 'subscription' concerns that were wrongly assumed separate. | Boundary placed badly | What undoing it costs | |---|---| | A class boundary inside a monolith | Getting it wrong is a same-day refactor, caught by the compiler, and safely undoable. | | A service boundary | Getting it wrong means the wrong data now lives behind the wrong network API, other code has already started depending on that API's shape, and un-splitting or re-splitting two live services with real traffic and real data is a materially harder, riskier migration than moving code within one codebase. | Premature service decomposition effectively locks in a guess about the domain before you have the evidence to make that guess well. ## The signals that it's time to reconsider The signals that it's time to reconsider are concrete and specific, not a vague sense that 'the codebase feels big.' 1. **The first is divergent scaling needs.** If one component (say, a video-transcoding pipeline) needs to scale to ten times the instance count of the rest of the application under load, forcing the whole monolith to scale along with it wastes resources scaling parts that don't need it — that's a legitimate, measurable reason to extract that component. 2. **The second is organizational.** Once distinct, stable teams genuinely own distinct areas of the product and are being blocked by a shared release train (the deployment-simplicity cost discussed elsewhere — one team's broken build blocking another team's urgent fix), splitting along those now-real team boundaries starts to pay for itself. 3. **The third is a hard technical or compliance constraint.** A component that must run in a different runtime, meet a stricter compliance boundary (e.g., PCI scope for payment handling), or use a fundamentally different technology than the rest of the stack is a legitimate forcing function regardless of team size. 4. **The fourth is when the shared build/test pipeline has become the actual bottleneck** on how fast the team can ship — measured, not felt, via degrading deploy frequency and lead time for changes. ## Shopify's trajectory A well-known real-world pattern following exactly this trajectory is Shopify, which built and scaled its core commerce platform as a Ruby on Rails monolith well past the point most conventional wisdom says you should have split it, specifically because the team judged that domain boundaries stayed genuinely unclear for a long time and the shared-transaction, shared-deploy simplicity kept outweighing the coupling costs; where they did eventually need independent scaling or isolation (certain high-load or compliance-sensitive components), they extracted those specific pieces rather than decomposing the whole system upfront. That's the general shape of the right call: start monolithic when the team is small and the domain is unproven, and extract specific components later in response to specific, measured pressure — not on a fixed schedule or because microservices are perceived as the more modern default.

  • If the startup gets it wrong and one part of the monolith later needs independent scaling, how costly is it to extract that part into its own service?
    It's real work but bounded and well-understood: identify the component's boundary (ideally it was already a clean internal module), define an API contract for it, stand up its own deployment and data store if needed, and migrate callers from in-process calls to network calls behind an anti-corruption layer or facade. It's meaningfully cheaper if the monolith already had clean internal module boundaries — which is the main argument for keeping code well-organized internally even while staying deployed as one unit.
  • Isn't it risky to "guess wrong" and have to rewrite everything as microservices later — shouldn't you just build it right the first time?
    Building 'right the first time' with microservices actually carries the bigger risk here, because it means committing to service boundaries before you have the domain knowledge to place them well — the cost of being wrong is much higher for a live service split than for an in-process module boundary. Deferring the decision and extracting services only once real, measured pressure justifies a specific boundary is generally the lower-risk path, not the higher-risk one, despite feeling like it 'delays' an inevitable decision.
  • Are there startups or situations where you should NOT start with a monolith, even at small team size?
    Yes — if the product's core differentiator genuinely requires independent scaling from day one (e.g., a real-time video processing pipeline bolted onto a simple CRUD dashboard, where the two truly have wildly different load profiles from the start), or if there's a hard regulatory isolation requirement (a payment component that must be PCI-scoped separately) that's known upfront rather than discovered later, those are legitimate reasons to split specific pieces early — the general advice to start monolithic assumes the scaling and compliance needs are genuinely unknown or uniform, not that they always are.

It's like renting one shared apartment before you know your long-term living situation, instead of signing five separate leases for rooms you've guessed you'll each want — moving a wall inside your own apartment is a weekend project, but breaking five leases because your guess about who needs their own space was wrong is expensive and slow.

saying these in an interview costs you the question

  • Recommends microservices by default regardless of team size or domain maturity
  • Can't name any concrete cost of starting with microservices at small scale (only vague 'it's more complex')
  • Treats 'codebase feels big' as a sufficient signal to split, rather than a measured pressure like scaling or org structure
  • Doesn't recognize that getting a service boundary wrong is more expensive to undo than getting a module boundary wrong
  • Has no example of extracting a specific component later in response to specific pressure, only 'rewrite everything'

context