Why We Migrated Our Monolith to Microservices (And What We Learned)
The Problem With Our Monolith
Three years ago, Geek Labs’ core platform was a classic Rails monolith. It worked beautifully until our team grew past 15 engineers and deployments started taking 45 minutes. A single bug in the billing module could take down the entire API. Something had to change.
What We Did
We adopted a strangler fig pattern — gradually extracting services from the monolith rather than rewriting everything at once. We started with the authentication service, then payments, then notifications.
The key decisions that helped us:
- Kafka for async communication between services kept things decoupled
- A dedicated platform team handled the shared infrastructure so product engineers could focus on their domains
- Feature flags let us roll out incrementally without big-bang cutover risk
What Didn’t Work
Distributed tracing was an afterthought. We spent two weeks debugging a latency issue that turned out to be a cascade of N+1 queries across three services. If we’d instrumented with OpenTelemetry from day one, we’d have caught it in hours.
Contract testing between services also lagged behind. We had a few painful incidents where a service changed its API without notifying downstream consumers.
The Outcome
Today our deployments take under 4 minutes. Each team ships independently. Our on-call load dropped by 60% in the first six months.
Would we do it again? Absolutely. But we’d invest in observability and contract testing from week one.