The Strangler Fig pattern isn’t about replacing a monolith all at once; it’s about gradually carving out functionality until the old system is "strangled" by the new.

Let’s see this in action. Imagine we have a monolithic e-commerce application. We want to extract the product-catalog service.

First, we deploy our new product-catalog microservice, running on a separate server or container. It has its own database, maybe PostgreSQL.

# product-catalog-service.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: product-catalog-service
spec:
  replicas: 3
  selector:
    matchLabels:
      app: product-catalog-service
  template:
    metadata:
      labels:
        app: product-catalog-service
    spec:
      containers:
      - name: product-catalog-service
        image: your-docker-repo/product-catalog-service:v1.2.0
        ports:
        - containerPort: 8080
        env:
        - name: DATABASE_URL
          value: "postgresql://user:password@product-catalog-db:5432/products"

Now, the critical part: the facade. This is a proxy (like Nginx, Envoy, or an API Gateway) that sits in front of both the old monolith and the new microservice. Initially, it routes all traffic for /api/products/* to the monolith.

# nginx.conf snippet for the facade
server {
    listen 80;
    server_name your-ecommerce.com;

    location /api/products/ {
        proxy_pass http://monolith-service:8000/api/products/;
    }

    location / {
        proxy_pass http://monolith-service:8000/;
    }
}

The facade intercepts requests. When a request comes in for /api/products/123, it checks a routing table. Initially, that table says "send this to the monolith."

The "strangling" happens when we update the facade’s routing table to send specific product-related requests to the new microservice. We start small: maybe only requests for products with IDs greater than 10000 go to the new service.

# nginx.conf snippet after initial strangulation
server {
    listen 80;
    server_name your-ecommerce.com;

    # New routing for specific product IDs
    location ~ ^/api/products/([0-9]+) {
        set $product_id $1;
        if ($product_id > 10000) {
            proxy_pass http://product-catalog-service:8080/api/products/$product_id;
            break; # Stop processing other locations
        }
        # Fallback to monolith for older IDs
        proxy_pass http://monolith-service:8000/api/products/$product_id;
    }

    location / {
        proxy_pass http://monolith-service:8000/;
    }
}

To do this, we need to migrate data. We’d run a script to copy existing product data from the monolith’s database to the product-catalog service’s database. This might be a one-time dump and load, or a more sophisticated data synchronization process if the systems are live.

Once the data is migrated and the facade is updated, we can start testing. We’d observe logs and metrics. If everything looks good, we gradually increase the range of product IDs routed to the new service. Eventually, all product-related traffic is handled by the microservice.

The monolith is now "strangled" for product catalog functionality. The facade acts as the nervous system, redirecting traffic as the new services take over. We repeat this for other functionalities – orders, users, etc. – until the monolith is a husk, only handling the very last pieces of functionality.

The key here is the facade. It’s the central point of control that allows us to incrementally shift traffic without downtime. It doesn’t care what the underlying service does, only where to send the request based on defined rules.

What most people miss is that the facade doesn’t just route based on URL path. It can inspect request headers, query parameters, even the request body, allowing for very granular control over which requests go where. For example, you could route requests from a specific X-User-Group: beta-testers header to a new version of a service before rolling it out to everyone.

The next step is to tackle a more complex domain, like the order-processing service, which has intricate dependencies on inventory and customer data.

Want structured learning?

Take the full Microservices course →