ServicesAboutNotesContact Get in touch →
EN FR
Note

dbt Mesh Governance Triad

How contracts, access controls, and model versioning combine in dbt Mesh to turn models into data products — and which models actually deserve that treatment.

Planted
dbtdata modelingdata qualitydata engineering

dbt Mesh has three governance features: contracts, access controls, and model versions. Each solves a specific problem independently. Applied together, they turn internal tables into data products with defined interfaces, explicit consumption boundaries, and managed evolution.

The Three Features, Each Doing Its Job

Contracts guarantee shape. When contract: {enforced: true} is set, dbt refuses to materialize a model if its output columns and types don’t match the YAML declaration. Downstream consumers know which columns and types they’ll get, enforced at every build. The guarantee is structural: if the model builds, it has the schema you declared. See dbt Model Contract Mechanics for the mechanics.

Access controls define who can reference a model. public models are available to any other dbt project. protected models stay within their own project. private models are restricted to their directory group. In a multi-project Mesh setup, access controls determine which outputs are intentionally exposed as APIs versus which are internal implementation details other teams shouldn’t build on.

Model versions manage evolution. When a breaking change is needed — removing a column, changing a type — you create a new version rather than modifying the existing one. The old version and the new version both materialize as separate tables (mrt__analytics__customers_v1, mrt__analytics__customers_v2). Consumers on v1 keep working while they migrate. The old version gets a deprecation_date so dbt warns anyone still referencing it. See dbt Model Versioning for the full pattern.

Individually, each feature is useful. A contracted model without access controls is still a reliable building block for your own project. Access controls without contracts are useful for project structure. Versioning without contracts handles schema evolution without formal guarantees.

What Changes When You Combine Them

A contracted, access-controlled, versioned model looks different from an internal table — not just in configuration, but in what it represents in your organization.

When another team uses ref('your_project', 'mrt__analytics__customers') in a dbt Mesh setup, they get three things at once:

  • The contract defines exactly which columns and types to expect
  • The access control (public) confirms they’re allowed to depend on this model
  • The version (latest_version: 2) means they can depend on stability even as the underlying implementation changes

That combination turns a cross-project ref() from an informal agreement into an enforceable interface. The consuming team doesn’t have to coordinate with you every time you refactor. They don’t need to check whether you renamed a column. The contract catches structural breaks at compile time — in their project, in CI, before anything ships.

This maps directly onto data mesh principles, made operational rather than theoretical:

  • Domain ownership: each team manages its own dbt project and sets its own contracts
  • Data as product: contracted, versioned, access-controlled models serve as outputs to other domains with defined interfaces
  • Federated governance: contracts and access controls enforce consistency without a central team reviewing every change

Which Models Actually Deserve This

Not every model needs to be a data product. The overhead is real — every column and type must be declared in YAML, every breaking change requires a new version, access levels must be deliberate. Applying this treatment universally means you’re spending that effort on models nobody else depends on.

The right candidates, roughly in priority order:

Mart models crossing team boundaries. If another team’s dbt project has a ref() pointing at your model, that model should have all three. You don’t know when they’re running, you can’t coordinate every change, and breaking their builds has organizational costs beyond the technical ones.

Models feeding critical dashboards. Executive dashboards and SLA-sensitive reports have a wide blast radius when they break. A model that 20 people check every morning deserves the structural guarantee a contract provides.

Intermediate models at cross-team boundaries. Even within a single project, if one team produces data another team consumes, treating that boundary like a public interface prevents the most common source of intra-team coordination overhead: “someone refactored something and my models stopped building.”

Base models on volatile sources. When a source schema changes frequently — volatile API, upstream team that ships without notice — a contracted base model gives you the earliest possible signal. The contract fails at compile time, before any transformation runs.

What doesn’t need this treatment: internal intermediate models that nobody outside your team references, base models on stable sources, utility models that simplify logic for other models in the same layer. For those, contracts add YAML overhead without meaningful governance benefit.

The Data Mesh Connection

For teams working through what “data product” means in practice, the governance triad makes it concrete. A data product isn’t a philosophy or an org chart change — it’s a model with:

  1. A defined interface (the contract says exactly what you’re providing)
  2. Explicit consumption boundaries (access controls say who can use it)
  3. Managed evolution (versions let the interface change without breaking consumers)

The ODCS specification goes further — it adds SLAs, ownership metadata, and quality rules to the interface definition. dbt’s native governance covers the structural layer; ODCS covers the organizational layer. For most teams, the dbt-native triad is enough to start. The move to ODCS makes sense when you need to formalize agreements with teams outside your dbt project entirely — software engineering teams producing source data, ML teams consuming your outputs, external partners receiving data feeds.

One contracted public mart model is more tractable than an org-wide “data mesh initiative.” Starting with the most depended-on model and applying all three governance features is a practical entry point.