Lesson 10 of 17
27. Monolith vs Microservices

27.9 What does "database per service" mean?

3 min read+10 XP

In the restaurant: Each stall has its own pantry. The biryani stall doesn't walk into the dosa stall's pantry to take rice; it asks, or keeps its own rice. That's what lets each stall change its recipes freely.

In the system: Each service owns its data and is the only one that reads or writes it directly. Others go through its API or its events.

orders asks catalog through an API; no direct SQL joins across service databases.

Figure: own your data; share it through APIs and events.

Why:

  • A team can change its schema, pick its own store (PostgreSQL for orders, Elasticsearch for search, Redis for carts) and scale it, without breaking anyone.
  • A shared database quietly couples every service: one team's migration breaks another's queries, and nobody can change anything.

What it costs, and the usual answers:

  • No cross-service joins. "Order history with book titles" needs data from orders and catalogue:
    • API composition: fetch orders, then fetch the titles in one batched call. In the chapter's code, 50 orders with one catalogue call each take about 150 ms; one batched call takes about 3 ms.
    • Keep a copy: orders stores the title at purchase time, or keeps a read model updated by book_updated events (Chapter 23).
  • No cross-service transactions. Use sagas with compensations (Chapter 17), the outbox to publish events reliably (Chapter 23), and idempotent consumers (Chapter 22).
  • Duplicated data is normal and fine, as long as one service is clearly the source of truth.

A pragmatic middle step: one database server, but separate schemas per service with separate credentials, so no one can read another's tables.

Memory code: "Each stall keeps its own pantry and asks politely for the rest."