Source-Aligned vs Domain-Oriented Data Models
A practical comparison of source-aligned and domain-oriented data models, including where each belongs and how they respond to system change.

Most warehouses begin by reflecting the systems that feed them.
The CRM contributes companies, contacts and deals. The billing platform contributes customers, subscriptions and invoices. The application database contributes users, workspaces and events. Those names become schemas, staging models and eventually columns in dashboards.
This is a sensible place to start. Source structure is observable, easy to trace and already understood by the engineers responsible for ingestion.
The problem begins when the source structure becomes the permanent language of the warehouse. A sales report depends on hubspot_dealstage. Customer reporting joins stripe_customer_id directly to an application user. A metric called active account inherits the lifecycle rules of whichever system happened to provide its first implementation.
Then the company replaces its CRM.
The migration changes more than a connector. Source-specific names, identifiers and assumptions have spread through transformation models, reports and extracts. The warehouse has no boundary at which HubSpot stops and the company's sales process begins.
Source-aligned and domain-oriented models solve different parts of this problem. They are not competing architectures from which a team must select one. A maintainable warehouse usually needs both, separated by an intentional boundary.
What source-aligned modeling preserves
A source-aligned model stays close to the structure and grain of one upstream system. A common dbt staging layer might look like this:
models/
staging/
hubspot/
stg_hubspot__companies.sql
stg_hubspot__contacts.sql
stg_hubspot__deals.sql
stripe/
stg_stripe__customers.sql
stg_stripe__subscriptions.sql
stg_stripe__invoices.sql
Each model has a clear upstream relation. stg_hubspot__deals represents deals as HubSpot records them. It may rename columns, cast timestamps, normalise empty values and expose a tested primary key. It should not pretend that a HubSpot deal is already the company's complete definition of a sales opportunity.
This structure has useful properties:
- Lineage remains direct. An unexpected value can be traced back to one source field.
- Source-specific cleaning happens once instead of being repeated downstream.
- Engineers can reconcile staged data against the operational system.
- A connector or API change has a defined place to be handled.
The original dbt project structure guidance described staging models as source-centric and marts as business-centric. That distinction still gives a useful architectural boundary. Source alignment is valuable close to ingestion because hiding the source too early makes reconciliation and debugging harder.
What domain-oriented modeling changes
A domain-oriented model starts with a business entity or process rather than an upstream table.
Examples include:
- one row per customer,
- one row per sales opportunity,
- one row per invoice line,
- one row per subscription state transition.
The model may combine several sources. A customer can have an application account, a CRM company and one or more billing profiles. A sales opportunity can begin as a marketing lead, become a CRM deal and later produce a signed contract. None of those source records represents the whole business concept alone.
A domain-oriented layer gives downstream consumers a stable interface:
models/
marts/
customers/
dim_customers.sql
sales/
fct_sales_opportunities.sql
fct_opportunity_stage_history.sql
billing/
fct_invoice_lines.sql
fct_subscription_periods.sql
The table name, grain and lifecycle come from the business process. Source identifiers remain available for lineage, but they no longer define the public interface.
This is close to the dimensional design discipline described by the Kimball Group: select a business process, declare the grain, identify dimensions and then identify facts. The grain should be expressed in business terms, not inferred from a source table's primary key.
A CRM migration exposes the difference
Consider a simplified migration from HubSpot to Salesforce. The exact objects and configuration differ between companies, but several structural changes are common.
| Concern | HubSpot-oriented implementation | Salesforce-oriented implementation |
|---|---|---|
| Organisation | Company | Account |
| Sales record | Deal | Opportunity |
| Early prospect | Contact lifecycle or deal state | Lead, later converted |
| Stage | Pipeline-specific deal stage | Opportunity stage |
| Owner | Owner record | User record |
| History | Property or object history | Field history and related records |
These are not simple column renames. Lead conversion changes how identity is represented. Stage history may have different completeness and timestamps. An organisation can be created at a different point in the sales process. The meaning of closed, qualified or active must be mapped rather than copied.
In a warehouse where source structure reaches the reporting layer, the dependency graph can look like this:
hubspot_deals
-> stg_hubspot__deals
-> int_hubspot__deal_funnel
-> rpt_hubspot__pipeline
-> rpt_sales_forecast
-> rpt_marketing_attribution
-> executive_revenue_dashboard
Replacing the CRM changes the staging model, but it also forces each downstream consumer to understand Salesforce objects and recreate the old HubSpot assumptions. The migration propagates through the graph.
With a domain boundary, the graph is different:
hubspot_deals --------\
-> int_sales__opportunities
salesforce_opportunity /
-> fct_sales_opportunities
-> sales pipeline
-> forecast
-> attribution
During migration, both CRM sources can feed the integration model. The public contract of fct_sales_opportunities remains stable while the mapping behind it changes. Reports do not need to know which CRM produced the record.
This does not make the migration automatic. Someone still has to decide how a converted lead maps to an existing contact, which timestamp represents entry into a stage and whether historical HubSpot stages correspond to the new Salesforce pipeline. Domain modeling concentrates those decisions in one layer instead of distributing them across every consumer.
The right boundary is layered
The practical architecture is a progression from source truth to business meaning.
| Layer | Organising principle | Primary responsibility |
|---|---|---|
| Raw | Source delivery | Preserve what arrived and the metadata required to audit it |
| Staging | Source-aligned | Rename, cast, deduplicate and expose a clean interface to each source |
| Integration | Domain-oriented | Resolve identities, align lifecycle states and combine sources |
| Marts | Business process and declared grain | Publish stable facts, dimensions and metrics for consumers |
The transition does not always require four physical schemas. A small dbt project may have staging and marts only. The important part is that each model has a clear responsibility and that the transition from source language to business language happens once.
A staging model named stg_salesforce__opportunities is useful. A company-wide revenue metric that requires every consumer to understand Salesforce opportunity types is a warning sign.
Domain models have their own failure modes
Moving away from source structure does not justify building an abstract enterprise ontology before the first report exists.
The most common mistake is creating generic entities that erase useful distinctions. A universal party table containing customers, suppliers, employees and prospects may look consistent while making every query harder to understand. A canonical status field can hide lifecycle differences that the business still needs to see.
Domain models also introduce decisions that sources previously made on the team's behalf:
- Which records from separate systems represent the same customer?
- What is the authoritative identifier when systems disagree?
- Which source owns a particular attribute?
- How should conflicting updates be resolved?
- Which history must remain available after the source is retired?
Those decisions require explicit rules, tests and ownership. A domain layer without them becomes another set of tables whose names sound cleaner but whose meaning remains uncertain.
The goal is a stable interface around a real business process. It is not maximum abstraction.
When a source-aligned model is enough
Some datasets should remain source-aligned all the way to consumption.
Operational reconciliation is one example. A finance report designed to match a Stripe payout needs Stripe-specific objects and terminology. A support operations dashboard may intentionally describe Zendesk tickets, queues and statuses. Abstracting those details into a universal case-management model can remove information the users need.
Source-aligned consumption is reasonable when:
- one system is the recognised authority for the process,
- consumers need to reconcile directly with that system,
- the analysis depends on source-specific behaviour,
- no other source represents the same entity or process,
- the cost of another modeling layer exceeds the expected change.
The architecture becomes fragile when the same source-specific logic is repeated across several domains or exposed as the definition of a company-wide metric.
How to review an existing warehouse
The boundary can be evaluated without redesigning the whole project.
Start with the models consumed by finance, product and executive reporting. For each one, ask:
- Is the grain written in business terms?
- Do public column names contain vendor or application terminology?
- Would replacing one source require changes to this model's consumers?
- Is identity resolved once, or independently inside several reports?
- Are lifecycle mappings maintained centrally?
- Can the model be reconciled back to each contributing source?
A high number of source-specific dependencies in marts indicates that the integration boundary is missing or positioned too late. A staging layer full of generic business entities indicates the opposite problem: source details have been hidden before they can be audited.
The corrective work can be incremental. Define the grain of one important mart. Introduce a stable domain model alongside the existing source-aligned output. Reconcile both during a transition period, then move consumers one at a time. A warehouse does not need a large migration to improve its boundaries.
Design for change without predicting every change
No model can make source replacement free. Different systems encode different workflows, and those differences require engineering work.
The purpose of a domain boundary is containment. Source changes should be absorbed near staging and integration. Business definition changes should be handled in the domain model. Reports should change only when the question they answer has changed.
That separation keeps the warehouse traceable near its inputs and stable near its consumers. Source-aligned and domain-oriented models both belong in the design. The quality of the architecture depends on where the team draws the line between them.
If source-specific logic has spread through an existing dbt project, a Data Platform Audit can identify where the modeling boundary is missing and turn the findings into a prioritised implementation plan.
