---
name: lightdash-dashboards
description: Create and manage Lightdash dashboards programmatically using the Lightdash MCP connector and CLI dashboards-as-code workflow.
disable-model-invocation: true
argument-hint: "[dashboard description or action]"
---

# Lightdash Dashboard Management

Create, modify, and deploy Lightdash dashboards using the MCP connector for data exploration and the Lightdash CLI for dashboards-as-code.

This skill adds **Gemma-specific dashboard patterns and MCP-first workflow** on top of the native `developing-in-lightdash` skill, which provides the full chart type reference (all 9 types), CLI documentation, and dashboard YAML schema.

## Prerequisites

### 1. Lightdash MCP Connector

The MCP connector lets you explore data models, search fields, and run queries.

```bash
claude mcp add lightdash https://<your_instance>.lightdash.cloud/api/v1/mcp -t http
```

See `${CLAUDE_SKILL_DIR}/references/lightdash-mcp-setup.md` for detailed setup instructions.

### 2. Lightdash CLI

The CLI enables downloading and uploading dashboards as YAML files. For the full CLI reference, see the native `developing-in-lightdash` skill.

```bash
npm install -g @lightdash/cli
lightdash login https://<your_instance>.lightdash.cloud
lightdash config set-project
```

### 3. Verify Target Project

**Always check which project you're deploying to before making changes:**

```bash
lightdash config get-project
```

### 4. dbt Project with Lightdash Meta

Models must have Lightdash `config.meta` blocks defining dimensions and metrics. Use the `lightdash-semantics` skill to add these if missing.

## Key Principle: YAML First

**Always prefer editing YAML files over making direct API changes.** The YAML files in `lightdash/charts/` and `lightdash/dashboards/` are the source of truth when CI/CD is configured with `lightdash upload`. Direct API or UI changes will be overwritten on the next deploy.

Workflow:
1. Edit the chart/dashboard YAML files
2. Push to trigger CI deploy (or run `lightdash upload` locally)
3. Only use the REST API for quick verification or when YAML upload is not yet set up

If you must use the API for immediate changes (e.g., live demos), always sync those changes back to the YAML files before committing.

## Workflow

### Step 1: Verify Setup

Check that both MCP and CLI are available:

```bash
lightdash config get-project
```

For MCP, try using the `list_projects` or `find_explores` MCP tool. If MCP is not available, guide the user through setup per the reference doc.

### Step 2: Explore Available Data

Use MCP tools to understand what data is available for the dashboard:

1. **Find explores**: Use `find_explores` to list available tables
2. **Search fields**: Use `search_fields` to find relevant dimensions and metrics matching `$ARGUMENTS`
3. **Check existing dashboards**: Use `find_dashboards` to see if similar dashboards already exist
4. **Test queries**: Use `run_query` with a small set of dimensions/metrics to verify data availability and shape

Document the explores, dimensions, and metrics that will be used.

### Step 3: Design Dashboard Layout

Based on `$ARGUMENTS`, plan the dashboard:

1. **Determine charts needed** — what questions does the dashboard answer?
2. **Select chart types** — see the native `developing-in-lightdash` skill for all 9 chart types (cartesian, pie, table, big_number, funnel, gauge, treemap, map, custom)
3. **Plan grid layout** using the **36-column grid** (row height = 45px):
   - KPI cards across the top: `w: 9, h: 6` (4 cards per row)
   - Standard charts: `w: 18, h: 9` (2 per row)
   - Wide charts/tables: `w: 36, h: 9` (full width)
   - Section headers: `w: 36, h: 1` (heading tile) or `w: 36, h: 2` (markdown tile)
4. **Plan filters** — date range, categorical filters, required vs optional

### Step 4: Create or Download Dashboard Files

**Option A: Modify an existing dashboard**

```bash
lightdash download -d <dashboard-slug-or-url>
```

This creates YAML files in `lightdash/dashboards/` and `lightdash/charts/` that you can edit.

**Option B: Create from scratch**

Create the directory structure:

```
lightdash/
├── dashboards/
│   └── <dashboard-slug>.yml
└── charts/
    ├── <chart-1-slug>.yml
    └── <chart-2-slug>.yml
```

#### Chart YAML essentials

Each chart needs its own YAML file. Include `contentType: chart` at the top level:

```yaml
contentType: chart
name: "Chart Title"
slug: "chart-slug"
spaceSlug: "space-slug"
tableName: "explore_name"
version: 1
chartConfig:
  type: "cartesian"         # or: pie, table, big_number, funnel, gauge, treemap, map, custom
  config:
    layout:
      xField: "explore_name_dimension_name"
      yField:
        - "explore_name_metric_name"
    eChartsConfig:
      series:
        - encode:
            xRef: { field: "explore_name_dimension_name" }
            yRef: { field: "explore_name_metric_name" }
          type: "bar"
          yAxisIndex: 0
metricQuery:
  dimensions:
    - "explore_name_dimension_name"
  metrics:
    - "explore_name_metric_name"
  exploreName: "explore_name"
  filters: {}
  limit: 500
  sorts:
    - descending: false
      fieldId: "explore_name_dimension_name"
  additionalMetrics: []
  customDimensions: []
  tableCalculations: []
tableConfig:
  columnOrder:
    - "explore_name_dimension_name"
    - "explore_name_metric_name"
```

**Field ID format**: `{table_name}_{field_name}` — e.g., `fct_orders_total_revenue`, `fct_orders_date_key_month`.

For time dimensions, append the granularity: `_day`, `_week`, `_month`, `_quarter`, `_year`.

For stacked/grouped charts, add `pivotConfig.columns` listing the dimension to group by.

**Chart scoping:** Use `spaceSlug` for shared charts. Add `dashboardSlug: "my-dashboard"` to scope a chart to a specific dashboard (it won't appear in the space).

#### Dashboard YAML essentials

```yaml
contentType: dashboard
name: "Dashboard Title"
description: "What this dashboard shows"
slug: "dashboard-slug"
spaceSlug: "space-slug"
tabs: []
version: 1

tiles:
  - type: saved_chart
    x: 0
    y: 0
    w: 18
    h: 9
    properties:
      chartSlug: "chart-1-slug"
    tabUuid: null
    tileSlug: "tile-1"

filters:
  dimensions: []
  metrics: []
  tableCalculations: []
```

For the complete YAML schema (all tile types, filter operators, config options), see the native `developing-in-lightdash` skill's dashboard reference.

### Step 5: Validate and Upload

**Always lint before uploading:**

```bash
lightdash lint
```

For new dashboards and charts:

```bash
lightdash upload --force
```

For updates to existing content:

```bash
lightdash upload -d <dashboard-slug> --include-charts
```

For larger changes, test in isolation first:

```bash
lightdash preview --name "my-feature"
# Make changes and iterate
lightdash stop-preview --name "my-feature"
```

### Step 6: Verify

After uploading:

1. Use MCP `find_dashboards` to confirm the dashboard exists
2. Share the dashboard URL with the user
3. Note any charts that may need visual tweaking in the Lightdash UI

## Common Mistakes

| Mistake | Consequence | Prevention |
|---|---|---|
| **Guessing filter values** | Case mismatches cause charts to silently return no data | Run `lightdash sql "SELECT DISTINCT column FROM table LIMIT 50"` and use exact values |
| **Not updating dashboard tile titles after chart rename** | Dashboard tile shows old title — `title` and `chartName` are independent overrides | Download dashboard, find tiles by `chartSlug`, update `title` and `chartName` |
| **Unused dimensions in metricQuery** | "Results may be incorrect" warning — extra dimensions change SQL grouping | Every dimension in `metricQuery.dimensions` must appear in chart config (axis, pivot) |
| **Deploying to wrong project** | Overwrites production content | Always run `lightdash config get-project` before deploying |
| **Missing `contentType` field** | Content type can't be determined without directory structure | Always include `contentType: chart`, `contentType: dashboard`, or `contentType: sql_chart` |

## Common Dashboard Patterns

### Executive KPI Dashboard
- Top row: 3-4 `big_number` tiles (KPIs)
- Middle: 1-2 time series charts (trends)
- Bottom: breakdown table or bar chart

### Revenue Dashboard
- KPIs: total revenue, avg revenue per unit, transaction count
- Time series: monthly revenue trend (bar or line)
- Breakdown: revenue by category/company (stacked bar)
- Table: detailed breakdown with all dimensions

### Operational Dashboard
- KPIs: active count, churned count, new this month
- Lifecycle chart: first/last activity over time
- Status distribution: pie or bar chart
- Detail table: entity-level data

## Tips

- Use `run_query` via MCP to test metric combinations before building charts
- Start with a simple dashboard and iterate — upload frequently
- Dashboard filters automatically apply to all charts that share the filtered field
- Use heading tiles for section breaks and markdown tiles for explanatory notes
- The `spaceSlug` determines which Lightdash space the dashboard appears in — check existing spaces first
- After the first upload, run `lightdash download` to normalize YAML (sorted keys, server-added fields) — commit the result
- **Axis labels**: Add `eChartsConfig.yAxis: [{name: "Label"}]` and `eChartsConfig.xAxis: [{name: "Label"}]` for readable axis titles
- **100% stacking**: Use `layout.stack: stack100` for percentage-normalized stacked bars — no table calculations needed
- **Additional metrics**: Define chart-specific calculated metrics via `metricQuery.additionalMetrics` when a metric doesn't belong in the dbt semantic layer
- **Dimension colors**: Add `colors` mapping in dbt schema YAML on the dimension's `config.meta.dimension` for consistent colors across all charts
- **Data labels**: Add `label: { show: true, position: inside }` to cartesian series; add `showDataLabels: true` for pie charts
- **Total labels on stacked bars**: Add a table calculation as invisible line with labels (see `${CLAUDE_SKILL_DIR}/references/gemma-dashboard-patterns.md`)
- **Tab UUIDs**: Dashboard tab UUIDs must be valid UUIDs — generate with `uuidgen` or Python
- **Chart scoping**: Use `dashboardSlug` to scope a chart to a dashboard (won't appear in the space)
- **Cross-explore filters**: Use `tileTargets` to control which tiles a filter applies to in multi-explore dashboards
- **REST API fallback**: When MCP is unavailable, use the REST API directly with `Authorization: ApiKey <PAT>`. See `${CLAUDE_SKILL_DIR}/references/gemma-dashboard-patterns.md` for endpoint reference
- **API vs YAML drift**: If CI runs `lightdash upload --force`, YAML is the source of truth. Always sync API changes to YAML files to prevent overwrite on next deploy
- **CLI version mismatch**: Pin the CLI to match server: `npm install -g @lightdash/cli@<server-version>`
- **Self-hosted instances**: Use `http://` (not `https://`) if no TLS. Token-based login avoids interactive prompts: `lightdash login http://<host> --token <PAT>`
- **`round` on additionalMetrics**: Add `round: <n>` to control decimal places — `type: average` can produce many decimals

## References

- Gemma dashboard patterns and tips: `${CLAUDE_SKILL_DIR}/references/gemma-dashboard-patterns.md`
- MCP setup: `${CLAUDE_SKILL_DIR}/references/lightdash-mcp-setup.md`
- Full Lightdash reference: see the native `developing-in-lightdash` skill (dashboard reference, chart types, CLI reference, workflows)
