Single Database to Database-per-Service Blueprint
A blueprint to break a shared monolithic database into per-service stores using DDD bounded contexts, event-driven decoupling, sagas, and incremental strangler-fig migration.
Overview
A shared database is the most common coupling that blocks microservices: many services read and write the same tables, so they cannot deploy or scale independently. The database-per-service pattern gives each service exclusive ownership of its data, with all access through the service's API or events. This blueprint decomposes a shared schema into per-service stores.
Phases
Assessment. Map which services touch which tables. Identify cross-service joins, foreign keys, and shared transactions, the coupling you must break.
Bounded-context design. Use domain-driven design to group tables into bounded contexts, each owned by one service. Define the contracts (APIs, events) other services will use instead of direct table access.
Decoupling. Replace cross-service SQL joins and foreign keys with API calls or asynchronous events. Introduce an anti-corruption layer where models differ. This is the hardest step; do it incrementally with the strangler-fig pattern.
Data split. Move each context's tables into its own schema or database instance. For data needed by multiple services, publish it via events and let consumers maintain local read models (CQRS).
Cutover. Migrate one bounded context at a time. Use the saga pattern to coordinate operations that previously relied on a single ACID transaction across now-separate databases.
Key Risks and Mitigations
- Data consistency: Eventual consistency replaces ACID across services. Use sagas with compensating actions and the transactional outbox pattern for reliable event publication.
- Distributed transactions: Avoid two-phase commit; redesign workflows around sagas and idempotent handlers.
- Downtime: Migrate context-by-context behind feature flags; keep the shared database as a fallback during transition.
Recommended Tooling
Kafka or another event broker for inter-service events; Debezium for the transactional outbox/CDC; per-service PostgreSQL instances; a schema registry for event contracts; OpenTelemetry for tracing cross-service flows.
Success Metrics
Higher deployment frequency and lower lead time as services deploy independently, plus measurable service autonomy (no shared-DB dependencies remaining).
Prerequisites
A bounded-context map, agreed data contracts, an event backbone, and disciplined incremental migration with strong observability.