Shared Database vs Database per Service
Fast recall
Quick revision
Core answer
Coupling implications of shared schema, why DB-per-service is the canonical pattern, and how to handle the resulting distributed-data problems (sagas, CQRS, events).
Sharing tables across services 'just for joins', or treating shared DB as a permanent compromise.
Discuss the spectrum (shared DB, shared schema with per-service tables, shared instance with per-service schemas, separate instances), and how event-driven architecture replaces cross-service joins.
Interview-ready guide
Interview answer
The two extremes
Shared DB: all services connect to the same DB, often share tables. Cross-service joins via SQL. One team's schema migration affects all. One service's slow query degrades everyone. Easy to start, hard to evolve.
Database per service: each service has its own DB instance/schema, accessible only via the service's API. No cross-service joins. Each service picks the best DB for its workload. Schema changes local. Deployment independent. Distributed transactions need sagas.
The spectrum
- 1Single shared DB, shared tables — worst coupling, avoid
- 2Shared DB, per-service tables — better, still shared instance
- 3Shared instance, per-service schemas — logically isolated, physically shared. Common compromise
- 4Separate instances per service — different engines per service if needed
- 5Separate instances + read models — services publish events, others build local projections. Best for scale
Mature microservices land at 4 or 5.
Trade-off matrix
Independent deployment: hard / easy Schema evolution: coordinated / per-team Cross-service queries: SQL joins / service calls + read models Transactions: local ACID / Saga Failure isolation: DB out = all down / one service degraded Tech choice: locked / free per workload Resource contention: one slow query slows all / per-service capacity Operational complexity: low / high (N DBs) Consistency: strong / eventual between services
How to replace cross-service joins
- 1API composition: order service calls user service when serving an order page. Simple but latency cost and synchronous coupling.
- 2Local read model: user service publishes UserUpdated events; order service stores customer name/email locally, denormalized. Eventually consistent, fast and resilient. Best for high-traffic reads.
- 3CQRS read store: dedicated read service consumes events from multiple services into Elasticsearch. Flexible but more infrastructure.
Events replace joins. Data still gets joined — at write time, not query time.
Distributed transactions — sagas
Place order = create order + reserve inventory + charge payment. Local transactions don't reach across services.
Saga: sequence of local transactions with compensating actions on failure. If charge fails: release inventory, cancel order.
Choreography (services react to events) or orchestration (central saga commands each step).
Correct but requires explicit failure planning. Trade ACID for eventual consistency + compensations.
When shared DB is honest
Acceptable:
- Monolith → microservices migration: extract one service at a time, share DB temporarily, migrate data ownership later
- Read-only reporting via replica or warehouse — read model, not shared write
- Tiny org / single team owning all services
Unacceptable long-term:
- Multiple teams owning different services on shared write tables
- One team's deploy blocked by another team's schema migration
If in the unacceptable case: identify each service's tables, give them their own schema, then their own instance.
Common mistakes
- 'Just join across schemas' — defeats isolation
- One team modifying another team's tables
- Sharing DB but pretending it's per-service
- No data ownership matrix — boundary erodes silently
- Synchronous cross-service calls everywhere — composes latency and failure
- Pretending eventual consistency away — build UX assuming brief lag
Recommendation
Default to database per service for new microservices: own your data, expose only an API, never let another service touch your tables. Replace cross-service joins with local read models populated by events; use sagas for distributed transactions. Shared DB is acceptable only as a transitional state during a monolith decomposition — with a documented plan to split. The spectrum (shared schema → per-service schema → per-service instance) lets you stage the move; aim to land at separate instances + event-driven read models for any system that's expected to live more than a year.
Shared Database vs Database per Service
Direct Answer
Database per service is the canonical microservices pattern: each service owns its data exclusively; other services access it only via the service's API. This gives independent schema evolution, technology choice per workload, and clean failure isolation — at the cost of distributed transactions, eventual consistency, and harder cross-service queries. Shared database removes those costs but creates invisible coupling: a schema change in one service breaks others; one slow query can lock tables that another service depends on. Use shared DB only as a transitional state during a monolith → microservices migration, never as a long-term target.
Common Mistakes & Pitfalls
Sharing tables across services 'just for joins', or treating shared DB as a permanent compromise.
Check your understanding
Answer these without looking back at the article.
- How do you migrate from shared DB to database per service incrementally without downtime?
- Walk through a saga for a 4-step e-commerce order placement.
- How do you handle a 'show me all orders for this customer' query when User and Order are in different services?
- What does 'eventual consistency' mean for the user-facing UX?
Related interview prep categories
1Want a guided curriculum order?
These modules are also sequenced in our flagship backend interview track — open it when you prefer an ordered path instead of browsing by topic.