Quickstart for dbt Charts
Introduction
dbt Charts is a visualization layer that turns YAML files into interactive dashboards. You define queries, charts, and layouts as text and store them in Git alongside your dbt project. Because dbt Charts queries your dbt models directly, your dashboards stay in sync with the same transformations your team already trusts.
You develop dbt Charts locally with the dct command-line tool: it reads a board file, runs its queries against the connection in your dbt profiles.yml, and serves the result in your browser with hot reload as you edit.
In this quickstart, you'll learn how to:
- Create the
charts/directory and a board file by hand. - Write your first five charts — a line, bar, area, pie, and table — from your dbt models.
- Install dbt Charts and preview the board locally.
This guide uses the fusion-jaffle-shop sample project, which is built for v1.12+ and includes marts such as order_items and location_performance. When you finish, you'll have a board that trends revenue over time, compares performance across store locations, and lists location-level key performance indicators (KPIs).
Prerequisites
- You have dbt v1.12+ installed. This guide assumes dbt v2.
- If you're using v2, you must install the v1 adapter for your dbt Charts project to load in your browser. You don't have to do any additional configuration. For example, if you're using Snowflake, run
pip install dbt-snowflakebefore installing dbt Charts. As development on dbt Charts continues, this prerequisite will eventually be removed.
- If you're using v2, you must install the v1 adapter for your dbt Charts project to load in your browser. You don't have to do any additional configuration. For example, if you're using Snowflake, run
- You have Git and basic familiarity with the command line and YAML.
- You have Python 3.9 or later and a package manager such as uv or
pip, to install thedcttool. - You have a working connection to your data platform (Snowflake in this guide) that dbt can build into.
Related content
- Build your dbt models
- How we structure our dbt projects
- dbt Charts query types
- dbt Charts documentation
Clone the sample project and build it
dbt Charts queries tables that already exist in your data platform, so build the project's models before you chart them.
-
Clone the sample project and change into it:
git clone https://github.com/matthewshaver/jaffle-shop-multi-adapter.git
cd fusion-jaffle-shop -
Add a
profiles.ymlfor your data platform. The project'sdbt_project.ymlsetsprofile: default, so name your profiledefaultand give it adevtarget. dbt reads aprofiles.ymlin the project root, or falls back to~/.dbt/profiles.yml. For platform-specific fields, refer to Connection profiles. -
Install the project's packages:
dbt deps -
Seed the raw CSVs and build the models and tests in one command:
dbt buildThe
dbt buildcommand runs seeds, models, snapshots, and tests in dependency order, so you don't need a separatedbt seedstep. For the full list of commands, refer to dbt commands. -
Confirm that a mart the charts read returns rows:
dbt show --inline "select count(*) from {{ ref('order_items') }}"
Record the database and schema that dbt built into — your chart SQL references them. To find them, run dbt list --output json and read each model's relation_name.
Create the charts directory and board file
The sample project doesn't ship any dbt Charts files, so you create them yourself. dbt Charts needs two things: a project config at the root that declares a data source, and at least one board file under charts/.
-
From the project root, create the directory that holds your boards:
mkdir chartsEvery
.yaml,.yml, and.mdfile undercharts/becomes a served page, and nested directories become nested paths. -
Create
dbt_charts.ymlin the project root. Locally, dbt Charts reuses your dbt connection — there's no separate credential setup. Declare a source that points at a dbt profile and target, and boards reference it by name:dbt_charts.ymlsources:
analytics:
type: dbt_profile
profile: default
target: devThe
profileandtargetmatch yourprofiles.yml(defaultanddevin this project). Credentials stay inprofiles.yml, including Snowflake key-pair auth throughprivate_key_pathif your account requires it. -
Create an empty board file at
charts/analytics.ymland give it a title and a source:charts/analytics.ymltitle: "Jaffle Shop overview"
source: analytics
Over the next two steps, you add the queries and charts to this file, then the layout that positions them.
Add your first five charts
Now add five charts to charts/analytics.yml, one for each of the most common chart types. Each chart references a SQL query — defined in a queries: block — and maps that query's output columns to the chart's channels (x, y, theta, color).
Each snippet below shows the query and the chart to add. Charts don't render until you add the layout in the next step, and the complete file appears in Lay out your board.
Each query references its model by fully qualified location. Replace MY_DATABASE.MY_SCHEMA with the database and schema that dbt built your marts into. The SQL uses Snowflake syntax, so adjust functions like date_trunc if you build on another platform.
1. Line chart: revenue over time
Line charts show trends over time. This query aggregates revenue by month from the order_items model.
queries:
revenue_by_month:
sql: |
SELECT date_trunc('month', ordered_at) AS month,
sum(product_price) AS revenue
FROM MY_DATABASE.MY_SCHEMA.order_items
GROUP BY 1
ORDER BY 1
charts:
revenue_trend:
type: line
query: revenue_by_month
x: month
y: revenue
title: "Revenue by month"
2. Bar chart: revenue by location
Bar charts compare a value across categories. This query reads pre-aggregated revenue per store from the location_performance mart.
queries:
revenue_by_location:
sql: |
SELECT location_name,
total_revenue AS revenue
FROM MY_DATABASE.MY_SCHEMA.location_performance
ORDER BY total_revenue DESC
charts:
revenue_by_location:
type: bar
query: revenue_by_location
x: location_name
y: revenue
title: "Revenue by location"
3. Area chart: cumulative revenue
Area charts emphasize accumulation over time. This query uses a window function to running-total monthly revenue.
queries:
cumulative_revenue:
sql: |
SELECT month,
sum(revenue) OVER (ORDER BY month) AS cumulative_revenue
FROM (
SELECT date_trunc('month', ordered_at) AS month,
sum(product_price) AS revenue
FROM MY_DATABASE.MY_SCHEMA.order_items
GROUP BY 1
)
ORDER BY month
charts:
cumulative_revenue:
type: area
query: cumulative_revenue
x: month
y: cumulative_revenue
title: "Cumulative revenue"
4. Pie chart: revenue by product type
Pie (sector) charts show part-to-whole comparisons. This query splits revenue into food and drink. A sector chart uses theta for the wedge size and color for the category.
queries:
revenue_by_type:
sql: |
SELECT CASE WHEN is_food_item
THEN 'Food' ELSE 'Drink' END AS product_type,
sum(product_price) AS revenue
FROM MY_DATABASE.MY_SCHEMA.order_items
GROUP BY 1
charts:
revenue_by_type:
type: pie
query: revenue_by_type
theta: revenue
color: product_type
title: "Revenue by product type"
5. Table: location KPIs
Tables show detailed values. This query lists several columns per location for a scannable KPI table.
queries:
location_kpis:
sql: |
SELECT location_name,
total_revenue,
total_orders,
avg_order_value
FROM MY_DATABASE.MY_SCHEMA.location_performance
ORDER BY total_revenue DESC
charts:
location_kpis_table:
type: table
query: location_kpis
title: "Location KPIs"
Lay out your board
Charts don't appear until you reference them in a layout. Boards use rows: to stack content vertically and cols: to place content side by side. Combine the queries and charts from the previous step under single queries: and charts: blocks, then add a layout that references each chart by its ID.
Your complete charts/analytics.yml should now look like this, with MY_DATABASE.MY_SCHEMA replaced by the database and schema that dbt built your marts into:
title: "Jaffle Shop overview"
source: analytics
queries:
revenue_by_month:
sql: |
SELECT date_trunc('month', ordered_at) AS month,
sum(product_price) AS revenue
FROM MY_DATABASE.MY_SCHEMA.order_items
GROUP BY 1
ORDER BY 1
revenue_by_location:
sql: |
SELECT location_name,
total_revenue AS revenue
FROM MY_DATABASE.MY_SCHEMA.location_performance
ORDER BY total_revenue DESC
cumulative_revenue:
sql: |
SELECT month,
sum(revenue) OVER (ORDER BY month) AS cumulative_revenue
FROM (
SELECT date_trunc('month', ordered_at) AS month,
sum(product_price) AS revenue
FROM MY_DATABASE.MY_SCHEMA.order_items
GROUP BY 1
)
ORDER BY month
revenue_by_type:
sql: |
SELECT CASE WHEN is_food_item
THEN 'Food' ELSE 'Drink' END AS product_type,
sum(product_price) AS revenue
FROM MY_DATABASE.MY_SCHEMA.order_items
GROUP BY 1
location_kpis:
sql: |
SELECT location_name,
total_revenue,
total_orders,
avg_order_value
FROM MY_DATABASE.MY_SCHEMA.location_performance
ORDER BY total_revenue DESC
charts:
revenue_trend:
type: line
query: revenue_by_month
x: month
y: revenue
title: "Revenue by month"
revenue_by_location:
type: bar
query: revenue_by_location
x: location_name
y: revenue
title: "Revenue by location"
cumulative_revenue:
type: area
query: cumulative_revenue
x: month
y: cumulative_revenue
title: "Cumulative revenue"
revenue_by_type:
type: pie
query: revenue_by_type
theta: revenue
color: product_type
title: "Revenue by product type"
location_kpis_table:
type: table
query: location_kpis
title: "Location KPIs"
rows:
- title: "Trends"
cols:
- revenue_trend
- cumulative_revenue
- title: "Locations"
cols:
- revenue_by_location
- revenue_by_type
- title: "Detail"
rows:
- location_kpis_table
Your project root should now contain:
fusion-jaffle-shop/
├── charts/
│ └── analytics.yml # Your board
├── dbt_charts.yml # dbt Charts project config
├── dbt_project.yml
├── models/
├── profiles.yml
└── seeds/
Install dbt Charts and view your board
dbt Charts ships as a Python package with a command-line tool named dct.
-
Install dbt Charts with
uv:uv tool install dbt-chartsOr, with
pip:pip install dbt-charts -
From the project root, validate the board to catch YAML, reference, and SQL errors before it renders:
dct validateWith no arguments,
dct validatechecks every board undercharts/. Pass a path —dct validate charts/analytics.yml— to check one. -
Start the local development server:
dct servedctwalks up from the current directory to finddbt_charts.ymlordbt_project.yml, infers the SQL dialect from your profile target, and picks a port derived from the project directory. -
Open the URL
dctprints. The page lists every board undercharts/. Selectanalytics.ymlto open yours.All five charts render across the three rows: the two trend charts side by side, the two location charts below them, and the KPI table at the bottom. The server hot-reloads as you edit YAML, so keep it running while you iterate.
-
Optionally, render static output to share or to inspect the compiled SQL:
dct render charts/analytics.yml --format html
Troubleshooting
dbt_charts.ymlvalidation error: extra inputs are not permitted —dbt_charts.ymlaccepts a fixed set of top-level keys, such assourcesandserver. Remove anything else, including anamekey.- A chart shows no data — Confirm your
profiles.ymlconnection works (dbt debug) and that the profile's role canSELECTfrom the schemas your queries read. - Some charts show data but others are all zeros — Check whether the empty charts read a model that your dev target filters. A common pattern limits development data to a recent time window, such as a
limit_in_devmacro on orders. On a static demo dataset, that window can exclude every row and zero out the models downstream of it, while models without the filter still populate. Anchor the window to the data's ownmax()timestamp, widen it, or build against a target that skips the filter. - Table or view not found — Confirm the database and schema prefix on each
FROMmatches where dbt actually builds the model. Rundbt list --output jsonand readrelation_nameto get the exact location. - Column not found — A chart's channels (
x,y,theta,color) must match the column names your query'sSELECTreturns. Alias columns in SQL so the names line up. - A chart renders blank — Confirm the chart's
typesupports the channels you set. Sector charts (pie and donut) usethetaandcolor, notxandy. dct validatewarns about re-aggregation — The cumulative revenue query sums an already-aggregated column on purpose, so you can ignore this warning.dct validatestill exits successfully.
What's next
Congratulations 🎉! You built a dbt project locally, created your own dbt Charts directory and board file, wrote five charts from your dbt models, and previewed the board in your browser.
From here, you can:
- Add interactivity with variables so viewers can filter by location or date range.
- Explore more chart types, such as small multiples, layered charts, and maps.
- Add more files under
charts/— each one becomes its own page, so you can break a large dashboard into focused boards. - Chart additional dbt models by adding more SQL queries, or explore other query types such as values and HTTP sources.
Was this page helpful?
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.