Architectural · Data & Consistency · DWG NO. 052

Database per Service

Give each microservice exclusive ownership of its own data store, so no service can be broken by another team's schema change.

TypeData & Consistency
ScopeWhole microservice system
ComplexityMedium–High
Common inMicroservice architectures, team-autonomous systems

A shared database quietly re-couples services that were split apart

Splitting a monolith into services but leaving them all reading and writing one shared database doesn't actually decouple them — any service can still be broken by another team changing a column, and nobody can deploy a schema migration without coordinating with every other service that touches that table.

Each service owns its schema; others go through its API

Every service has its own database, accessible only to that service. Other services never query it directly — if they need that data, they call the owning service's API. The owning service is free to change its internal schema at will, as long as its API contract stays stable.

Orders SvcOrders DBprivateUsers SvcUsers DBprivateAPI call onlyBilling SvcBilling DBprivate

Services own their data; cross-service access goes through an API

`billingService` never opens a connection to the orders database — it asks `ordersService`'s API for what it needs.

database-per-service.js
// Orders service owns this data exclusively.
const ordersDB = new Map([["order-1", { id: "order-1", total: 42 }]]);
const ordersService = {
  getOrder: (id) => ordersDB.get(id), // the only way anyone reaches this data
};

// Billing service has its own, separate database.
const billingDB = new Map();
const billingService = {
  createInvoice(orderId) {
    const order = ordersService.getOrder(orderId); // via API, never a direct DB query
    if (!order) throw new Error("order not found");
    billingDB.set(orderId, { orderId, amount: order.total });
    console.log(`billing: invoice created for ${orderId}, amount ${order.total}`);
  },
};

billingService.createInvoice("order-1");
// billingService has no idea what ordersDB even looks like internally.

Trade-offs