Overview

A shared database lets multiple services read and write the same tables through one common schema, while database per service gives each service its own private data store that only it can touch directly. The choice determines how tightly services are coupled at the data layer, how independently teams can deploy, and how much work cross-service queries and transactions require.

Comparison Diagram

Shared DatabaseDatabase per ServiceService AService BService CShared DBone schema, every service reads/writes it directlyService XService YService ZDB XDB YDB Zeach service owns a private schema, accessed only via its API

Comparison Table

AspectShared DatabaseDatabase per Service
Data ownershipNo single owner — all services see and can modify the same tablesEach service exclusively owns its schema; no one else can touch it directly
Access pathServices query the database directly, often with raw SQL against shared tablesOther services only get data through the owning service’s API or published events
Cross-service transactionsNative ACID transactions and joins span all the data in one commitNo shared transaction; consistency across services needs sagas or eventual consistency
Cross-service queriesSimple SQL joins pull data from any table in one queryRequires API composition, data replication, or a separate CQRS read model
Schema changesA column or table change can silently break unrelated servicesSchema changes are internal; only the public API contract must stay stable
Technology choiceAll services are locked into one database engine and schemaEach service can pick the storage engine that fits its data (polyglot persistence)
Failure isolationA database outage or lock contention affects every service at onceAn outage in one service’s database doesn’t directly take down the others
Operational overheadOne database to provision, back up, and tuneN databases to provision, monitor, back up, and scale independently

Key Differences

  • Shared database gives every service direct access to the same tables, so a change in one place can silently break another service’s queries — a form of tight coupling.
  • Database per service forces all cross-service data access through an API, giving each service true encapsulation of its data.
  • Cross-entity consistency is a native ACID transaction in a shared database, but needs a saga pattern or eventual consistency once data is split per service.
  • Reporting and ad-hoc joins are trivial with a shared database’s SQL, while database per service usually needs a separate CQRS read model to answer cross-service queries.
  • Database per service allows polyglot persistence — each service picks its own database engine — whereas shared database locks every service to one engine and schema.

When to Use Each

Shared Database

  • Early-stage monolith: When the system is small and still finding its shape, a shared database avoids premature distributed-systems complexity.
  • Heavy cross-entity reporting: When the main need is ad-hoc SQL joins and reports across all business data, one schema is far simpler than composing across services.
  • Single team, single deploy cadence: When one team owns the whole system, they can coordinate schema changes directly without cross-team negotiation.

Database per Service

  • Independently deployable services: When teams need to ship and scale their service without coordinating schema changes with other teams.
  • Polyglot data needs: When different services fit different storage models, such as graph, document, relational, or time-series data.
  • Fault isolation required: When one service’s data outage or overload must not cascade into unrelated services.
  • Clear bounded contexts: When domain boundaries from DDD map cleanly onto services that should each own their own data.