All posts
Backend·May 2026·8 min

Refactoring a Monolith into Microservices Without a Big-Bang Rewrite

The phased migration playbook I used to cut P99 latency by 33% while keeping the legacy API live. Feature-flagged parallel runs, contract testing, and the rollback gateway that saved us twice.

Refactoring a Monolith into Microservices Without a Big-Bang Rewrite

Big-bang rewrites fail because they require a freeze. The strangler-fig pattern succeeds because it never freezes anything — it just routes new code behind a feature flag, runs it parallel to legacy for two weeks, then flips the flag.

The bottleneck

The monolith was a 47K-line NestJS app. Every route shared the same database connection pool. When one endpoint spiked, every other endpoint's p99 went with it. Connection pool exhaustion every morning at 9am.

The architecture

**Step 1: Gateway in front.** Put a feature-flag gateway (I used a simple Caddy config) in front of the legacy API. Every route goes through the gateway. This gives you a single point to flip traffic.

api.example.com {
    @feature_new route /dashboard/* {
        header X-Feature-Flag new-dashboard
    }
    reverse_proxy @feature_new new-dashboard-svc:3000
    reverse_proxy legacy-monolith:3000
}

**Step 2: Pick the worst endpoint first.** The dashboard endpoint was the one causing connection pool exhaustion. I rewrote it as a standalone microservice with its own connection pool. The gateway routes 5% of traffic to the new service, 95% to legacy.

**Step 3: Parallel run for two weeks.** Both services run simultaneously. I log every response from both and diff them. If the diff is non-empty, that's a bug. Fix it before increasing traffic.

**Step 4: Flip the flag.** Once the diff is clean for two weeks straight, flip the flag to 100% new. Rollback is a flag toggle, not a redeploy — takes 8 seconds.

**Step 5: Repeat for the next endpoint.** The next worst was the billing webhook. Same process. Then auth. Then search. Twelve endpoints over six months.

The payoff

  • p99 latency dropped 33% because the dashboard no longer competed with billing for connections
  • Connection pool utilization dropped from 94% peak to 31%
  • Zero downtime windows across the entire six-month migration
  • Two rollbacks — both caught within 8 seconds, both before any customer noticed

The lesson: a strangler-fig rewrite isn't slower than a big-bang — it's faster, because you never stop shipping features. The big-bang requires a freeze; the strangler requires patience.