Monolith or microservices: how to modernize the backend without stopping the service
The question “is it time to switch to microservices” usually appears when the current backend is already difficult to change: the release of one function requires testing the entire product, integrations influence each other, and an increase in load forces us to scale even those parts that do not need it. But microservices are not a one-size-fits-all fix. They replace some constraints with new ones: network calls, distributed data, observability, complex testing and operation.
It’s safer to start not with code decomposition, but with an understanding of business scenarios and boundaries of responsibility. This approach underlies development of high-load systems: First capture workload, data, and risks, then choose an architectural path.
When a monolith is still a smart choice
Monolith does not mean bad architecture. A modular application with clear boundaries, automated tests, observability, and secure releases is often faster to develop than a prematurely distributed system.
A monolith is usually worth saving and improving if:
- the product is developed by one or more closely related teams;
- parts of the system are released at the same rhythm;
- the main load does not require independent scaling of modules;
- the data model is highly coupled and transactional integrity is more important than autonomy;
- the key issue is in queries, integrations or infrastructure, not code boundaries.
In these circumstances, profiling, database optimization, cache, background tasks, queuing, and modularization within a single application often provide the first benefit. It is useful to first confirm the problem by measurements via load testing, not an assumption.
Signs that a separate service may be justified
Removing part of the product makes sense when there is a specific boundary and a measurable reason. For example:
Different load profile
Search, report generation, file processing, or a public API can grow faster than the main application. Their isolation allows you to scale the expensive circuit, and not the entire product.
Independent life cycle
If a feature has its own team, its own release schedule, and a clear contract with the rest of the system, it can be a candidate for a service. But first, it's worth checking whether the teams can actually maintain this independence.
Risky integrations and background processes
Integrating with an external vendor, processing large imports, or sending notifications should not block a critical user path. For these, queuing and processing isolation is often sufficient; a separate service is needed when the boundary is firmly confirmed.
Security or location requirements
Sometimes part of the data needs to live in another circuit, and a separate component simplifies access, auditing and processing rules. This is an architectural reason, not a cosmetic decomposition.
What microservices will require in return
After dividing the system, tasks appear that were not within one process:
- API versioning and contract compatibility;
- network latency, timeouts, retries, and cascading failure protection;
- data consistency and event processing;
- centralized logs, tracing and metrics;
- Reproducible release and configuration management;
- testing the entire chain of services.
Therefore, migration should not start with the creation of dozens of repositories. It's more important to ensure observability, negotiate contracts, and prepare a secure release path. Even automatic scaling in Kubernetes requires metrics and a clear resource model, which is described in official documentation Horizontal Pod Autoscaling.
A safe way to upgrade your backend
1. Draw the current data flow
For a critical process, show where the data originates, who changes it, what external services are involved, and how the user sees the result. This scheme quickly detects hidden dependencies that may break when part of the code is taken out.
2. Select the first narrow but valuable contour
There is no need to separate “everything at once.” A good candidate is a report, import, public API, catalog or notification: it has clear responsibilities, it can live under a separate contract, and its effect is easy to measure.
3. Add compatibility before switching
The new component must be able to work alongside the old one. To do this, they use API versions, feature flags, phased data migration and reversible releases. This way you can switch traffic in parts and roll back without losing operations.
4. Check load and degradation
Before a full switchover, they check not only the speed of the new service, but also the behavior of the system during queue delays, dependency unavailability, event re-delivery and peak traffic. We need metrics, alerts and people responsible for the reaction.
5. Leave documentation and ownership
A service must have an owner, a contract, a data schema, a metrics dashboard, and a runbook. Otherwise, technical debt will simply move from the monolith to the network of services.
Real contours in which integration is more important than the loud name of the architecture
In the case AI2Media the platform combines Node.js and Python backend, PostgreSQL, Redis and API integration with CMS and external services. The key issue here is not the number of services, but how data and tasks flow between components and how the team controls this path.
B OfficeScanner the product connects sales, documents, telephony, marketing channels and analytics. For such ERP loops, it is especially important not to lose data integrity when integrations change. Sometimes the right move is to strengthen the boundaries within the application and accommodate asynchronous operations, rather than creating an entire distributed system.
How to choose a path for your product
Ask the team four questions:
- What business scenario is currently limiting growth or creating risk?
- Which technical bottleneck is confirmed by measurements?
- Is it possible to solve it inside a modular monolith without complicating the operation?
- If a component is taken out, who will own its contract, data, releases and incidents?
If the answers are not yet obvious, you should start with an audit. On highload development page you can describe the current stack, the nature of the load and integration; The result of the first stage will be a modernization plan with an order of work, and not a template recommendation “switch to microservices.”
FAQ
Is it possible to remove one service and leave the rest as a monolith?
Yes. This is often safer than a full migration. The main thing is to select a component with clear responsibilities, define a contract and organize the joint work of the old and new circuits during the transition.
Is Kubernetes needed for microservices?
Not always. It is useful when there is a corresponding operational task and the team is ready to support the platform. A small number of services may run more easily on a different managed infrastructure.
How long does it take to modernize a backend?
The timing depends on the first phase boundary, data, integrations, and business continuity requirements. It's best to start with a limited, measurable iteration: audit, one critical loop, and retest.
