Design effective BI dashboards with clear layout, metric hierarchy, and filtering strategy. Use when building a new dashboard, improving an existing one, or establishing dashboard standards. Triggers: 'design dashboard', 'build dashboard', 'BI dashboard', 'dashboard layout', 'visualization', 'reporting dashboard', 'dashboard best practices'.
I'll help you design dashboards that answer business questions clearly — from layout and metric hierarchy to the underlying data requirements.
.claude/data-stack-context.md for BI tool choice and team maturity level.kpi-framework skill if not).Before any layout, answer:
| Type | Audience | Update frequency | Design principle |
|---|---|---|---|
| Executive | C-suite | Daily/weekly | 3-5 KPIs, no drilling |
| Operational | Team managers | Hourly/daily | Trends + alerts, action links |
| Analytical | Data/product teams | On-demand | Filters, drill-downs, raw data |
| Self-serve | Business users | On-demand | Guided exploration, no SQL |
A viewer should understand the dashboard's primary message within 5 seconds. Structure:
┌─────────────────────────────────────────────────────────┐
│ [Dashboard Title] [Date range filter] [Refresh] │
├──────────┬──────────┬──────────┬──────────┬─────────────┤
│ Revenue │ Orders │ Cust. │ Churn │ NPS │ ← KPI row (hero metrics)
│ $2.1M │ 4,832 │ 12,433 │ 2.1% │ 42 │
│ ↑12% │ ↑8% │ ↑5% │ ↓0.3% │ ↑3 │ ← vs. prior period
├──────────┴──────────┴──────────┴──────────┴─────────────┤
│ │
│ Revenue Over Time (line chart) │ Revenue by Segment │ ← Main trends
│ │ (bar or pie chart) │
├──────────────────────────────────┴───────────────────────┤
│ Top Customers Table │ Recent Orders │ Support Queue │ ← Detail tables
└─────────────────────────────────────────────────────────┘
| Data question | Best chart | Avoid |
|---|---|---|
| How is X changing over time? | Line chart | Bar chart (unless few periods) |
| Compare A vs. B vs. C? | Bar chart | Pie chart (> 5 categories) |
| Part of a whole? | Stacked bar or donut | 3D pie |
| Relationship between X and Y? | Scatter plot | Line chart |
| Distribution of a value? | Histogram or box plot | Average alone |
| Progress toward a goal? | Bullet chart or gauge | Red/green traffic lights alone |
| Table of records? | Data table with sorting | Dense pivot table |
Define three levels for every dashboard:
Level 1 — NORTH STAR (1 metric, always visible)
└─ "Monthly Recurring Revenue"
Level 2 — DRIVERS (3-5 metrics that explain the north star)
├─ "New MRR" (expansion)
├─ "Churned MRR" (churn)
└─ "Net Revenue Retention"
Level 3 — DIAGNOSTICS (drill-down metrics, shown on click or filter)
├─ "Churn by Customer Segment"
└─ "Top Churned Accounts"
Before building, confirm:
For dashboard: Revenue Overview
**Grain needed**: Daily revenue by customer_segment and product_category
**Source model**: marts.finance.fct_revenue_daily
**Filters needed**: Date range, customer_segment, product_category, region
**Comparison**: vs. prior period (DoD, WoW, MoM, YoY)
**Aggregations**: SUM(revenue), COUNT(distinct customers), AVG(order_value)
**Freshness required**: By 7am UTC (matches SLA on fct_revenue)
**Performance SLA**: Dashboard loads in < 3 seconds
**BI tool**: Looker
**Explore**: finance/revenue
**Fields to expose**:
- revenue_daily.revenue_date (dimension)
- revenue_daily.customer_segment (dimension)
- revenue_daily.revenue_usd (measure)
- revenue_daily.order_count (measure)
-- Optimize: pre-aggregate to the smallest grain the dashboard needs
-- Instead of hitting fct_orders (line-item level), hit a daily aggregate
-- Bad: BI queries fct_orders at query time
select date_trunc('day', ordered_at), sum(net_revenue_usd)
from fct_orders
where ordered_at >= '2024-01-01'
group by 1 -- Scans 500M rows on every dashboard load
-- Good: dbt pre-aggregates to daily grain
-- models/marts/metrics/mtr_revenue_daily.sql
-- Dashboard queries 365 rows instead of 500M
| BI Tool | Caching approach |
|---|---|
| Looker | PDT with datagroup_trigger |
| Metabase | Question caching (Pro); pre-aggregated models |
| Lightdash | dbt model is the "query"; use incremental models |
| Tableau | Extracts for large datasets; live for < 10M rows |
| Antipattern | Problem | Fix |
|---|---|---|
| 20 KPIs in a row | Cognitive overload | Limit to 5, hide rest behind toggle |
| Raw counts without context | "1,247 orders" — good or bad? | Always show vs. prior period |
| Unlinked date filters | KPI shows March, chart shows April | Sync all tiles to global date filter |
| Pie charts > 5 slices | Unreadable | Bar chart or "Other" bucket |
| Embedded SQL in BI | No reuse, no testing | Move logic to dbt model |
Do not present output from this skill as complete until every command below passes without error. If a command fails, consult "If Something Goes Wrong" before asking the user.
dbt test --select <model> on the source mart to check for freshness or data quality failures upstream.