Dashboard JSON

A dashboard is a single JSON object. This page is the top-level contract; the authoritative machine-readable version is the published JSON Schema.

Top level

json
{
  "name": "My dashboard",
  "description": "Optional.",
  "version": "1.0.0",
  "settings": { "interval_enabled": false },
  "layout": [ /* tiles */ ]
}
FieldRequiredDescription
nameyesHuman-friendly title (1–140 chars).
descriptionnoOptional summary.
versionnoContent/schema version for future migrations.
settingsnoDashboard runtime settings (see below).
layoutyesArray of one or more tiles.

Settings

json
"settings": { "interval_enabled": true, "interval_ms": 60000 }
FieldDescription
interval_enabledIf true, the dashboard may refresh tiles on an interval.
interval_msDashboard refresh interval in ms (5000–3600000). Required when interval_enabled is true.
Note
Theme is intentionally not part of the dashboard. It is owned by the app, account, user, or deployment environment — so the same dashboard looks right wherever it runs.

Tiles

Each entry in layout is a tile. The minimum is an id, a position, and a block:

json
{
  "id": "notes",
  "position": { "row": 0, "order": 0, "width": 12 },
  "block": { "type": "markdown", "config": { "content": "# Hello" } }
}

A tile may also carry title, card, load, exec, query, depends_on, triggered_by, tags, artifact, and controls. See Tiles for the full field reference.

Responsive layout & orientation

Default behavior (no configuration needed). On wide viewports, tiles lay out using their width (the 12-column grid). On narrow viewports — a phone, or whenever the usable width shrinks, such as when an AI side panel is open next to the dashboard — tiles stack vertically, full-width, in row then order. This reflow is purely presentational: your dashboard JSON is unchanged, and desktop layouts are unaffected. Most dashboards need nothing more.

Two optional fields (schema 1.2.0) let you tune that narrow/mobile experience. Both are additive — omit them and the default stacking above applies.

position.portrait — per-tile overrides applied only in mobile portrait:

json
"position": {
  "row": 1, "order": 2, "width": 12,
  "portrait": { "order": 1, "width": 12, "height": 340, "align": "center" }
}
FieldTypeMeaning
orderintReorder within the same row, in portrait
widthint (1–12)Tile width in portrait (same 12-column convention)
heightint (160–1200)Tile height in pixels in portrait
alignstart / center / endCross-axis alignment in portrait

Overrides stay within the existing row; there is no free positioning. Outside mobile portrait they are ignored.

position.hide_on — hide a tile in a given orientation:

json
"position": { "row": 0, "order": 0, "width": 6, "hide_on": "portrait" }

"portrait" or "landscape". Absent = always shown. Note that desktop monitors count as landscape, so "landscape" hides on desktop too — use "portrait" to simply declutter narrow/portrait views.

Source values

Anywhere the schema allows it, a literal can be replaced with a dynamic reference resolved by the runtime:

json
{ "?source": "region_options" }

StrataBI looks the id up in the source registry, loads the payload from S3, and substitutes the value before execution. See Inputs & parameters.

Validation

Dashboards validate against dashboard.schema.json (JSON Schema 2020-12). Invalid documents are rejected before they run — validate at author time to catch mistakes early.