Skip to content

Releases: dbt-labs/dbt-charts

dbt-charts-v0.9.1

Choose a tag to compare

0.9.1 (2026-10-02)

Fixes

  • Hovering a bar, heatmap cell or arc now dims the other marks, and line and area hover markers draw, for charts inside a cols: row. Before, the hover runtime read its background from a rect that charts transparent over their board never paint, so only the tooltip showed.

dbt-charts v0.9.0

Choose a tag to compare

0.9.0 (2026-10-01)

Features

  • The render_board agent tool (dct mcp, dbt_charts.ai) returns a compact text summary instead of JSON with every row, and no longer takes format. Set include_raw_data: true to also get the rows. dct render gains --format text-data.
  • Amazon Athena support: install dbt-charts[athena] and point a source at an Athena target with type: dbt_profile. Closes dbt-labs/dbt-charts#7
  • ClickHouse support: install dbt-charts[clickhouse] and point a source at a ClickHouse target with type: dbt_profile. The read-only user needs readonly = 2. Closes dbt-labs/dbt-charts#26
  • ProjectSession.render_board accepts compile_result= to render an already compiled board without compiling it again.
  • Streamlit support: st_board(board, project_dir=...) from the dbt-charts[streamlit] extra renders a board with live variable controls. Pass a Snowpark session to run snowflake queries through it.
  • dct render --format text shows formatted values: KPI values, chart value ranges, table column labels and formats, plus render warnings.
  • Date and datepicker controls have a "Today" button.
  • Endpoint labels, stacked-bar rails, pie slice labels, and support-table strips derive their label color from each mark color against the chart background, so custom palettes and dark themes get legible labels. Tune it under chart_rendering.color_variants in dbt_charts.yml.
  • Every categorical palette offers derived variants via a trailing token: category.blue.dark, category[2].light, vivid-10.3.pale, or a whole list such as vivid-10.deep. The companion palettes (vivid-10-dark, editorial-10-ghost, ...) and the category_dark, category_light, category_ghost, and category_ink roles are retired. Boards and themes are migrated on load and by dct migrate, except a nested board's own charts: block and a KPI background scale palette, which fail to compile with an error naming the new spelling. dct migrate does not rewrite retired tokens inside a flow-style list.
  • Bars and bar layers accept y_start, for floating bars, dumbbells, waterfalls, candlesticks, and gantts.
  • Board text warns when heading or body text has too little contrast against its row background.
  • Stacked area charts accept style.stack_order; data stacks a y: list in authored order.
  • dct skills intro covers board basics; dct --help, dct skills, and dct init point to it.

Fixes

  • CJK, kana, and hangul text is measured at full width, so text: paragraphs wrap instead of clipping. Closes dbt-labs/dbt-charts#6
  • A single-series horizontal bar with an attached support_table keeps its value-descending sort. Closes dbt-labs/dbt-charts#8
  • dct validate --warehouse no longer crashes with AssertionError on a board that relies on an auto-detected dbt project with no sources:. Closes dbt-labs/dbt-charts#11
  • Jinja inside a query referenced via {{ queries.X }} is rendered instead of sent to the warehouse verbatim. Closes dbt-labs/dbt-charts#12
  • The color-reuse warning scales with palette size and fires on line, area, and stacked bar charts with endpoint labels. Closes dbt-labs/dbt-charts#14
  • Heatmap axes follow query row order by default, and sort: applies to y as well as x. Closes dbt-labs/dbt-charts#13
  • multiples: panels follow query row order instead of sorting alphabetically. Closes dbt-labs/dbt-charts#18
  • A date format on a numeric table column, or a number format on a date column, raises ERR-TABLE-FORMAT-KIND-MISMATCH instead of ERR-INTERNAL. Closes dbt-labs/dbt-charts#16
  • Date-valued KPIs honor date formats and default to date_short. Time directives (time_short, %H:%M) show the actual time instead of midnight. Closes dbt-labs/dbt-charts#15
  • grid.columns must be positive and spans and sizes must not be negative; columns: 0 crashed dct render. Closes dbt-labs/dbt-charts#17
  • Grouped bars with a numeric or boolean color field render instead of raising ERR-CHART-PAINTED-NO-MARKS. Closes dbt-labs/dbt-charts#19
  • WARN-BAR-BAND-WIDTH-TOO-NARROW fires on horizontal bar charts.
  • Warehouse connection failures show an actionable message instead of the driver's raw exception text, which moves to a separate detail field.
  • Date and datepicker controls use their own calendar popover and label format, matching daterange, instead of the browser's native date input.
  • Time axes with an authored time_format no longer overprint tick labels. When no layout fits, labels are dropped and WARN-AXIS-LABEL-COLLISION fires.
  • The cloud-setup skill states its requirements up front: pushing to the default branch and a read-only warehouse credential.
  • dct init skills reports an unwritable directory instead of a PermissionError traceback. dct render --output creates missing parent directories. dct cloud status warns when the working directory is not tied to a project. dct cloud project connect --git-url warns that github.com repositories need the GitHub App flow.
  • A dual-axis layer with its own axis_y.labels.format no longer triggers WARN-LIKELY-CURRENCY-OR-PERCENT-MISSING-FORMATTER. Closes dbt-labs/dbt-charts#30
  • dct render, dct validate, and dct describe resolve a relative board path from the working directory first.
  • "No dbt charts project found" errors say to create dbt_charts.yml; an empty file is enough.
  • ERR-FORMAT-NATIVE-IN-VEGA-SLOT no longer suggests a .1% spec for percent_number formats, which painted values 100 times too large.
  • A support_table aggregate: row no longer adds a phantom "undefined NaN" tooltip row. Closes dbt-labs/dbt-charts#29
  • A support_table row's source: works with column names containing spaces, hyphens, or other special characters. Closes dbt-labs/dbt-charts#32
  • When a stacked bar's color maps one-to-one to its x categories, the legend and stack order follow the x order (sort: or query order) instead of stacked totals. Closes dbt-labs/dbt-charts#28
  • Line and area stroke.width set at board, theme, or meta.yml level is honored instead of replaced by the density-based default. Closes dbt-labs/dbt-charts#37
  • Partial style.charts.title overrides are accepted, and per-family overrides such as style.charts.bar.title apply. Closes dbt-labs/dbt-charts#35
  • style.title.font.family applies to board titles and markdown headings. Closes dbt-labs/dbt-charts#36
  • Role tokens such as category[1] work in conditional_formatting rules. Closes dbt-labs/dbt-charts#34
  • render_dashboard no longer modifies a compile_result passed to it, so rendering the same result twice returns the same status without duplicate warnings.
  • Ctrl-C on dct serve no longer prints an ASGI traceback, and dct mcp serve no longer hangs on shutdown.
  • Redshift queries no longer fail with parameter 'statement_timeout' requires an integer value. Closes dbt-labs/dbt-charts#39
  • Nested items in loose Markdown lists in text: blocks are no longer dropped. Closes dbt-labs/dbt-charts#41
  • Tables whose percentage column widths sum to 100% no longer fire a spurious WARN-TABLE-COLUMNS-OVERFLOW. Closes dbt-labs/dbt-charts#46
  • An unknown dct query source name raises ERR-SOURCE-NOT-FOUND instead of running against an in-memory DuckDB. Closes dbt-labs/dbt-charts#45
  • The static column check resolves models ending in select * from final, so column typos are caught. Closes dbt-labs/dbt-charts#40
  • A diverging gradient's hinge is honored on every chart type. Diverging palettes may have an even number of stops, and the legend labels the hinge. Closes dbt-labs/dbt-charts#48
  • Board style values such as fonts and colors can no longer inject script into rendered boards.
  • dct serve no longer reloads endlessly when the query cache lives inside the project.
  • dct render charts/*.yml skips meta.yml with a warning instead of failing.
  • An empty board file raises ERR-EMPTY-YAML-DOCUMENT instead of ERR-INTERNAL.
  • BigQuery invalid_grant errors note that a new service account key may still be propagating.
  • chart_focus no longer triggers WARN-UNREFERENCED-CHART for every other chart.
  • The value-label crowding warning measures the text actually painted, fixing missed and false warnings.
  • Category axis labels with a d3 number format or labels.font.case no longer clip or overlap.
  • %q, %L, and %Q in time formats render correctly. %c, %x, %X, %Z, and %s fail compile with a clear error.
  • Titles and headings use the body text color in every built-in theme. An authored style.font.color also colors titles unless `style.tit...
Read more

dbt-charts v0.8.0

Choose a tag to compare

0.8.0 (2026-09-15)

Features

  • dct can point at a dbt project outside the board project: --dbt-project-dir on the commands that read a dbt project, the DBT_PROJECT_DIR environment variable behind it, and a dbt_project_dir: key in dbt_charts.yml. The flag wins over the config key, which wins over today's default of the board project directory; a named path that does not exist is an error rather than a silent fallback.
  • dct cloud login opens the approval page in a browser, the way gcloud auth login and gh auth login do; the URL is still printed as a fallback. --no-browser prints it without opening anything, and --start never opens a browser.

Fixes

  • A variable's min, max or step must be a finite number. .inf or .nan published a bound the control read back as NaN, so the board now errors at parse time instead of rendering a control that ignores it.
  • A board rendered to SVG, dct render's default format, is a static picture: every interactive rule left the board's embedded stylesheet for the HTML host page. A standalone .svg, or a page embedding one without the host stylesheet, no longer draws hover tooltips or hover emphasis, no longer shows a text cursor or selection highlight on chart text, and no longer lets a table row's link be clicked through its own cell values. All of it still works in --format html and under dct serve; an embedder that wants it back ships controls_stylesheet() alongside the SVG.
  • Variable controls: a multiselect can be emptied again through its All row, a default: true checkbox can be unchecked, the slider commits a drag on both track and thumb, an option menu opens under its own field instead of drifting away from it, and a pressed control draws a focus ring.
  • A multiselect's option menu stays open while you pick members and reopens after the board re-renders, rather than closing on the first pick.
  • List-valued variables are read from and written as repeated URL keys (?region=west&region=east); dct serve previously kept only the last repeat. Existing JSON-encoded links still resolve.
  • A text variable input draws the value you committed immediately, instead of snapping back to the previous one until the render lands. It also follows its field when the page scrolls or resizes and takes the field's own type size, so it no longer shrinks on a scaled board.
  • A number variable input honors authored min, max and step, clamping and snapping on commit and passing them to the native spinner. An empty text or number field draws its placeholder as a muted hint rather than in the value color.
  • Horizontal bar charts with a support_table beside their category labels no longer reserve the table's width twice, recovering the plot width that indentation cost.
  • The bundled Pygments lexer opens the queries.<name>: | SQL shorthand only under a top-level queries: key, so a nested mapping of that name is no longer highlighted as SQL.
  • A zero baseline rule is no longer painted when the resolved y domain excludes 0. An all-negative line or area chart, or a bar chart with zero: false on data far from zero, drew the rule outside the plot rect, which grew the card to several times its slot height (and stretched every sibling card sharing that row) or, on the independent dual-axis path, rendered the chart blank.
  • dct docs error-reference and dct docs warning-reference work on an installed wheel. Both reference documents were excluded from the package build, so every PyPI install answered those two topics with "error-reference.md is missing from the installed package." and its warning-side equivalent.
  • A board-level style.charts.bar.orientation now reaches its bar charts. Only an inline style.orientation on the chart was consulted, so the board default was a silent no-op while its sibling bar.stack cascaded normally.
  • dct docs lists the three generated references (reference, error-reference, warning-reference) in its topic index, and dct docs all includes the field reference it already advertised as "unsliced". The reference also documents the dbt_charts.yml project-config keys, execution.max_template_output_bytes among them. dct docs all grows from roughly 68KB to 310KB, worth knowing before loading it into an agent's context.
  • Static column attribution no longer gives up on a set operation carrying its own ORDER BY. A UNION of ref() arms with a sort reported WARN-DBT-QUERY-COLUMNS-INDETERMINATE, and dct validate stopped checking that query's columns against the dbt models; the sort restates output columns the arms already attributed, so the query is checked like any other.
  • On a 100%-stacked bar or area chart, an authored percent format is applied to the raw measure value in the hover rows, the printed value labels and the stack total: a count of 20 reads 2000%, its group total of 80 reads 8000%. The normalized stack pins its own 0-100% axis, so the format never reaches the axis it was written for. dbt Charts now warns (WARN-NORMALIZE-PERCENT-FORMAT-READS-RAW-VALUE) when the measure is not already a 0..1 share; a chart whose stack groups each sum to about 1 is silent, since there the raw value and the painted share are the same number.
  • A quantitative axis's ticks below 1 now write out in digits instead of d3's SI sub-unit prefixes, whether the axis has a baked tick ladder or none (a theme leaving ticks.count unset, or multiples.scale: independent). A y-axis over 0.29-0.38 reads 0.3 / 0.35, where it used to read 300m / 350m and be taken for millions. Ticks at or above 1 keep the axis's own k/M compaction, and any axis with an authored literal format: spec or a style.formats alias of its own, or a log scale, is unaffected.
  • A bar chart's sort: orders categories by the sort column's own value rather than by that column's total across the category's rows, so a category holding fewer rows than its neighbors no longer sorts out of place. Sorting a stacked bar by its own measure still orders by the stacked total; a grouped bar sorted by its measure now ranks each category by its smallest series, so sort by a pre-summed column when you want the group total.
  • A support_table below the plot now clears x labels the chart rotated to fit: the gap is measured from the angle the labels are actually drawn at, rather than assumed to be two lines of horizontal text, so a chart with enough categories to auto-tilt its labels no longer needs style.support_table.label_max_lines tuned by hand. Two more cases are covered wherever an authored labels.angle pins the tilt: a date axis whose points sit further apart than their own grain (ten dates 45 days apart, say) shows Vega's own date labels (September, 2024) instead of short 1 Jan labels, and an axis setting labels.font.case: upper or lower paints its labels in that casing. In both cases the painted text can differ in width from the text the gap was measured against.
  • A bar chart with style.orientation: horizontal now gets an auto-generated link on its x category, like a vertical bar. x is always the category or time channel for a bar, never the measure, so orientation no longer suppresses the link.

dbt-charts v0.7.1

Choose a tag to compare

Scatter charts gain multi-y support, the VS Code extension now auto-updates, and dct playground moves to the hosted app.

  • dct playground now opens the hosted playground; --with-playground removed: dct playground no longer boots a local server — it opens/prints the hosted https://play.dbtcharts.com/ URL instead. The dct init --with-playground flag and the playground pip extra are gone (#8888).
  • Scatter charts support multi-y (y: [a, b]): Scatter is now the last cartesian chart type to accept y: [a, b], folding multiple measures into a color series the same way bar, area, and line already do. Tooltips, click interactivity, mirror axis, and related warnings all work with it (#8865).
  • Editor extension installs now auto-update via the Marketplace/Open VSX: dct init code|cursor|vscode installs the dbt Charts extension by its published Marketplace/Open VSX ID instead of side-loading a VSIX from an internal bucket, so it now auto-updates through the editor (#8890).
  • Fixed PDF export failing on deeply nested report boards: dct render --format pdf no longer fails with an SVG-nesting-depth error on large multi-section report boards; PNG export was never affected. Caused by inert no-op group wrappers counting against PDF's 28-level nesting limit (#8859).
  • New warning flags unstacked area charts that read as stacked: dct render/dct validate now warn when a multi-series type: area chart without stacking is visually indistinguishable from a stacked one, since every band fills to zero and the outer edge can be misread as a total (#8852, #8896).

dbt-charts v0.7.0

Choose a tag to compare

A correctness pass across chart rendering, sorting, and style cascading, plus a dct serve security fix, three breaking grammar cleanups, and an 11x faster board parser.

Breaking

  • style.color and style.page.background removed from the board grammar: style.color never affected rendering, and style.page.background only ever painted the exported HTML page background, which is now hardcoded white. Boards authoring style.page migrate automatically; boards authoring style.color fail to compile since there is no safe automatic replacement (#8491).
  • Shipped skills install under a dct- prefix and overwrite unconditionally on upgrade: dct init skills now writes skills into namespaced dct-* directories so they never collide with a project's own skills, and re-running it after an upgrade always refreshes skill bodies instead of silently skipping existing files. The -f/force flag and the old un-prefixed skill directories are gone; skills retired from a release are now swept automatically (#8850).
  • conditional_formatting removed from bar, line, area, scatter, pie, map, and other non-table/KPI charts: the key only ever honored rule.background on these chart types and silently dropped font, glyph, glyph_color, and tone; it's now removed there entirely, with an automatic migration deleting the key from those boards. table and kpi, where it fully works, are unaffected (#8490).
  • Pie/donut chart total format moves from total.format to style.total.value.format: a format string is paint, not authored copy, so it now lives under style.total.value.format alongside every other format field (tooltip, bar total label, axis labels); existing boards using the old total.format key keep working, auto-migrated in place. Authoring style.total.label as a caption now gets a clear error pointing back to total.label: instead of a raw extra-field error (#8828).

Features

  • Hover emphasis now covers lines, areas, scatter, pie/donut, and heatmaps: hovering a chart now visually ties the tooltip to the data it describes on every chart family: bars, histograms, pie/donut slices, and categorical heatmap cells recede toward the background, while lines, areas, and scatter get a marker dot (or ring) and a neutral drop line to the baseline. Charts whose color encodes a value never recede, since dimming would misrepresent the magnitude; turn the whole feature off with style.charts.hover_emphasis.visible: false (#8827).
  • Board renders now cap total template output; oversized boards fail fast instead of exhausting memory: a board render's cumulative Jinja-emitted output is now bounded by a configurable byte ceiling (execution.max_template_output_bytes, default 50MB), raising a new ERR-TEMPLATE-OUTPUT-TOO-LARGE error instead of letting a small amplifying template, such as nested loops, emit an unbounded amount of text (#8735).
  • Zero/threshold baseline now renders on scatter charts and every quantitative axis: the bold rule marking zero (or 100% on a percent axis) now fires on any quantitative axis, not just bar/line/area's measure axis, so a scatter plot crossing zero gets a baseline too. The authoring key grid.zero is renamed grid.threshold and gains a visible switch to turn off just that rule without hiding the whole axis's gridlines (#8343).
  • Single-series area charts now render with a solid fill instead of a washed-out translucent one: the translucent overlap fill, meant to signal overlapping series, was applied even when there was nothing to overlap. A single-series area chart now gets the same solid fill and edge treatment as one authored with style.stack: zero (#8729).
  • dct init starter board now uses real SQL and a working filter: the scaffolded guide.yml board now queries a sample CSV with real SQL and a filter control that actually re-runs the charts, replacing an inert filter and a detour into unsupported markdown boards. New users see a board that behaves correctly from the first render (#8794).
  • dct init starter board no longer ships a sample CSV file: the starter board's sample data now lives inline in the YAML as values queries instead of a scaffolded CSV, so dct init no longer drops a data file into new projects. The region control now drives the board's own explanatory text, since inline rows can't be filtered by a variable (#8808).
  • Board footers show "made with dbt Charts" as text, not a logo: the SVG wordmark lockup in every board's footer is replaced with live text, "made with dbt Charts", set a weight heavier than the surrounding words and still linked to dbtcharts.com. The change also fixes an emphasis bug in the previous text-based footer: PNG and PDF exports could not resolve the CSS rule that bolded the name (#8755).

Fixes

  • dct serve's directory listing no longer lets a crafted filename inject template code: a file whose name contained Jinja syntax could have that name evaluated as template source on the next render pass. Filenames are now passed through as plain variable values, so a filename can never be re-tokenized as code (#8730).
  • Broken chart queries no longer get silently reported as successful: a query failure that wasn't a plain execution error, for example a Jinja template error in SQL or a too-large-template-output error, could lose its error code and be swallowed into an empty chart instead of a recorded failure, making board-artifact generation report success on a board with a genuinely broken chart; this path now surfaces the failure correctly (#8743).
  • Charts no longer silently drop every row when dates fall on period ends: a time series reported at month-end, quarter-end, or similar period-end dates (for example LAST_DAY(month)) with an authored time_unit used to render a full axis with zero data points and no warning; rows are now matched to the bucket they fall inside, and two rows landing in the same bucket now raise a clear ERR-GAP-FILL-BUCKET-COLLISION error instead of one silently overwriting the other (#8739).
  • sort: is respected on layered charts that also use color:: a bar chart authoring color:, layers:, and sort: together silently rendered its x-axis alphabetically, discarding the sort key, direction, and query row order, so a time series could read as scrambled with no warning. Layered categorical x-axes now keep the intended order. One side effect: a layered scatter chart, which has no sort key of its own, now renders in query row order instead of alphabetical (#8785).
  • sort: now works on area, line, and heatmap charts: sort: was previously silently ignored on area, line, and heatmap charts (only bar and scatter honored it), so a warehouse query returning rows in a different order could reverse a chart's axis with no warning. All five documented chart types now honor sort: (#8796).
  • Chart x-axis labels no longer misread month-end, quarter-end, and year-end data as daily: time-axis grain detection now looks at the spacing between dates instead of where they fall on the calendar, so month-end, quarter-end, year-end, and fixed-day-of-month series get the correct monthly/quarterly/yearly tick ladder instead of one gridline and label per day (#8815).
  • Line, area, and scatter charts no longer draw hundreds of extra gridlines on sparse date data: sparse monthly or quarterly data on a line, area, or scatter chart could be misdetected as daily grain, drawing over 1,000 gridlines that rendered as a solid gray band; these chart types now use the same grain-budget check bar charts already had (#8737).
  • style.legend.values now actually reorders and filters legend entries on every chart type: the authored legend order was previously overwritten on most chart families, and matching an entry meant guessing a per-family label spelling. Entries now resolve by rendered label or by column/measure name, and an entry that still can't be matched produces a warning instead of silently vanishing from the legend (#8430).
  • Old boards using dead style keys (style.color, kpi.style.color, and others) no longer fail to load: four keys retired in earlier grammar versions (board-root style.color, kpi.style.color, style.charts.kpi.color, and heatmap's chart-local style.axis_quantitative) are now migrated away automatically instead of raising an extra_forbidden error, so old boards that still authored one of them load again (#8848).
  • dct render now resolves env_var() templating in profiles.yml: profiles fields that dbt renders via Jinja, such as a Snowflake private_key_path built from env_var(...), no longer reach the file system as a literal template string. Any dbt project relying on templated profiles.yml values can now run dct render (#8854).
  • dct query --validate and --describe no longer fail on boards using ref(): both flags previously errored with a raw "Jinja template error: Undefined variable: 'ref' is undefined" on any board query using ref(), even though dct query, dct render, and dct validate ran fine on the same query. They now resolve refs the same way execution does, and a project with no dbt manifest gets a clear ERR-DBT-MANIFEST-MISSING instead of the Jinja error (#8776).
  • Cloud connection tests no longer hang for minutes on an unreachable warehouse: testing a connection to an unreachable warehouse (firewalled, wrong host, black-holed DNS) could previously block a worker for up to 5 minutes; connection tests, including dct cloud connection test, now time out within about 15 seconds and still surface the driver's real error message when one is available (#8805).
  • dct cloud connection create for BigQuery no longer hangs indefinitely, and its failure message stops contradicting itself: BigQuery dataset discovery, location lookup, and per-relation readability probes are now time-bounded like the connection test, so a slow or unreachable warehouse fa...
Read more

dbt-charts v0.6.0

Choose a tag to compare

dbt charts v0.6.0

A broad three-week batch: theme and grammar cleanup (several retired names and fields removed), a wave of dct cloud CLI onboarding fixes, and well over a hundred rendering/authoring bug fixes.

Breaking changes

  • MetricFlow support removed: type: metricflow queries, the MetricFlow-only chart model: sugar, and the Variable.model/dimension/measure fields are no longer supported — boards authoring them will need to migrate to standard SQL/dbt queries. The dbt-charts[metricflow] install extra is also gone, shrinking the install footprint for everyone who wasn't using it. (#7732).
  • Four inert grid keys removed: row_height, default_width, default_height, gap: These keys were accepted by dct validate and documented but silently ignored by rendering. They're now removed from the board schema; use style.layout.grid for spacing and per-item col_span/width for sizing instead. (#7769).
  • description: renamed to notes:: Boards, charts, queries, layout/grid/tab items, and variables now author notes: for non-rendering metadata instead of description:. This is a straight rename with no alias — the field never rendered anything (despite sitting next to title:/label:/text:), and boards still using description: need to be updated by hand; a schema auto-migration was considered but did not ship in this PR. (#7823).
  • style.font/style.border on bar, line, area, scatter, histogram, heatmap, pie, and donut now error instead of silently doing nothing: These eight chart types never had a rendering path for chart-level font/border — the keys parsed but changed nothing, with no warning. The dead fields are removed for those chart types (with a migration for existing boards), so authoring them now surfaces a clear error instead of being silently ignored. (#7840).
  • KPI styling: style.color is gone, tones moves under kpi, align now works: charts.kpi.style.color (a bare string, unlike every other chart family) is removed — use style.font.color or style.value.font.color instead. Semantic tones (used by both KPI and table conditional glyphs) now lives under charts.kpi.tones instead of being read cross-family. KPI text also gains a real align option instead of being hardcoded to left-aligned. Existing boards using the old kpi.style.color key need migration. (#7844).
  • style.charts.table.border no longer accepts width/radius; only markdown rule color remains: width and radius on the table's border style did nothing — the table chart has no outer border to draw. Those fields are removed. The one field that actually did something, color, only ever painted markdown tables and <hr> rules on the board, not the table chart itself; it's been relocated to a board-level markdown style slot so the key name no longer misleads authors into thinking it styles their table chart. (#7858).
  • style.columns no longer hides unlisted table columns: Naming a column under a table's style.columns used to silently drop every column not listed there. Styling and visibility are now separate: style.columns only styles the columns you name, and a new visible: false field on a column entry is the only way to hide one. Boards that relied on the old show-list behavior will start rendering previously-hidden columns until visible: false is added explicitly. (#7870).
  • dct query --json output shape changes: no error field, structured diagnostics: ExecuteQueryResult's duplicate error/errors fields collapse into errors: list[str] only, and diagnostics on query results is now a list of structured objects instead of raw dicts, serialized with null fields omitted. Scripts parsing the old error string field or dict-shaped diagnostics from dct query, --validate --json, or the MCP query tools need updating. (#7926).
  • axis_quantitative removed from heatmap's style surface: Heatmap's axes are both nominal and its magnitude lives on the color channel, so style.axis_quantitative never had any visual effect when authored on a heatmap — it just parsed and did nothing. Authoring it now raises a parse-time error instead of silently no-op-ing. (#7952).
  • Chart attachment field renamed: data_table: is now support_table:: The per-x-tick value strip attached to bar/line/area charts was authored as data_table:, colliding in name (though not in shape) with the standalone type: table chart. It's renamed to support_table: to disambiguate the two; boards using the old key need dct migrate. (#7984).
  • currency and number formats now default to compact, not full precision: Authoring number_format: currency used to render full precision (e.g. $400,000,000.00); the compact form ($400M) required the separate currency_compact name. That's now flipped: bare currency/number are compact by default — matching the engine's own unauthored default — and the old _compact suffixes are gone. Full precision is now reached via currency_full/number_full. Any board authoring the old currency/number/*_compact names will render differently; update format names when upgrading. (#8102).
  • Theme set trimmed from seven to five: Removed the unused plain theme and the near-duplicate solid theme; renamed editorial to clarity (still the shipped default) and cream to paper. stark, vivid, and neon are unchanged. A board authored with an old theme name (theme: or extends:) migrates to its replacement automatically. (#8326).
  • Category-axis number formats now always raise instead of silently misrendering: A numeric format authored on a category axis (scatter's y as a dot plot, heatmap axes, mirrored axes) used to silently drop the format or paint "$NaN"; it's now a designed error everywhere, matching the existing axis_x behavior. Boards that relied on the old silent-drop or NaN rendering now need to fix or remove the format. (#8395).

Features

  • dct warns when it's answering from a stale global build: If bare dct resolves through PATH to a global uv tool install/pip install shim instead of the current checkout's own editable build, it now prints a non-fatal stderr warning naming the mismatch, instead of silently validating against an old, different source tree. (#6998).
  • Consistent category colors across a board's charts: Charts on the same board that share a categorical column (e.g. Electronics, North/South) now read color from one board-wide scale instead of each chart independently sorting its own data and assigning palette slots positionally, so a value keeps the same color everywhere on the board. Adds a category_colors pinning option and a new WARN-CATEGORY-COLOR-PIN-UNSEEN warning when a pinned value never shows up in the data. (#7167).
  • data_table accepts bare column names: data_table: [resolution_rate] now works instead of requiring data_table: [{source: resolution_rate}] for the common case of just listing columns. Also unblocks attaching or detaching a data table strip from Cloud's design panel, which could previously only write simple column lists. (#7661).
  • Incremental refresh for SQL chart queries: A query or board can now declare incremental: <watermark-column> so warm renders refresh only the new tail of a query instead of rescanning the full history — the executor computes a watermark from cached rows and appends what's new. A nested scope can opt out with incremental: false; a bare incremental: true is rejected at parse time since there's no column to key on. (#7671).
  • New dct examples command: dct examples <name> surfaces complete, validated board YAML from the playground gallery — multi-chart layout, query wiring, and variables working together — as a third knowledge surface alongside dct skills and dct docs. (#7680).
  • New hard limits on files: sources protect against runaway disk usage: File sources (files: in sources:) had no cap on per-relation materialized size or on the number of tables in a namespace. New execution.file_source_max_tables (default 500) and execution.file_source_max_bytes (default 5GB) config keys enforce hard errors (ERR-FILE-SOURCE-TOO-MANY-TABLES, ERR-FILE-SOURCE-TOO-LARGE) before a large or wide file source is read. (#7794).
  • Bar and histogram marks gain a fill_opacity field: style.marks.bar.fill_opacity is now accepted (histogram charts share bar marks, so they get it too), matching the opacity field already available on area, point, rule, rect, and circle marks. Useful for keeping bin/bar boundaries visible when bars sit close together. (#7833).
  • KPI cards can now center- or right-align their text: KPI values were hardcoded to left-aligned text. A new align field on KPI styling accepts left | center | right, matching the alignment already available on table columns. (#7873).
  • dct validate --warehouse now checks Postgres, Redshift, and Snowflake: Warehouse-level query validation previously worked only for DuckDB and BigQuery; every other adapter reported unchecked. Postgres, Redshift, and Snowflake now get real validity checks via EXPLAIN. Also adds dct init ci, which scaffolds a GitHub Actions workflow that runs dct validate charts on pull requests. (#7879).
  • New dct impact command finds boards affected by a column change: dct impact COLUMN [--table] [--json] answers "which boards break if this column changes" by building a reverse index from warehouse columns to the boards and queries that reference them, using compiled board SQL and no warehouse connection. Unparseable SQL, SELECT *, and boards that fail to compile are reported as indeterminate rather than silently omitted. (#7893).
  • dct validate catches renamed dbt columns before you run dbt: A new check derives each dbt model's output columns statically from the compiled SQL in target/manifest.json (a bare dbt parse, no build or ...
Read more