dbt Charts で Athena の dbt モデルからダッシュボードを作ってみた

dbt Charts で Athena の dbt モデルからダッシュボードを作ってみた

dbt Charts の CLI を使って、Amazon Athena + Iceberg の dbt project から注文状況のダッシュボードを作成してみました。実装方法と動作確認の結果を紹介します。
2026.10.12

はじめに

データ事業本部のkasamaです。
dbt Charts は、dbt project の中に YAML でダッシュボードを書けるツールです。Athena には、dbt の profile を経由して接続します。今回は dbt Charts の CLI(dct)を使って、Amazon Athena + Iceberg の dbt project から注文状況のダッシュボードを作ってみたいと思います。

前提

dbt Charts とは

dbt Charts は、dbt project の中に YAML でダッシュボードを書くツールです。YAML 1 ファイルを board と呼び、board にクエリ・チャート・レイアウトを定義します。dct が board を読んで SQL を実行し、dct serve でブラウザに表示します。

https://dbtcharts.com/
https://dev.classmethod.jp/articles/dbt-charts-snowflake-dbt-model-yaml-dashboard/

dct(CLI)で Athena を使うときの条件

dct がデータベースに接続する方法は 2 種類あります。

方式 接続設定を書く場所 対応するデータベースの例
直接接続 dbt_charts.yml に type: postgres などと接続設定を書く Postgres、Snowflake、BigQuery、Redshift、DuckDB
dbt_profile dbt の profiles.yml。dbt_charts.yml には type: dbt_profile と profile 名だけを書く Athena、SQL Server、ClickHouse、Spark

直接接続は、dbt_charts.yml だけで接続設定が完結します。dbt_profile は、dbt で使っている profiles.yml の接続設定をそのまま使えます。Web 版ドキュメントの Sources ページでは、Athena の接続方法は type: dbt_profile、インストールは dbt-charts[athena] と書かれています。

https://docs.dbtcharts.com/sources/

dct で Athena を使うときの条件は以下のとおりです。

項目 内容
接続方法 dbt_charts.yml に type: dbt_profile を書く
インストール dbt-charts[athena] でインストールする。extra athena が dbt-athena>=1.10,<2.0 を追加する。

検証環境

dbt-charts(dct)は、2026 年 10 月 12 日時点で最新のリリースである 0.9.1 を使います。リリースの一覧は GitHub で確認できます。

https://github.com/dbt-labs/dbt-charts/releases

項目 値
dbt-charts(dct) 0.9.1
dbt-core 1.12.5
dbt-athena 1.11.1
リージョン ap-northeast-1

アーキテクチャ

dbt と dct はどちらもローカルで実行し、役割を次のように分けています。

  • dbt(dbt build)
    • seed とモデルを Athena で実行し、テーブルと view を作る
    • テーブルの定義は Glue Data Catalog に、データは S3 に保存される
    • target/manifest.json を生成する
  • dct(dbt Charts)
    • dbt の profiles.yml を使って Athena に接続する
    • target/manifest.json を読んで、board の SQL の ref() をテーブル名に置き換える
    • board に書いた SELECT 文を Athena で実行し、dbt が作ったテーブルから取得した結果をグラフにする
    • dct serve で board をブラウザに表示する

サンプルデータは、dbt Labs が dbt のデモ用に公開している jaffle_shop を元にしています。jaffle_shop は架空の EC サイトの顧客と注文のデータです。今回は列の構成を同じにして件数を減らし、seed(CSV)として dbt project に含めました。

https://github.com/dbt-labs/jaffle-shop-classic

dbt のモデルは、seed から staging の view を作り、staging から mart の Iceberg テーブルを作ります。

mart 内容 行数
order_status_summary ステータス別の注文件数 5
customer_orders 顧客ごとの注文数、初回注文日、最終注文日 10

dct は、注文状況を 1 画面で確認する board を 1 つ表示します。board には総注文数、日別注文数、ステータス別件数、顧客別の注文一覧を並べます。テーブルの結合は dbt の mart で済ませ、board の SQL は order_status_summary、customer_orders、stg_orders を読むだけにしています。

実装

実装コードはGitHubに格納しています。

https://github.com/cm-yoshikikasama/blog_code/tree/main/73_dbt_charts_athena

73_dbt_charts_athena/
├── cfn/
│   └── datastore.yaml              # S3 バケットと Glue Database
├── docs/
│   └── architecture.drawio         # 構成図
└── dbt/
    ├── pyproject.toml              # dbt-core と dbt-athena のバージョン固定
    ├── dbt_project.yml
    ├── profiles.yml                # dbt と dct が共通で使う profile
    ├── dbt_charts.yml              # dct の source 定義
    ├── seeds/
    │   ├── raw_customers.csv
    │   └── raw_orders.csv
    ├── models/
    │   ├── staging/
    │   │   ├── stg_customers.sql
    │   │   └── stg_orders.sql
    │   └── marts/
    │       ├── order_status_summary.sql
    │       └── customer_orders.sql
    └── charts/
        └── order_overview.yml      # dct の board

CloudFormation

https://github.com/cm-yoshikikasama/blog_code/blob/main/73_dbt_charts_athena/cfn/datastore.yaml

datastore.yaml では、S3 バケットと Glue Database を定義しています。S3 バケットには seed と mart のデータ、Athena のクエリ結果を置きます。Glue Database は dbt の schema として使います。

dbt

https://github.com/cm-yoshikikasama/blog_code/blob/main/73_dbt_charts_athena/dbt/profiles.yml

profiles.yml は dbt と dct の両方が読みます。バケット名は環境変数 DBT_S3_BUCKET から受け取ります。s3_staging_dir は Athena のクエリ結果の保存先、s3_data_dir は dbt が作るテーブルのデータの保存先です。同じバケットの中で athena-results/ と data/ に分けています。dbt は schema に書いた Glue Database にテーブルと view を作るため、CloudFormation で作った Glue Database 名と同じ値にします。

https://github.com/cm-yoshikikasama/blog_code/blob/main/73_dbt_charts_athena/dbt/dbt_project.yml

dbt_project.yml では、mart を Iceberg テーブル(materialized: table)にしています。dbt-athena は Iceberg のテーブルを作るときに RENAME を使うため、テーブルの S3 パスが毎回異なる必要があります。そのため profiles.yml の s3_data_naming を schema_table_unique にし、data/<スキーマ名>/<テーブル名>/<UUID>/ のように実行ごとに異なるパスにしています。

dbt Charts

https://github.com/cm-yoshikikasama/blog_code/blob/main/73_dbt_charts_athena/dbt/dbt_charts.yml

dbt_charts.yml は dbt project のルートに置き、dct が接続する source を定義します。type: dbt_profile を指定すると、dct は profiles.yml の profile と target を使って Athena に接続します。profiles_dir は dbt project からの相対パスです。今回は profiles.yml を dbt project 直下に置いたため . を指定しました。

https://github.com/cm-yoshikikasama/blog_code/blob/main/73_dbt_charts_athena/dbt/charts/order_overview.yml

SQL の {{ ref('order_status_summary') }} などの ref() は、dct が target/manifest.json を読んで relation 名に置き換えます。dct は ref() の呼び出しを文字列として読み、manifest からテーブル名を引きます。

manifest は dbt parse や dbt build で生成されます。manifest がない状態で ref() を使うと、dct validate は警告(WARN-DBT-MANIFEST-MISSING)を出して成功します。dct render は ref() をテーブル名に置き換えられず、エラー(ERR-DBT-MANIFEST-MISSING)で失敗します。dct を実行する前に、dbt で manifest を生成しておく必要があります。

デプロイ

リポジトリを取得する

サンプルのリポジトリを clone し、73_dbt_charts_athena ディレクトリに移動します。以降のコマンドは、このディレクトリを起点に実行します。

git clone https://github.com/cm-yoshikikasama/blog_code.git
cd blog_code/73_dbt_charts_athena

CloudFormation スタックを作成する

S3 バケットと Glue Database を作成し、Outputs からバケット名を取得します。

aws cloudformation deploy \
  --profile <your-profile> \
  --region ap-northeast-1 \
  --stack-name cm-kasama-dbt-charts-athena \
  --template-file cfn/datastore.yaml

aws cloudformation describe-stacks \
  --profile <your-profile> \
  --region ap-northeast-1 \
  --stack-name cm-kasama-dbt-charts-athena \
  --query 'Stacks[0].Outputs'

dct と dbt をインストールする

dct は、Athena 用の extra を付けた dbt-charts[athena] でインストールします。extra を付けると dbt-athena も一緒に入ります。dbt は dbt/pyproject.toml でバージョンを固定し、uv sync で dbt project 用の仮想環境に入れます。

uv tool install 'dbt-charts[athena]'
cd dbt
uv sync

認証情報とバケット名を環境変数に設定する

profiles.yml が参照する DBT_S3_BUCKET に、スタックの Outputs で取得したバケット名を設定します。dbt と dct が使う AWS profile は AWS_PROFILE で指定します。

export AWS_PROFILE=<your-profile>
export DBT_S3_BUCKET=<your-bucket>

試してみた

dbt build

seed から mart までを作成します。

uv run dbt build --profiles-dir .
1 of 6 OK loaded seed file cm_kasama_jaffle_shop_dev.raw_customers ............. [INSERT 10 in 7.10s]
2 of 6 OK loaded seed file cm_kasama_jaffle_shop_dev.raw_orders ................ [INSERT 20 in 8.18s]
3 of 6 OK created sql view model cm_kasama_jaffle_shop_dev.stg_customers ....... [OK -1 in 1.95s]
4 of 6 OK created sql view model cm_kasama_jaffle_shop_dev.stg_orders .......... [OK -1 in 1.92s]
5 of 6 OK created sql table model cm_kasama_jaffle_shop_dev.customer_orders .... [OK 10 in 8.47s]
6 of 6 OK created sql table model cm_kasama_jaffle_shop_dev.order_status_summary  [OK 5 in 8.59s]
Done. PASS=6 WARN=0 ERROR=0 SKIP=0 NO-OP=0 REUSED=0 TOTAL=6

seed から mart まで 6 件とも問題なく作成できました。

接続と board の検証

dct query で Athena への接続を確認し、dct validate で board の YAML を検証します。どちらも dbt ディレクトリで実行します。

dct query athena 'SELECT 1'
dct validate charts/
_col0
1

1 rows
✓ charts/order_overview.yml OK

編集中は text で確認する

board を編集している間は、--format text で集計結果を確認します。--format text は、チャートごとの値や行数、値の範囲を出力します。

dct render charts/order_overview.yml --format text
# 注文状況

## 注文状況_row0

### kpi_orders (kpi)
- value: 20

### kpi_customers (kpi)
- value: 10

## 注文状況_row1

### 日別注文数 (line)
- x: order_date, y: order_count
- 18 rows | order_count: 1–2

### ステータス別件数 (bar)
- x: status, y: order_count
- 5 rows | status: completed, placed, return_pending, returned, shipped | order_count: 1–9

## 顧客別の注文 (table)
- columns: 顧客名, 注文数, 初回注文日, 最終注文日
- showing first 3 of 10 rows
| customer_name | order_count | first_order_date | last_order_date |
| --- | --- | --- | --- |
| Frank R. | 2 | 2018-01-11 | 2018-01-19 |
| Henry W. | 2 | 2018-01-12 | 2018-01-20 |
| Jennifer F. | 2 | 2018-01-04 | 2018-01-17 |
- 10 rows

総注文数 20 と顧客数 10 は、seed の行数と一致しました。

ターミナルにグラフを描く --format terminal では、ステータス別件数の棒グラフの x 軸ラベルがずれました。5 本の棒に対してラベルが 4 つしか出ず、高さ 9 の棒(placed)の下に completed と表示されます。値の確認には --format text を使います。

   ┌───────────────────────────────────────────────────────────────┐
9.0┤███████████                                                    │
7.5┤███████████  ███████████                                       │
6.0┤███████████  ███████████                                       │
3.0┤███████████  ███████████                                       │
1.5┤███████████  ███████████  ███████████  ███████████  ███████████│
0.0┤███████████  ███████████  ███████████  ███████████  ███████████│
   └─────┬────────────┬────────────┬────────────┬──────────────────┘
    completed    returned   return_pending   shipped

dct serve でブラウザに表示する

dbt Charts は、board を dct serve の URL か hosted の dbt charts Cloud の URL で見る使い方を想定しています。今回は dct serve でローカルに配信します。

dct serve --port 8080

board のファイルパスが URL に対応し、charts/order_overview.yml は http://localhost:8080/order_overview/ で表示されます。ブラウザで開くと、次の画面になりました。

注文状況を 1 画面で確認できる board がブラウザに表示されました。1 段目に総注文数と顧客数、2 段目に日別注文数の折れ線とステータス別件数の横棒、3 段目に顧客別の注文一覧が表示されました。

共有用に HTML を書き出す

board をファイルで共有する場合は、--format html で書き出します。

dct render charts/order_overview.yml --format html

renders/order_overview.htmlが出力されます。この HTML には描画時点のデータが埋め込まれ、表示されるデータは描画時点のまま固定されます。出力形式はほかに svg, png, pdf, terminal, json, text, text-data, yaml, data があります。

最後に

dbt Charts の dct を dbt_profile 経由で Athena + Iceberg の dbt project に接続し、注文状況の board を dct serve で表示してみました。board は dbt project の中に YAML で置き、mart を ref() で参照するので、モデルとダッシュボードを同じリポジトリで管理してプルリクエストでレビューできます。dbt と Athena でデータ基盤を作っているプロジェクトで、モデル開発中に集計結果をグラフで確かめる場面や、BI ツールを導入する前に関係者と数値を確認する場面等で役立つと思います。データを定期的に更新するなら、dbt build と dct render --format html を続けて実行するジョブを CI などで定期実行し、書き出した HTML を共有する形が考えられます。どなたかの参考になれば幸いです。


dbtの導入支援はクラスメソッドにお任せください!

クラスメソッドでは dbt の導入を支援しております。
製品の詳細や支援の内容についてお気軽にお問い合わせください。

dbtの詳細を見る

この記事をシェアする

関連記事