SOFTWARE / SYSTEMS / AIEngineering news. Technical depth.
Architecture / 4 MIN READ

How can several services share a database without all being allowed to change every table?

Use table ownership, schema boundaries, explicit read views, and PostgreSQL grants so multiple services can share one database without sharing unrestricted write power.

Assign a single service as the write and schema owner for each table, then enforce that decision in PostgreSQL with separate roles, schemas, and grants. In a shared database, the practical goal is not “everyone can see everything,” but “each service can change only its own objects, and everyone else reads through an explicit contract.” PostgreSQL supports this model because objects have owners, only owners can inherently modify or destroy them, and access for other roles must be granted deliberately in PostgreSQL privileges documentation and PostgreSQL schemas documentation.

Who should own a table and its migrations?

Each table needs one service owner, one owning database role, and one migration path. That owner decides schema changes, write rules, indexes, and retention for that table. In PostgreSQL, “when an object is created, it is assigned an owner,” and only the owner inherently has the right to modify or destroy it, as documented in PostgreSQL privileges documentation. That makes ownership the cleanest boundary for migration authority.

Operational database administration is a separate concern. Your platform or DBA team may manage backups, instance settings, and role creation, while the orders service still owns sales.orders. Do not blur those responsibilities. If every service runs migrations with a broadly privileged role, your shared database becomes a shared blast radius.

How should services read shared data without coupling to every table?

Use read contracts. In practice, that means the owning service exposes stable views for other services instead of encouraging direct reads from internal tables. PostgreSQL schemas help here because they let you group objects and qualify them explicitly, and the docs note that users can access objects across schemas if privileges allow it in PostgreSQL schemas documentation.

A good pattern is:

  • sales.orders owned and written only by Orders
  • sales.order_lines owned and written only by Orders
  • reporting.order_summary as a view granted SELECT for Reporting

Reporting should not get INSERT, UPDATE, DELETE, TRIGGER, or REFERENCES on Orders tables. Grant only SELECT on the approved view. Also qualify object names with schemas. PostgreSQL warns that adding writable schemas to search_path effectively trusts users with CREATE there, so explicit schema qualification is safer in shared setups, as explained in PostgreSQL schemas documentation.

What does a concrete setup look like?

Prerequisite: separate PostgreSQL roles per service and a deployment process that runs migrations as the owning role.

Example:

  • Role orders_owner owns schema sales and tables inside it.
  • Role reporting_app can connect and read only the published view.
  • Orders migrations run as orders_owner.
  • Reporting ships no DDL against sales.

Decision checklist:

  1. For every table, name one owning service.
  2. Put owned objects in that service’s schema or clearly named domain schema.
  3. Run DDL only through the owning role.
  4. Grant other services the minimum privilege, usually SELECT on a view.
  5. Treat view definitions as contracts with versioning, review, and deprecation windows.
  6. Approve any breaking view change jointly between the owning service and every consumer.
  7. Move a table to another service only when the new service becomes the sole writer.

Who approves a breaking change, and when should a table move?

The owner proposes the change, but every known consumer of the read contract must approve breaking changes to a shared view. If consumers need different shapes or lifecycles, publish versioned views such as reporting.order_summary_v1 and reporting.order_summary_v2 during migration.

Move a table when another service has become the natural source of truth and can be the only writer. Until then, keep one writer and avoid cross-service check-then-write flows that pretend to be atomic. The enforced boundary is the owner’s write transaction on its own tables; anything across services needs an asynchronous handoff or explicit orchestration.

Follow-up Q&A?

Can two services both write the same table if they touch different columns? Usually no. Column-level etiquette is not a durable ownership model. One table should still have one write owner.

Is direct table read access ever acceptable? Yes, for short-lived internal use, but treat it as tighter coupling than a view contract and document who can break it.

Next step: make a table inventory this week, assign one owner and one migration role to each table, then replace cross-service table writes with grants on explicit read views.

Reviewed: 2026-09-05

SOURCES & REVIEW

Sources are linked throughout this guide. Product capabilities can change; consult the linked documentation for your deployment.

Read our editorial approach ↗