working-with-dbt-mesh について
dbt Mesh のモデルガバナンスやプロジェクト間の依存関係を管理する分析エンジニア向けスキルです。変更の影響を事前に評価し、モデルのバージョン、アクセス制御、コントラクトを適切に扱います。
主な機能
- 01プロジェクト間参照の設定と確認
- 02モデルの破壊的変更の影響評価
- 03モデルコントラクトとアクセス制御
- 04モデルのバージョン管理と移行
活用シーン
- 01共有モデルの変更前に依存関係を確認
- 02プロジェクト間参照用の公開モデルを設定
- 03列の改名や削除に伴う移行を計画
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ dbt-labs/ dbt-agent-skills --skill working-with-dbt-meshインストール後、Claude Code で/working-with-dbt-meshを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/cross-project-collaboration.mdgroups-and-access.mdmodel-contracts.mdmodel-versions.md詳細
dbt Mesh の操作
基本原則: Mesh プロジェクトでは、上流データは source() ではなく ref() を通じて取得します。プロジェクトをまたぐ参照では、必ずプロジェクト名が必要です。迷ったら、まず dependencies.yml を確認してください。
使用する場面
- モデルに破壊的変更を加える可能性がある場合(列の名前変更、削除、型変更など)、特に他のモデル、エクスポージャー、BI ツールが依存している場合。 変更前に影響範囲を評価し、モデルをそのまま編集するのではなく、モデルのバージョン管理を検討してください。
- モデルのバージョン管理を行う場合(
versions:、latest_version、latest_version_pointer、deprecation_date)。これは単一プロジェクトにも適用され、マルチプロジェクト環境だけに限りません - 他の dbt プロジェクトのモデルを参照する dbt プロジェクトで作業する場合
- 同じような名前のモデル(例:複数の
stg_モデル)を持つ複数の上流プロジェクトがある場合に、曖昧さを解消するとき - モデルコントラクト、アクセス修飾子、またはグループを追加する場合
dependencies.ymlを使ってプロジェクト間参照を設定する場合- モノリシックな dbt プロジェクトを複数の Mesh プロジェクトに分割する場合
次の場合には使用しないでください:
- 一般的なモデルの構築やデバッグ(
using-dbt-for-analytics-engineeringスキルを使用してください) - モデルのユニットテスト(
adding-dbt-unit-testスキルを使用してください) - セマンティックレイヤーの作業(
building-dbt-semantic-layerスキルを使用してください)
最初に:マルチプロジェクト環境を把握する
dbt Mesh を使用するプロジェクトで SQL を記述または変更する前に、次の手順に従ってください。
1. dependencies.yml を確認する
プロジェクトのルートにあるこのファイルで、存在する上流プロジェクトを確認できます。
# dependencies.yml
projects:
- name: core_platform
- name: marketing_platform
このファイルに projects: キーがある場合、マルチプロジェクトの Mesh 環境です。これらの上流プロジェクトから参照するすべてのモデルでは、プロジェクト間の ref() を必ず使用してください。
2. 上流データがこのプロジェクトに取り込まれる方法を理解する
Mesh 環境では、上流プロジェクトのモデルが、通常ならソースとなるものに置き換わります。
| 代替手段 | Mesh のマルチプロジェクト環境 |
|---|---|
{{ source('stripe', 'payments') }} | {{ ref('core_platform', 'stg_payments') }} |
| データは生のデータベーステーブルから取得されます | データは別の dbt プロジェクトのパブリックモデルから取得されます |
sources.yml で定義されます | dependencies.yml で宣言されます |
上流プロジェクトでは、生データのステージングと変換がすでに行われています。自分のプロジェクトでは、生のソースではなく、上流プロジェクトのパブリックモデルを基盤にします。
3. 同じような名前のモデルを区別する
複数の上流プロジェクトに同じ名前のモデル(例:core_platform と marketing_platform の両方に stg_customers)がある場合は、2 つの引数を取る ref() を必ず使用してください。
-- Correct: explicit project name, no ambiguity
select * from {{ ref('core_platform', 'stg_customers') }}
select * from {{ ref('marketing_platform', 'stg_customers') }}
-- WRONG: dbt cannot determine which project's stg_customers you mean
select * from {{ ref('stg_customers') }}
4. コードベースにある既存のパターンを確認する
新しい SQL を記述する前に:
- 既存の 2 引数の
ref()呼び出しを検索し、どの上流プロジェクトやモデルがすでに使用されているか確認します - 上流プロジェクトの YAML を確認し、
access: publicのモデルを探します。プロジェクト間で参照できるのはこれらのモデルのみです ref()の最初の引数は、上流プロジェクトのdbt_project.ymlにあるnameフィールドと完全に一致している必要があります(大文字と小文字を区別します)
5. 参照できるものとできないものを把握する
| 上流モデルのアクセス設定 | プロジェクト間で ref() できますか? |
|---|---|
access: public | はい |
access: protected(デフォルト) | いいえ — 同じプロジェクト内でのみ可能です |
access: private | いいえ — 同じグループ内でのみ可能です |
public ではないモデルが必要な場合は、アクセス範囲を広げてもらえるよう上流チームと調整してください。
プロジェクト間の ref() には dbt Cloud Enterprise が必要です
プロジェクト間の ref() と、dependencies.yml の projects: キーは、dbt Cloud Enterprise または Enterprise+ プランでのみ利用できます。プロジェクト間のコラボレーションを設定する前に、プランの対象要件を確認してください。
dependencies.ymlにすでにprojects:キーがあり、プロジェクトでプロジェクト間の ref を実際に使用している場合 — すでに Enterprise を利用しています。続行してください。- それ以外の場合 —
dependencies.ymlにprojects:を追加したり、2 引数の新しいref()呼び出しを記述したりする前に、dbt Cloud Enterprise または Enterprise+ を利用していることをユーザーに確認してください。
ユーザーがプランレベルを確認できない場合、または Enterprise 未満のプランを利用していると確認できた場合は、プロジェクト間の ref を設定しないでください。この機能を利用するには Enterprise または Enterprise+ へのアップグレードが必要であることを説明し、代わりにプロジェクト内のガバナンス機能(グループ、アクセス修飾子、コントラクト)の使用を提案してください。
プロジェクト間の ref() 構文
-- Reference an upstream model (latest version)
select * from {{ ref('upstream_project', 'model_name') }}
-- Reference a specific version
select * from {{ ref('upstream_project', 'model_name', v=2) }}
プロジェクト間の設定に関する詳細(dependencies.yml、前提条件、オーケストレーション)については、references/cross-project-collaboration.md を参照してください。
ガバナンス機能
dbt Mesh には、4 つのガバナンス機能があります。これらはそれぞれ独立して機能し、段階的に導入できます。
| 機能 | 目的 | 主な設定 | リファレンス |
|---|---|---|---|
| モデルコントラクト | ビルド時に列名、型、制約を保証します | contract: {enforced: true} | references/model-contracts.md |
| グループ | チームやドメインの所有権に基づいてモデルを整理します | group: finance | references/groups-and-access.md |
| アクセス修飾子 | どのモデルが自身のモデルを ref できるかを制御します | access: public / protected / private | references/groups-and-access.md |
| モデルバージョン | 移行期間を設けて破壊的変更を管理します | latest_version: と latest_version_pointer を含む versions:(v1.12 以降) | references/model-versions.md |
YAML の配置ルール
モデルプロパティの YAML ファイルでは、access、group、contract は設定項目であり、必ず config: キーの下にネストする必要があります。モデルプロパティの最上位には配置しないでください。最上位に配置すると、dbt Core では動作するように見える場合がありますが、dbt の Fusion エンジンでは解析エラーが発生します。
# ✅ CORRECT — all governance configs under `config:`
models:
- name: fct_orders
config:
group: finance
access: public
contract:
enforced: true
columns:
- name: order_id
data_type: int
# ❌ WRONG — governance configs as top-level properties (breaks Fusion)
models:
- name: fct_orders
access: public # WRONG — not under config:
group: finance # WRONG — not under config:
contract: # WRONG — not under config:
enforced: true
columns:
- name: order_id
data_type: int
これはプロパティの YAML ファイルにのみ適用されます。dbt_project.yml では、ディレクトリレベルの割り当てに + プレフィックスを使用してください(例:+group: finance、+access: private)。SQL ファイルでは、{{ config(access='public', group='finance') }} を使用してください。
導入順序
1. Groups & Access → 2. Contracts → 3. Versions → 4. Cross-Project Refs
(organize teams) (lock shapes) (manage changes) (split projects)
- グループとアクセス — スキーマの変更は不要です。まずここから始めてください
- コントラクト — YAML で全列とデータ型を宣言する必要があります
- バージョン — モデルに破壊的変更を導入する必要があり、利用者に移行期間が必要な場合に使用します(強制コントラクトの併用を推奨しますが、必須ではありません)
- プロジェクト間の ref — dbt Cloud Enterprise または Enterprise+ と、上流の本番ジョブが正常に実行されていることが必要です。プランレベルが Enterprise 以上であると確認できない場合は、プロジェクト間の ref を設定しないでください。
コントラクトとテストの違い
| コントラクト | データテスト | |
|---|---|---|
| タイミング | ビルド時(事前確認) | ビルド後(事後確認) |
| 対象 | 列名、データ型、制約 | データ品質、ビジネスルール |
| 失敗時 | モデルはマテリアライズされません | モデルは存在しますが、テストに失敗します |
| 用途 | 下流の利用者に対する形状の保証 | 内容の検証と異常の検出 |
コントラクトはテストの実行前に適用されます。コントラクトに違反するとモデルはビルドされず、テストも実行されません。
判断フレームワーク
このモデルに契約を設定すべきですか?
次の場合は契約を使用します:
- モデルの
access: publicが設定されている(特にプロジェクト間で参照される場合) - 他のチームがこのモデルのスキーマの安定性に依存している
- このモデルが公開先(ダッシュボード、ML パイプライン、リバース ETL)にデータを供給している
- 外部の利用者(他の dbt プロジェクト、BI ダッシュボード、リバース ETL)がテーブルを直接クエリしており、カラム名の変更や削除によって影響を受ける
次の場合は契約を追加しないでください:
- ステージングモデル(
stg_*)— これらは内部実装の詳細であり、利用者向け API ではありません - モデルがまだ進化中 — ユーザーが設計を反復していると述べている場合は、スキーマが安定するまで待つよう提案してください
- 外部の利用者がいない — プロジェクトが単独で、プロジェクト間の参照も、スキーマに依存する BI ツールも、公開先もない場合、契約を追加してもメリットがなく、保守の負担が増えるだけです。契約を勧める前に、利用者について確認してください。
- 動的な列/ピボット列 —
pivot()、unpivot()を使用するモデルや、列を動的に生成するモデルは、列のリストが固定されず、動的な値が変わるたびに契約が破綻するため、適していません - エフェメラルモデル — エフェメラルマテリアライゼーションでは契約はサポートされていません
ユーザーが上記の「追加しない」条件に該当するモデルに契約を求めた場合は、理由を説明し、追加しないよう勧めてください。 そのまま要求に応じないでください。ユーザーは契約が不適切だと気付いていない可能性があります。代替案(たとえば、ステージングモデルへのデータテスト、スキーマが安定するまで待つこと、エフェメラルモデルのマテリアライゼーションを切り替えること)を提案してください。
このモデルをバージョン管理すべきですか?
次の場合はモデルをバージョン管理します:
- 利用者が依存しているモデルに破壊的変更(カラムの削除、名前の変更、型の変更)を加える必要がある — 強制適用された契約の有無は問いません。契約があれば変更はビルド時エラーになりますが、契約がなければ変更は通知されないまま下流のモデルやダッシュボードに反映されるため、移行期間はさらに重要になります。「契約がない」ことを理由に、破壊的変更のバージョン管理を見送らないでください。
- 古い形式がなくなる前に利用者に移行期間が必要 — アトミックに更新できない利用者も含みます: 他チームのモデル、公開先、ダッシュボード、テーブルを直接読み取る BI ツールなどです。
次の場合はモデルをバージョン管理しないでください:
- 追加的な変更(新しいカラム)— 破壊的ではありません
- バグ修正 — そのまま修正してください
- 予防目的の「念のため」— 破壊的変更が実際に必要な場合にのみバージョン管理してください
- バージョン管理を省略できるのは、dbt の外部でこのモデルを読み取るものが何もない場合のみです — 公開先も、BI ツールも、他のプロジェクトもありません。1つでも存在する場合は、バージョン管理してください。
バージョンを追加するだけでは移行期間は生まれません — latest_version が決め手です
新しいバージョンの追加と、それを latest_version に昇格することは、移行期間を挟んだ別々のデプロイです。同じ変更にしてはいけません。 これは、「安全な」バージョン変更でもダッシュボードが壊れてしまう、最もよくある原因です。
外部の利用者(BI ツール、リバース ETL、ダッシュボード)は、物理リレーションを名前で読み取ります。ほとんどの場合、バージョンなしの model_name(最新バージョンへのポインタービュー、またはバージョン管理されていない通常のモデル)です。この名前は、latest_version が指すバージョンに解決されます。そのため、次のようになります。
- デプロイ 1 — 導入: 新しい形状の新バージョン(例:
v2)を追加しますが、latest_versionは古いバージョン(v1)のままにします。 これにより、外部の利用者は名前で引き続き古い列を読み取れます。最新バージョンを追跡する、正規の(バージョン接尾辞のない)リレーションを維持してください。latest_versionがまだv1を指している間、その正規リレーションは古い形状を提供します(仕組みは下の表を参照)。新しい形状はmodel_v2で利用できるため、利用者はこれを基に移行できます。管理下にある内部の利用者は、ref('model', v=2)に固定することで早めに移行できます。 - デプロイ 2 — 昇格(後日): すべての外部利用者が移行を確認した後に限り、
latest_versionを2に上げ、v1にdeprecation_dateを設定します。正規リレーションは新しい形状を自動的に指すようになります。リレーション名の変更は不要です。
正規リレーションで古い形状を提供し続けるには、仕組みを1つだけ選んでください(併用禁止):
| dbt バージョン | デフォルトの仕組み | 結果 |
|---|---|---|
| ≥ 1.12 / Fusion | 組み込みの latest_version_pointer(現在はベータ版) | model_v1、model_v2、ポインタービュー model(3つのリレーション) |
| ≤ 1.11 | create_latest_version_view() マクロとプロジェクトの post-hook(dbt が公式に推奨するパターン) | model_v1、model_v2、正規ビュー model(3つのリレーション) |
| いずれのバージョンでも — フォールバック時のみ | 古いバージョンをバージョン接尾辞のない名前に固定する config.alias | 2つのリレーション。デプロイ 2 で手動のエイリアス解除と付け替えが必要 |
常にバージョンに適したポインターを優先してください。config.alias を使うのは、どちらのポインターも利用できない場合、またはユーザーが明示的に使わない意向を示した場合に限ります。同じ名前にポインター/ビューと alias を併用してはいけません(名前の衝突エラーになります)。model-versions.md を参照してください。
latest_version の引き上げ自体が、バージョン接尾辞のない名前を使う利用者にとっての破壊的リリースです。 新しいバージョンを最新バージョンとして導入した場合(または同じ変更で最新バージョンを引き上げた場合)、移行期間はゼロとなり、ダッシュボードはすぐに壊れます。新しいバージョンは必ず最新ではないバージョンとして導入してください。
デプロイ 1 の後、移行期間が実際に確保されていることを確認してください。利用者が読み取るリレーションから、引き続き古い列が返される必要があります。
dbt show --inline "select <old_col> from {{ target.schema }}.<unsuffixed_relation>"
column does not exist エラーが発生した場合、latest_version の昇格が早すぎて、利用者はすでに影響を受けています。
このモデルにはどのアクセスレベルを設定すべきですか?
Is it referenced cross-project?
└─ Yes → public (with contract recommended)
└─ No
Is it referenced outside its group?
└─ Yes → protected (default)
└─ No
Is it internal to a small team?
└─ Yes → private
└─ No → protected (default)
ベストプラクティス: 新しいモデルは private をデフォルトにし、必要な場合にのみアクセス範囲を広げます。デフォルトの protected は許容範囲が広いため、意図的に選択してください。
よくある間違い
| 間違い | なぜ誤りなのか | 修正方法 |
|---|---|---|
複数プロジェクトのセットアップで単一引数の ref() を使用する | 曖昧で、dbt が意図したプロジェクトを解決できない場合があります | プロジェクト間の参照には、必ず ref('project_name', 'model_name') を使用します |
上流プロジェクトのデータに source() を使用する | メッシュでは、上流のデータは生のソースではなく、公開モデルを通じて取得します | 代わりに ref('upstream_project', 'model_name') を使用します |
最初に dependencies.yml を読まない | どの上流プロジェクトが存在するか、またその名前が何かを把握できません | プロジェクト間の SQL を記述する前に、必ず dependencies.yml を読みます |
すべてのモデルを public にする | プロジェクトをまたいで内部実装の詳細を公開してしまいます | 他のチーム向けの API として意図されているモデルのみ public にします |
| 公開モデルのコントラクトを省略する | スキーマの変更によって、下流の利用者が気付かないうちに壊れる可能性があります | access: public のモデルには、必ずコントラクトを適用します |
| 破壊的でない変更にバージョンを付ける | 不必要なメンテナンス負担とウェアハウスのコストが発生します | 破壊的変更(列の削除、型の変更、名前の変更)に限り、バージョンを付けます |
新しいバージョンを latest_version として導入する(または同じ変更で latest を引き上げる) | サフィックスのないリレーション/ポインターが直ちに新しい形を提供するため、名前で読み込む BI ツールやリバース ETL が壊れ、移行期間がなくなります | latest_version を OLD バージョンのままにして新しいバージョンを導入し、利用者が移行を確認した後にのみ引き上げます |
バージョンに応じたポインターが利用可能なのに、サフィックスのない名前を保持するために config.alias を使用する | リレーションが 2 つに集約され、昇格時に自動で参照先を切り替える代わりに、手動でのエイリアス解除と再配線が必要になります | デフォルトでは latest_version_pointer(≥1.12)または create_latest_version_view の post-hook(≤1.11)を使用し、alias は代替手段としてのみ使用します |
dependencies.yml を忘れる | 上流プロジェクトを宣言しないと、プロジェクト間の参照は失敗します | 2 引数の ref() を使用する前に、上流プロジェクトを dependencies.yml に追加します |
| プロジェクト間で非公開モデルを参照する | 他のプロジェクトが利用できるのは public モデルのみです | プロジェクト間での利用を想定したモデルには access: public を設定します |
YAML で access、group、または contract をモデルのトップレベルプロパティとして配置する | Fusion エンジンの解析が失敗します。トップレベルへの配置は有効な設定ではありません | 必ず config: の下にネストします。例:config: { access: public } |
| ステージングモデルにコントラクトを追加する | ステージングモデルは内部向けです。コントラクトを追加しても外部の利用者を保護せず、手間が増えるだけです | 追加しないよう助言し、代わりにデータテストを提案します |
| 動的な列/ピボット列を持つモデルにコントラクトを追加する | データによって列リストが変わり、コントラクトに違反します | 追加しないよう助言し、列リストが固定されていない理由を説明します |
| 外部の利用者を確認せずにコントラクトを追加する | コントラクトはスキーマ境界を保護します。利用者がいなければ、保護すべき境界もありません | コントラクトを追加する前に、このモデルに依存しているのは誰かを尋ねます |
グループ外からすでに参照されているモデルを private にする | 既存の参照が DbtReferenceError で失敗します | まずアクセス範囲を protected に広げるか、呼び出し元を同じグループにリファクタリングします |
| dbt Cloud Enterprise を確認せずにプロジェクト間参照を設定する | 下位のプランではプロジェクト間の ref() を利用できません | dependencies.yml に projects: を追加したり、2 引数の ref() 呼び出しを記述したりする前に、プランレベルを確認します |
上流の本番ジョブが成功していない状態で dependencies.yml を追加する | dbt Cloud は上流の manifest.json を通じてプロジェクト間の参照を解決します。ジョブが実行されていなければ、マニフェストがありません | まず上流プロジェクトで、本番環境へのデプロイを少なくとも 1 回成功させます |