⏱ 21 min read
Most enterprise data estates don’t collapse in a dramatic fire. They sink slowly, like a cargo ship taking on water from a hundred hairline cracks. A report breaks because an upstream table changed shape. A machine learning feature drifts because nobody noticed the “temporary” enrichment job became permanent. A finance dashboard disagrees with operations by 2.3%, and suddenly three directors are in a meeting nobody wanted.
This is usually described as a tooling problem. It isn’t. It is a semantics problem wearing a technical disguise.
Data mesh changed the conversation by insisting that data should be treated as a product and owned by the domains that understand it. That was the necessary correction to years of centralized data platforms acting as reluctant landlords for everyone else’s mess. But once organizations begin publishing data products across domains, another problem appears quickly: products depend on other products, and those dependencies are not merely technical links. They encode business meaning, contractual obligations, freshness assumptions, quality guarantees, and operational risk.
That is where a data product dependency graph becomes important. Not as a pretty lineage picture for architecture slide decks, but as a working model of how value, semantics, and failure move through a data mesh.
A dependency graph diagram in a data mesh should answer practical questions:
- What data products does this one rely on?
- Which dependencies are hard contracts versus soft enrichments?
- What breaks if an upstream product misses its service level objective?
- Which downstream products are using “customer” as a legal entity, and which mean a billing account?
- How do we migrate legacy pipelines into this model without freezing delivery for eighteen months?
- Where do Kafka streams, microservices, and operational systems fit?
- How do we reconcile competing versions of the truth when domains evolve at different speeds?
Those are architecture questions, not catalog questions.
This article lays out the reasoning, the architecture, the migration path, and the tradeoffs behind a dependency graph for data products in a data mesh. I’ll lean on domain-driven design because without domain semantics, a graph is just wiring. And wiring alone has never saved an enterprise.
Context
Data mesh is often introduced with four ideas: domain ownership, data as a product, self-serve platform, and federated governance. Fair enough. But in practice, teams usually struggle not with the slogan, but with the middle layer between slogans and implementation. EA governance checklist
A retail enterprise might define these data products:
Customer ProfileOrder EventsInventory PositionShipment StatusProduct MasterFinance Revenue Recognition
Each is a product with an owner, interface, documentation, quality expectations, and consumers. But these products do not live in isolation. Revenue Recognition may consume Order Events, Shipment Status, and Product Master. Customer 360 may combine Customer Profile, Order History, Support Interactions, and Consent Status.
Soon the estate looks less like a library and more like a city grid.
That grid needs a map.
Traditional lineage tooling tracks tables, jobs, columns, and dashboards. Useful, but incomplete. In a data mesh, the more important object is the data product contract. The dependency graph should make visible:
- domain ownership
- semantic boundaries
- input-output contracts
- runtime dependencies
- quality inheritance
- policy propagation
- blast radius of changes
The point is not to centralize ownership again. The point is to make decentralization survivable.
Problem
Without an explicit dependency graph, data mesh implementations usually drift into one of three bad outcomes.
First, hidden coupling. Teams publish data products, but downstream consumers quietly bind themselves to implementation details: file structures, internal event names, warehouse schemas, or undocumented derivations. The product appears decoupled until a change lands and half the estate discovers they were depending on a private field that “was never meant for public use.”
Second, semantic fragmentation. Domains use the same words differently. “Customer” in sales means prospect or account. In billing it means an invoiced legal entity. In identity it may mean an authenticated principal. A graph that only shows pipelines and not domain semantics becomes dangerously reassuring. It says “connected” when the reality is “misunderstood.”
Third, operational opacity. Enterprises can tell you where data came from, but not what the business impact is when it arrives late, arrives incomplete, or changes meaning. A lineage trace might show that a dashboard depends on twelve upstream tables. A dependency graph for data products should tell you that if the Shipment Status product falls behind by four hours, the Revenue Recognition product enters a reconciliation state and the CFO report must switch to provisional numbers.
That difference matters. One is metadata. The other is architecture.
Forces
Architects live in tension. This problem is full of it.
Domain autonomy vs enterprise coherence
Data mesh correctly pushes ownership to domains. But the enterprise still needs coherent definitions for key business concepts, especially when regulation, finance, or customer experience cross domain boundaries. Let every team define “customer” independently and you get autonomy. You also get lawsuits, revenue leakage, and circular arguments in governance councils. ArchiMate for governance
Local optimization vs graph-wide reliability
A domain can produce a perfectly good product while externalizing fragility to its consumers. For example, a marketing domain may republish CRM extracts every time the source schema shifts, expecting downstream consumers to adapt. Locally convenient. Systemically reckless.
Event-driven immediacy vs analytical stability
Kafka and microservices encourage streaming interactions and fine-grained events. Analytics and finance often need stable snapshots, slowly changing dimensions, and late-arriving correction logic. The graph must represent both event-time dependencies and curated state dependencies.
Reuse vs bounded context integrity
Shared data products can reduce duplication. They can also create accidental central platforms in disguise. If every domain must depend on a universal Golden Customer, you have not created a mesh. You have rebuilt the monolith with more YAML.
Progressive migration vs clean design
Enterprises never start on greenfield terrain. The legacy warehouse, ETL estate, MDM platform, and operational integration layer are already there. Any serious architecture must explain how to move gradually, with strangler patterns and reconciliation, without pretending the old world disappears because the target slide looks elegant.
Solution
A data product dependency graph is a graph model in which nodes are data products and edges represent explicit dependency relationships governed by product contracts.
That sounds obvious. The devil is in what counts as a node, what counts as an edge, and what metadata rides along.
My opinionated view is this:
- The node should be the data product, not the table, topic, or pipeline.
- The edge should represent a contracted dependency, not just observed lineage.
- The graph must include semantic, operational, and governance metadata, not only technical connectivity.
In other words, this is not just a dependency graph diagram. It is the runtime and design-time map of the mesh.
What a node should contain
Each data product node should include:
- owning domain and team
- bounded context
- product purpose and consumer class
- business entities and domain semantics
- published interfaces: batch tables, APIs, Kafka topics, files, semantic layer objects
- quality SLOs: freshness, completeness, accuracy, availability
- change policy and versioning rules
- classification: source-aligned, aggregate, consumer-aligned, or platform-provided
- reconciliation policy for corrections and late data
- canonical identifiers and key mapping approach
This is domain-driven design applied to data architecture. The bounded context matters because dependencies across contexts always carry translation cost. If you don’t model that, you will pay it later in defects.
What an edge should contain
An edge is not merely “A uses B.” It should identify:
- dependency type: hard, soft, enrichment, reference, derivation, policy, identity resolution
- consumption mode: stream, micro-batch, batch, API lookup
- contract strength: stable product interface, provisional field set, internal-only, deprecated
- semantic dependency: direct reuse, transformation, aggregation, context translation
- latency and freshness expectation
- inherited policy constraints
- blast radius indicators
- fallback behavior when dependency fails
A hard dependency means downstream cannot function without upstream. A soft dependency means the product can degrade gracefully. Most enterprises discover too late that they modeled all dependencies as equal. They aren’t. Some are load-bearing walls. Some are wall art.
The graph should represent both lineage and meaning
A useful pattern is to model three overlapping views:
- Semantic graph: bounded contexts, entities, and product meaning
- Contract graph: product interfaces and dependency agreements
- Execution graph: pipelines, Kafka topics, jobs, APIs, storage objects
The semantic graph tells you whether a dependency is sensible.
The contract graph tells you whether it is governed.
The execution graph tells you whether it is alive.
You need all three.
Architecture
At a practical level, the architecture usually has five layers:
- Operational systems and microservices
- Domain data product publishing
- Dependency graph and metadata control plane
- Consumption and composition
- Governance and observability
Here is a simplified view.
This diagram is deliberately simple. Real estates are messier, but the shape matters.
Domain publishing
A domain should publish data products from systems it actually understands. Not from random downstream copies. If the order domain owns order lifecycle semantics, it should own the Order Events product. If finance derives recognized revenue from those events plus shipment and billing rules, finance should own Revenue Recognition.
That ownership boundary is not bureaucracy. It is how semantics stay attached to data.
Kafka and event-driven dependencies
Kafka is often the spine for source-aligned products and streaming derivatives. It works well when:
- operational services already emit domain events
- event-time processing matters
- downstream products need near-real-time updates
- contracts can be managed with versioning and schema discipline
But Kafka is not the graph. Kafka is one transport and persistence mechanism in the graph. event-driven architecture patterns
A common architecture is:
- microservices emit domain events to Kafka
- domain product teams curate stable product topics or derived state tables
- downstream products consume those topics and produce curated datasets or serving views
- the dependency graph records the contract, SLO, and semantics at the product level
This distinction is critical. If teams consume raw service events directly, they often couple themselves to microservice internals. A service event is not automatically a data product. The former tells you what happened in software. The latter tells the enterprise what it can safely depend on. microservices architecture diagrams
Semantic translation across bounded contexts
Domain-driven design gives us bounded contexts for a reason: words do not mean the same thing everywhere. The graph should explicitly model translation points.
For example:
- Sales
CustomerAccount - Identity
UserPrincipal - Billing
LegalEntity - Support
ContactProfile
Trying to flatten these into one universal customer model is the kind of move that looks efficient right before it fails expensively. Better to model relationships and translation products explicitly.
This is where many data programs lose the plot. They attempt a universal semantic model first. In reality, enterprises need a translation mechanism and a reconciliation policy, not semantic fantasy.
Dependency graph as control plane
The graph should sit in the metadata control plane, but with operational teeth.
It should support:
- impact analysis before changes
- SLO propagation across dependencies
- consumer notification
- policy propagation for PII and retention
- dependency-aware deployment checks
- reconciliation workflows for late or corrected upstream data
- product deprecation planning
If your graph cannot tell a team, “Changing this field version will affect two gold-tier products and one regulatory report,” it is a poster, not a control plane.
Migration Strategy
This is where architecture earns its keep. Anyone can draw the target state. The job is getting there without stopping the business.
The right strategy is usually progressive strangler migration. Not a big bang. Never a big bang if you can help it.
Step 1: Identify domains and product candidates
Start with the business capabilities and bounded contexts, not the current warehouse folders. Good candidates are products already consumed by multiple teams and associated with clear domain meaning:
- orders
- shipments
- product catalog
- customer profile
- invoice and payment state
Do not start with highly ambiguous, heavily transformed “enterprise marts” unless you understand the source semantics. Otherwise you will publish confusion as a product.
Step 2: Separate observed lineage from intended contracts
In a legacy environment, observed lineage tells you what exists today. Useful, but often ugly. You need to distinguish:
- accidental dependencies
- hidden direct table reads
- duplicated logic
- stable business dependencies that deserve product contracts
This is where many teams discover ten dashboards reading a supposedly internal staging table. That is not reuse. That is architecture debt with a reporting veneer.
Step 3: Publish façade products over legacy assets
Before replatforming, define product contracts over stable slices of the legacy estate. This gives consumers a product interface while the implementation remains old underneath.
For example:
- expose
Order Events Product v1backed initially by warehouse ETL - publish quality and freshness SLOs
- document semantics and field definitions
- move consumers from direct table reads to the product interface
That is classic strangler logic. Change the relationship first, the plumbing second.
Step 4: Introduce dual-run and reconciliation
As new product pipelines replace legacy jobs, run both in parallel where risk justifies it. Reconciliation is essential, especially for financial, regulatory, and customer-impacting products.
You should compare:
- row counts
- aggregate balances
- key coverage
- event completeness
- semantic rule outcomes
- late-arriving correction behavior
Reconciliation is not just data diffing. It is agreement on meaning. Two pipelines can produce identical totals and still differ materially in timing, eligibility rules, or identity matching.
Step 5: Move upstream toward source-aligned products
Once consumers depend on product contracts rather than warehouse internals, domains can modernize the implementation:
- emit events from microservices into Kafka
- create stream processing or batch curation pipelines
- replace legacy ingestion paths
- preserve contract stability while changing internals
This is the strangler move in earnest. You migrate from the edge inward, preserving the product interface and tightening ownership around domains.
Step 6: Retire legacy paths explicitly
Legacy systems rarely die from neglect. They linger. Put retirement criteria in the graph:
- zero approved consumers
- reconciliation signed off
- policy migration completed
- audit evidence retained
- fallback period elapsed
Otherwise your enterprise will run both worlds for years and call it resilience.
Here is a migration sketch.
This is not glamorous. It is also how migrations actually succeed.
Enterprise Example
Consider a global retailer with stores, e-commerce, and marketplace channels. It has grown through acquisition. Customer, order, inventory, and finance systems all exist in multiple variants. The company wants a data mesh because the central data team has become a bottleneck and every transformation request now takes a quarter.
The starting point
The retailer has:
- a large cloud warehouse
- nightly ETL from ERP, e-commerce platform, WMS, CRM, and billing systems
- Kafka used by some digital platforms but not tied to analytics systematically
- dozens of downstream marts
- recurring disputes between finance and commercial reporting
The central team has lineage on jobs and tables, but nobody can answer cleanly why “net sales” differs between dashboards.
Domain product design
The company defines initial products:
Order Lifecycle Productowned by commerceShipment Fulfillment Productowned by logisticsProduct Availability Productowned by supply chainCustomer Identity & Consent Productowned by customer platformRevenue Recognition Productowned by financeMarketplace Settlement Productowned by marketplace operations
These are not random technical artifacts. They align to bounded contexts.
The graph then records that Revenue Recognition Product depends on:
Order Lifecycle Productfor order commitments and cancellationsShipment Fulfillment Productfor transfer of controlProduct Availability Productonly as a reference enrichment for fulfillment classificationCustomer Identity & Consent Productnot at all, because consent is irrelevant for finance recognition
That last point matters. A bad architecture often drags unnecessary dependencies into the graph because the data exists. Mature architecture resists that urge.
The semantic conflict
Commerce uses “order” to include pending cart conversions and payment-authorized transactions. Finance only recognizes confirmed commercial obligations and later recognized revenue events. Previously, both were using a warehouse table called fact_orders, leading to endless confusion.
With bounded contexts made explicit, the graph shows that finance does not consume raw commerce order facts directly. It consumes a contracted product with translated semantics. The dependency is visible and governed.
Migration
Initially, the retailer wraps existing warehouse outputs as façade products. Consumers are moved from table reads to product endpoints and certified views. Then commerce begins emitting domain events into Kafka:
OrderPlacedPaymentAuthorizedOrderCancelledOrderShippedOrderReturned
A commerce-owned pipeline curates those into the Order Lifecycle Product. Finance continues using the old warehouse-backed contract while reconciliation runs between old and new outputs. Late return events initially create discrepancies. The graph records that Revenue Recognition Product enters “provisional reconciliation” when return windows are open. Dashboards display provisional labels automatically based on graph metadata.
That is real architecture value. Not prettier lineage. Better business behavior.
Outcome
Over time, the retailer reduces direct warehouse coupling, localizes ownership, and gains clearer impact analysis. When logistics changes the shipment event schema, the graph identifies which products depend on the curated Shipment Fulfillment Product contract and which rogue pipelines still consume raw events. The former remain stable. The latter finally get fixed or shut down.
Operational Considerations
A dependency graph only works if it becomes operationally relevant.
SLO inheritance
Downstream data products inherit upstream risk. Not mechanically, but materially. If Order Lifecycle Product is fresh within 15 minutes and Shipment Fulfillment Product within 30 minutes, a downstream Revenue Recognition Product cannot honestly claim 5-minute freshness.
The graph should support composed SLO reasoning. At minimum:
- freshness windows
- schema stability
- completeness thresholds
- reconciliation lag
- known fallback modes
Change management
Every product should have versioning discipline. Breaking changes require:
- declared new version
- consumer impact analysis
- migration period
- automated contract testing
- graph update
If teams can change product semantics without graph updates, the graph will rot quickly.
Access control and policy propagation
PII, retention, geographic restrictions, and purpose limitations need to travel through dependencies. If a source product is classified with privacy restrictions, downstream products should inherit or transform those obligations explicitly.
This is where data mesh skeptics often have a point: federated ownership can produce governance chaos. The answer is not to recentralize all delivery. The answer is to centralize policy enforcement in the platform while leaving domain semantics with domains.
Observability
Track the graph against reality:
- unresolved failed dependencies
- products consuming deprecated interfaces
- undocumented downstream consumers
- schema drift against contract
- reconciliation mismatch trends
- orphaned products with no consumers
An enterprise graph that is not continuously observed becomes fiction.
Tradeoffs
There is no free lunch here. A dependency graph in a data mesh solves real problems, but it introduces cost.
Benefits
- makes cross-domain coupling explicit
- improves impact analysis
- supports bounded context-aware semantics
- enables safer migration from legacy systems
- helps govern Kafka and batch products consistently
- reduces accidental direct dependencies
- improves blast radius management and reconciliation discipline
Costs
- requires product thinking maturity
- adds metadata and contract management overhead
- demands stronger domain ownership than many organizations really have
- exposes semantic disagreements that were previously hidden
- can become bureaucratic if overgoverned
- needs platform investment to stay synchronized with runtime reality
A plain truth: many enterprises like the idea of domain ownership more than the reality of domain accountability. A graph will surface that quickly.
Failure Modes
This pattern fails in predictable ways.
1. Modeling technical lineage as if it were product dependency
If every Spark job and table becomes a node, the graph turns into spaghetti. Teams drown in noise and stop trusting it. Product-level abstraction is non-negotiable.
2. Pretending semantics are solved by naming conventions
Renaming a field from cust_id to customer_id does not reconcile bounded contexts. If semantic translation is not explicit, confusion migrates downstream.
3. Allowing raw Kafka topics to become de facto products
Raw event topics are often too volatile, too implementation-specific, or too incomplete to serve as stable enterprise products. Curate product interfaces above service events.
4. Skipping reconciliation during migration
Teams under deadline often compare a few totals, declare success, and switch over. Months later they discover timing, correction, or identity edge cases that break finance, regulatory, or customer-facing logic.
5. Central team becomes the hidden owner of all products
If every dependency edge, contract update, and semantic decision must be approved centrally, you have rebuilt the bottleneck the mesh was supposed to remove.
6. No retirement discipline
Legacy dependencies remain “just in case.” New and old worlds coexist indefinitely. Cost doubles, confidence halves.
When Not To Use
This pattern is powerful, but not universal.
Do not use a full data product dependency graph if:
- your organization has only a small number of stable analytical datasets and little domain complexity
- teams are not ready to own products operationally and semantically
- there is no meaningful cross-domain consumption
- your biggest problem is basic data quality or source system chaos, not dependency management
- you are still in an early platform phase and need a simpler catalog-first approach
In a smaller company with a compact data team and a few shared models, a lightweight lineage plus catalog setup may be enough. Do not build a graph cathedral for a village chapel.
Also, if the business domains themselves are unstable due to reorgs, mergers, or unresolved operating model questions, avoid overformalizing product boundaries too early. Domain-driven design helps, but it cannot compensate for an enterprise that has not decided how it actually works.
Related Patterns
Several patterns sit adjacent to this one.
Data as a Product
The dependency graph assumes product thinking. Without ownership, SLOs, documentation, and change policy, there is nothing meaningful to graph.
Bounded Context Mapping
From domain-driven design, this is the semantic backbone. It helps identify where translation is needed and where direct dependency is appropriate.
Event Carried State Transfer
Useful with Kafka when domains publish state changes for downstream products. Works well when contracts are curated and versioned.
Consumer-Aligned Data Products
Not every product should be source-aligned. Some should serve specific analytical or operational use cases. The graph helps distinguish these from raw reusable sources.
Strangler Fig Migration
Essential for moving from centralized warehouse dependencies to mesh-aligned product contracts gradually.
Reconciliation Pipeline
A companion pattern for dual-run migration, correction handling, and semantic validation between legacy and new products.
Summary
A data product dependency graph in a data mesh is not just a dependency graph diagram. It is the architectural map of how domain semantics, contracts, operational risk, and governance move through the enterprise.
That distinction matters.
If you model only pipelines, you get lineage.
If you model products with semantics and contracts, you get architecture.
The graph should center on data products, not technical artifacts. It should describe dependency strength, consumption mode, SLOs, policy inheritance, semantic translation, and failure behavior. It should be informed by domain-driven design, because bounded contexts explain why data that looks similar often cannot be used interchangeably. It should support progressive strangler migration, because legacy estates do not disappear on command. And it must include reconciliation, because in enterprise environments correctness is not a feeling, it is evidence.
Kafka and microservices fit naturally into this picture, but they are not the point. The point is to let domains publish dependable products without turning the mesh into chaos. A well-designed dependency graph lets teams move faster because it makes coupling visible, change safer, and failures more understandable.
The best enterprise architectures do not eliminate complexity. They put it where people can see it, reason about it, and survive it.
That is exactly what this pattern is for.
Frequently Asked Questions
What is a data mesh?
A data mesh is a decentralised data architecture where domain teams own and serve their data as products. Instead of a central data team, each domain is responsible for data quality, contracts, and discoverability.
What is a data product in architecture terms?
A data product is a self-contained, discoverable, trustworthy dataset exposed by a domain team. It has defined ownership, SLAs, documentation, and versioning — treated like a software product rather than an ETL output.
How does data mesh relate to enterprise architecture?
Data mesh aligns data ownership with business domain boundaries — the same boundaries used in domain-driven design and ArchiMate capability maps. Enterprise architects play a key role in defining the federated governance model that prevents data mesh from becoming data chaos.