---
title: "dbt public models with no enforced contract | Metacenta"
description: "A dbt model marked access: public is an interface other teams build on. Without an enforced contract its columns can change under them unannounced."
url: "https://metacenta.com/rules/public-model-without-contract"
updated: "2026-10-14"
tokens: 696
---

Modelling correctness · rule public-model-without-contract

# dbt public models with no enforced contract

A Metacenta review checks this under the rule **Publicly-accessible models enforce a contract**. Everything below applies whether or not you ever commission one.

## What this rule checks

This rule flags every model declared `access: public` that doesn't enforce a contract. A model with no `contract` block fails, and so does one with `enforced: false`. Models that are `protected` or `private` aren't judged.

## Why it matters

Marking a model public tells other teams it is a stable interface. Without an enforced contract its column names and types can still change without warning, and their models break on the next run.

## How to fix it

**Enforce contracts on publicly-accessible models.** Set `contract: {enforced: true}` on the model and declare a `data_type` for every column. dbt then fails the build when the model's output stops matching.

Before:

```yaml
models:
  - name: dim_customers
    access: public
    columns:
      - name: customer_id
```

After:

```yaml
models:
  - name: dim_customers
    access: public
    config:
      contract:
        enforced: true
    columns:
      - name: customer_id
        data_type: integer
```

## When it is fine to leave

A model marked public in advance of any consumer, while its shape is still settling, can wait for a contract. So can one whose only readers sit in the same team. If nothing outside the project reads it yet, `protected` is the more accurate label.

## What we need to check it

`manifest.json` alone. If no model in the manifest carries an `access` field, we cannot identify public models. The rule then says it could not assess; dbt added model access in 1.5.

## Published rules it corresponds to

**[dbt_project_evaluator](https://dbt-labs.github.io/dbt-project-evaluator/)**, rule `fct_public_models_without_contracts`. Ours checks the same condition and threshold.

This means our check corresponds to their rule. It does not mean the publisher reviewed or endorses it.

[Ask about a review](https://metacenta.com/enquire?src=rule-public-model-without-contract&via=md)

## Related pages

- [dbt incremental models: how unique_key works](https://metacenta.com/rules/incremental-without-unique-key)
- [dbt sources declared twice for one table](https://metacenta.com/rules/duplicate-source)
- [dbt staging models: how to set up the staging layer](https://metacenta.com/rules/staging-depends-on-staging)
- [dbt staging models that read marts](https://metacenta.com/rules/staging-depends-on-downstream)
- [A sample review, as a client reads it](https://metacenta.com/sample)
- [All published rules](https://metacenta.com/rules)
- [How a review is assessed](https://metacenta.com/standard)
