CH-UICH-UI

Dashboards

Build and share ClickHouse dashboards with SQL-powered panels

Dashboards let you build visual panels backed by SQL queries against your ClickHouse data. Each panel supports time-range interpolation, multiple chart types, and a grid layout.

Available on all plans (limits scale by plan).

Overview

Each dashboard has:

  • A name and description
  • One or more panels — each with its own SQL query, chart type, and layout position
  • A shared time range — applied to all panels simultaneously

A default "System Overview" dashboard is auto-created on first access.

Folders, tags and stars

Open Visualize → Dashboards to get the dashboard browser: a folder tree next to a table of dashboards. Each dashboard opens as its own page, with a breadcrumb that shows its folder path.

  • Folders nest as deep as you like. Names are unique within the same parent. Rename a folder or move it under another one; moving a folder inside its own subtree is refused.
  • Move a dashboard by dragging it onto a folder in the tree, or from its menu.
  • Deleting a folder deletes no dashboards. Its dashboards and subfolders move up one level, in a single transaction.
  • Tags are free-form labels on a dashboard, set when you create it or later.
  • Stars are per person: starring a dashboard does not change what anyone else sees. Anyone who can view dashboards can star them.
  • The command palette (⌘K) shows each dashboard with its folder path.

Creating, moving and tagging dashboards and changing folders needs the analyst or admin role. Folder changes and moves are recorded in the audit log (dashboard.folder.created, dashboard.folder.updated, dashboard.folder.deleted, dashboard.moved).

# Folders
GET    /api/dashboards/folders
POST   /api/dashboards/folders
{ "name": "Payments", "parent_id": "" }          # empty parent_id: top level
PUT    /api/dashboards/folders/{folderId}
{ "name": "Billing", "parent_id": "<folder-id>" } # rename, move, or both
DELETE /api/dashboards/folders/{folderId}         # contents move up one level

# Move a dashboard (empty folder_id: top level)
PUT /api/dashboards/{id}/move
{ "folder_id": "<folder-id>" }

# Replace tags
PUT /api/dashboards/{id}/tags
{ "tags": ["prod", "finance"] }

# Star / unstar for the current user
POST   /api/dashboards/{id}/star
DELETE /api/dashboards/{id}/star

Dashboard CRUD

# List all dashboards (each carries folder_id, tags, and whether you starred it)
GET /api/dashboards

# Create (folder_id and tags are optional)
POST /api/dashboards
{ "name": "Production Metrics", "description": "Key production KPIs", "folder_id": "<folder-id>", "tags": ["prod"] }

# Get dashboard + panels
GET /api/dashboards/{id}

# Update
PUT /api/dashboards/{id}
{ "name": "Updated Name" }

# Delete (cascades to all panels)
DELETE /api/dashboards/{id}

Panel Types

TypeUse Case
tableTabular data display (default)
statSingle metric / KPI card
timeseriesLine/area chart over time (via uplot)
barBar chart (via uplot)

Panel Editor

Each panel is configured with:

FieldDescriptionDefault
NamePanel titleRequired
Panel Typetable, stat, timeseries, or bartable
QuerySQL query (supports template variables)Required
ConfigChart options (JSON): xColumn, yColumns, colors, legendPosition{}

Chart Config

{
  "chartType": "timeseries",
  "xColumn": "timestamp",
  "yColumns": ["value", "count"],
  "colors": ["#3b82f6", "#ef4444"],
  "legendPosition": "bottom"
}

Layout

Panels are arranged on a 12-column grid. Each panel stores its position:

FieldDescriptionDefault
layout_xColumn offset (0-11)0
layout_yRow offset0
layout_wWidth in columns6
layout_hHeight in rows4

Drag and resize panels in the UI to adjust layout. Positions are saved automatically.

Time Range

A shared time-range selector applies to all panels in the dashboard.

Presets

1h, 6h, 24h, 7d, 30d, or custom ISO timestamps.

Persisted in localStorage (ch-ui-dashboard-time-range, default 1h).

Template Variables

Panel queries support time-range macros that are interpolated before execution:

VariableDescriptionExample
$__fromStart timestamp (ISO 8601)2026-03-15T00:00:00Z
$__toEnd timestamp (ISO 8601)2026-03-15T01:00:00Z
$__intervalBucket interval1m, 5m
$__rateRate query modifier—

Example Query

SELECT
  toStartOfInterval(timestamp, INTERVAL $__interval) AS ts,
  count() AS events
FROM default.events
WHERE timestamp BETWEEN '$__from' AND '$__to'
GROUP BY ts
ORDER BY ts

Panel Query Execution

Panel queries use a dedicated endpoint with time-range interpolation:

POST /api/dashboards/query
{
  "query": "SELECT ...",
  "timeout": 30,
  "time_range": { "from": "2026-03-15T00:00:00Z", "to": "2026-03-15T01:00:00Z" },
  "time_field": "timestamp",
  "max_data_points": 1000
}

Timeout max: 5 minutes. max_data_points controls downsampling (default 1000).

The response includes the interpolated query and the resolved variable values.

Panel CRUD

# Create panel
POST /api/dashboards/{id}/panels
{
  "name": "Events per Hour",
  "panel_type": "timeseries",
  "query": "SELECT toStartOfHour(timestamp) AS ts, count() AS n FROM events WHERE timestamp > '$__from' GROUP BY ts ORDER BY ts",
  "config": "{\"xColumn\":\"ts\",\"yColumns\":[\"n\"]}",
  "layout_x": 0, "layout_y": 0, "layout_w": 12, "layout_h": 4
}

# Update panel
PUT /api/dashboards/{id}/panels/{panelId}
{ "name": "Updated Title", "query": "..." }

# Delete panel
DELETE /api/dashboards/{id}/panels/{panelId}

Public Sharing

Any dashboard can be shared with a public read-only link — no CH-UI login required to view it. Create a share from the dashboard's share menu (or via the API) and send the link; revoke it anytime to cut access instantly.

# List share links for a dashboard
GET /api/dashboards/{id}/shares

# Create a share (returns the public token)
POST /api/dashboards/{id}/shares

# Invite someone by email to a share
POST /api/dashboards/{id}/shares/{shareId}/invite

# Revoke a share
DELETE /api/dashboards/{id}/shares/{shareId}

Public viewers load the dashboard at /public/d/<token>. Their panel queries execute through a token-scoped endpoint (/api/public/dashboards/{token}/query) — they can only run the queries the dashboard's panels define, never arbitrary SQL, and they never see your connection credentials.

On this page