dbt

dbt Model Access Design Guide: When to Use public / protected / private

2026-04-19
NicheeLab Editorial Team

In dbt, access is a property that controls which models can be referenced via ref, improving design consistency and the safety of future changes. It pairs especially well with a layered architecture (staging / intermediate / marts), where it makes dependency boundaries explicit and simplifies impact assessment when you extend the project.

This article walks through the basics of public / protected / private, common design patterns, YAML implementation examples, and CI verification checkpoints. It also covers what shows up on the dbt Analytics Engineer exam: model boundaries, how access combines with contracts and versions, and how it differs from grants.

access Basics and When to Use Each Level

access is a resource property used mainly on models that controls whether they can be referenced from other packages or projects. dbt detects access violations at compile time and blocks unintended references.

The baseline policy is: private for staging, protected for integration and intermediate layers, and public for consumer-facing marts. This keeps the blast radius of changes contained in successive stages.

  • private: the most closed scope. Protects raw data and unstable intermediate shapes
  • protected: shared only within the project or a defined boundary. Prevents over-exposure
  • public: allows references from external packages too. A stable, API-like interface
LevelReference scope (conceptual)Primary use and caveats
privateSame package onlyStaging and experimental intermediates. Less reusable but safer to change
protectedSame package (plus any boundary you define)Integration and intermediate. Prevents direct external references; boundary discipline matters
publicFrom any packageMarts and public APIs. Change carefully. Recommended to combine with versions/contract

Layered Design Pattern (stg / int / mart)

The most stable approach in practice is to fix access per layer. Doing so blocks unintended back-references and skip-references (for example, referencing stg directly from mart).

External packages can only reference the public mart layer, and int (protected) is treated as untouchable from outside the boundary.

  • stg_*: private (resilient to source-shape drift and naming churn)
  • int_*: protected (intermediate layer for aggregation, normalization, key assignment, etc.)
  • mart_*: public (curated, with explicit contracts and versions)

Dependencies and exposure boundaries (example)

OKBLOCKEDstg_*privateint_*protectedmart_*public (public API)package_b: model_xref(a.mart_*) → OKpackage_b: model_yref(a.int_*) → BLOCKEDprivate = same package only, protected = within the boundary only, public = external access allowed

Implementation Example (YAML) and Basic Verification Flow

The example below assigns access and group per layer within a single project. Combining contracts and versions raises the stability of public models.

access violations are detected during dbt's compile-to-build phase. In CI, run dbt build with dependent packages included and fail the job when a violation occurs.

  • group is useful for documentation and signaling boundary intent (keep naming consistent)
  • Combine contract and version on public models; ship breaking changes as a new version
  • Build with dependencies in CI to detect access violations early

models/schema.yml (example)

version: 2
models:
  - name: stg_orders
    description: Raw orders from source, lightly cleaned
    config:
      access: private
      group: staging
      contract:
        enforced: true
    columns:
      - name: order_id
        data_type: int
      - name: order_ts
        data_type: timestamp

  - name: int_orders
    description: Conformed orders, with keys and normalized types
    config:
      access: protected
      group: integration
    columns:
      - name: order_id
        tests: [not_null]

  - name: dim_customers
    description: Curated customer dimension (public interface)
    config:
      access: public
      group: marts
      contract:
        enforced: true
    versions:
      - v: 1
      - v: 2
    latest_version: 2
    columns:
      - name: customer_id
        data_type: int
      - name: customer_tier
        data_type: string

Exposure Strategy Across Multiple Projects/Packages

Models that are intended to be referenced from other packages should be limited to public. If you try to ref a protected or private model from outside, dbt flags it as a violation before the build stage.

When changing a public model, separate breaking from non-breaking changes. The safe pattern is to ship breaking changes as a new version and run the old and new versions side by side until latest_version is switched over.

  • External exposure = public. Non-exposure = protected/private
  • Breaking changes = new version. Non-breaking = add columns within the same version (watch the contract)
  • Explicitly manage the lifetime of the old version to absorb downstream upgrade timing

How access Relates to contracts, versions, and grants

access controls 'whether you can reference a model within dbt.' Database read privileges are managed separately via grants (an adapter implementation). Even a public model cannot be read by direct SQL without warehouse-side privileges.

contracts guarantee schema consistency, and versions guarantee interface compatibility over time. For public models, the three-piece combo (access + contract + version) is close to the canonical answer for both production use and the exam.

  • access: dbt's ref guard (a design-level boundary)
  • grants: actual privileges on the warehouse. Affects exposure to BI and external tools
  • contracts/versions: manage the compatibility of public APIs (columns, types, evolution)

Exam Tips and Pitfalls

On the Analytics Engineer certification, expect frequent questions on per-layer exposure, the combination of access / contracts / versions, and how access differs from grants. Read the scenario for 'who uses it' and 'how widely it should be exposed.'

Key points: do not confuse protected with private, do not casually expand public, and use versioning for breaking changes.

  • Per-layer defaults: stg = private / int = protected / mart = public
  • Attach contract and version to public models (design for compatibility)
  • Be clear on the split: access governs ref, grants governs warehouse privileges

Check Your Understanding

Analytics Engineer

問題 1

Multiple teams run separate dbt projects on the same data platform. Team A wants its intermediate model int_orders to be freely referenced inside Team A but not directly from outside. Meanwhile, the customer-facing mart dim_customers is also referenced by Team B. Which combination of access values is appropriate?

  1. A. int_orders = protected, dim_customers = public
  2. B. int_orders = private, dim_customers = protected
  3. C. int_orders = public, dim_customers = protected
  4. D. int_orders = private, dim_customers = private

正解: A

An intermediate layer that should block direct references from external packages fits protected, and an externally exposed mart fits public. private is too narrow even within a single package and is a poor fit for sharing an intermediate layer.

Frequently Asked Questions

Does setting access also control SELECT privileges on the warehouse?

No. access is a design-level guard that controls whether a model can be referenced via dbt's ref. Warehouse-level privileges are managed separately via grants (an adapter-specific implementation).

How should I handle breaking changes to a public model?

Ship breaking changes as a new version using versions, and combine it with contract to make compatibility explicit. Give downstream consumers a migration window and manage when you switch latest_version.

How do protected and private differ in practice?

private is for sealing off raw or experimental shapes, while protected fits shared intermediate layers within the same project. Reserve public exclusively for external exposure.

Check what you learned with practice questions

Practice with certification-focused question sets

無料で問題を解いてみる
Author

NicheeLab Editorial Team

NicheeLab editorial team focused on data engineering and cloud certification learning. Content is structured around practical study needs and official exam domains.


Related articles
dbt

dbt Models: SQL-Defined Transformation Units (2026)

Model fundamentals — SELECT-based definitions, naming, refs,...

dbt

dbt Analytics Engineering Exam: Complete Guide (2026)

Pass the AE Certification — scope, weighting, sample questio...

dbt

dbt Cloud vs dbt Core: Feature & Cost Comparison (2026)

Honest comparison of dbt Cloud vs. dbt Core — IDE, scheduler...

dbt

dbt Project Structure: models/seeds/macros Layout (2026)

Recommended dbt project layout — models, seeds, macros, snap...

dbt

dbt_project.yml Explained: Every Config (2026)

Every dbt_project.yml setting that matters — paths, vars, ma...

Browse all dbt articles (101)
© 2026 NicheeLab All rights reserved.