Instructions for developing a canvas dashboard in Rill
Introduction
Canvas dashboards are free-form dashboard resources that display custom chart and table components laid out in a grid. They enable building overview and report-style dashboards with multiple visualizations, similar to traditional business intelligence tools.
Canvas dashboards differ from explore dashboards in important ways:
- Explore dashboards: Best for explorative analysis, drill-down investigations, and letting users freely slice data by any dimension.
- Canvas dashboards: Best for fixed reports, executive summaries, or combining multiple metrics views into a single view.
Canvas dashboards are lightweight resources found downstream of metrics views in the project DAG. Each component within a canvas fetches data individually, typically from a metrics view resource.
When to use canvas dashboards:
- Building executive summaries with KPIs and multiple visualizations
- Creating report-style dashboards with markdown explanations
- Comparing metrics across different metrics views
- Designing custom layouts not possible with explore dashboards
Canvas Structure
A canvas dashboard is defined in a YAML file with type: canvas. Here is the basic structure (most canvas dashboards work great without any of the optional properties here):
Filter settings
filters.pinned and filters.required both reference dimensions or measures by name (they must exist on at least one referenced metrics view). They control different things:
pinned: keeps a filter pill visible at the top of the dashboard so users can change it without opening the filter menu. The dashboard renders normally whether or not the user has set a value.required: the dashboard refuses to render until every required filter has a value. Set a default value indefaults.filtersto satisfy a required filter automatically; otherwise the user is prompted to pick one. Required filters are implicitly pinned — do not also list them underpinned.
Use required for filters that are unsafe or meaningless to omit (e.g. tenant ID, customer scope, region when results would otherwise mix incompatible data).
Default filters
defaults.filters is a map keyed by metrics view name, where each value is a Metrics SQL WHERE expression applied when the dashboard first loads.
Rules for writing defaults.filters:
- Each key must be the name of a metrics view that is referenced by at least one component on the canvas.
- A filter only applies to the components backed by its metrics view. To filter several metrics views, add one entry per metrics view, including duplicating shared dimension/measure names.
- Expressions reference dimension and measure names as defined on that metrics view, not the underlying table columns. Table prefixes, aliases, and subqueries are not supported.
- Write only the expression itself; do not include the
WHEREkeyword. - Supported syntax:
=,!=,<,<=,>,>=,IN,NOT IN,LIKE,ILIKE,IS NULL,IS NOT NULL,BETWEEN, combined withAND,OR, and parentheses. String literals use single quotes.
Layout System
Canvas dashboards use a 12-unit grid system for layout.
Row Configuration
Each row defines a horizontal section with a specific height:
Recommended row heights:
- Markdown headers: 40px - 80px
- KPI grids: 128px - 240px (depending on number of measures)
- Charts and visualizations: 300px - 500px
- Leaderboards: 300px - 450px
- Tables: 300px - 500px
Item Widths
Items within a row share the 12-unit width:
Width guidelines:
width: 12- Full width; use for KPI grids, markdown headers, wide chartswidth: 6- Half width; use for side-by-side comparisonswidth: 4- Third width; use for three equal chartswidth: 3- Quarter width; use for four small components (minimum practical width)
Tab groups
A row entry can be a tab group instead of a plain row. A tab group has a name (URL key) and a list of tabs, each with a label, optional name, and its own rows. Only the active tab loads data. Allowed only at the top level, not nested inside a tab.
Dashboard Composition Best Practices
When building a new canvas dashboard, follow this recommended structure:
- Row 1 - Context: Start with a markdown component providing dashboard title and overview
- Row 2 - Key Metrics: Add a KPI grid with 2-4 of the most business-relevant measures
- Row 3 - Primary Analysis: Split into two halves:
- Left (width 6): A leaderboard showing top entities by a key dimension
- Right (width 6): A time-series chart (line_chart or stacked_bar) showing trends
- Additional Rows: Add 1-2 more rows with relevant charts based on the data
Choosing chart types:
- Time-series analysis: Use
line_chartorarea_chartwith temporal x-axis - Categorical comparisons: Use
bar_chartorstacked_barwith nominal x-axis - Part-to-whole: Use
donut_chartorstacked_bar_normalized - Two-dimensional patterns: Use
heatmap - Dual-metric comparison: Use
combo_chartfor two measures with different scales - Funnel analysis: Use
funnel_chartto visualize sequential stage drop-offs - Two-measure relationships: Use
scatter_plotto explore correlation, clusters, or outliers between two numeric measures
Field guidelines
The field names are case sensitive and should match exactly to the fields present in the metrics view.
Time dimension restrictions: The time dimension (timeseries field from the metrics view) is special and can ONLY be used in the x-axis field for temporal charts. Never use the time dimension in:
- Leaderboard dimensions
- Color fields
- Any other dimension configuration
Component Types
Markdown
Add text content, headers, and documentation:
Best practices:
- Use markdown for dashboard titles, section headers, and explanatory text
- Add blank lines between markdown elements for proper rendering
- Use
---for horizontal rules to separate sections
KPI Grid
Display key metrics with comparison values and sparklines:
With dimension filters:
Leaderboard
Display ranked dimension values by measures:
With multiple dimensions:
Important: Never use time dimensions in leaderboard dimensions. Leaderboards are for categorical ranking, not time-series analysis.
Line Chart
Show trends over time:
With color dimension breakdown:
With custom color mapping:
Bar Chart
Compare values across categories:
With color dimension:
Stacked Bar
Show cumulative values across categories or time:
With multiple measures:
Stacked Bar Normalized
Show proportional distribution (100% stacked):
With custom color mapping for measures:
Area Chart
Show magnitude over time with optional stacking:
With color dimension:
Donut Chart
Show proportional breakdown:
Heatmap
Show patterns across two dimensions:
With custom color range:
With custom Vega-Lite config for colors:
Combo Chart
Combine bar and line on dual axes:
With custom color mapping:
Scatter Plot
Visualize the relationship between two measures, with each point representing a data value. Points can be optionally colored by a dimension and sized by a measure. Useful for correlation analysis and identifying outliers across two numeric metrics.
Interactive controls (rendered automatically):
Shift + Drag: pan the plot- Scroll wheel: zoom in/out
- Double-click: reset zoom and pan to default view
Scatter-specific fields:
x(required): Measure on the x-axis. Must betype: quantitative.y(required): Measure on the y-axis. Must betype: quantitative.dimension(optional): Nominal dimension; each distinct value renders as a separate point. Uselimitto cap the number of points.size(optional): Measure that controls point radius. Must betype: quantitative.color(optional): A color string or a nominal dimension field object to color points by.
Notes:
- Setting
zeroBasedOrigin: falseon both axes is usually preferred for scatter plots, since the interesting range often does not include zero. comparison_time_rangeis not supported for scatter plots.
Funnel Chart
Show flow through stages or conversion processes:
With multiple measures breakdown and step-to-step percentages:
Breakdown modes and color options:
breakdownMode: dimensionwithcolor: stage(different colors per stage) orcolor: measure(similar colors by value)breakdownMode: measureswithcolor: name(different colors per measure) orcolor: value(similar colors by value)
Percent mode (percentMode):
top(default): the on-bar percentage label is each stage's value as a share of the top stage. Use for overall conversion ("how many of the entry-point users reached this stage").previous: the on-bar percentage label is each stage's value as a share of the immediately prior stage. Use for stage-to-stage drop-off ("what fraction of the previous stage continued").- The tooltip always shows both
% of topand% of previousregardless of this setting, so users can disambiguate without the author surfacing both.
Pivot
Create pivot tables with row and column dimensions:
Simple pivot (rows only):
Table
Display tabular data with specified columns:
With dimension filters:
Image
Display external images:
Custom Chart
Build fully custom visualizations using Metrics SQL queries and Vega-Lite specifications. Use this when the built-in chart types are insufficient and you need complete control over the visualization.
Custom charts use metrics_sql to query data from metrics views and vega_spec to define the Vega-Lite visualization. The data from each query is available in the Vega-Lite spec as named datasets: query1, query2, etc.
metrics_sql Query Language
metrics_sql lets you write SELECT queries against metrics views as virtual tables. Each metrics view exposes its dimensions and measures as columns.
Query rules:
- Table names: use the name of any valid metrics view in the project
- Columns: only reference dimension and measure names defined in that metrics view's schema
- Measures are pre-aggregated; never wrap them in
SUM(),COUNT(),AVG(), or other aggregate functions - Grouping is implicit by selected dimensions; you do not need
GROUP BYunless combining with expressions likedate_trunc() - Use
date_trunc('<grain>', <time_dimension>)for time bucketing (grain: minute, hour, day, week, month, quarter, year) - Always include
ORDER BYfor deterministic results - Use
LIMITto keep result sets reasonable (default to 50 for top-N queries, 500 for time series) - Do not alias column names unless strictly required for disambiguation in multi-query specs
- Canvas-level time and dimension filters are injected automatically at runtime; do not add
WHEREclauses for them - You may write multiple queries against different metrics views; results are bound as
query1,query2, etc.
Example queries:
Single view:
Time series:
Cross-view (two queries):
Vega-Lite Specification Rules
- Generate a valid Vega-Lite v5 JSON specification
- Bind data with
{"name": "query1"},{"name": "query2"}, etc. Do not include"data": {"values": [...]}sections; data comes from query results - Set
"width": "container"and"height": "container"so the chart fills its parent - Always include
"autosize": {"type": "fit"}at the top level of the spec - Use
display_namevalues from the metrics view schema for axis titles, legend titles, and tooltip labels - Apply
format_d3orformat_presetfrom measure metadata to axis and tooltip format strings - Pick the best mark type for the data: bar, line, area, point, rect (heatmap), arc (pie/donut), etc.
- Include tooltips with all relevant fields and human-readable formatting
- Use a clean, professional color scheme; prefer Rill's categorical palette when possible
- For temporal axes: set
"type": "temporal"and choose an appropriatetimeUnit - For categorical axes: sort by the primary measure descending unless the user specifies otherwise
- For layered or multi-view charts, use the
"layer"or"concat"composition operators - Avoid unnecessary chart junk: remove gridlines on categorical axes, use concise axis labels
YAML Examples
Simple custom chart with one query:
Time series custom chart:
Custom chart with multiple queries (cross-view):
Additional guidelines:
- The
vega_specfield must contain valid JSON (not YAML) as a string - The
promptfield is optional and stores the user's natural language description for reference - When refining an existing custom chart, apply targeted edits to the existing SQL and spec rather than regenerating from scratch
Field Configuration
Data Types
nominal: Categorical data (strings, categories). Use for dimensions.temporal: Time-based data (dates, timestamps). Use for time dimensions.quantitative: Numerical data (counts, amounts). Use for measures.value: Special type for multiple measures. Use only in color field withrill_measures.
Axis Properties
Sort Options
"x"or"-x": Sort by x-axis values (ascending/descending)"y"or"-y": Sort by y-axis values (ascending/descending)"color"or"-color": Sort by color field (heatmaps)"measure"or"-measure": Sort by measure (donut charts)- Array of values: Custom sort order (e.g.,
["Mon", "Tue", "Wed"])
Y-Axis Properties
Multiple measures:
Color Configuration
Simple color string:
Field-based color:
Custom color mapping:
Color scheme:
Special Field: rill_measures
Use rill_measures in the color field when displaying multiple measures in stacked charts:
Advanced Features
Dimension Filters
Filter component data without affecting other components:
Time Range Override
Override the default time range for a specific component:
Time Filters
Override time settings with detailed control:
Vega-Lite Configuration
Customize chart appearance with Vega-Lite config:

