Monolith vs microservices for a small team
When to start with one deployable and when a split is justified, with three real splits and one deliberate merge from my own projects.
In short: for a small team building a first version, start with a single deployable application (a "monolith") organised into clear modules, and split a part out only when it has a concrete reason to be separate: a different security boundary, a different runtime, or a different scaling need. Microservices solve organisational and scaling problems a five-person team usually does not have yet, and they add operational cost from day one. Below is the reasoning, with real examples of when I split and when I deliberately did not.
What the two words mean
- Monolith: one codebase, deployed as one unit, usually talking to one database. It can be well organised (modules with clear boundaries) or messy; the word says nothing about quality.
- Microservices: many small services, each deployed on its own, communicating over the network. Each service has its own release process, monitoring and failure modes.
What you pay for when you split
- Network failures replace function calls. Every call between services can time out or fail halfway.
- Data consistency gets harder. A change that was one database transaction becomes a sequence you must reconcile.
- Operations multiply: deployment pipelines, logs, monitoring and credentials, per service.
- Debugging spans several systems.
- Onboarding slows: a new developer must understand the map before changing a line.
A small team pays all of this out of the time it would use to build the product.
When a split is justified: three real examples
1. A security boundary: a legacy database behind a read-only bridge
On a health-insurance platform, a legacy Oracle system could not be exposed to the outside, and duplicating its data risked inconsistency. The answer was a separate, minimal, read-only API on a single port whose only job was to talk to Oracle, with the main Node.js/MySQL API consuming it as one data source. The reason to split was a security and ownership boundary, not scale. See the LAMAS case study.
2. Different jobs on a constrained host
For a recruitment platform running on shared hosting with no root or SSH access, I built several independent Node.js services: a gateway to the applicant tracking system, a CV extractor and a sourcing engine. They could be deployed and checked separately, and the extraction and matching parts had different runtimes and failure modes. See Werin Sourcing.
3. A file service with its own signing
On a multi-tenant federation platform, files are served by a separate HMAC-secured file service, because file access needed its own security model, distinct from the main application. See SportIQ.
When I deliberately did not split
This portfolio's own API could have been two services (a public read-only site API and an authenticated admin API), and it is modelled on two such earlier services. I merged them into one Express application with two route groups: /public, read-only and rate-limited, and /private, authenticated. Same codebase, same database, same deploy, but the boundary stays clear in the code. For a single-author product with one database, two deployables had no benefit.
A practical rule
- Default to one deployable, organised in modules, each with its own data access and a small public interface.
- Write the boundary before you cut it. If you cannot describe the module's interface in a page, it is not ready to become a service.
- Split for a reason you can name: a security boundary, a different runtime, an independent scaling need, or a different team that releases on its own schedule.
- Count the cost. For each service ask: who monitors it, who deploys it, and what happens when it is down?
Questions to ask a vendor who proposes microservices
- What problem does this solve that a modular monolith does not?
- How many people will operate it, and who is on call?
- How is data consistency handled between services?
- What is the monthly infrastructure cost compared with one application?
A founder once brought a vendor estimate of 45 days for a multi-tenant SaaS backend and asked whether it was real. It was not, because the estimate assumed a single-tenant data model; the architecture question hiding behind it was tenancy, not service count. Architecture decisions are cheapest before the commitment. The Architecture Power Hour is one prepared hour with a one-page written decision. For tenancy specifically, see multi-tenant architecture explained.
Related articles
Notes
Technical due diligence checklist for non-technical founders
Nine areas to check before you invest in, buy or rescue a codebase, and why most serious findings are about access and ownership, not code.
Notes
What a code audit checks, and what it costs
What a useful code audit covers, real findings from audits of production projects, what drives the price, and the questions to ask any auditor.
Notes
Fractional CTO vs dev agency vs in-house: how to decide
What each option buys you, how fractional CTO work is priced, what the titles really mean, and the combination that fails most often.
Newsletter
Get my upcoming articles straight to your inbox.