system design30 min

Microservices vs Monolith

Choosing between a single deployable unit and many small services

0/9Not Started

Why This Matters

When you build a new application, you face a fundamental architectural choice: do you build one big application (monolith) or break it into many small, independent services (microservices)? This decision affects how your team works, how you deploy, how you scale, and how you debug problems.

Monoliths are simpler to build, test, and deploy -- everything is in one place. Microservices let teams work independently and scale individual components, but they introduce network complexity, data consistency challenges, and operational overhead. Neither approach is universally better. The right choice depends on your team size, traffic patterns, and how quickly different parts of your system need to change. Understanding both architectures -- and the tradeoffs between them -- is essential knowledge for any system designer.

Define Terms

Visual Model

MonolithAll features in one unit
API GatewayRoutes requests
User ServiceOwns user data
Order ServiceOwns order data
Payment ServiceOwns billing data
API call
API call

The full process at a glance. Click Start tour to walk through each step.

The journey from monolith to microservices: identify boundaries, extract services, establish communication.

Code Example

Code
// MONOLITH: Everything in one application
class MonolithApp {
  async createOrder(userId, items) {
    // User logic — tightly coupled
    const user = await db.query(
      "SELECT * FROM users WHERE id = $1", [userId]
    );
    if (!user) throw new Error("User not found");

    // Order logic
    const total = items.reduce((sum, i) => sum + i.price, 0);
    const order = await db.query(
      "INSERT INTO orders (user_id, total) VALUES ($1, $2)",
      [userId, total]
    );

    // Payment logic — also tightly coupled
    await this.processPayment(user.paymentMethod, total);

    // Notification logic
    await this.sendEmail(user.email, "Order confirmed!");

    return order;
  }
}

// MICROSERVICES: Separate services with clear APIs
// Order Service
app.post("/api/orders", async (req, res) => {
  const { userId, items } = req.body;
  const total = items.reduce((sum, i) => sum + i.price, 0);

  // Call User Service over HTTP
  const user = await fetch(
    `http://user-service/api/users/${userId}`
  ).then(r => r.json());

  // Call Payment Service
  await fetch("http://payment-service/api/charge", {
    method: "POST",
    body: JSON.stringify({ userId, amount: total }),
  });

  // Publish event for Notification Service
  await messageQueue.publish("order.created", {
    userId, total, email: user.email,
  });

  res.status(201).json({ orderId: order.id, total });
});

Interactive Experiment

Try these exercises:

  • Draw a diagram of an e-commerce system as a monolith. Then redraw it as microservices. How many services would you create?
  • List three advantages of a monolith for a two-person startup. Then list three advantages of microservices for a 50-person company.
  • Think about what happens when the payment service goes down in a microservices architecture. How would you handle the failure?
  • Identify a service boundary in an application you use. What data does it own?

Quick Quiz

Coding Challenge

Service Registry

Write a `ServiceRegistry` class that simulates service discovery in a microservices architecture. It should have three methods: `register(name, url)` adds a service, `discover(name)` returns the URL for a service (or throws 'Service not found'), and `deregister(name)` removes a service. Then write a `callService(registry, serviceName, path)` function that uses the registry to build a full URL (url + path) and returns it.

Loading editor...

Real-World Usage

Both architectures are used extensively in production:

  • Netflix: Pioneered the microservices approach with hundreds of services handling streaming, recommendations, billing, and user profiles independently.
  • Shopify: Ran as a large Ruby on Rails monolith for years before selectively extracting services where scaling demanded it.
  • Amazon: Started as a monolith and gradually decomposed into services. The mandate to use service APIs internally led to AWS.
  • Basecamp: Intentionally stays as a monolith, arguing that the simplicity benefits outweigh the scaling advantages of microservices for their team size.
  • Uber: Moved from a monolith to microservices to support their global scale and hundreds of engineering teams.

Connections