Migrating from 2-Tier to 3-Tier Architecture: A Modular Monolith and GraphQL Case Study
A case study on migrating a two-tier system to a three-tier architecture with a modular monolith and GraphQL, enhancing scalability, maintainability, and accelerating feature delivery.
Migrating from 2-Tier to 3-Tier Architecture: A Modular Monolith and GraphQL Case Study
This article presents a real-world case study on migrating a system from a two-tier to a three-tier architecture, introducing a scalable and robust GraphQL API. The client, possessing a diverse portfolio of digital products, faced significant challenges in developing new features, reusing business logic across products, and scaling their engineering team. A deeper analysis revealed an outdated two-tier architecture, ill-suited for their growth, and years of accumulated technical debt as the root cause of these issues.
Before diving into the migration journey, it's essential to understand the fundamental differences between two-tier and three-tier architectures.
What is Two-Tier Architecture?
A two-tier architecture represents a simple setup where the application directly communicates with a database. It consists of two primary layers: a presentation layer (the front-end) and a data layer (the database), with no intermediate layer. This design is typical for simpler applications or websites that send requests directly to the database, retrieve data, and display it to users.

What is Three-Tier Architecture?
A three-tier architecture introduces a crucial middle layer between the front-end and the database. This structure comprises:
- Presentation Layer: The user interface (front-end) that users interact with.
- Business Logic Layer: The API layer where core business logic, security, and data processing reside.
- Data Layer: The database where all data is stored.
The middle layer acts as an intelligent intermediary, handling complex operations and ensuring a clear separation of concerns.

The primary distinction between a two-tier and a three-tier architecture lies in the separation of concerns. In a two-tier model, the front-end often holds too much knowledge about the data layer. Conversely, in a three-tier architecture, the business logic layer serves as a protective and flexible intermediary, safeguarding data and enhancing system adaptability.
The Starting Architecture (Two-Tier)
The client's original system, before migration, featured three main services all sharing a single MySQL database:

- Portal: The customer-facing web portal, with a React front-end and a back-end built on the outdated CakePHP 2 framework.
- Admin: The internal management web portal, used by various departments (operations, finance) and also built with CakePHP 2.
- API: A small REST API offering only three methods for customers, also developed using CakePHP 2.
All three services were directly connected to the same MySQL database, which functioned as the central integration point. This setup led to several significant problems.
The Top Technical Challenges
The existing architecture presented a multitude of challenges:
- Duplicated Logic: Identical business logic and rules were repeatedly implemented across multiple services.
- Database as an Integration Point: Relying on the database as the sole integration point for multiple services introduced risks. It prevented a single source of truth for business logic and data validation, making database updates or migrations extremely difficult with multiple clients.
- Technical Debt: The use of CakePHP 2, an end-of-life framework, necessitated a modernization of the technology stack with more current and widely adopted technologies.
- Difficulty Scaling the Engineering Team: The existing technologies made it challenging to recruit developers proficient in both front-end and back-end, hindering the ability to hire full-stack developers.
- Slow Feature Development: The combination of the above challenges severely impacted feature development speed, impeding the business's growth trajectory.
To overcome these issues, a new middle layer—a GraphQL API—was introduced.
The Final Architecture (Three-Tier)
The GraphQL API became the core of the redesigned system, strategically positioned between all front-end clients and the database.

Main Architectural Improvements
The new architecture effectively resolved the major pain points:
- Centralized Business Logic: All business-related logic is now consolidated within the GraphQL API, establishing it as the single source of truth for all features.
- Single Database Owner: Only the GraphQL API is authorized to access the database, significantly enhancing system security and simplifying refactoring efforts.
- Modern Tech Stack: The API was built using Node.js, aligning with technologies already utilized by the company. Furthermore, GraphQL offers flexible and efficient data fetching capabilities, catering to the diverse needs of various API clients.
- Full-Stack Friendly: By adopting JavaScript as the core technology for both front-end and back-end, the company gained the flexibility to hire skilled Full-Stack JavaScript developers.
- Microservices Ready: To ensure future flexibility and support the company's growth, the API was meticulously designed as a Modular Monolith. This approach allows internal modules to be seamlessly extracted into separate microservices when the need arises.
The Migration Approach
A complete system rebuild overnight was deemed too risky from both a business and engineering perspective. The business operations needed to continue uninterrupted while the foundational changes were implemented. Therefore, an iterative migration strategy was adopted:
- Phase 1: Build the GraphQL API: The new API layer was developed, prioritizing the most critical business logic shared across multiple services.
- Phase 2: Migrate Portal: The Portal front-end began integrating with the GraphQL API. Features were migrated and thoroughly tested one by one.
- Phase 3: Update Admin: The Admin portal was upgraded to a modern version of CakePHP. Its logic was then gradually shifted to the GraphQL API, starting with shared functionalities.
- Phase 4: Rewrite REST API: The customer-facing REST API, having only three methods, was rewritten in Node.js to align with the new technology stack.
- Phase 5: Migrate Admin to React: The migration of the Admin portal to React commenced, with newly incoming feature requests being prioritized for the new stack.
Conclusion
The transition from a two-tier to a three-tier architecture, centered around a GraphQL API and a modular monolith design, brought significant improvements. It centralized business logic, eliminating duplicated code and establishing a single source of truth. This enhancement simplified the onboarding process for new team members, enabled quicker feature delivery, and prepared the system for future scaling into microservices as required.