皆さんこんにちは。広告プロダクト本部プロダクト開発部でデータサイエンティストをしている三浦です。
データ変換のツールとして dbt を使う現場は、ここ数年でかなり増えてきました。TVer でも分析基盤で dbt を使っています。
その dbt を作っている dbt Labs から、最近 dbt Charts(PyPI パッケージ名 dbt-charts、CLI 名 dct)という新しいツールが出てきました。
ダッシュボードを GUI で作るのではなく、YAML で「コードとして」書いてしまうツールです。
dbt を日常的に使っているチームとしては、エコシステムに新しいツールが出てきたら、早めに実際に触って「自分たちの運用に効きそうか」を見極めておきたいところです。公式ドキュメントや dct docs は揃っているものの、日本語の実践記事はまだ少ないので、まずはダミーデータを使って自分で動かしてみることにしました。
先に結論だけ書いておくと、こういう整理になりました。
- dbt Labs 公式の「ダッシュボード as コード」ツール
- 自由に探索したいなら Lightdash、定義をコードで管理して自動生成・配布したいなら dbt Charts、というすみ分け
- ただし pre-1.0 で動きが速いので、本番採用の判断は時期を見たい
この記事では、dbt Charts がどんなものか・導入手順・Lightdash とのすみ分け・触ってみて分かったことを、順番に書いていきます。
dbt Charts とは
dbt Charts は、ダッシュボードを YAML で宣言して、中で SQL を実行し、その結果をチャートとして静的ファイルに書き出すツールです。 「YAML でボードを定義 → 各データソースに SQL を投げる → チャートを描画 → HTML などに出力」という順序で動きます。
作っているのは dbt 本体と同じ dbt Labs です。GitHub の dbt-labs/dbt-charts(Apache-2.0)で開発されています*1。「サードパーティの実験ツール」ではなく、dbt 本家が BI/ダッシュボードをコードに寄せに来た、という位置づけです。
そして、かなり新しいツールでもあります。PyPI で確認できる最初の公開が 2026-08-28(v0.5.0)で、そこから 3 週間足らずで v0.8.0 まで一気に上がっています(この記事で触ったのは 2026-09-15 リリースの v0.8.0 です)。
つなげられるデータソースは幅広く、v0.8.0 で実際に受け付けられた種別は dbt_profile / postgres / snowflake / bigquery / redshift / mysql / trino / duckdb / sqlite / csv / json / parquet / http の 13 種類でした。
ちなみに README には Databricks / Spark も対応と書かれていますが、これは dbt_profile(dbt adapter)経由での対応で、type: databricks のように直接指定すると Unknown source type で弾かれました。
type: に書けるのは上の 13 種で、それ以外のウェアハウスは dbt_profile で profiles.yml の target を参照する形になります。
csv / json / parquet みたいなファイル系のソースは DuckDB で処理されるので、ローカルにファイルさえあれば追加の DB なしでそのまま動きます。
出力形式は svg / html / png / pdf / terminal / json / text / yaml / data の 9 種類で、デフォルトは svg です(v0.8.0 の dct render --format で確認)。
チャートは内部で Vega-Lite の spec に変換され、vl-convert がサーバ側で SVG にします。
そのため出力された HTML には、Vega-Lite や D3 のような JS ライブラリの参照が含まれていませんでした。
なお、まだ pre-1.0(今回は v0.8.0)なので、記法は今後変わる可能性が高そうです。実際、上に書いたとおり短い期間でどんどんバージョンが上がっています。
検証環境
先に今回の検証範囲を書いておきます。試したのは CSV / DuckDB のダミーデータと、bigquery ソースでの実データ接続まで(BigQuery は後半の章で触れます)。一方、dbt の dbt_profile ソースを介した dbt 連携そのものは、今回は検証していません。dbt を使う身としては一番気になる部分なので、次回あらためて試すつもりです。
検証データは DuckDB / CSV のダミー広告データです。
架空のスポンサー 8 キャンペーン × 365 日 × 4 デバイス(CTV / Mobile / PC / Tablet)の日次データにしました。列は date / campaign / device / impressions / completes / clicks の 6 つ、計 11,680 行です。数値はサンプル用に小さめで、実際の配信規模とは無関係です。
ダッシュボードが寂しくならないよう、季節性・キャンペーンの放映期間・週末の視聴増だけスクリプトで作り込んでいます。放映期間といってもオフシーズンの行を消しているわけではなく値を小さくしているだけなので、行数は全キャンペーン分そろって 11,680 で一定です。乱数は使っていないため、何度実行してもまったく同じ CSV になります。
# gen_data.py(抜粋)— すべて架空のスポンサー CAMPAIGNS = [ ("ソライロ生命「みらい応援」", 70_000, 0.87, 0.0050, "year"), ("ことのは温泉 夏の大旅行", 64_000, 0.80, 0.0058, "summer"), ("ホクホク製菓 冬のあまいギフト", 56_000, 0.86, 0.0055, "winter"), # ... 他5件(通年 / 夏 / 冬 / 新生活) ]
date,campaign,device,impressions,completes,clicks 2025-09-01,ソライロ生命「みらい応援」,CTV,40630,34768,204 2025-09-01,ソライロ生命「みらい応援」,Mobile,17957,15629,89 ...
導入手順
実際に叩いたコマンドを、順番に載せていきます。
先に、今回作ったプロジェクトのディレクトリ構成を載せておきます。dbt_charts.yml をルートに置き、ボードの YAML は charts/boards/ に、データは data/ に置く、という構成にしました。これを頭に入れておくと、このあとのコマンドが追いやすいと思います。
dct-verify/
├── dbt_charts.yml # プロジェクト設定(データソース・サーバ)
├── gen_data.py # ダミーデータ生成スクリプト
├── data/
│ └── ad_daily.csv # ダミーデータ(gen_data.py で生成)
└── charts/
└── boards/
└── ad-overview.yml # ボード定義(YAML)
まずインストールですが、今回は uv run --with で都度実行しました(pip install などでの常設インストールは試していません)。
# 検証で使った実行方法(ダミーCSVだけなら [bigquery] は不要) uv run --with dbt-charts dct --help
次に、プロジェクト設定の dbt_charts.yml で、データソースとサーバのポートを宣言します。
server: port: 19410 sources: db: type: csv files: ad_daily: data/ad_daily.csv
ダミーデータを生成します。
python gen_data.py # data/ad_daily.csv (11,680 rows) を生成
ボードを YAML で書きます。KPI・エリア・バーといったチャートを charts: に、画面の並びを rows: に書きます。
title: TVer広告 配信オーバービュー(ダミーデータ) source: db queries: totals: sql: SELECT SUM(impressions) AS total_impressions FROM ad_daily daily_imp: sql: | SELECT date::DATE AS date, SUM(impressions) AS impressions FROM ad_daily GROUP BY 1 ORDER BY 1 charts: kpi_imp: { label: 総インプレッション, type: kpi, query: totals, value: total_impressions } imp_trend: { title: 日次インプレッション, type: area, query: daily_imp, x: date, y: impressions } rows: [kpi_imp, imp_trend]
ここでは最小構成で載せましたが、実際に作ったボードは KPI(総 imp・完視聴率=動画を最後まで見た割合・CTR)+日次トレンド+キャンペーン別+デバイス別+月次 CTR を並べ、cols: で横並びも使っています。この記事のスクリーンショットはそちらのボードです。
書いたボードを検証します。dct validate はコンパイラがかなり厳格で、設定ミスをその場で弾いてくれました。
dct validate # ✓ charts/boards/ad-overview.yml OK
たとえば KPI チャートのタイトルは label: で書く必要があり、うっかり title: と書くとこう落ちます(知らないキーを書いても同様にエラーです)。
╭──────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ ERR-VALIDATION-FIELD Field 'charts.kpi_imp.kpi': Value error, `title:` is not used on `type: kpi`. │ │ Use `label:` instead. │ │ At: charts/boards/ad-overview.yml:58 │ │ Docs: dct docs board │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────╯
落ちた場所は At: にファイルと行番号で出ます(58 行目というのは、上の抜粋ではなく実際に作ったボードのほうです)。Docs: に調べ方まで添えてあるのも助かりました。
最初は戸惑いましたが、ミスに早く気づけるのは安心感があります。
ローカルサーバでプレビューします。
dct serve # http://localhost:19410

変数フィルタを使うと、期間やキャンペーンで絞り込めます。書き方は、variables: に入力ウィジェットを宣言して、SQL 側でマクロを呼ぶだけです。
variables: period: input: daterange label: 期間 default: ["2025-09-01", "2026-08-31"] # データ期間に合わせる campaign: input: multiselect label: CP # ラベルは短めに(理由は下記) column: ad_daily.campaign # 列から選択肢を自動生成
-- 各クエリの WHERE でフィルタを効かせる WHERE {{ filter('campaign', campaign) }} AND {{ filter_date_range('date', period) }}
ちなみにこの label: は最初「キャンペーン」にしていたのですが、ヘッダーの変数表示で文字がラベル枠からはみ出し、値と重なってしまいました(期間 は短いので問題なし)。日本語の長いラベルは幅の計算がうまくいかないようで、CP のように短くしたら直りました。
下は期間を 11〜1 月に絞った例です。KPI もチャートも、指定した期間の集計に切り替わります。

最後に、静的ファイルに書き出します。
ここで地味にハマったのが、render にはボード名ではなく ファイルパスを渡す点でした(ドキュメントには「board YAML へのパス」と明記されているのですが、つい名前を渡してしまいました)。
ボード名(ad-overview)を渡すと ERR-FILE-NOT-FOUND になり、charts/boards/ad-overview.yml とパスで渡したら通りました。
dct render charts/boards/ad-overview.yml --format html --output out.html
書き出した out.html はサーバなしで開ける単体ファイルです(見た目は上と同じボードです)。
BigQuery の実データにつなぐ
ここまではダミーの CSV / DuckDB でしたが、bigquery ソースで BigQuery 上の実データにもつないでみました。
dbt-charts[bigquery] を入れて、dbt_charts.yml のソースを bigquery にするだけです。今回実際に動いたのは、次のような設定でした(プロジェクト名などはマスクしています)。
sources: bq: type: bigquery project: <your-gcp-project> dataset: <your-dataset> location: asia-northeast1 # データセットのロケーション
認証は gcloud の application-default credentials(gcloud auth application-default login 済みの環境)でそのまま通り、今回は method: などのキーは指定していません。あとは [bigquery] 付きで起動すれば動きました。
uv run --with 'dbt-charts[bigquery]' dct serve
クエリを投げてボードをレンダリングするところまで問題なく動いたので、ダミーデータ専用のツールではなく、いま使っている DWH にそのまま向けられることは確認できた形です(実データのスクリーンショットは数値の都合で本記事には載せていません)。
Lightdash とのすみ分け
軸ごとに整理した比較表です。 dbt Charts 列はおおむね今回触って把握した内容、Lightdash 列は公開情報からの整理です*2(Lightdash は今回ハンズオンしていません)。
| 軸 | dbt Charts (dct) | Lightdash(公開情報) |
|---|---|---|
| 位置づけ | ダッシュボード as コード(YAML → 静的/live 出力) | フル BI ツール(Web アプリ・セルフサーブ探索) |
| 主な利用者 | エンジニア/アナリストが書く前提 | 非エンジニア含む(GUI 探索) |
| 定義の置き場 | YAML をリポジトリ管理・PR レビュー可 | dbt の metrics/dimensions + UI |
| インタラクティブ性 | 限定的(変数フィルタはあるが探索型ではない) | 高い(ドリルダウン・自由探索) |
| 出力 | HTML/PDF/PNG/SVG/JSON/terminal ほか = 配布・埋め込み・自動化向き | Web 共有・スケジュール配信 |
| ホスティング | 不要(CLI で render)。別途 Cloud もあり | 要(self-host / Lightdash Cloud) |
| 成熟度 | pre-1.0(v0.8.0・記法が変わりうる) | 成熟(OSS +商用) |
所感
触ってみて「つまずいた」のは、このあたりでした。
- デフォルトのフォントが大きめ(レポート寄り)。サイズは
theme:(これは配色だけが変わる)では変わらず、style.title.levelや KPI のvariant、style.font.sizeで調整した。 daterangeフィルタのデフォルトがデータのない期間だと、チャートが空っぽになった(デフォルトをデータ期間に合わせて回避した)。- 横棒グラフだと日本語のキャンペーン名が見切れた。
max_widthもpaddingも効かず、結局 縦棒+ラベル角度 に変えて収めた。
見切れの話は絵にすると分かりやすいので、横棒(before)と縦棒+ラベル角度(after)を並べておきます。


逆に「これは良い」と感じたのは、render した HTML がサーバ不要の単体ファイルとして完結していて、そのまま配布や資料への埋め込みに使えたことです。
触ってみての実感としては、validate の厳しさやラベル調整のクセも含めて、「クリックで探る」より「仕様を読んで正しく書く」道具だと感じました。慣れれば速いものの、最初の学習コストはそれなりにあります。
まとめ
ざっくり整理すると、自由に探索してドリルダウンしたいなら Lightdash、定義をコードで管理して自動生成・配布したいなら dbt Charts、というすみ分けになりそうです。 dbt Charts は YAML と SQL でボードを宣言して CLI でファイルに書き出せるので、PR レビューや CI に載せやすいのが構造的な強みだと感じました。 一方で、探索的な操作が限定的な点は、採用するなら見込んでおく必要がありそうです。
自分たちの場合、最初に効きそうなのは営業向けの定型レポートです。 決まったフォーマットに指標をまとめる依頼が、同じ切り口で繰り返し発生するので、そのたびに手作業で組み直している部分を減らせそうです。 指標の定義が変わったときに PR の差分として残るのも、すでに dbt でモデルを管理している流れと地続きです。
正直なところ、まだ出たばかりで毎週のようにバージョンが上がっているツールなので、現時点で「使える/使えない」を言い切るのは早いと思っています。TVer のフェーズも見ながら、これからも動向を追って引き続き触っていくつもりです。進展があれば、また続きを書きます。
*1:PyPI のメタデータ上の作者は Fivetran, Inc. になっていますが、開発リポジトリは dbt Labs の dbt-labs/dbt-charts です(dbt Labs と Fivetran は統合済み)。バージョン・公開日は PyPI で確認: https://pypi.org/project/dbt-charts/
*2:Lightdash 公式サイト: https://www.lightdash.com/










