top of page

When Is It Time to Move Beyond a Monolith?

Writer: Elo Sandoval
Elo Sandoval
5 hours ago
11 min read
Rubik's cube representing monolithic architecture and microservices with one connected system compared to independent services

You don't need to move beyond a monolith just because your product is growing. A monolithic application can support a growing business when its structure remains manageable and the system can handle its workload.


The time to consider a different architecture comes when the monolith starts creating specific problems that are difficult to solve within its current structure. Deployments may become harder to manage, teams may interfere with each other's work, or certain parts of the application may need to scale or operate independently.


Moving beyond a monolith does not automatically mean adopting microservices. A modular monolith can be a useful step when the main problem is how the application is organized rather than its ability to run as a single system.


The goal is not to build a more complex architecture. It is to choose an architecture that makes your software easier to build, operate, maintain, and grow.


What Does “Moving Beyond a Monolith” Actually Mean?


“Moving beyond a monolith” does not necessarily mean breaking an application into dozens of separate services.


There are several ways an application can be structured as it grows.


Monolith


A monolith is an application where the main parts of the product run together as one system.


For example, an e-commerce application might handle:

  • Customer accounts

  • Product catalog

  • Shopping carts

  • Orders

  • Payments


inside the same application.


This can make development and deployment relatively simple because the main parts of the system are managed together.


Modular Monolith


A modular monolith keeps the application as one system, but its internal parts are separated into clearly defined modules.


Using the same e-commerce example, the application could have separate modules for customers, products, orders, and payments.


The application still runs as one unit, but the boundaries between its different areas are clearer.


This approach can provide more structure without introducing the operational complexity of multiple separate services.


Microservices


Microservices take the separation further.


Instead of keeping the main parts of the application inside one system, individual areas can become separate services. The order system, payment system, and customer system, for example, could each run independently and communicate with one another.


This creates more independence between parts of the application, but it also means there are more systems to deploy, monitor, maintain, and troubleshoot.


These are not simply three stages of the same architecture. They are different ways of organizing software, each with different trade-offs.


Moving beyond a monolith means recognizing when the current structure no longer fits the problems your team needs to solve. The right next step could be clearer internal boundaries, a modular monolith, or separate services, depending on what is actually causing the problem.


Can a Monolith Still Scale?


Yes. A monolithic application can support a growing product.


More users, more traffic, or more revenue do not automatically mean that an application needs to be split into microservices. A well-structured monolith can continue to handle growth when its infrastructure, database, and application are able to support the workload.


When performance problems appear, the first step is to understand what is actually causing them. A slow database query, inefficient application code, limited infrastructure, or a sudden increase in traffic can all create performance problems without meaning that the architecture itself needs to change.


A monolith can also be scaled by adding more computing resources or running additional instances of the application behind a load balancer. Other improvements, such as better database design, caching, or more efficient queries, can sometimes address the real limitation without introducing a distributed architecture.


The more important question is what happens as the application and the team become more complex.


If adding more users is not the problem, but changing one part of the application increasingly affects unrelated parts, deployments become difficult, or different teams need to work independently, the architecture may eventually become a constraint.


That is different from simply needing more computing capacity.


Growth alone is not a reason to leave a monolith. A growing problem is.


What Are the Signs Your Monolith Is Becoming a Problem?


High-end 3D isometric dark mode diagram illustrating software architectural bottlenecks, CI/CD pipeline issues, and independent component scaling in a monolithic application.

A monolith does not become a problem simply because it is large. The more useful question is whether its structure is making the product harder to build, operate, or change.


Some warning signs include:


Changes in one area keep affecting other areas


A small change to one part of the application unexpectedly breaks something somewhere else.


This is often a sign of tight coupling, where different parts of the application depend heavily on each other. As these dependencies grow, the blast radius of a change can grow with them, meaning a change in one area can create unexpected effects across unrelated parts of the system.


When routine changes require extensive testing and coordination because of these dependencies, the structure of the application may be becoming a constraint.


Deployments become harder to manage


A change to one part of the product requires deploying the entire application, even when the rest of the system has not changed.


This can become a problem when teams need to release changes at different times or when a small change carries unnecessary risk because it is bundled with unrelated changes.


The problem can also appear in the delivery process itself. Large test suites and tightly connected components can create CI/CD bottlenecks, making builds and deployments slower as the application and engineering organization grow.


Different teams are constantly getting in each other’s way


As a company grows, more people may work on the same application.


If teams frequently need to coordinate changes, wait for each other, or avoid modifying certain areas because they might affect someone else's work, the architecture may no longer support clear ownership.


This becomes more significant when teams need to make and release changes independently but remain tightly connected through the same parts of the application.


One part of the application has very different needs


Not every part of an application necessarily has the same workload or reliability requirements.


For example, a reporting feature may have very different resource needs from a customer-facing checkout process. If one area consistently needs to scale or operate differently from the rest of the application, separating it may eventually become worth considering.


The system is becoming difficult to understand


A growing codebase can become harder to navigate when its internal boundaries are unclear.


Developers may struggle to determine which part of the application owns a particular responsibility, where a change should be made, or what other areas could be affected.


This is an important distinction: a large codebase is not automatically a reason to change architecture. A codebase that has become difficult to change safely may be.


These signs do not mean that microservices are automatically the answer. They indicate that the current structure may be creating problems that are worth addressing.


When Do Microservices Actually Make Sense?


Microservices can make sense when there is a clear reason to separate parts of an application.


The goal should not be to create more services. It should be to gain a type of independence that is difficult to achieve within the current architecture.


When different parts need to scale independently


If one part of an application consistently needs more resources than the rest, separating it can allow that component to scale without scaling the entire application.


For example, a reporting system may have heavy processing requirements while the rest of the application has a much lighter workload.


This can be useful when the difference in workload is consistent enough that managing the components separately provides a meaningful benefit.


When teams need independent ownership


A growing engineering organization may have multiple teams responsible for different areas of a product.


If teams need to release changes independently and clearly own different parts of the system, separate services can sometimes support that way of working.


This is most useful when the boundaries between responsibilities are already clear. Splitting an application without clear ownership can create more coordination rather than less.


This is also where Conway’s Law can become relevant: the way teams are organized and communicate can influence the structure of the systems they build. If teams are expected to operate independently but the architecture keeps forcing them to coordinate through shared components, the architecture may be working against the organization.


When a component has different reliability requirements


Some parts of an application may need to operate differently from others.


For example, a background processing system may be able to retry failed work, while a customer-facing payment process may require a different approach to availability and failure handling.


Separating these responsibilities can provide more control over how each part operates when those differences are significant.


When there are clear boundaries


Microservices work better when the responsibilities of each service are well understood.


If the team cannot clearly explain what a service owns, what data it controls, and how it interacts with other services, splitting the application may simply move existing complexity into a distributed system.


Once parts of an application communicate over a network, problems that were previously handled inside a single process can become distributed-system concerns. Network latency, service failures, and the need for distributed tracing can all become part of normal operation.


Data can also become more difficult to manage. A transaction that was previously handled within a single database may now involve multiple services, which can introduce consistency challenges and require


What If You’re Not Ready for Microservices?


Technical editorial illustration of a software architecture divided into independent modules with clear boundaries and controlled connections. One module has greater processing capacity to represent independent scaling, while the others show different operational and reliability requirements within a distributed system. The composition uses sophisticated 3D geometry, a colorful professional palette, a neutral background, and soft lighting.

Sometimes a monolith is becoming difficult to manage, but there is still no strong reason to split the application into separate services.


In that situation, a modular monolith can provide a middle ground.


The application remains one deployable system, while its internal responsibilities are organized into well-defined modules with explicit boundaries and limited dependencies.


For example, an e-commerce application might have separate modules for:

  • Customers

  • Products

  • Orders

  • Payments


The application still runs as one system, but each module has a defined responsibility and a clear boundary around the code and data it owns.


In practice, maintaining those boundaries is what makes a modular monolith different from simply organizing a large codebase into folders.


Modules can expose specific interfaces for other parts of the application to use while keeping their internal implementation private. Teams can also reduce direct dependencies between modules by controlling how data is accessed instead of allowing every part of the application to query every other part's data directly.


This can make it easier for developers to understand the codebase, make changes, and identify which part of the application is responsible for a particular function.


It can also keep future options open.


If the payment module eventually needs to scale independently or requires a different operational setup, having a well-defined boundary can make it easier to consider separating that part later.


But a modular monolith is not automatically the right answer either. It still requires discipline. If the boundaries between modules are ignored and everything starts depending on everything else, the application can gradually return to the same problems.


The main advantage is simplicity.


You can improve the internal structure of an application without immediately taking on the operational complexity of multiple services.

For teams that are experiencing structural problems but do not have a clear need for independent services, a modular monolith can be a practical place to stay while the product and its requirements continue to evolve.


Can You Move From a Monolith to Microservices Later?


Yes. You do not have to decide how your application will be structured for the long term at the beginning of a product's life.


A well-structured monolith can provide a simpler starting point while the product, team, and technical requirements are still changing. If a specific part of the application eventually creates a problem that is better solved by separating it, that part can be considered for extraction.


The key is to avoid treating the migration as an all-or-nothing project.


Instead of rebuilding the entire application, a team can start with one area that has a clear reason to become independent. That might be a component that needs to scale differently, requires independent deployments, or has responsibilities that are clearly separated from the rest of the system.


The team can then evaluate whether the change actually improves the situation before separating anything else.


This approach can reduce the risk of turning a working application into a large migration project without a clear outcome.


However, moving from a monolith to microservices is not always simple. Data ownership, dependencies between different parts of the application, and communication between services all need to be considered before a component is separated.


A gradual approach allows the team to learn from each step instead of committing to a large architectural change before the benefits are clear.


You do not need to predict exactly how your application will look years from now. You need to make decisions based on the problems you actually have as your needs become clearer.


What Should You Consider Before Changing Your Architecture?


Changing the architecture of an application can be a significant engineering decision. Before making that change, it helps to start with the problem rather than the architecture you want to adopt.


Ask these questions first:


What problem are we trying to solve?


Be specific.


Is the application too slow?

Are deployments becoming risky?

Are teams blocking each other?

Does one part of the system need to scale independently?


If the problem cannot be clearly identified, changing the architecture may not address the underlying issue.


Is the problem actually architectural?


Not every technical problem requires an architectural change.


A slow application might need better queries or more resources. Difficult code might need refactoring. A deployment problem might come from the release process rather than the structure of the application.


Before changing the architecture, make sure the current structure is actually contributing to the problem.


Would changing the structure solve the problem?


If you are considering microservices, ask what you would gain by making a particular component independent.


Would it scale independently?

Would a team be able to deploy it independently?

Would it need different reliability or operational requirements?


If there is no clear benefit, separating the component may simply introduce more moving parts without solving the original problem.


Can we operate the new architecture effectively?


More services mean more things to deploy, monitor, test, secure, and troubleshoot.


The team needs the skills, processes, and tools to manage that additional responsibility. Otherwise, the new architecture can create operational problems that did not exist before.


Can we make the change gradually?


A full rewrite is rarely the only option.


If a change is justified, look for a small, well-defined part of the application where the expected benefit can be tested first.


This creates an opportunity to learn from the change before making a larger commitment.


The best architecture decision is not necessarily the one that looks most advanced.


It is the one that solves a real problem without creating more complexity than the team can reasonably manage.


If your application is becoming harder to maintain, change, or scale, the next step may be understanding what is actually creating the problem. Custom software development can help you assess the current system, address specific technical constraints, and evolve the application without assuming that a complete rebuild is necessary.


Frequently Asked Questions


Can a monolith become too large to maintain?


Yes, but size alone is rarely the problem. A large codebase can remain manageable if it has clear internal boundaries. Maintenance problems usually appear when different parts of the application become so tightly connected that developers can no longer make changes safely without breaking unrelated features or triggering extensive regression testing.


Does moving to microservices automatically improve performance?


No. Microservices allow specific parts of an application to scale independently, but they also introduce network calls between services, which can add small delays (network latency). They can improve how teams manage ownership and how specific parts of the infrastructure scale, but they do not automatically make individual queries or features faster.


Can a large engineering team work on a single monolith?


Yes. Large teams can work effectively on monoliths when the codebase is structured into clear modules with well-defined ownership. The friction usually starts when multiple teams need to modify the same shared components or wait on the same deployment pipeline to release their work.


Does a modular monolith require less infrastructure than microservices?


In most cases, yes. A modular monolith runs as a single deployable application, which can make it simpler to host, monitor, and maintain. Microservices introduce multiple independently deployed components, along with additional service-to-service communication, monitoring, deployment, and operational requirements.


What is the biggest risk when extracting a service from a monolith?


One of the biggest risks is continuing to share the same database. If you extract application code into a separate service but both systems still read and write directly to the same central database, you can create a distributed monolith. This can introduce many of the operational challenges of microservices without providing true independence between the components.


Conclusion


Moving beyond a monolith is not a milestone you reach simply because your product or company gets bigger.


The right time to reconsider your architecture is when the current structure starts creating problems that are difficult to solve without changing how the system is organized.


For some teams, a well-structured monolith may continue to be the right choice. For others, a modular monolith may provide the structure they need without adding distributed-system complexity. And when there is a clear need for greater independence between parts of the system, microservices may be worth considering.


The important thing is to start with the problem, not the architecture.


Good architecture is not about building the most complex system. It is about having the right structure for the problems you need to solve today while keeping room to evolve tomorrow.

Logo Hristov Development

Comments


bottom of page