Monolith Application to MicroServices Migration Guide
Over the years I have worked with various Monolith applications and migrated few of them to micro-services. I am going to write about my learnings and strategy for a successful migration from my experience. In this post I’ll use AWS for the reference but the underlying principle will remain same and can be used for any type of infrastructure.
The Monolith
A monolith is a large code repository with all the functionality implemented in a single place. This makes it complex and hard to maintain as application feature and complexity increases. The code repository not only contains all the core logic to support related functionality but code to support unrelated functionality as well. Even a minor bug fix or feature release will need testing complete application. The main pain-point I have faced are:
- Collaboration: There are ’n’ number of engineers working on a single repository. Due to this, there are high chances of merge conflict which lead to unnecessary burden on fixing the conflict rather than focusing on core development, thus slowing the pace of feature release.
- Bugs: With time, separation of concerns, code quality, best practices fades away. Due to this, there are high chances of introducing bugs for unrelated features. Often times, we do a sanity test for core functionality and miss these bugs or find ourselves surprised to see a bug for distantly unrelated changes
- Time to Production: The pace of innovation is hampered by various factors in a monolith system. In case of a full CI/CD system and all tests in place, due to size of repository and tests, it takes time for dev testing, integration testing etc. and release them in production
- Tech Stack: A monolith system is implemented in a single tech stack which limits the flexibility to adopt to emerging technology. Also, this introduce learning curve as well.
- Fault Isolation: A monolith system has all the components tied together and failure in one module/component could lead to complete system failure.
- Time to Fix: Sometimes, It’s not easy to identify a bug and fix it. As different components are tied together, there are chances a change in one module cause issue in another module. This increases the time to debug, fix and apply the patch to production
- Scalability: Scaling is not always an easy task in terms of time and cost in a monolith system. As a monolith has all the components together, there is a high chance some of components/code block is heavily utilized while other are less. Due to this, If some component requires horizontal scaling, whole system needed a scaling.
There are other issues than the one mentioned above. Having said that, A monolith is not alway bad option and there are various advantages like:
- Implement fast, Fail fast: In a fast paced environment where there is no liberty to follow all the best practices and wait to implement a proper software application to test it’s product market fit, It’s always preferred to implement the MVP and do a UAT to understand PMF.
- Development: As monolith system have all the components implemented in a single codebase, there is no overhead of inter-service communication/collaboration and implemented faster.
- Operational Overhead: There will be only one system to take care of. It is easy to implement alarms, monitors and ensure a healthy application. This reduces the operational overhead of maintaining various services as well.
- Performance: Having all the code at one place, the operations could be faster. This again depends on the size and components of monolith as well.
These advantages are case to case basis and highly depend on the magnitude of features a monolith has implemented.
Typical Monolith Flow

This is a typical flow of a monolith application where:
- Infrastructure hosting the application is backed by a load balancer
- A DNS mapping redirect the interaction to the infrastructure which then invoke the business logic
- A single database is implemented to persist data
- For an optimization, there can be cache layer
- In order to complete the user request, there could be interactions between various downstream systems and orchestration is managed within infrastructure layer
This simplifies a lot of things like:
- Routing: All the traffic route to single piece of code running on single or multiple infrastructure
- Database: No need to worry about data isolation, data sharing etc. The data is accessed by single application.
- Authn & Authz: A single point of auth implementation is easy to implement and mange.
The Microservices
In past years, the micro serivce pattern has become popular and proved itself. It is easier to implement, manage, contribute and scale these services. A microservice can be as small as a single API to multiple co-related functionality API’s. There are various benefit of using microservice like:
- Ease of Development: It’s faster to develop, deploy, test and manage a microservice. Related functionality can be clubbed together and developed independently.
- Debugging: Easier to debug, fix and deploy.
- Scalability: As required, different microservices can be scaled without impacting others.
- Tech Stack: Flexibility in chosing different stack to implement different functionality
There are other benefits as well. Having said that, Microservices are not all about benefit but there are pitfalls too like:
- Cost: Each service run on independent infrastructure which could lead to a higher cost
- Operation: There will be more and more operational overhead associated with more and more microservices
- Dependency: A microservice can depend on lot other microservices which could lead to latency, authn, authz, isolation challenges
- Data Consistency: Each microservice can have their own data stores. Data synchronization have it’s own issue in a distributed system.
Typical Microservice Flow

Migration Strategy
Migrating a monolith system to microservice is not an easy and simple task. Before proceeding, A complete understanding of monolith system in terms of code, functionality, dependencies etc are needed. Once documented:
- Identify common piece of functionality that could go together. This will help you in designing various microservices needed. Once identified, you can design individual services independently.
- Once you’ve identified the various microservices needed, you might need an orchestration layer. For e.g earlier a single endpoint was enough for a webpage to interact with a monolith, but with microservices, each of them will have separate endpoints. I prefer BFF (Backend For Frontend) orchestration layer which will orchestrate calls from front end to different microservices.
- Authentication and Authorization is a very important aspect of the application. With microservices, this will be responsibility of each microservice to authenticate and authorize. Identify auth mechanism to protect each microservices.
- Data storage is another aspect that needs proper investigation. It is recommended to isolate the related data in each microservice, but there could be cases when a complete isolation is not possible. In such scenario, identify such kind of data and have a proper implementation plan to mitigate any race conditions, data leakage, data sharing etc.
- There could be common functionality like reading from database, writing to database, reading from cache etc. which can be abstracted into a common library and used in these microservices.
- Set up a common coding practice. With various different services, there could be a possibility of different coding conventions or practice in different services. Setting up a common ground will make it standard across various microservices.
- Release planning is another important aspect. This includes roll out strategy, identifying UAT customers, test plan, roll back plan etc.
- Canary service is a very important for your migration. This will provide a clear picture of your microservice health.
- Comparator Service is another important piece to have. Design a service which will route your traffic to both monolith and microservice. This service will compare results from both monolith and microservices for data accuracy to avoid any security incident of over exposing information. Once you’ll have enough confidence, the routing can be changed from monolith to microservice
- Operation health and rollback strategy is another point to consider. Have a well defined runbook for incidents and mitigation plans.
- Implement Scaling for each microservice to avoid any downtime