2-Tier to 3-Tier Architecture: Migration Journey With Modular Monolith and GraphQL
A real-world case study of migrating a two-tier architecture to a three-tier architecture. (5 min)
A while ago, I worked for a client who had a diverse portfolio of digital products.
They’ve struggled to develop new features, reuse business logic and functionality across products, and also scale the engineering team.
By digging deeper into the case, I’ve found they have:
bad architecture, which doesn’t support their growth
years of accumulated technical debt
The root cause turned out to be a 2-Tier Architecture that had outlived its purpose.
In today’s article, I’ll share how I tackled this challenge by migrating their system from a Two-Tier Architecture to a Three-Tier Architecture, introducing a scalable, robust GraphQL API.
IcePanel is a collaborative diagramming and modelling tool for designing software architecture. Create interactive, layered views for different stakeholders from a single source of truth.
Before we dive into the actual migration journey, let’s ensure we understand what a 2-Tier and a 3-Tier architecture are.
What is Two-Tier Architecture?
2-Tier Architecture is a simple setup in which your application talks directly to a database.
You have a presentation layer (the front-end) and a data layer (the database).
That’s it. No middle layer.
Think of it like a simple website or app that sends requests directly to the database, retrieves the data, and displays it to users.

What is Three-Tier Architecture?
3-Tier Architecture adds an essential middle layer between your front-end and database. Now you have:
Presentation Layer - the front-end (what users see).
Business Logic Layer - the API (where the magic happens).
Data Layer - the database (where data lives).
The middle layer handles all the business logic, security, and data processing.
The main difference between a 2-Tier and a 3-Tier architecture is the separation of concerns.
In a Two-Tier architecture, your front-end must know too much about your data, whereas in a Three-Tier architecture, the business logic layer acts as a smart middleman.
This smart middleman protects your data and enables the whole system to be more flexible.
The Starting Architecture (Two-Tier)
Now, let me show you what the client’s system looked like before the migration.

They had three main services, all sharing one MySQL database:
Portal - The customer-facing web portal. The front-end was React, but the back-end was built with CakePHP 2 (an outdated PHP framework).
Admin - The internal management web portal of the company. Everyone in the company used it to run the business, from operations to finance. Also built with CakePHP 2.
API - A small REST API with just three methods for customers. Again, Cake PHP 2.
All three services are connected directly to the same MySQL database.
The database was the integration point for everything.
This setup created several serious problems.
The Top Technical Challenges
Duplicated logic - The same business logic and rules were duplicated in multiple services.
Database as an integration point - Having multiple services write to the same database is risky. There is no single source of truth for business logic and data validation. Also, it is very hard to update or migrate the database when having multiple clients.
Technical debt - CakePHP 2 reached end of life. There was a need to modernize the tech stack by using well-adapted technologies.
Hard to scale the engineering team - This was hard to find developers to work on front-end and back-end with the present technologies. There was a need to enable full-stack developers.
Slow feature development - With the challenges mentioned above, feature development was slow, hindering the business's growth.
To address these challenges, we introduced a new middle layer—a GraphQL API.
The Final Architecture (Three-Tier)
The GraphQL API became the heart of the system.
It sits between all front-ends and the database.
The Main Architectural Improvements
The new architecture solved our major pain points:
Centralized business logic - All business-related logic lives in one place now. The GraphQL API is the single source of truth for all features.
Single database owner - Only the GraphQL API can access the database. This makes the system safer and easier to refactor.
Modern tech stack - We built the API using Node.js, a technology already used by the company. Apart from that, GraphQL provides flexible, efficient data fetching to accommodate the needs of different API clients.
Full-stack friendly - Having the same core technology, JavaScript, on the front-end and back-end, enabled the company to hire Full-Stack JavaScript developers.
Ready for microservices - To ensure the system's future flexibility and the company’s growth, the API was designed as a Modular Monolith, so that, when needed, internal modules could be extracted into separate services.
The Migration Approach
We didn’t rebuild everything overnight.
This was too risky from both a business and an engineering perspective.
The business must continue operating while the groundwork is being done under the hood.
That’s why we took an iterative approach:
Phase 1: Build the GraphQL API - We created the new API layer, starting with the most critical business logic, shared across multiple services.
Phase 2: Migrate Portal - The Portal front-end started using the GraphQL API. We moved features one by one and tested thoroughly.
Phase 3: Update Admin - We upgraded Admin to a modern version of CakePHP. Then we gradually moved its logic to the GraphQL API, starting with shared functionality.
Phase 4: Rewrite REST API - The customer-facing REST API had only three methods, so we rewrote it in Node.js to align with the new stack.
Phase 5: Migrate Admin to React - We started migrating the Admin to React, instead of CakePHP, prioritizing newly incoming feature requests.
📌 TL;DR
2-Tier Architecture is when multiple clients or services directly communicate with the Database.
3-Tier Architecture is when multiple clients or services communicate with a middle layer, usually an API, which then communicates with the actual DB.
Having three clients communicating with a DB means duplicated business logic everywhere.
Having a middle layer, in this case a GraphQL API, means a single user communicates with the DB, removing duplicate business logic.
Centralizing business logic in the GraphQL API eliminated duplicate code, made onboarding new teammates easier, enabled quicker feature delivery, and created a system ready to scale into microservices when needed.
Hope this was helpful.
See you next time! 🙌
👋 Let’s connect
You can find me on LinkedIn, Twitter(X), Bluesky, or Threads.
I share daily practical tips to level up your skills and become a better engineer.
Thank you for being a great supporter, reader, and for your help in growing to 28.7K+ subscribers this week 🙏




