Skip to content
Merged
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
79 changes: 79 additions & 0 deletions guides/data-apps/themes.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,85 @@ You create and manage themes from the **Themes** page in **Settings**.

Bootstrapping a theme with an agent (for example, asking an LLM to draft CSS rules and a `skill.md` against these guidelines) is a quick way to get a usable first version. From there, iterate on the instructions until the agent produces apps that match what you have in mind.

## Manage themes as code

You can download, version, review, and upload themes through the same organization content-as-code workflow used for custom roles, users, and groups:

```bash
lightdash download --organization
# Edit or add lightdash/themes/<slug>/
lightdash upload --organization
```

This lets you move an existing UI-created theme into version control or create a theme locally. Organization download includes every theme and writes each one under its immutable slug:

```text
lightdash/
themes/
acme-brand/
lightdash-theme.yml
css/
theme.css
fonts/
acme-sans.woff2
images/
logo.svg
instructions/
skill.md
```

The directory name must exactly match the manifest's `slug`. Every manifest field is required; use `null` for an empty description or extra instructions:

```yaml lightdash/themes/acme-brand/lightdash-theme.yml
codeVersion: 1
slug: acme-brand
name: Acme Brand
description: Brand theme for customer-facing data apps
extraInstructions: |-
Use the horizontal logo in page headers.
Keep data-dense tables compact.
```

To create a new theme locally, choose a new lowercase, hyphenated slug, create this manifest and any asset folders you need, then run `lightdash upload --organization`. Upload creates or updates the theme by manifest slug. Treat the slug as immutable; change `name` when you only want to rename the theme for display.

<Warning>
Organization mode has no theme-only selector. Before uploading, review custom roles, users, and groups under the same `lightdash/` directory as well as your themes.
</Warning>

### Files and validation

The CLI validates every local theme before changing any organization resource. A theme package accepts:

- `.css` files under `css/`
- `.woff`, `.woff2`, `.ttf`, and `.otf` files under `fonts/`
- `.png`, `.jpg`, `.jpeg`, `.gif`, `.webp`, and `.svg` files under `images/`
- Markdown files under `instructions/`

Files must live directly inside one of these folders. Nested folders, symlinks, unknown paths, unsafe filenames, unsupported file types, empty files, and files whose contents don't match their extension are rejected. The manifest is limited to 64 KiB, each asset to 10 MB, all assets combined to 100 MB, and the complete uncompressed package to 110 MB.

Don't commit or upload restricted Apple system-font binaries such as SF-family or New York fonts. Use a system font stack instead:

```css
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
```

### Synchronization behavior

- A successful download replaces the complete local `themes/` directory with the remote theme set. If any theme cannot be downloaded or validated, your previous local themes are preserved.
- Upload preflights every local theme before applying custom roles, users, groups, or themes. One invalid theme prevents all organization changes in that run.
- An existing slug is updated, a new slug is created, and a theme whose manifest and files already match is skipped as unchanged.
- A missing or empty local `themes/` directory is a no-op. Removing one local theme directory does not delete the remote theme.
- Upload preserves each theme's UUID and whether it is the organization default. Set the default or delete a theme in the Lightdash UI.
- Each theme import is atomic, but a multi-theme upload is not one transaction. If a later import fails, themes that completed earlier remain applied and the CLI reports the partial failure.

There is no standalone `lightdash themes` command, theme-specific `--only` flag, or local theme preview. If an organization theme endpoint returns `404`, check that the Lightdash CLI and server versions both support theme packages.

### Evaluate your changes

Uploading proves the package is valid, but it doesn't rebuild or restyle existing data app versions. To see whether you like a theme, select it when generating a new data app or apply it to an existing app from the theme picker above the prompt. Lightdash creates a new app version that you can compare with the previous version.

If you edit themes with an AI coding agent, install or update the [Lightdash agent skills](/guides/developer/agent-skills). The existing `developing-in-lightdash` skill teaches the agent this package format and the safe organization download/upload workflow. The agent can verify the CLI round trip without browser access; you still evaluate the generated app visually in Lightdash.

## Setting a default theme

You can mark one theme as the default for your organization. New data apps will use the default theme unless you pick a different one.
Expand Down
6 changes: 6 additions & 0 deletions guides/developer/agent-skills.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ Once installed, your AI coding agent automatically picks up the Lightdash skills
- Fix validation errors in your semantic layer
- Refactor existing metric definitions
- Add joins between tables
- Create, edit, and synchronize organization Data App themes as code

### Example prompts

Expand All @@ -115,6 +116,11 @@ Add a customer_segment dimension based on the lifetime_value field
Generate the Lightdash YAML configuration for my users dbt model
```

```
Download our organization content, update the acme-brand Data App theme with
the new logo and typography rules, upload it safely, and verify the CLI round trip
```

The agent uses the installed skills to generate correct, up-to-date Lightdash configurations.

## Keeping skills updated
Expand Down
19 changes: 16 additions & 3 deletions guides/developer/dashboards-as-code.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -1049,7 +1049,7 @@ Agent config as code is **opt-in**: a bare `lightdash download` does not include

## Organization content as code

Three organization-scoped resources — **custom roles**, **users**, and **groups** — can also be downloaded and uploaded as YAML using the `--organization` mode of `lightdash download` and `lightdash upload`. This is a separate workflow from project content (charts, dashboards, virtual views, and data apps) and requires an **organization admin**.
Four organization-scoped resources — **custom roles**, **users**, **groups**, and **Data App themes** — can also be downloaded and uploaded using the `--organization` mode of `lightdash download` and `lightdash upload`. This is a separate workflow from project content (charts, dashboards, virtual views, and data apps) and requires an **organization admin**.

A single `lightdash download --organization` writes every organization resource to a top-level folder in your working directory:

Expand All @@ -1061,14 +1061,27 @@ lightdash/
<email-slug>.yml
groups/
<group-slug>.yml
themes/
<theme-slug>/
lightdash-theme.yml
css/
fonts/
images/
instructions/
```

A single `lightdash upload --organization` reads all three folders and applies them **sequentially in dependency order**: custom roles first, then users, then groups. A failed phase prevents the dependent phases from running, so a user file can safely reference a custom role added in the same commit, and a group file can safely list a user added in the same commit.
A single `lightdash upload --organization` preflights all local theme packages, then applies resources **sequentially in dependency order**: custom roles first, then users, groups, and themes. A failed phase prevents later phases from running, so a user file can safely reference a custom role added in the same commit and a group file can safely list a user added in the same commit. One invalid local theme prevents any organization resource from changing.

<Note>
Organization mode cannot be combined with project-content flags such as `--charts`, `--dashboards`, `--project`, `--nested`, or `--force`. Uploads never delete resources in Lightdash — remove unwanted roles, users, or groups in the UI.
Organization mode cannot be combined with project-content flags such as `--charts`, `--dashboards`, `--project`, `--nested`, or `--force`. Uploads never delete resources in Lightdash — remove unwanted roles, users, groups, or themes in the UI.
</Note>

### Data App themes as code

Themes are strict multi-file packages under `lightdash/themes/<slug>/`, rather than single YAML documents. Organization download exports UI-created themes into the canonical package layout. Organization upload creates or updates themes by manifest slug, skips unchanged packages, and leaves remotely existing themes alone when their local directory is absent.

Theme upload does not change the organization default. Each theme import is atomic, but the complete multi-theme upload is not one transaction. For the manifest, supported assets, validation limits, synchronization behavior, and visual evaluation workflow, see [Manage themes as code](/guides/data-apps/themes#manage-themes-as-code).

### Custom roles as code

[Custom roles](/references/workspace/custom-roles) are managed as code. Unlike charts and dashboards, custom roles are **organization-scoped** rather than project-scoped, so downloading and uploading them uses the `--organization` mode of `lightdash download` and `lightdash upload` and requires an organization admin.
Expand Down
16 changes: 10 additions & 6 deletions references/lightdash-cli.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -820,7 +820,7 @@ You can make changes to the code and upload these changes back to your Lightdash
- opt-in flag to download every AI agent in the project as code. The endpoint is paginated, so the CLI walks all pages automatically. Agent files are written to `lightdash/ai-agents/`. Bare `lightdash download` does not include agents.
- `--organization`
- (default: false)
- switch to organization mode and download [organization-scoped content](/guides/developer/dashboards-as-code#organization-content-as-code) — [custom roles](/guides/developer/dashboards-as-code#custom-roles-as-code), [users](/guides/developer/dashboards-as-code#users-as-code), and [groups](/guides/developer/dashboards-as-code#groups-as-code) — instead of project content. Files are written to `lightdash/custom-roles/<role-slug>.yml`, `lightdash/users/<email-slug>.yml`, and `lightdash/groups/<group-slug>.yml`. Requires organization admin permissions. If the groups feature is disabled on the instance, the groups folder is skipped (run with `--verbose` for the explanation). Cannot be combined with project-content flags such as `--charts`, `--dashboards`, `--project`, or `--nested`.
- switch to organization mode and download [organization-scoped content](/guides/developer/dashboards-as-code#organization-content-as-code) — [custom roles](/guides/developer/dashboards-as-code#custom-roles-as-code), [users](/guides/developer/dashboards-as-code#users-as-code), [groups](/guides/developer/dashboards-as-code#groups-as-code), and [Data App themes](/guides/data-apps/themes#manage-themes-as-code) — instead of project content. Files are written to `lightdash/custom-roles/<role-slug>.yml`, `lightdash/users/<email-slug>.yml`, `lightdash/groups/<group-slug>.yml`, and `lightdash/themes/<theme-slug>/`. Theme packages are staged and validated before the local `themes/` directory is replaced, so a failed theme download preserves the previous local theme set. A successful download removes local theme directories that no longer exist remotely. Requires organization admin permissions. If the groups feature is disabled on the instance, the groups folder is skipped (run with `--verbose` for the explanation). Cannot be combined with project-content flags such as `--charts`, `--dashboards`, `--project`, or `--nested`.

**Examples:**

Expand Down Expand Up @@ -896,6 +896,8 @@ Download only a specific AI agent by slug (or UUID).

```bash
lightdash download --agents orders-support-agent
```

Download all charts and dashboards, plus every virtual view in the project.

```bash
Expand All @@ -906,7 +908,9 @@ Download only specific virtual views by slug.

```bash
lightdash download --virtual-views orders_enriched customers_enriched
Download every [organization-scoped resource](/guides/developer/dashboards-as-code#organization-content-as-code) as code — custom roles, users, and groups (requires org admin).
```

Download every [organization-scoped resource](/guides/developer/dashboards-as-code#organization-content-as-code) as code — custom roles, users, groups, and Data App themes (requires org admin).

```bash
lightdash download --organization
Expand Down Expand Up @@ -984,7 +988,7 @@ If there have been changes made to a chart or dashboard in the application that
- skip uploading AI agents even when `lightdash/ai-agents/` contains files. Use this to keep an agents folder in your repo without pushing changes on every `lightdash upload`.
- `--organization`
- (default: false)
- switch to organization mode and upload [organization-scoped content](/guides/developer/dashboards-as-code#organization-content-as-code) — [custom roles](/guides/developer/dashboards-as-code#custom-roles-as-code), [users](/guides/developer/dashboards-as-code#users-as-code), and [groups](/guides/developer/dashboards-as-code#groups-as-code) — instead of project content. Reads YAML files from `lightdash/custom-roles/`, `lightdash/users/`, and `lightdash/groups/` and applies them sequentially in that order (custom roles → users → groups), so a user file can reference a custom role and a group file can reference a user from the same upload. Each resource is upserted by its portable identity (role name, primary email, group name) — creating, updating, or reporting no change per file. Requires organization admin permissions. Cannot be combined with project-content flags such as `--charts`, `--dashboards`, `--project`, or `--force`. Uploads never delete roles, users, or groups.
- switch to organization mode and upload [organization-scoped content](/guides/developer/dashboards-as-code#organization-content-as-code) — [custom roles](/guides/developer/dashboards-as-code#custom-roles-as-code), [users](/guides/developer/dashboards-as-code#users-as-code), [groups](/guides/developer/dashboards-as-code#groups-as-code), and [Data App themes](/guides/data-apps/themes#manage-themes-as-code) — instead of project content. The CLI validates every local theme before making any organization change, then applies custom roles → users → groups → themes. Document resources are upserted by role name, primary email, or group name; themes are upserted by manifest slug and skipped when unchanged. A missing or empty `lightdash/themes/` directory is a no-op, and removing one theme directory never deletes the remote theme. Theme imports preserve the organization default and are atomic per theme, not per batch. Requires organization admin permissions. Cannot be combined with project-content flags such as `--charts`, `--dashboards`, `--project`, or `--force`. Uploads never delete roles, users, groups, or themes.
- `--send-invites`
- (default: false)
- only valid with `--organization`. When uploading users, send invitation emails to eligible staged users. Users who have already authenticated, are disabled, or already have a valid outstanding invitation are skipped. Without this flag, users authenticate through the instance's existing domain, SSO, or manually triggered invitation flows — credentials are never carried in the YAML.
Expand Down Expand Up @@ -1071,8 +1075,6 @@ Fork a data app into a new record in the current project.
lightdash upload --apps revenue-explorer --create-new
```

Upload every [organization-scoped resource](/guides/developer/dashboards-as-code#organization-content-as-code) — custom roles, users, and groups — back to the organization (requires org admin).

Upload every AI agent file under `lightdash/ai-agents/` (creates missing agents, updates existing ones by slug).

```bash
Expand All @@ -1083,7 +1085,9 @@ Upload only a specific AI agent by slug.

```bash
lightdash upload --agents orders-support-agent
Upload every custom role in `lightdash/custom-roles/` back to the organization (requires org admin).
```

Upload every [organization-scoped resource](/guides/developer/dashboards-as-code#organization-content-as-code) — custom roles, users, groups, and Data App themes — back to the organization (requires org admin).

```bash
lightdash upload --organization
Expand Down
2 changes: 1 addition & 1 deletion references/workspace/custom-roles.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ scopes:

Malformed files, unknown scopes, and scopes that aren't allowed at the role's level are rejected per file with the file path and error message; other files continue to process. The CLI exits with a non-zero status if any file fails validation.

Organization users and groups can be managed through the same `--organization` workflow, and uploads apply resources sequentially — custom roles first, then users, then groupsso a user file can safely reference a custom role added in the same commit. See [Organization content as code](/guides/developer/dashboards-as-code#organization-content-as-code) for the full workflow, [Users as code](/guides/developer/dashboards-as-code#users-as-code), and [Groups as code](/guides/developer/dashboards-as-code#groups-as-code).
Organization users, groups, and Data App themes can be managed through the same `--organization` workflow. The CLI preflights themes, then uploads custom roles, users, groups, and themes in that order, so a user file can safely reference a custom role added in the same commit. See [Organization content as code](/guides/developer/dashboards-as-code#organization-content-as-code) for the full workflow, [Users as code](/guides/developer/dashboards-as-code#users-as-code), [Groups as code](/guides/developer/dashboards-as-code#groups-as-code), and [Data App themes as code](/guides/data-apps/themes#manage-themes-as-code).

## Troubleshooting

Expand Down
Loading