Chart Types¶
dbt Charts renders most charts through Vega-Lite, but authored chart YAML uses
a typed dbt Charts surface. Choose one of the supported built-in chart types, use
top-level dbt Charts fields such as x, y, color, theta, value, and
href. Arbitrary Vega-Lite spec, mark, encoding, config, transform,
params, and composition blocks are rejected on the authored surface.
Bar Chart¶
Best for: Comparing values across categories
source: examples_db
charts:
bar_example:
query:
sql: |
SELECT DATE_TRUNC('week', date) AS week, SUM(revenue) AS revenue FROM ecommerce_orders GROUP BY week ORDER BY week
type: bar
title: Weekly Revenue
x: week
y: revenue
rows:
- bar_example
| Field | Required | Description |
|---|---|---|
x |
Yes | Category field |
y |
Yes | Value field |
color |
No | Group by color |
Horizontal Bar Chart¶
Use style.orientation: horizontal for horizontal bars - great for long category labels or ranked lists. When sort: is omitted, horizontal bars rank by the value field descending so the largest bar appears at the top.
source: examples_db
charts:
horizontal_bar_example:
query:
sql: |
SELECT product, category, SUM(revenue) AS revenue, SUM(units_sold) AS units_sold FROM ecommerce_orders GROUP BY product, category ORDER BY revenue DESC
type: bar
title: Revenue by Product
x: product
y: revenue
style:
orientation: horizontal
rows:
- horizontal_bar_example
| Style field | Value | Description |
|---|---|---|
style.orientation |
horizontal |
Swaps x/y axes for horizontal bars |
Add sort: when a horizontal bar needs a different category order.
Line Graph¶
Best for: Trends over time
source: examples_db
charts:
line_example:
query:
sql: |
SELECT DATE_TRUNC('week', date) AS week, product, SUM(revenue) AS revenue, SUM(units_sold) AS units_sold FROM ecommerce_orders GROUP BY week, product ORDER BY week, product
type: line
title: Revenue Trend
x: week
y: revenue
color: product
rows:
- line_example
| Field | Required | Description |
|---|---|---|
x |
Yes | Time/category field |
y |
Yes | Value field |
color |
No | Series grouping |
Area Chart¶
Best for: Stacked trends, showing composition over time
source: examples_db
charts:
area_example:
query:
sql: |
SELECT date, category, SUM(revenue) AS revenue, SUM(units_sold) AS units_sold FROM ecommerce_orders GROUP BY date, category ORDER BY date, category
type: area
title: Revenue by Category
x: date
y: revenue
color: category
rows:
- area_example
| Field | Required | Description |
|---|---|---|
x |
Yes | Time/category field |
y |
Yes | Value field |
color |
No | Stack grouping |
Scatter Plot¶
Best for: Relationships between two metrics
source: examples_db
charts:
scatter_example:
query:
sql: |
SELECT * FROM ecommerce_orders WHERE date >= DATE '2024-06-01'
type: scatter
title: Revenue vs Units
x: units_sold
y: revenue
color: category
rows:
- scatter_example
| Field | Required | Description |
|---|---|---|
x |
Yes | First metric |
y |
Yes | Second metric |
color |
No | Category grouping |
size |
No | Bubble size |
Pie Charts¶
Best for: Part-to-whole relationships, proportions
source: examples_db
queries:
sales_by_category:
sql: |
SELECT category, SUM(revenue) AS revenue, SUM(units_sold) AS units_sold FROM ecommerce_orders GROUP BY category ORDER BY revenue DESC
charts:
pie_example:
query: sales_by_category
type: pie
title: Revenue by Category
theta: revenue
color: category
donut_example:
query: sales_by_category
type: donut
title: Units by Category
theta: units_sold
color: category
cols:
- pie_example
- donut_example
| Field | Required | Description |
|---|---|---|
theta |
Yes | Numeric value field (angle encoding) |
color |
No | Category field |
style.inner_radius |
No | Inner radius ratio (hole/outer disk, 0–1). Use type: donut as a shorthand (sets 0.6 by default). |
KPI Display¶
Best for: Single metric highlights, key numbers
source: examples_db
queries:
sales_summary:
sql: |
SELECT SUM(revenue) AS revenue, SUM(units_sold) AS units_sold, COUNT(DISTINCT category) AS category_count FROM ecommerce_orders
charts:
revenue_kpi:
query: sales_summary
type: kpi
label: Total Revenue
value: revenue
units_kpi:
query: sales_summary
type: kpi
label: Units Sold
value: units_sold
cols:
- revenue_kpi
- units_kpi
| Field | Required | Description |
|---|---|---|
value |
Yes | Column reference (string column name) for the headline number or text |
label |
No | Text rendered above the headline value (KPI uses label: instead of title:) |
glyph |
No | Glyph (for example, ▲, ●) drawn before the headline value |
support |
No | Trailing line: { value, label, glyph } |
style.variant |
No | Layout: stacked (default), inline, or compact |
style.value.format |
No | Format for the headline value. Numbers default to compact narrative notation (1.50mn); override notation: analytic for the dense register. Dates default to date_short. Since this can be a board-wide default shared across every KPI, a non-date format that doesn't fit a date-valued headline falls back to date_short there rather than erroring (a mismatched style.support.format errors instead) |
style.support.format |
No | Format for the support value |
style.support.tone |
No | Semantic color for the support value and glyph: positive, negative, warning, or info |
style.value.font |
No | Headline value font; its color also paints the affix and glyph unless they set their own |
style.value.affix.font, style.value.glyph.font |
No | Fonts for the currency/percent affix and the headline glyph |
style.label.font |
No | Label font |
style.label.overflow |
No | How a long label fits: clip, truncate, wrap-two, or wrap |
style.support.font, style.support.glyph.font |
No | Fonts for the support row and its glyph. The support explainer takes every field but color |
style.align |
No | Horizontal alignment of the value, label, and support text: left (default), center, or right |
KPI charts require a query that returns exactly 1 row (for example, SELECT SUM(revenue) as revenue). For status-style KPIs displaying a fixed string, use an inline values query with rows::
query: rows: - status: "On track" value: status
Table¶
Best for: Detailed data view, exact values
source: examples_db
charts:
table_example:
query:
sql: |
SELECT * FROM ecommerce_orders
type: table
title: Sales Data
rows:
- table_example
Tables automatically format numbers, convert snake_case headers to sentence case, and show a "more rows" indicator when data is truncated.
Waterfall and Gantt Recipes¶
Waterfall and Gantt charts are composed from type: bar with a y_start
column. The query owns the start and end values: a waterfall query computes the
running total for each step, while a Gantt query returns the start and finish
dates for each task.
queries:
bridge:
type: values
columns: [step, start_value, end_value, direction]
values:
- [Q1 revenue, 0.0, 120.0, Total]
- [New customers, 120.0, 148.0, Increase]
- [Expansion, 148.0, 161.0, Increase]
- [Churn, 161.0, 139.0, Decrease]
- [Q2 revenue, 0.0, 139.0, Total]
plan:
type: values
columns: [task, start_date, finish_date]
values:
- [Scope, "2026-01-05", "2026-01-23"]
- [Design, "2026-01-19", "2026-02-20"]
- [Build, "2026-02-09", "2026-04-10"]
charts:
waterfall:
query: bridge
type: bar
title: Revenue Bridge
x: step
y: end_value
y_start: start_value
color: direction
style:
overlap: full
gantt:
query: plan
type: bar
title: Delivery Plan
x: task
y: finish_date
y_start: start_date
style:
orientation: horizontal
rows: [waterfall, gantt]
For both shapes, y_start and y must have the same kind: both numeric for a
waterfall, or both dates for a Gantt. See Forecasting with SQL
for the related pattern of returning actual and forecast measures from SQL.
Related¶
- Line Graphs - Detailed line-graph surface and Vega-Lite mapping
- Sector Charts - Detailed pie and donut surface and Vega-Lite mapping
- Maps - Choropleth, point, and bubble maps for geographic data
- More Chart Types - Heatmaps, histograms, and all Vega-Lite marks
- Charts Overview - Field reference and styling
- Interactions - Hover tooltips and
link:click-through links