---
title: Writing dashboards
description: Build a dashboard from page.md, typed inputs, SQL data sources, charts, tables, maps, and custom components.
species: guide
---
# Writing dashboards

A dashboard is a `dashboards/<slug>/page.md` document plus optional sibling `.sql` and `.tsx` files. Markdown supplies the narrative. Components turn named query results into charts, tables, numbers, pivots, and maps.

## Create the page

```text
dashboards/revenue/
  page.md
  revenue-daily.sql
```

Put the page title, refresh interval, result cap, and optional theme in frontmatter:

```text
---
title: Revenue
refresh: 4h
max_rows: 2000
theme: supernova
---
```

## Add a query

`revenue-daily.sql` is addressed as `revenue-daily` from the page:

```sql
select
  cast(created_at as date) as day,
  sum(amount) / 100.0 as revenue
from titan.stripe.charges
where status = 'succeeded' and not _deleted
group by day
order by day
```

An inline fence named after its language is also a data source: ```` ```sql revenue-daily ````. Sibling files keep longer queries easier to review.

## Render the result

```text
<Chart data={revenue-daily} type="line" x="day" y="revenue"
       title="Revenue by day" format={{"type":"money","currency":"USD"}} />
```

Built-in data components are `Chart`, `Table`, `BigNumber`, `Pivot`, and `Map`. Chart types are `line`, `bar`, `area`, `donut`, and `scatter`. Put related components inside `<Row>` to share a row.

## Add typed inputs

```text
<DateRange name="period" default="-30d" />
<Select name="currency" options={["usd","eur","gbp"]} default="usd" />
```

Reference inputs in SQL as `$period.start`, `$period.end`, and `$currency`. Values are validated against the declaration and bound as prepared-statement parameters. URL values are never interpolated into SQL.

`TextInput`, `NumberInput`, `Select`, and `DateRange` are supported. A `Select` with `multiple` binds a bounded list. Relative date presets include `-30d`, `-2w`, `-6m`, `-1y`, `mtd`, `ytd`, `today`, and `all`.

## Extend a dashboard

Add `<Name>.tsx` beside `page.md` for a page-specific component, or place a shared component under `dashboards/components/`. Custom components receive bounded table data and the same theme utilities as built-ins.
