Case study · Fincaraiz.com.co · 2019 to 2022
Monolith to microservices, without stopping a 5M-visit platform.
As CTO of Fincaraiz.com.co, one of Colombia's leading real estate portals, I led the move from a legacy ASP.NET monolith to Django and React microservices on Kubernetes. We migrated in four tiers behind a Kong API gateway, kept old and new data in sync with AWS Lambda, and rebuilt search so it understands how people really describe places. The platform never went down, stayed as fast as before, and hosting and maintenance costs fell by 50%.
The situation
Fincaraiz.com.co is one of Colombia's leading real estate portals, part of the Adevinta group at the time. More than 5 million people visited it every month to search for lots, apartments, houses and commercial property, and agents published and updated listings on it every day.
All of that ran on a legacy ASP.NET monolith, served by Windows IIS on VM-based Amazon EC2 instances, with Microsoft SQL Server for data and Apache Solr for search. Four problems had built up:
- A monolith that was hard to change. Everything was tightly coupled, so every deployment carried risk for the whole site, and servers were patched by hand.
- High running costs. Virtual machines and Microsoft licenses made hosting and maintenance expensive.
- Search that matched keywords, not intent. The Solr setup couldn't handle the variety of real estate searches well, across very different property types.
- Coarse location matching. People search with informal neighborhood names, local nicknames and conversational phrases. The search engine missed most of them.
And one constraint above all: the site had to keep running. No downtime, no data inconsistencies, no latency spikes, and no drop in search rankings.
The goal
- Replace the monolith with Django and React services the team could change and deploy independently.
- Move off licensed software and hand-managed servers to cut costs.
- Keep the site up the whole time, for users and for agents.
- Keep Core Web Vitals at or better than the legacy site, and keep listing publication at its 30-minute benchmark.
- Make search understand what people mean, including how they name places.
The approach: four tiers, one layer at a time
A big-bang rewrite was never an option. I used the strangler fig pattern: build the new system around the old one, move traffic over piece by piece, and retire the monolith once nothing depends on it. To make that manageable, I split the work into four tiers, each one making the next possible.
| Tier | Before | After |
|---|---|---|
| 1. Platform | VM-based EC2, Windows IIS, manual patching | Docker containers on Kubernetes, NGINX, automated CI/CD |
| 2. Edge and identity | Traffic straight into the monolith | Kong API Gateway routing every request, Keycloak for identity and access |
| 3. Data and search | Microsoft SQL Server, Apache Solr | PostgreSQL for transactions, Elasticsearch for search, Lambda keeping both worlds in sync |
| 4. Services and frontend | One ASP.NET codebase | Django services split by business domain, React frontend |
Architecture during the migration
Tier 1: a platform for the new system
Before moving any code, the new services needed somewhere to run. We replaced hand-managed EC2 virtual machines with Docker containers orchestrated by Kubernetes, swapped Windows IIS for NGINX as the web server and reverse proxy, and put automated CI/CD pipelines in front of every deployment. Shipping went from a risky manual event to a routine one, and the new stack used fewer resources for more traffic.
Tier 2: one front door, one identity
Next, we put Kong API Gateway in front of both systems. From then on, every request went through one place that decided whether the old or the new system answered it. That let us move traffic route by route, and send a route back to the old system if something looked wrong. Keycloak gave both systems one shared identity and access layer.
Tier 3: data and search, kept in sync
We moved transactional data from Microsoft SQL Server to PostgreSQL, which improved integrity and performance and removed the license cost. Search moved from Apache Solr to Elasticsearch, built for fast, high-volume reads. PostgreSQL handled what had to be correct; Elasticsearch handled what had to be fast.
The hardest part was running two systems at once. Event-driven AWS Lambda functions copied every change between the legacy and new datastores in real time, so the two never disagreed while services were cut over one by one. A listing published on either side still appeared within the same 30-minute window as before.
Tier 4: services by domain, and a new frontend
With the platform, the gateway and the data in place, we split the monolith into Django services, one per business domain, with a React frontend. Each service took over its part of the site behind Kong, one domain at a time. Heavy work like publishing listings at high volume moved to background tasks with Celery and RabbitMQ, so a spike of agent uploads no longer slowed the site down for everyone else.
Search that understands how people describe places
Moving search to Elasticsearch was also a chance to make it smarter. This was early AI work, years before the current wave of generative AI.
- Natural language queries. We added natural language understanding, so the search could read intent from a conversational query, for example a property type, a size and a place in one sentence, instead of needing filters.
- A map of the whole country. We acquired cartographic and street-network data for Colombia: cities, municipalities, neighborhoods and local landmarks.
- Official names and local nicknames. We mapped official place names alongside the informal names and aliases people actually use, and turned boundaries and areas of interest into geographic polygons and vectors inside Elasticsearch.
For example, many people in Bogotá call one area "Zona T", but no official map uses that name. This is how the search resolved it:
Example: from a local nickname to an official neighbourhood
Search moved from matching keywords to understanding places.
What went wrong: single sign-on
Not every decision worked. Keycloak was the right idea, one identity layer for both systems, but it was new to the team and built on Java, which was outside our core skills. We hit integration problems we had not planned for, and gaps in the documentation made them slow to solve. That part of the project took six times longer than estimated.
For mission-critical tools, the team's familiarity and the support around the tool matter as much as its features.
We ran an open lessons-learned session instead of looking for someone to blame, and we added a vetting step for mission-critical tools: does the team know the stack, how good are the docs and community, and who do we call when it breaks? I wrote about that checklist in Pick the tool your team can support.
Leading 30 engineers through it
I led a team of 30 during the migration. A few things made the difference:
- Ownership for seniors. I designed the high-level architecture and gave senior engineers full ownership of implementing it. That grew our leadership capacity from inside the team, and kept me from becoming a bottleneck.
- Scrum across departments. We rolled out Scrum beyond engineering and agreed on one Definition of Done and one format for sprint reviews, so product, engineering and the business saw the same progress.
- Getting hands-on when it mattered. When the new stack overwhelmed the team, I learned it fast enough to unblock people directly, until they were confident on their own.
- Growing people. I coached a junior engineer to own a critical module and defend their design choices, like PostgreSQL over NoSQL. They were promoted to mid-level after five months.
Results
| Measure | Before | After |
|---|---|---|
| Hosting and maintenance cost | VM instances and Microsoft licenses | 50% lower |
| Availability during the migration | n/a | 100%, zero downtime |
| Deployments | Manual patching, high risk | Automated CI/CD, containerized |
| Largest Contentful Paint | Under 3 s | Under 3 s, despite a more complex system |
| Listing publication time | 30 minutes | 30 minutes, with two systems running |
| Search | Keyword matching in Apache Solr | Natural language and geographic matching in Elasticsearch |
| Web server | Windows IIS on EC2 | NGINX on Kubernetes, smaller footprint, higher throughput |
| REST APIs on the new backend | n/a | 15+, with 25% lower latency |
What I'd take to the next migration
- Build the platform and the gateway first. After that, every move is a routing decision you can undo.
- Budget real time for keeping two systems in sync. It is the hardest part, and the one that protects the business.
- Choose tools the team already knows for anything security-critical.
- Measure what users feel, like page speed, from day one, so "no regressions" is a number and not a hope.
Get my next case studies and articles in Google Search.