Data Mesh Guide

Data mesh domain ownership: who owns what, once the slides are over

By the engineer who builds Datadef, from client work on data platforms · Reviewed August 21, 2026

Domain ownership means the team that runs a business capability also owns the analytical data about it, end to end: the pipeline, the schema, the contract, the freshness promise, and the pager. The hard part is not agreeing with that sentence. It is drawing the boundaries, deciding what stays central, and surviving the handover from the team that owns everything today.

8 min readFor central data teams preparing to hand pipelines to product domains

See it as a diagram

Everything below, as a diagram you can edit. Describe yours and see it in seconds.

207/20003 credits left
Try:

No account needed · Editable canvas, not a picture

Draw boundaries around business capabilities, not source systems

The reliable rule comes from domain-driven design: a domain boundary is a bounded context, the span inside which one word means one thing. If "order" means a different thing in checkout than it does in fulfilment, those are two contexts and two domains, no matter that both read the same Postgres instance.

The tempting alternative, one domain per source system, feels tidy and fails within a quarter. Source systems get replaced, merged, and split. A domain named after Salesforce becomes homeless the day the CRM changes. A domain named "customer acquisition" survives the migration because the business capability did.

Practical test for a proposed boundary: can you name the team that decides the roadmap for it, name the vocabulary it defends, and name at least one data product it would publish. If any of the three has no answer, the boundary is wrong.

Write the answer down where the code enforces it. A CODEOWNERS entry per domain path is the cheapest ownership record a repository has, it is checked by the host on every pull request, and it survives reorganisations better than any wiki page. If a path in the transformation project has no owning domain in CODEOWNERS, that path is the boundary you have not drawn yet.

The three shapes a domain data product takes

Source-aligned products mirror facts native to the owning domain: checkout publishing orders, catalog publishing products. They change when the business capability changes, which makes them the most stable of the three. They should be published close to raw, with the domain vocabulary, not pre-aggregated for one consumer.

Aggregate products compose several source-aligned products into something no single domain owns cleanly, for example a customer 360 built from checkout, support, and marketing. These are where ownership fights start, so assign a single owning domain before the first pipeline runs.

Consumer-aligned products are shaped for a specific use, a machine learning feature set or an executive reporting mart. They are the most volatile, and they belong to the consuming domain rather than the producing one. Putting a consumer-aligned product in a producer domain makes the producer responsible for a shape they cannot predict.

What stays central after decentralization

Storage and compute provisioning, orchestration, the catalog, access control, secrets, lineage collection, and observability tooling stay central and are offered as a platform. Domains consume those capabilities; they do not choose their own orchestrator.

Cross-domain semantics stay central as decisions, not as implementations. The definition of customer_id, the privacy classification vocabulary, the naming convention for output ports, and the minimum quality bar are set by the federated group and enforced by the platform, while each domain writes its own transformation code.

Everything else moves: transformation logic, schema evolution, the data contract, the SLA, documentation, and the on-call rotation for the products the domain publishes.

# CODEOWNERS in the transformation repo: the boundary, enforced
models/checkout/**            @acme/checkout-data
contracts/checkout/**         @acme/checkout-data
models/catalog/**             @acme/catalog-data
contracts/catalog/**          @acme/catalog-data
models/marketing/**           @acme/marketing-data

# Central, and deliberately so: changing these needs the platform team
macros/**                     @acme/data-platform
packages.yml                  @acme/data-platform
policy/**                     @acme/data-governance

# Anything not matched above is a boundary nobody has drawn yet.

The handover, and how not to lose the map during it

The handover is the risky month. Pipelines change hands, repositories split, and the one accurate architecture diagram becomes wrong within days because the person who maintained it is no longer the person who owns the pipeline. This is the failure mode worth designing against explicitly.

Connect the repositories that survive the split (the dbt project, the Terraform that provisions each domain account) to Datadef with read-only access on GitHub, GitLab, or Azure DevOps, pick the branch each domain ships from, and the diagram plus its architecture.md regenerate on a daily sync rather than depending on whoever remembers. A node someone dragged more than twelve pixels from where the last sync left it is treated as hand-placed and restored after the redraw, so the picture updates instead of reshuffling.

What the sync reads is worth knowing before you judge the result. It walks the tree once and takes at most forty files, 250KB in total and 30KB per file, in a priority order. Under the architecture focus, infrastructure files get a ceiling of sixteen while dbt models get three, because sixteen model files would tell you which columns exist and nothing about which domain owns what. If your mesh boundary lives in the model layer rather than in separate accounts or repositories, connect the domain repositories separately instead of expecting one sync of a monorepo to find it. See how repository sync works.

Put the resulting picture where the argument happens: one markdown line renders it as a live embed in each domain README, and viewers need no account to open it.

FAQ

How do you decide where a data mesh domain starts and stops?

Use bounded contexts from domain-driven design: a domain covers the span inside which one term has one meaning, and it maps to a business capability with an identifiable owning team. Avoid drawing domains around source systems, because source systems get replaced and the domain then has no home.

What does a domain team actually own in a data mesh?

The transformation code, the schema and its evolution, the data contract, the service level for freshness and completeness, the documentation, and the on-call response when a published product breaks. Platform capabilities such as orchestration, storage provisioning, catalog, and access control stay with a central platform team. The cheapest place to record the split is a CODEOWNERS entry per domain path, which the repository host enforces on every pull request.

Who owns a data product that spans several domains?

One domain, named before the first pipeline runs. Aggregate products such as a customer 360 draw from several sources, but shared ownership means no ownership. The usual choice is the domain with the most consumers of that product, with the contributing domains bound by their own contracts upstream.

Does every domain need its own data engineer?

It needs analytics engineering capacity, which can be a dedicated hire, an embedded engineer from the platform team, or a rotation. What does not work is handing a product squad a dbt project with no capacity attached, because the project stops being maintained within a quarter.

How many domains should a data mesh start with?

Two or three, chosen for clear boundaries, willing teams, and well understood data. Starting from a full org-chart decomposition produces many small domains, none with the capacity to publish a real product, and it commits you to the model before anything has been proven. Run the first two for six months with real contracts and real service levels, then decide.