Overview
The Database per Service pattern defines a private database for each microservice, making the database a component of the service. No other service can access it directly — only through the API the service exposes. This is the foundational data architecture pattern for microservices.
Problem
How should data be persisted in a microservices architecture? The most intuitive approach — a single shared database — contradicts the core principles of microservices:
- A shared database creates tight coupling between services at the data layer
- Schema changes in one service can break others
- Services cannot independently choose the best database technology for their needs
- It becomes impossible to scale individual services' databases independently
Solution
Assign a private database to each microservice. Only that service can access its own data store directly. Other services must go through the service's API. This enforces decoupling and enables independent evolution.
Implementation Approaches
There are three ways to implement this pattern, with different trade-offs:
Private Tables per Microservice
Each microservice owns a set of tables within a shared relational database. Access control is enforced at the application level. This approach shares infrastructure but provides logical isolation.
Advantages: Lower resource overhead, simpler infrastructure.
Disadvantages: Harder to enforce boundaries — other services could bypass the API and access tables directly. Cannot use different database technologies per service.
Schema per Microservice
Each microservice gets its own schema within a shared database server. Stronger isolation than private tables, but still shares the underlying database engine.
Advantages: Better logical isolation than private tables, still shared infrastructure.
Disadvantages: Still cannot use different database technologies. Coordination overhead to prevent schema boundary violations.
Database Server per Microservice
Each microservice has its own dedicated database server. This is the most complete implementation of the pattern.
Advantages:
- Freedom to choose the best technology for each service (SQL, NoSQL, graph, search engine, etc.)
- No resource sharing — one service's load doesn't affect others
- Can apply quality attributes independently per service (scalability, availability, replication)
- True decoupling — changes to one service's database have no impact on others
Disadvantages: More resources needed; more components to maintain, monitor, and deploy.
Trade-offs
Benefits
- True service independence — no shared data layer
- Freedom to choose the best database technology per service
- Independent scalability of each service's data store
- Schema changes are fully isolated to the owning service
Drawbacks
- Queries spanning multiple services require additional patterns (API Composition, CQRS)
- Distributed transactions are no longer possible — requires Saga pattern
- More infrastructure to provision, monitor, and maintain
When to Use
Apply Database per Service when:
- Building a microservices architecture — this is the default pattern for data persistence
- Different services have significantly different data access patterns or scaling requirements
- You need different database technologies per service (e.g., a search service needs Elasticsearch, an order service needs a relational DB)
Related Patterns
Adopting this pattern introduces new challenges that are addressed by companion patterns: