Skip to content

Board Imports & Dynamic Layouts

Build modular dashboards by importing other board files as layout items.


Importing Files

Include the entire content of another board file by using its path as a layout item. This is useful for splitting large dashboards into smaller, manageable files.

Two rules govern the path:

  • The .yml (or .yaml) extension is required. It is what marks the item as a file import at all. A layout item without it is read as a chart name.
  • The path is relative to the importing file's own directory. For a board sitting directly in charts/, that is charts/. A board in charts/sales/overview.yml imports its sibling as _header.yml, not sales/_header.yml.
# File: charts/main_dashboard.yml
title: "Company Overview"
rows:
  - composition/_report-base.yml   # imports charts/composition/_report-base.yml
  - composition/_dark-brand.yml    # imports charts/composition/_dark-brand.yml

How this compares to extends:

Both anchor a relative path the same way — against the authoring file's own directory. What differs is when an entry counts as a path at all: extends: treats one as a path only if it contains / or ends .yml/.yaml, and resolves a bare name as a theme or a project-root board instead. A layout item has no such fallback — see below.

Dropping the extension does not work

There is no bare-filename form. Omitting the extension does not import anything — the item falls through to chart-name lookup and the board fails to compile:

# File: charts/main_dashboard.yml
rows:
  - composition/_report-base   # no .yml — read as a chart name, not a file
ERR-UNRESOLVED-REFERENCE  Reference 'composition/_report-base' not found in layout item.

Partial Files

Files starting with _ are commonly used for components that aren't meant to be viewed alone:

charts/
├── main_dashboard.yml      # Main entry point
├── _header_section.yml     # Partial: header
├── _sales_kpis.yml         # Partial: sales KPIs
├── _marketing_kpis.yml     # Partial: marketing KPIs
└── _footer.yml             # Partial: footer

Templated Import Paths

An import path may contain Jinja, so the partial a board includes can come from a variable rather than being written inline:

# File: charts/main_dashboard.yml
variables:
  brand:
    default: _report-base
rows:
  - composition/{{ brand }}.yml

The choice is fixed at compile time. The path is resolved while the layout is being built, from the variable's declared default: — so a plain defaulted variable is what this feature takes. It is a way to parameterise a board across projects or environments, not a runtime switch: an interactive input: control cannot change which file gets imported, because runtime values are applied after the layout is already fixed.

Whole files only

An import brings in an entire file. There is no way to pull a single named section out of another board — no anchor syntax, no board.section_id spelling. To share one section, put that section in its own file and import it from both places.


Use Cases

Shared Headers/Footers

# charts/_header.yml
text: |
  # Company Dashboard
  Last updated: {{ now }}
style:
  background: "#1e40af"
  color: white
# charts/any_dashboard.yml
rows:
  - _header.yml
  - main_content
  - _footer.yml

Reusable KPI Rows

# charts/_standard_kpis.yml
cols:
  - revenue_kpi
  - orders_kpi
  - growth_kpi
# charts/sales.yml
rows:
  - _standard_kpis.yml
  - sales_specific_content
# charts/marketing.yml
rows:
  - _standard_kpis.yml
  - marketing_specific_content

Component Library

# charts/components/_metric_card.yml
# A board in charts/ imports it as components/_metric_card.yml; a board in
# charts/sales/ imports it as ../components/_metric_card.yml.
id: metric_card
style:
  background: "#f3f4f6"
  padding: "1rem"
cols:
  - text: "{{ title }}"
  - text: "{{ value }}"

Palette Swatches

A swatch row is just cells with a color() background. color("<palette>.<n>") addresses any stop-list palette by 1-indexed position — see Palette Resolver.

title: "Palette Swatches"
rows:
  - cols:
      - text: " "
        width: "60px"
        style: {background: "vivid-10.1"}
      - text: " "
        width: "60px"
        style: {background: "vivid-10.2"}
      - text: " "
        width: "60px"
        style: {background: "vivid-10.3"}
      - text: " "
        width: "60px"
        style: {background: "vivid-10.4"}
      - text: " "
        width: "60px"
        style: {background: "vivid-10.5"}
      - text: " "
        width: "60px"
        style: {background: "vivid-10.6"}
    height: "60px"
Palette Swatches Data as of 14:52 UTC on 21 Aug 2026 made with dbt charts

Best Practices

File Organization

charts/
├── main.yml                # Entry points
├── sales.yml
├── marketing.yml
├── _components/            # Shared components
│   ├── _header.yml
│   ├── _footer.yml
│   └── _kpi_row.yml
├── partials/               # reusable imported sections
│   ├── numeric.yml         # Numeric column visualization
│   ├── date.yml            # Date column visualization
│   └── categorical.yml     # Categorical visualization
└── _queries/               # Shared queries
    └── _common_queries.yml

Naming Conventions

  • Use _ prefix for partials that aren't standalone files
  • Use descriptive names: _sales_kpis.yml not _kpis.yml
  • Group related partials in folders
  • Name partials by what they visualize: numeric.yml, date.yml

When to Extract to Partials

Extract to a partial when: - Content is used in 2+ places - Section is large and complex - You want to test a section in isolation - The same section is needed under more than one board