Groups and access levels establish clear architectural boundaries and team ownership within a dbt project. Groups assign sets of models to specific teams, while access levels control which models can be referenced by code outside that group. This structure prevents downstream teams from building critical reports on top of unvetted, internal staging tables.
Group boundaries and ownership
A group defines a team boundary and sets ownership in dbt_project.yml or YAML model files:
groups:
- name: finance
owner:
email: finance-data@example.comModels assigned to the finance group belong to that team, making code reviews and maintenance responsibilities explicit.
Three access levels
Every model in dbt has an access level that dictates where other models may reference it:
- Private models can only be referenced by other models within the same group. If a model in the marketing group attempts to call ref on an internal payments model, dbt throws a compilation error.
- Protected models can be referenced by any model within the same dbt project, but cannot be called across projects in dbt Mesh. This is the default access level.
- Public models serve as published interfaces. Any model in any group or external dbt project can reference them. Public models require enforced model contracts so that interfaces remain stable over time.
These three tiers define a clean visibility hierarchy for data assets.
Stopping the staging spaghetti
Without access controls, analytics engineering repositories often devolve into a web of tangled dependencies. An analyst building a marketing attribution model might discover an internal model like stg_stripe__charges and reference it directly. If the billing team refactors that staging table, the marketing model breaks unexpectedly.
By marking staging and intermediate models as private to the billing group, you force external teams to depend only on public mart models like fct_mrr. This protects internal implementation details and keeps cross-team dependencies clean.