← Back to Cecep Azhar
Cecep Azhar #architecture#microservices#monolith#engineering#devops

Microservices vs Monolith: When to Choose What in 2026

Cecep Saeful Azhar • 16 Oct 2026
Microservices vs Monolith: When to Choose What in 2026
The microservices debate is over. The answer isn't one or the other — it's knowing when to use which. Here's a decision framework based on real-world Indonesian company experience.

The Architectural Pendulum

For years, the industry swung between extremes: monolith is dead → everything must be microservices → actually, monoliths are fine again.

After building systems for Indonesian companies ranging from 5-person startups to 500-person enterprises, here's my honest take: the right architecture depends on your team size, complexity, and business stage.

Decision Framework

Here's the framework I use when advising clients:

Choose Monolith When:

Choose Microservices When:

The Monolith That Scales

Here's the thing nobody tells you: a well-structured monolith can handle 90% of what most companies need.

I built a monolithic Go application that handles 50K requests/second for an e-commerce platform with 2M+ users. The key? Clean internal architecture.

// Modular monolith structure
type App struct {
    // Internal modules
    Products   *product.Module
    Orders     *order.Module
    Payments   *payment.Module
    Users      *user.Module
    Inventory  *inventory.Module
    
    // Shared infrastructure
    DB         *sqlx.DB
    Cache      *redis.Client
    AI         *ai.Service
    Queue      *message.Queue
}

// Modules communicate through internal interfaces, not HTTP
type OrderModule struct {
    product ProductInterface // Depends on interface, not concrete type
    payment PaymentInterface
    inventory InventoryInterface
}

func (m *OrderModule) CreateOrder(ctx context.Context, req CreateOrderRequest) (*Order, error) {
    // Step 1: Validate inventory
    available, err := m.inventory.CheckAvailability(ctx, req.Items)
    if err != nil {
        return nil, err
    }
    
    // Step 2: Create order
    order := newOrder(req)
    
    // Step 3: Process payment
    payment, err := m.payment.Charge(ctx, order.Total)
    if err != nil {
        return nil, err
    }
    
    // Step 4: Reduce inventory
    m.inventory.Reserve(ctx, req.Items)
    
    return order, nil
}

When to Migrate from Monolith to Microservices

Don't migrate proactively. Migrate when you hit specific pain points:

The Strangler Fig Pattern

If you do need to migrate, use the Strangler Fig pattern — not a big-bang rewrite:

// Phase 1: Extract one service at a time
// Start with the most independent module

// Step 1: Create the new microservice
func NewPaymentService(config Config) *fiber.App {
    app := fiber.New()
    
    // New, independent database
    db := initDB(config.DatabaseURL)
    
    // API endpoints
    app.Post("/payments/charge", handlers.Charge(db))
    app.Post("/payments/refund", handlers.Refund(db))
    app.Get("/payments/:id", handlers.GetPayment(db))
    
    return app
}

// Step 2: Add API gateway routing
func setupGateway(monolithURL, paymentServiceURL string) {
    router := httputil.NewSingleHostReverseProxy(monolithURL)
    paymentRouter := httputil.NewSingleHostReverseProxy(paymentServiceURL)
    
    mux := http.NewServeMux()
    
    // Route payment endpoints to new service
    mux.HandleFunc("/api/v1/payments/", func(w http.ResponseWriter, r *http.Request) {
        paymentRouter.ServeHTTP(w, r)
    })
    
    // Everything else goes to monolith
    mux.Handle("/", router)
}

// Step 3: Migrate data incrementally
// Step 4: Switch traffic gradually (canary deployment)
// Step 5: Remove old code from monolith

The Hybrid Approach (What Most Indonesian Companies Actually Need)

Most successful Indonesian companies I work with use a modular monolith with strategic microservice extraction:

Cost Comparison

FactorMonolithMicroservices
Infrastructure costRp 500K-2M/monthRp 3-10M/month
DevOps complexityLowHigh
Deployment speedFast (single binary)Medium (multiple services)
Team needed1-3 developers5-10+ developers
Time to marketFasterSlower initially
ScalabilityVertical onlyHorizontal + vertical

The Bottom Line

Start with a monolith. Extract services when you have clear reasons and the team to support it. The best architecture is the one your team can build, maintain, and iterate on — not the one that looks best on an architecture diagram.

← More articles from Cecep Azhar Central Content Hub Home →