I tried creating a dashboard from Athena dbt models using dbt Charts

I tried creating a dashboard from Athena dbt models using dbt Charts

I tried creating an order status dashboard from an Amazon Athena + Iceberg dbt project using the dbt Charts CLI. I will introduce the implementation method and the results of the operation check.
2026.10.12

This page has been translated by machine translation. View original

Introduction

I'm Kasama from the Data Business Division.
dbt Charts is a tool that allows you to write dashboards in YAML within a dbt project. It connects to Athena via a dbt profile. This time, I'd like to use the dbt Charts CLI (dct) to create an order status dashboard from an Amazon Athena + Iceberg dbt project.

Prerequisites

What is dbt Charts?

dbt Charts is a tool for writing dashboards in YAML within a dbt project. A single YAML file is called a board, and you define queries, charts, and layouts in a board. dct reads the board, executes SQL, and displays it in the browser with dct serve.

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

Requirements for using Athena with dct (CLI)

There are two ways for dct to connect to a database.

Method Where to write connection settings Example supported databases
Direct connection Write connection settings in dbt_charts.yml with type: postgres, etc. Postgres, Snowflake, BigQuery, Redshift, DuckDB
dbt_profile dbt's profiles.yml. Write only type: dbt_profile and the profile name in dbt_charts.yml Athena, SQL Server, ClickHouse, Spark

Direct connection makes the connection settings self-contained within dbt_charts.yml. With dbt_profile, you can reuse the connection settings from the profiles.yml you already use with dbt. On the Sources page of the web documentation, the connection method for Athena is listed as type: dbt_profile, and the installation is dbt-charts[athena].

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

The requirements for using Athena with dct are as follows.

Item Details
Connection method Write type: dbt_profile in dbt_charts.yml
Installation Install with dbt-charts[athena]. The athena extra adds dbt-athena>=1.10,<2.0.

Verification Environment

We will use dbt-charts (dct) version 0.9.1, which is the latest release as of October 12, 2026. The list of releases can be checked on GitHub.

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

Item Value
dbt-charts (dct) 0.9.1
dbt-core 1.12.5
dbt-athena 1.11.1
Region ap-northeast-1

Architecture

Both dbt and dct run locally, with their roles divided as follows.

  • dbt (dbt build)
    • Runs seeds and models in Athena to create tables and views
    • Table definitions are stored in Glue Data Catalog, and data is stored in S3
    • Generates target/manifest.json
  • dct (dbt Charts)
    • Connects to Athena using dbt's profiles.yml
    • Reads target/manifest.json and replaces ref() in the board's SQL with table names
    • Executes SELECT statements written in the board against Athena and turns the results retrieved from dbt-created tables into charts
    • Displays the board in the browser with dct serve

The sample data is based on jaffle_shop, which dbt Labs has published for dbt demonstrations. jaffle_shop contains customer and order data for a fictional e-commerce site. This time, we kept the same column structure but reduced the number of rows, and included it as seeds (CSV) in the dbt project.

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

The dbt models create staging views from seeds, and Iceberg tables in the mart from staging.

mart Description Rows
order_status_summary Number of orders by status 5
customer_orders Number of orders per customer, first order date, last order date 10

dct displays one board that lets you check order status on a single screen. The board arranges total order count, daily order count, count by status, and a list of orders by customer. Table joins are handled in dbt's mart, and the board's SQL only needs to read order_status_summary, customer_orders, and stg_orders.

Implementation

The implementation code is stored on GitHub.

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

73_dbt_charts_athena/
├── cfn/
│   └── datastore.yaml              # S3 bucket and Glue Database
├── docs/
│   └── architecture.drawio         # Architecture diagram
└── dbt/
    ├── pyproject.toml              # Fixed versions of dbt-core and dbt-athena
    ├── dbt_project.yml
    ├── profiles.yml                # Profile shared by dbt and dct
    ├── dbt_charts.yml              # dct source definition
    ├── 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 defines the S3 bucket and Glue Database. The S3 bucket stores seed and mart data, as well as Athena query results. The Glue Database is used as the dbt schema.

dbt

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

profiles.yml is read by both dbt and dct. The bucket name is received from the environment variable DBT_S3_BUCKET. s3_staging_dir is the destination for Athena query results, and s3_data_dir is the destination for data in tables created by dbt. They are separated into athena-results/ and data/ within the same bucket. Since dbt creates tables and views in the Glue Database specified in schema, it should be set to the same value as the Glue Database name created with CloudFormation.

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

In dbt_project.yml, the mart is configured as an Iceberg table (materialized: table). Since dbt-athena uses RENAME when creating Iceberg tables, the S3 path of the table needs to be different each time. Therefore, s3_data_naming in profiles.yml is set to schema_table_unique, resulting in a different path for each run, like data/<schema_name>/<table_name>/<UUID>/.

dbt Charts

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

dbt_charts.yml is placed at the root of the dbt project and defines the source that dct connects to. When type: dbt_profile is specified, dct connects to Athena using the profile and target from profiles.yml. profiles_dir is a relative path from the dbt project. Since we placed profiles.yml directly under the dbt project, we specified ..

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

For ref() calls like {{ ref('order_status_summary') }} in SQL, dct reads target/manifest.json and replaces them with relation names. dct reads ref() calls as strings and looks up table names from the manifest.

The manifest is generated by dbt parse or dbt build. If you use ref() without a manifest present, dct validate will issue a warning (WARN-DBT-MANIFEST-MISSING) and succeed. dct render will fail with an error (ERR-DBT-MANIFEST-MISSING) because it cannot replace ref() with table names. You need to generate the manifest with dbt before running dct.

Deployment

Clone the Repository

Clone the sample repository and navigate to the 73_dbt_charts_athena directory. All subsequent commands are run from this directory as the base.

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

Create the CloudFormation Stack

Create the S3 bucket and Glue Database, then retrieve the bucket name from 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'

Install dct and dbt

Install dct with the Athena extra using dbt-charts[athena]. Adding the extra also installs dbt-athena. Pin the dbt version in dbt/pyproject.toml and install it into the virtual environment for the dbt project with uv sync.

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

Set Credentials and Bucket Name as Environment Variables

Set the bucket name obtained from the stack Outputs to DBT_S3_BUCKET, which is referenced by profiles.yml. Specify the AWS profile used by dbt and dct with AWS_PROFILE.

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

Trying It Out

dbt build

Create everything from seeds to 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

All 6 items from seeds to mart were created successfully.

Verifying the Connection and Board

Use dct query to confirm the connection to Athena, and dct validate to validate the board YAML. Run both from the dbt directory.

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

1 rows
✓ charts/order_overview.yml OK

Check with text format while editing

While editing a board, use --format text to check aggregation results. --format text outputs the values, row counts, and value ranges for each chart.

dct render charts/order_overview.yml --format text
# Order Status

## Order Status_row0

### kpi_orders (kpi)
- value: 20

### kpi_customers (kpi)
- value: 10

## Order Status_row1

### Daily Order Count (line)
- x: order_date, y: order_count
- 18 rows | order_count: 1–2

### Count by Status (bar)
- x: status, y: order_count
- 5 rows | status: completed, placed, return_pending, returned, shipped | order_count: 1–9

## Orders by Customer (table)
- columns: Customer Name, Order Count, First Order Date, Last Order Date
- 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

The total order count of 20 and customer count of 10 matched the number of rows in the seeds.

With --format terminal, which draws charts in the terminal, the x-axis labels for the count-by-status bar chart were misaligned. Only 4 labels appeared for 5 bars, and "completed" was displayed below the bar with a height of 9 (placed). Use --format text to verify values.

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

Display in the browser with dct serve

dbt Charts is intended to be viewed either via the dct serve URL or the hosted dbt Charts Cloud URL. This time, we serve it locally with dct serve.

dct serve --port 8080

The board file path corresponds to the URL, so charts/order_overview.yml is displayed at http://localhost:8080/order_overview/. When opened in a browser, the following screen appeared.

A board for checking order status on a single screen was displayed in the browser. The first row shows the total order count and customer count, the second row shows a line chart of daily order counts and a horizontal bar chart of counts by status, and the third row shows a list of orders by customer.

Export to HTML for sharing

To share a board as a file, export it with --format html.

dct render charts/order_overview.yml --format html

renders/order_overview.html is output. This HTML embeds the data at the time of rendering, and the displayed data remains fixed at that point in time. Other output formats include svg, png, pdf, terminal, json, text, text-data, yaml, and data.

Conclusion

We connected dbt Charts' dct to an Athena + Iceberg dbt project via dbt_profile and displayed an order status board with dct serve. Since boards are placed as YAML within the dbt project and reference marts via ref(), you can manage models and dashboards in the same repository and review them via pull requests. This will be useful in projects building a data platform with dbt and Athena — for example, when checking aggregation results as charts during model development, or when confirming numbers with stakeholders before introducing a BI tool. If you want to update data regularly, one approach would be to run a job on CI or similar that executes dbt build followed by dct render --format html, and then share the exported HTML. I hope this is helpful to someone.


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

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

dbtの詳細を見る

Share this article