Hosting dbt Charts
dbt Charts is a YAML syntax around SQL for building dashboards. You describe the queries and the charts in YAML, it runs the SQL against your warehouse, and it renders the result.
It suits Stackboard because of what it renders. --format html produces one
standalone document with the whole board drawn as an SVG inside it, fonts
embedded, no scripts loaded from anywhere. That is an app already.
What you need
Section titled “What you need”| dbt Charts | uv tool install dbt-charts, or pip install dbt-charts. Python 3.10 to 3.13 |
| A dbt adapter | For your warehouse: BigQuery, Snowflake, Postgres, Redshift, Databricks, Athena, Spark, Trino, or DuckDB |
| A board | A .yml file describing the queries and charts |
| A git repository | Where the rendered HTML is committed, and what Stackboard reads |
Rendering runs your board’s SQL, so the machine doing it needs warehouse credentials. Stackboard never does: it reads the finished HTML and nothing else.
Render the board
Section titled “Render the board”dct render boards/revenue.yml --format htmlThat writes renders/revenue.html by default. Put it where the repository wants
it instead with --output:
dct render boards/revenue.yml --format html --output dist/index.htmlBoard variables are resolved at render time, passed with --var:
dct render boards/revenue.yml --format html --var region=emea --var days=90Commit the output
Section titled “Commit the output”Stackboard runs no build, so the rendered file is what you commit. A repository holding both the source and the output keeps the board auditable next to the picture it produced:
boards/ revenue.yml the board, read by dbt Chartsdist/ index.html the render, read by StackboardNothing else has to be committed. The render is self-contained, so there are no assets beside it to keep in step.
Publish it
Section titled “Publish it”Add an app pointing at the repository, with the entry path set to the rendered file:
| Field | Value |
|---|---|
| Repository | Your repository URL |
| Entry path | dist/index.html |
Stackboard pins the commit it read, so the board on screen is a specific render you can trace back to a specific commit, not whatever the branch happens to say today.
What you get, and what you do not
Section titled “What you get, and what you do not”| Charts | Drawn as SVG, so they render with no JavaScript and no network |
| Tables | Paginate. Each page is pre-rendered and a small inline script switches between them |
| The data | A snapshot, taken when you rendered. The page does not query anything |
| Filters | Not interactive. Filtering needs a host that can re-run the board’s SQL, and a static page has no way to |
For more than one view of a board, render it more than once. A board rendered per region, committed as several files, becomes several apps or one app per entry path, each pinned and each shareable on its own.
Keeping it current
Section titled “Keeping it current”The snapshot is only as fresh as the last render, so refresh it where your warehouse credentials already live. A scheduled job that renders and commits is enough, and Stackboard picks up the new commit:
name: Render boardon: schedule: - cron: "0 6 * * 1-5" workflow_dispatch:
jobs: render: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: astral-sh/setup-uv@v5 - run: uv tool install dbt-charts - run: dct render boards/revenue.yml --format html --output dist/index.html env: # Whatever your adapter needs DBT_PROFILES_DIR: . - run: | git config user.name "board renderer" git config user.email "noreply@example.com" git add dist/index.html git diff --quiet --staged || git commit -m "chore: render revenue board" git pushA render that produces the same bytes commits nothing, so a board whose numbers have not moved leaves no empty commits behind.
A board with a large table renders a large SVG. The entry document has a 20 MB budget, which is a lot of chart and not much raw table, so cap long tables in the board rather than finding the limit with a render.
