CertSafari
    DBT Architect· Lessons

    Domain 7 · Lesson 37/39

    dbt model access and groups

    Utilizing model governance

    12 min read
    2.56% of exam
    4 sources
    Published 13 Oct 2026
    Docs as of 12 Oct 2026

    What you will be able to do

    • Explain which governance features dbt offers and which resource types they apply to
    • Define a group with an owner and assign models to it at project, model or file level
    • Choose between private, protected and public access and predict the error a disallowed ref raises
    • Recognise where access rules do not reach: warehouse grants, run-operation and installed packages

    Key concept

    Model governance — A set of model-level controls in dbt (access, contracts, versions and namespaces) that let you treat a model as a stable interface. They decide who may ref the model, what shape it is guaranteed to have, and how it can change without breaking its consumers.

    1.What model governance controls

    Once other teams build on your models, those models become interfaces, and model governance is how dbt lets you manage them that way. It answers three questions about a model: who is allowed to ref it, what shape it is guaranteed to have, and how it may change over time. Each question has its own feature. All of them work in dbt v1 and on the dbt platform except project dependencies, which need an Enterprise-tier plan.

    The governance building blocks and what each one controls
    FeatureWhat it controlsAvailability
    Model accessWhether a model is public or private, and so who can ref itdbt v1 and dbt platform
    Model contractsColumn names, data types and constraints, checked before the model buildsdbt v1 and dbt platform
    Model versionsAn upgrade pathway and deprecation window when a breaking change is unavoidabledbt v1 and dbt platform
    Model namespacesGroups and packages that mark ownership boundariesdbt v1 and dbt platform
    Project dependenciesResolving refs to public models in other projectsdbt Enterprise-tier plans only

    Cross-project references are built on access. A downstream project can only reach the models its producer has marked access: public, and that marker is the intentional interface the maintainer has designated. Wiring up the dependency itself is covered under [setting up additional projects](lesson:7.1). This lesson is about the governance that decides what the dependency is allowed to see.

    Governance has a cost, so adopt it on purpose. Access, contracts and versions add structure, and structure makes some rollbacks harder: once consumers depend on a public model, removing that access breaks them. If you add governance while models are still being reshaped every week, every reshape turns into a negotiation. Put it on models that have settled.

    Governance applies only to models. Snapshots, seeds and sources cannot be made public, contracted or versioned. Their structure can change over time (a snapshot captures evolving history, for example), so they don't suit those guarantees.

    Checkpoint 1 of 6· Check yourself

    A team wants to publish four resources to a downstream project with access: public. Which one can actually carry that setting?

    Sources12

    2.Groups define ownership boundaries

    A group is a named collection of nodes in the DAG, and every group has an owner. Groups do two things. They turn an implicit relationship, such as "these are the finance models", into an explicit one with someone responsible for it. They also give private access its meaning: a private model can be referenced only from inside its own group. Thinking about the interfaces between groups tends to produce a less tangled DAG, and those interfaces are natural candidates for the seams between separate projects later on.

    Groups are declared in YAML under a groups: key. Each one needs a name that is unique in the project and an owner with at least a name: or email:. From v1.10 a group can also take a description and config.meta, for things like a cost centre or a data classification. To keep the definitions in one place, use a single _groups.yml at the root of the models directory. Alternatively, put it at the root of a groups directory and add that directory to model-paths.

    You can assign membership at three levels: in dbt_project.yml for a whole folder, in a model's YAML, or in a config() block inside the SQL file. Most well-structured projects already use subdirectories, so the project-level form usually does most of the work:

    Assigning groups to whole subdirectories in dbt_project.ymlyaml
    models:
      my_project_name:
        marts:
          customers:
            +group: customer_success
          finance:
            +group: finance

    Membership is strict. A node belongs to at most one group, and groups cannot be nested. Models, tests, seeds, snapshots, analyses and metrics can be members. Sources and exposures cannot. A group set in a model's YAML or in-file config overrides the folder-level assignment, so one model can be moved out of its folder's group without restructuring the directory.

    Checkpoint 2 of 6· Check yourself

    dbt_project.yml applies +group: finance to models/marts/finance/. One model in that folder sets group: marketing in its YAML. What is its group membership?

    Sources34

    3.Private, protected and public access

    The access modifier sets how far a model's ref reaches. There are three levels, and each one widens the audience of the one before it.

    Access modifiers and who can reference the model
    AccessReferenceable byUse it for
    privateSame groupIntermediate transformations that are implementation details
    protected (default)Same project, or the project installed as a packageModels useful elsewhere in this project but not meant to be exposed outside it
    publicAny group, package, or projectStable, mature interfaces for other teams and projects

    Protected is the default so that existing projects don't break when groups are introduced, because their references may already cross the new boundaries. For new models, set private instead. That stops other parts of the project from depending on a model nobody designed for sharing. Promote a model to public when it really is a product, and rerun a production job afterwards so the change takes effect.

    A group with an owner, plus a public and a private model in that groupyaml
    # First, define the group and owner
    groups:
      - name: customer_success
        owner:
          name: Customer Success Team
          email: cx@jaffle.shop
    
    # Then, add 'group' + 'access' modifier to specific models
    models:
      # This is a public model -- it's a stable & mature interface for other teams/projects
      - name: dim_customers
        config:
          group: customer_success # changed to config in v1.10
          access: public # changed to config in v1.10
    
      # This is a private model -- it's an intermediate transformation intended for use in this context *only*
      - name: int_customer_history_rollup
        config:
          group: customer_success # changed to config in v1.10
          access: private # changed to config in v1.10

    dbt enforces access at parse time. If marketing_model in the marketing group refs a model that is private to finance, the run stops with a DbtReferenceError saying the referenced node is private to the finance group. No SQL reaches the warehouse. There is one more restriction to know: a model with materialized='ephemeral' cannot be public, and dbt parse rejects that combination as an invalid value for the access field.

    Checkpoint 3 of 6· Fill the gap

    marketing_model (group marketing) refs this model and fails with a DbtReferenceError. Which access value produces that error?

    models:
      - name: finance_private_model
        config:
          access:  ?  # changed to config in v1.10
          group: finance

    Checkpoint 4 of 6· Exam question

    A dbt Cloud admin defines `finance_model` with `access: private` inside the `finance` group. A model called `marketing_model`, which is not a member of the `finance` group, calls `ref('finance_model')` in the same project. What happens when the project is parsed?

    Sources43

    4.Where access rules stop

    Access controls who may build on a model in dbt. It does not control who can query the data. Setting public signals that other teams may take a dependency, on the assumption that they have asked for and been granted select on the underlying dataset. You grant that separately. Typical moves are to use the grants config to open public models to downstream queriers, and to restrict private ones by revoking default grants or landing them in a different schema.

    Inside the dbt account, access lines up with development permissions. Anyone who can develop in a project can see and change every model in it, private ones included. A user in the same account who can't develop there can't see its private models and can depend only on its public ones.

    There are two places where dbt does not enforce access at all, and both catch people out:

    - **dbt run-operation.** A macro invoked this way can ref() any model, private and protected included, because group and access controls are not enforced. - Package dependencies. When another project is installed as a package, its source code becomes part of your runtime. Access restrictions are off by default, so protected models can be referenced as if they were your own, and private ones too when your model shares their group.

    A package maintainer can close that gap from their own dbt_project.yml. With the flag below set, any ref from outside the package to a protected or private model fails, and only public models can be reached. Project dependencies on dbt Enterprise behave differently: they resolve refs through a metadata service, and only public models are reachable.

    Restricting external refs to public models in a package's dbt_project.ymlyaml
    restrict-access: True  # default is False

    Checkpoint 5 of 6· Check yourself

    Your project installs jaffle_finance as a package, and your model refs one of its protected models. The package's dbt_project.yml doesn't mention restrict-access. What happens?

    Checkpoint 6 of 6· Exam question

    Team B adds Team A's project `core_finance` to `dependencies.yml` and calls `{{ ref('core_finance', 'monthly_revenue') }}`. The build fails to resolve the reference. Team A confirms `monthly_revenue` already has `access: public` set. What is the most likely remaining cause of the failure?

    Sources4

    Exam traps

    Each one states something that sounds right. Open it to see what is actually true.

    1. 1.Models with no access setting are private to their group.Why is that wrong?

      The default is protected, so any model in the same project can ref them. Set private explicitly on new models that shouldn't be shared.

      Covered in Private, protected and public access

    2. 2.Marking a model access: public grants downstream users select on it in the warehouse.Why is that wrong?

      Access only governs who may ref the model in dbt. Warehouse permissions are managed separately, for example with the grants config.

      Covered in Where access rules stop

    3. 3.Any model, including an ephemeral one, can be published as public.Why is that wrong?

      Ephemeral models cannot have public access. dbt parse fails with an invalid value error for the access field.

      Covered in Private, protected and public access

    Sources

    Every claim above is drawn from one of these pages, quoted as it was written on the date shown.

    1. 1.
      “except project dependencies, which is only available to dbt Enterprise-tier plans”
      ↩︎ What model governance controls
      “Introducing governance while models are still changing can complicate future changes.”
      ↩︎ What model governance controls
      “dbt supports model governance to help you control who can access models, what data they contain, how they change over time”
      ↩︎ Key concept
      “Governance features are model-specific. They don't apply to other resource types, including snapshots, seeds, or sources.”
      ↩︎ Checkpoint
    2. 2.
      “You're using an intentional interface designated by the model's maintainer with access: public.”
      ↩︎ What model governance controls
    3. 3.
      “Group members may include models, tests, seeds, snapshots, analyses, and metrics. (Not included: sources and exposures.)”
      ↩︎ Groups define ownership boundaries
      “If a grouped model's access property is set to private, only resources within its group can reference it.”
      ↩︎ Private, protected and public access
    4. 4.
      “Each model can only belong to one group, and groups cannot be nested.”
      ↩︎ Groups define ownership boundaries
      “Any group, package, or project. When defined, rerun a production job to apply the change”
      ↩︎ Private, protected and public access
      “When a macro is invoked with dbt run-operation, dbt doesn't enforce model access or group controls”
      ↩︎ Where access rules stop
      “Users in the same dbt account without access to develop in a project cannot view that project's private models”
      ↩︎ Where access rules stop
      “Only models with access: public can be referenced outside the package.”
      ↩︎ Where access rules stop
      “it is recommended to set the access modifier of a new model to private”
      ↩︎ Exam trap 1
      “does not trigger dbt to automagically grant select on that model to every user or role in your data platform”
      ↩︎ Exam trap 2
      “Models with materialized set to ephemeral cannot have the access property set to public.”
      ↩︎ Exam trap 3
      “If you set a different group in that model's YAML or in-file config, it will override the group applied at the project level.”
      ↩︎ Checkpoint
      “By default, all models are protected.”
      ↩︎ Prediction
      “does not trigger dbt to automagically grant select on that model to every user or role in your data platform”
      ↩︎ Prediction
      “model access restrictions are "off" by default for models defined in packages”
      ↩︎ Checkpoint

    Continue to page 2 of 2

    dbt model contracts and versions

    Spotted a mistake, or was something unclear? Tell us.