Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
214 changes: 214 additions & 0 deletions guides/developer/dashboards-as-code.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -783,6 +783,220 @@ And the matching tile entry on a dashboard:
tileSlug: orders-by-status
```

## Scheduled deliveries, alerts, and Google Sheets syncs as code

Beyond charts and dashboards, `lightdash download` and `lightdash upload` can also manage three scheduler-driven domains as code:

- **Scheduled deliveries** — recurring email or Slack deliveries of a chart or dashboard as CSV, XLSX, image, or PDF.
- **Alerts** — chart-based notifications that fire when a threshold on a field is met, with a configurable notification frequency.
- **Google Sheets syncs** — recurring exports of a chart or dashboard's results into a specific Google spreadsheet.

Each domain has its own YAML contract and its own opt-in CLI flags, but they share the same content-as-code machinery as charts and dashboards: project-scoped slug identity, no-change detection, forced updates via `--force`, and portable references to charts, dashboards, dashboard tiles, and selected dashboard tabs (tab UUIDs are resolved from portable tab slugs on upload). Uploads preserve the original uploader's ownership on the scheduler side.

The same content-as-code permission scopes (`view:ContentAsCode`, `manage:ContentAsCode`, and so on) that apply to charts and dashboards also apply to these domains. Google Sheets uploads additionally require the personal access token's user to have Google Sheets permission and access to the referenced spreadsheet — the API validates the Google OAuth connection before writing changes.

Schedulers that use variants the content-as-code contract doesn't yet cover (for example webhook targets) are reported in the CLI output rather than downloaded, so it's clear which items were skipped and why.

### Directory layout

After `lightdash download`, these domains live alongside `charts/` and `dashboards/` in your `lightdash/` directory:

```text
lightdash/
├── charts/
├── dashboards/
├── scheduled-deliveries/
│ ├── charts/
│ │ └── weekly-orders-summary/
│ │ └── weekly-orders-email.yml
│ └── dashboards/
│ └── ecommerce-overview/
│ └── monday-morning-digest.yml
├── alerts/
│ └── charts/
│ └── weekly-orders-summary/
│ └── revenue-drop-alert.yml
└── google-sheets/
├── charts/
│ └── weekly-orders-summary/
│ └── orders-sheet-sync.yml
└── dashboards/
└── ecommerce-overview/
└── kpi-sheet-sync.yml
```

Each file is identified by a project-scoped `slug`, and each item references the chart or dashboard it belongs to by its slug too — so files stay valid when copied between projects that share the same chart and dashboard slugs.

### Scheduled deliveries

Scheduled deliveries send a chart or dashboard on a cron schedule to email or Slack. Use them as code when you want deliveries to move alongside their charts and dashboards — for example, when templating a project or when Git-managing a set of executive email digests.

Chart deliveries can carry portable filters and parameter values. Dashboard deliveries can additionally pin a `customViewportWidth` and a portable list of `selectedTabs` (tab slugs, which the server resolves back to tab UUIDs on upload).

```yml Chart scheduled delivery example
contentType: scheduled_delivery
version: 1
slug: weekly-orders-email
name: Weekly orders summary
message: Weekly snapshot of ecommerce orders.
cron: "0 9 * * 1"
timezone: Europe/London
enabled: true
includeLinks: true
resource:
type: chart
slug: weekly-orders-summary
format: csv
options:
formatted: true
limit: table
targets:
- type: email
recipient: analytics@ecom.example
- type: slack
channel: "#ecom-analytics"
filters: null
parameters: null
customViewportWidth: null
selectedTabs: null
```

```yml Dashboard scheduled delivery example
contentType: scheduled_delivery
version: 1
slug: monday-morning-digest
name: Monday morning digest
message: null
cron: "0 8 * * 1"
timezone: Europe/London
enabled: true
includeLinks: true
resource:
type: dashboard
slug: ecommerce-overview
format: image
options:
withPdf: false
targets:
- type: slack
channel: "#ecom-leadership"
filters: null
parameters: null
customViewportWidth: 1400
selectedTabs:
- revenue
- customers
```

Supported formats are `csv`, `xlsx`, `image`, and `pdf`, each with the same options they expose in the UI. Supported targets are `email` (with a `recipient`) and `slack` (with a `channel`). Deliveries that use unsupported variants — for example webhook targets — are reported as skipped during download.

Scheduled deliveries are opt-in on `lightdash download`. Use `--include-scheduled-deliveries` to download every delivery, or pass `--scheduled-deliveries <slugs...>` to download a specific set. On `lightdash upload`, deliveries are uploaded whenever their YAML files are present; use `--skip-scheduled-deliveries` to skip them. See [`lightdash download`](/references/lightdash-cli#lightdash-download) and [`lightdash upload`](/references/lightdash-cli#lightdash-upload) for full details.

### Alerts

Alerts are chart-based notifications that fire when a threshold on a field is met. Alerts as code use their own YAML contract that adds `thresholds` and `notificationFrequency` on top of the scheduler contract, and always target a chart.

Alerts are stored under `alerts/charts/<chart-slug>/<alert-slug>.yml`.

```yml Alert example
contentType: alert
version: 1
slug: revenue-drop-alert
name: Revenue drop alert
message: Weekly revenue fell below the threshold.
cron: "0 9 * * 1"
timezone: Europe/London
enabled: true
includeLinks: true
resource:
type: chart
slug: weekly-orders-summary
thresholds:
- fieldId: orders_total_revenue
operator: greaterThan
value: 1000
notificationFrequency: once
targets:
- type: email
recipient: analytics@ecom.example
filters: null
parameters: null
```

`notificationFrequency` controls how often the alert fires while the threshold remains met (for example, `once` only sends the first time the condition is met until it resets). Alerts are opt-in on `lightdash download`: use `--include-alerts` to download every alert, or `--alerts <slugs...>` for a specific set. On `lightdash upload`, alerts upload whenever their YAML files are present; use `--skip-alerts` to skip them.

### Google Sheets syncs

Google Sheets syncs push a chart or dashboard's results into a specific Google spreadsheet on a schedule. Google Sheets syncs as code are a separate content domain from scheduled deliveries — they live under `google-sheets/` and use their own YAML contract that includes the explicit spreadsheet `destination` metadata.

```yml Chart Google Sheets sync example
contentType: google_sheets_sync
version: 1
slug: orders-sheet-sync
name: Orders sheet
message: null
cron: "0 6 * * *"
timezone: Europe/London
enabled: true
includeLinks: false
resource:
type: chart
slug: weekly-orders-summary
destination:
spreadsheetId: 1AbCdEfGhIjKlMnOpQrStUvWxYz-ecom-example
spreadsheetName: Ecommerce KPIs
organizationName: Ecom Analytics
url: https://docs.google.com/spreadsheets/d/1AbCdEfGhIjKlMnOpQrStUvWxYz-ecom-example/edit
tabName: Orders
filters: null
parameters: null
customViewportWidth: null
selectedTabs: null
```

Dashboard syncs follow the same shape but with `resource.type: dashboard`, and can pin `customViewportWidth` and portable `selectedTabs` the same way dashboard scheduled deliveries do.

`destination.spreadsheetId` is the identifier the sync writes to; the other destination fields (`spreadsheetName`, `organizationName`, `url`, `tabName`) are captured for readability and to help identify the correct spreadsheet across environments. Uploads require the personal access token user to have Google Sheets permission in Lightdash and access to the referenced spreadsheet through the connected Google account — Lightdash validates the Google OAuth connection before persisting the sync, so an invalid or missing connection surfaces as an upload error.

Google Sheets syncs are opt-in on `lightdash download`: use `--include-google-sheets` to download every sync, or `--google-sheets <slugs...>` for a specific set. On `lightdash upload`, syncs upload whenever their YAML files are present; use `--skip-google-sheets` to skip them.

### Typical CLI flows

Scheduled deliveries, alerts, and Google Sheets syncs are **opt-in** on `lightdash download`. A plain `lightdash download` downloads charts, dashboards, and spaces, and leaves the scheduler-driven domains untouched — you opt each category in per-run.

Download everything, including every optional category (scheduled deliveries, alerts, Google Sheets syncs, virtual views, and data apps up to `--apps-limit`):

```bash
lightdash download --include-all
```

Opt in to one category at a time:

```bash
lightdash download --include-scheduled-deliveries
lightdash download --include-alerts
lightdash download --include-google-sheets
```

Download only a specific scheduled delivery, alert, or Google Sheets sync by slug. Passing a slug filter also opts that category in for the run:

```bash
lightdash download --scheduled-deliveries weekly-orders-email
lightdash download --alerts revenue-drop-alert
lightdash download --google-sheets orders-sheet-sync
```

Upload behaves the other way around: it uploads whatever it finds under `scheduled-deliveries/`, `alerts/`, and `google-sheets/` by default. Use `--force` to create new items or to re-upload unchanged files, and use `--skip-*` to leave a category alone:

```bash
lightdash upload --scheduled-deliveries weekly-orders-email --force
lightdash upload --alerts revenue-drop-alert
lightdash upload --google-sheets orders-sheet-sync --force

# Upload charts and dashboards only
lightdash upload --skip-scheduled-deliveries --skip-alerts --skip-google-sheets
```

## Editing with AI agents

You can use AI coding assistants like Cursor, Claude Code, and Codex to create and edit charts using natural language instead of clicking through the UI.
Expand Down
76 changes: 72 additions & 4 deletions references/lightdash-cli.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,8 @@ For examples and command-specific options, click through the command in the tabl
|[`lightdash generate`](/references/lightdash-cli#lightdash-generate) | Generate or update `schema.yml` file(s) for the selected model(s) |
|[`lightdash dbt run`](/references/lightdash-cli#lightdash-dbt-run) | Run dbt, then generate or update `schema.yml` file(s) for the selected model(s) |
|[`lightdash generate-exposures`](/references/lightdash-cli#lightdash-generate-exposures) | [Experimental command] Generates a YAML file for Lightdash exposures |
|[`lightdash download`](/references/lightdash-cli#lightdash-download) | Download all charts and dashboards from your Lightdash project as code |
|[`lightdash upload`](/references/lightdash-cli#lightdash-upload) | Upload charts and dashboards as code to your Lightdash project |
|[`lightdash download`](/references/lightdash-cli#lightdash-download) | Download project content — charts, dashboards, scheduled deliveries, alerts, and Google Sheets syncs — as code |
|[`lightdash upload`](/references/lightdash-cli#lightdash-upload) | Upload project content — charts, dashboards, scheduled deliveries, alerts, and Google Sheets syncs — as code |
|[`lightdash rename`](/references/lightdash-cli#lightdash-rename) | Rename model or field names across all your Lightdash content |
|[`lightdash diagnostics`](/references/lightdash-cli#lightdash-diagnostics) | Show diagnostic information about the CLI environment |
|[`lightdash sql`](/references/lightdash-cli#lightdash-sql) | Run raw SQL query against the warehouse using project credentials |
Expand Down Expand Up @@ -664,7 +664,9 @@ lightdash dbt run --select mymodel

### `lightdash download`

Downloads all charts and dashboards from your Lightdash project as code. A `lightdash` directory is created in your working directory and all of the charts and dashboards are written there as .yml files.
Downloads project content from your Lightdash project as code. A `lightdash` directory is created in your working directory and all of the content is written there as `.yml` files.

Alongside charts and dashboards, the CLI also downloads three scheduler-driven domains — scheduled deliveries, alerts, and Google Sheets syncs — into their own subfolders (`scheduled-deliveries/`, `alerts/`, and `google-sheets/`). See [Scheduled deliveries, alerts, and Google Sheets syncs as code](/guides/developer/dashboards-as-code#scheduled-deliveries-alerts-and-google-sheets-syncs-as-code) for the YAML contracts and directory layout.

E.g. if you're running this command inside your dbt directory (eg: `/home/javi/dbt`) then it will create a folder (`/home/javi/dbt/lightdash`).

Expand All @@ -677,6 +679,12 @@ You can make changes to the code and upload these changes back to your Lightdash
- select specific charts as code to download from your project. Use the chart SLUG, UUID or URL to specify the chart
- `--dashboards` or `-d`
- select specific dashboards as code to download from your project. This will also download all charts in the dashboard as code. Use the dashboard SLUG, UUID or URL to specify the dashboard
- `--scheduled-deliveries <slugs...>`
- select specific scheduled deliveries to download by their project-scoped slug. See [Scheduled deliveries as code](/guides/developer/dashboards-as-code#scheduled-deliveries) for the YAML contract
- `--alerts <slugs...>`
- select specific alerts to download by their project-scoped slug. Alerts are stored under `alerts/charts/<chart-slug>/<alert-slug>.yml`. See [Alerts as code](/guides/developer/dashboards-as-code#alerts) for the YAML contract
- `--google-sheets <slugs...>`
- select specific Google Sheets syncs to download by their project-scoped slug. See [Google Sheets syncs as code](/guides/developer/dashboards-as-code#google-sheets-syncs) for the YAML contract
- `--path` or `-p`
- specify a custom path to a directory where you want the downloaded files to be written to. You can use the full path, or a relative path to a directory
- `--project <project uuid>`
Expand Down Expand Up @@ -704,6 +712,21 @@ You can make changes to the code and upload these changes back to your Lightdash
- `--skip-dashboards`
- (default: false)
- skip downloading dashboards
- `--include-scheduled-deliveries`
- (default: false)
- opt in to download every scheduled delivery in the project. Not required when `--scheduled-deliveries <slugs...>` is also passed — providing a slug filter downloads just those items
- `--include-alerts`
- (default: false)
- opt in to download every alert in the project. Not required when `--alerts <slugs...>` is also passed — providing a slug filter downloads just those items
- `--include-google-sheets`
- (default: false)
- opt in to download every Google Sheets sync in the project. Not required when `--google-sheets <slugs...>` is also passed — providing a slug filter downloads just those items
- `--include-virtual-views`
- (default: false)
- opt in to download every virtual view in the project. Not required when `--virtual-views <slugs...>` is also passed
- `--include-all`
- (default: false)
- opt in to download every optional content category: scheduled deliveries, alerts, Google Sheets syncs, virtual views, and every [data app](/guides/data-apps#data-apps-as-code) that has been added to a space (capped by `--apps-limit`, default 50). Charts, dashboards, and spaces are always downloaded regardless of this flag

**Examples:**

Expand Down Expand Up @@ -769,10 +792,32 @@ Download just one data app and nothing else.
lightdash download --apps-only --apps 8f2b1c4d-1111-2222-3333-444455556666
```

Download a specific scheduled delivery, alert, or Google Sheets sync by slug. Passing a slug filter also opts that category in for the run.

```bash
lightdash download --scheduled-deliveries weekly-orders-email
lightdash download --alerts revenue-drop-alert
lightdash download --google-sheets orders-sheet-sync
```

Download every scheduled delivery, alert, or Google Sheets sync in the project by opting the category in explicitly.

```bash
lightdash download --include-scheduled-deliveries
lightdash download --include-alerts
lightdash download --include-google-sheets
```

Download everything — charts, dashboards, and every optional category (scheduled deliveries, alerts, Google Sheets syncs, virtual views, and data apps up to `--apps-limit`).

```bash
lightdash download --include-all
```


### `lightdash upload`

Uploads charts and dashboards that you've made changes to from the `lightdash/` directory in your dbt project to your Lightdash project. To upload new content as code to your project, you need to use the option `--force` (see **Options** below).
Uploads project content that you've made changes to from the `lightdash/` directory in your dbt project to your Lightdash project. This includes charts and dashboards, plus scheduled deliveries, alerts, and Google Sheets syncs when their YAML files are present. To upload new content as code to your project, you need to use the option `--force` (see **Options** below).

If there have been changes made to a chart or dashboard in the application that is being uploaded from code, `lightdash upload` will overwrite the changes.

Expand All @@ -788,6 +833,21 @@ If there have been changes made to a chart or dashboard in the application that
- select specific charts as code to upload back to your project. Use the chart SLUG to specify the chart
- `--dashboards` or `-d`
- select specific dashboards as code to upload back to your project. Use the dashboard SLUG to specify the dashboard
- `--scheduled-deliveries <slugs...>`
- select specific scheduled deliveries to upload by their project-scoped slug. Combine with `--force` to create new deliveries or re-upload unchanged files
- `--alerts <slugs...>`
- select specific alerts to upload by their project-scoped slug
- `--google-sheets <slugs...>`
- select specific Google Sheets syncs to upload by their project-scoped slug. Uploads require the PAT user to have Google Sheets permission and access to the referenced spreadsheet — Lightdash validates the Google OAuth connection before writing changes
- `--skip-scheduled-deliveries`
- (default: false)
- skip uploading scheduled deliveries
- `--skip-alerts`
- (default: false)
- skip uploading alerts
- `--skip-google-sheets`
- (default: false)
- skip uploading Google Sheets syncs
- `--path` or `-p`
- specify a custom path to a directory where the files you want to upload are. You can use the full path, or a relative path to a directory
- `--project <project uuid>`
Expand Down Expand Up @@ -877,6 +937,14 @@ Copy a data app to a different project as a brand-new app (non-interactive).
lightdash upload --apps --project 21eef0b9-5bae-40f3-851e-9554588e71a6 --create-new
```

Upload a specific scheduled delivery, alert, or Google Sheets sync by slug. Add `--force` to create new items or to re-upload unchanged files.

```bash
lightdash upload --scheduled-deliveries weekly-orders-email --force
lightdash upload --alerts revenue-drop-alert
lightdash upload --google-sheets orders-sheet-sync --force
```


### `lightdash rename`

Expand Down
Loading