# Add AI agent review item comment Source: https://docs.lightdash.com/api-reference/add-ai-agent-review-item-comment https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/aiAgents/admin/review-items/{fingerprint}/comments Add a comment to an AI agent review item # Capture AI review judge replay inputs Source: https://docs.lightdash.com/api-reference/capture-ai-review-judge-replay-inputs https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/aiAgents/admin/review-replay-capture Rebuild judge replay inputs for historical review signals so the eval scoreboard can replay the judge offline. Read-only; feature-flag gated. # Acquire tree lock Source: https://docs.lightdash.com/api-reference/catalog/acquire-tree-lock https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/dataCatalog/metrics/trees/{metricsTreeUuid}/lock Acquire an edit lock on a metrics tree # Add category to catalog item Source: https://docs.lightdash.com/api-reference/catalog/add-category-to-catalog-item https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/dataCatalog/{catalogSearchUuid}/categories Add a category to a catalog item # Check if metrics exist in catalog Source: https://docs.lightdash.com/api-reference/catalog/check-if-metrics-exist-in-catalog https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/dataCatalog/metrics/has Check if there are any metrics in catalog # Create metrics tree Source: https://docs.lightdash.com/api-reference/catalog/create-metrics-tree https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/dataCatalog/metrics/trees Create a new saved metrics tree with nodes and edges # Create metrics tree edge Source: https://docs.lightdash.com/api-reference/catalog/create-metrics-tree-edge https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/dataCatalog/metrics/tree/edges Create an edge in the metrics tree # Delete metrics tree Source: https://docs.lightdash.com/api-reference/catalog/delete-metrics-tree https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/projects/{projectUuid}/dataCatalog/metrics/trees/{metricsTreeUuid} Delete a saved metrics tree and its associated nodes # Delete metrics tree edge Source: https://docs.lightdash.com/api-reference/catalog/delete-metrics-tree-edge https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/projects/{projectUuid}/dataCatalog/metrics/tree/edges/{sourceCatalogSearchUuid}/{targetCatalogSearchUuid} Delete an edge from the metrics tree # Get all metrics tree edges Source: https://docs.lightdash.com/api-reference/catalog/get-all-metrics-tree-edges https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/dataCatalog/metrics/tree/edges Get all edges in the metrics tree for a project # Get catalog Source: https://docs.lightdash.com/api-reference/catalog/get-catalog https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/dataCatalog Get catalog items # Get field analytics Source: https://docs.lightdash.com/api-reference/catalog/get-field-analytics https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/dataCatalog/{table}/analytics/{field} Get catalog analytics for fields # Get filter dimensions Source: https://docs.lightdash.com/api-reference/catalog/get-filter-dimensions https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/dataCatalog/{tableName}/filter-dimensions Get dimensions that can be used to filter metrics # Get metric Source: https://docs.lightdash.com/api-reference/catalog/get-metric https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/dataCatalog/metrics/{tableName}/{metricName} Get metric by table and metric name # Get metrics tree Source: https://docs.lightdash.com/api-reference/catalog/get-metrics-tree https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/dataCatalog/metrics/tree Get the metrics tree structure (deprecated, use POST instead) # Get metrics tree Source: https://docs.lightdash.com/api-reference/catalog/get-metrics-tree-1 https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/dataCatalog/metrics/tree Get the metrics tree structure # Get metrics tree details Source: https://docs.lightdash.com/api-reference/catalog/get-metrics-tree-details https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/dataCatalog/metrics/trees/{metricsTreeUuidOrSlug} Get details of a saved metrics tree including nodes and edges # Get metrics with time dimensions Source: https://docs.lightdash.com/api-reference/catalog/get-metrics-with-time-dimensions https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/dataCatalog/metrics-with-time-dimensions Get metrics with time dimensions # Get segment dimensions Source: https://docs.lightdash.com/api-reference/catalog/get-segment-dimensions https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/dataCatalog/{tableName}/segment-dimensions Get dimensions that can be used to segment metrics # Get table analytics Source: https://docs.lightdash.com/api-reference/catalog/get-table-analytics https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/dataCatalog/{table}/analytics Get catalog analytics for tables # Get table metadata Source: https://docs.lightdash.com/api-reference/catalog/get-table-metadata https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/dataCatalog/{table}/metadata Get catalog metadata for tables # List metric owners Source: https://docs.lightdash.com/api-reference/catalog/list-metric-owners https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/dataCatalog/metrics/owners Get distinct metric owners for filter dropdown # List metrics in catalog Source: https://docs.lightdash.com/api-reference/catalog/list-metrics-in-catalog https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/dataCatalog/metrics Get metrics catalog # List metrics trees Source: https://docs.lightdash.com/api-reference/catalog/list-metrics-trees https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/dataCatalog/metrics/trees List saved metrics trees for a project # Refresh tree lock heartbeat Source: https://docs.lightdash.com/api-reference/catalog/refresh-tree-lock-heartbeat https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json put /api/v1/projects/{projectUuid}/dataCatalog/metrics/trees/{metricsTreeUuid}/lock/heartbeat Refresh the heartbeat on an edit lock to keep it alive # Release tree lock Source: https://docs.lightdash.com/api-reference/catalog/release-tree-lock https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/projects/{projectUuid}/dataCatalog/metrics/trees/{metricsTreeUuid}/lock Release an edit lock on a metrics tree # Remove category from catalog item Source: https://docs.lightdash.com/api-reference/catalog/remove-category-from-catalog-item https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/projects/{projectUuid}/dataCatalog/{catalogSearchUuid}/categories/{tagUuid} Remove a category from a catalog item # Update catalog item icon Source: https://docs.lightdash.com/api-reference/catalog/update-catalog-item-icon https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/projects/{projectUuid}/dataCatalog/{catalogSearchUuid}/icon Update the icon for a catalog item # Update metrics tree Source: https://docs.lightdash.com/api-reference/catalog/update-metrics-tree https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/projects/{projectUuid}/dataCatalog/metrics/trees/{metricsTreeUuid} Update a saved metrics tree including nodes and edges # Get change Source: https://docs.lightdash.com/api-reference/changesets/get-change https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/changesets/changes/{changeUuid} Get a specific change by UUID # List changesets Source: https://docs.lightdash.com/api-reference/changesets/list-changesets https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/changesets Get active changeset for a project # Revert all changes Source: https://docs.lightdash.com/api-reference/changesets/revert-all-changes https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/changesets/revert-all Revert all changes in the active changeset # Revert change Source: https://docs.lightdash.com/api-reference/changesets/revert-change https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/changesets/changes/{changeUuid}/revert Revert a specific change # Calculate total from saved chart Source: https://docs.lightdash.com/api-reference/charts/calculate-total-from-saved-chart https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/saved/{chartUuid}/calculate-total Calculate metric totals from a saved chart # Create saved chart scheduler Source: https://docs.lightdash.com/api-reference/charts/create-saved-chart-scheduler https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/saved/{chartUuid}/schedulers Create a scheduler for a saved chart # Export chart image Source: https://docs.lightdash.com/api-reference/charts/export-chart-image https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/saved/{chartUuid}/export Export a saved chart as a PNG image # Get chart and results Source: https://docs.lightdash.com/api-reference/charts/get-chart-and-results https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/saved/{chartUuid}/chart-and-results Deprecated — use the v2 Execute dashboard chart endpoint instead. This endpoint was deprecated on 20 March 2025 and is past its sunset date (20 June 2025) — it may be removed at any time. Migrate to the v2 async query flow: Execute dashboard chart, then Get results. **This endpoint is deprecated and past its sunset date (20 June 2025) — it may be removed at any time.** Migrate to the v2 async query flow: [Execute dashboard chart](https://docs.lightdash.com/api-reference/v2/execute-dashboard-chart) (`POST /api/v2/projects/{projectUuid}/query/dashboard-chart`) to start the query, then [Get results](https://docs.lightdash.com/api-reference/v2/get-results) to fetch rows. See also [Cancel query](https://docs.lightdash.com/api-reference/v2/cancel-query) and [Download results](https://docs.lightdash.com/api-reference/v2/download-results). # Get chart promotion diff Source: https://docs.lightdash.com/api-reference/charts/get-chart-promotion-diff https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/saved/{chartUuid}/promoteDiff Get diff from chart to promote # Get chart version Source: https://docs.lightdash.com/api-reference/charts/get-chart-version https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/saved/{chartUuid}/version/{versionUuid} Get chart version # Get chart version history Source: https://docs.lightdash.com/api-reference/charts/get-chart-version-history https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/saved/{chartUuid}/history Get chart version history from last 30 days # Get chart version results Source: https://docs.lightdash.com/api-reference/charts/get-chart-version-results https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/saved/{chartUuid}/version/{versionUuid}/results Deprecated — use the v2 Execute saved chart endpoint instead. This endpoint was deprecated on 20 March 2025 and is past its sunset date (30 April 2025) — it may be removed at any time. Migrate to the v2 async query flow: Execute saved chart, then Get results. **This endpoint is deprecated and past its sunset date (30 April 2025) — it may be removed at any time.** Migrate to the v2 async query flow: [Execute saved chart](https://docs.lightdash.com/api-reference/v2/execute-saved-chart) (`POST /api/v2/projects/{projectUuid}/query/chart`) to run the chart's latest version, then [Get results](https://docs.lightdash.com/api-reference/v2/get-results) to fetch rows. Running a query for a specific chart version has no v2 equivalent. # List saved chart schedulers Source: https://docs.lightdash.com/api-reference/charts/list-saved-chart-schedulers https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/saved/{chartUuid}/schedulers Get schedulers for a saved chart # Promote chart Source: https://docs.lightdash.com/api-reference/charts/promote-chart https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/saved/{chartUuid}/promote Promote chart to its upstream project # Rollback chart to version Source: https://docs.lightdash.com/api-reference/charts/rollback-chart-to-version https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/saved/{chartUuid}/rollback/{versionUuid} Rollback chart to version # Run chart query Source: https://docs.lightdash.com/api-reference/charts/run-chart-query https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/saved/{chartUuid}/results Deprecated — use the v2 Execute saved chart endpoint instead. This endpoint was deprecated on 20 March 2025 and is past its sunset date (30 April 2025) — it may be removed at any time. Migrate to the v2 async query flow: Execute saved chart, then Get results. **This endpoint is deprecated and past its sunset date (30 April 2025) — it may be removed at any time.** Migrate to the v2 async query flow: [Execute saved chart](https://docs.lightdash.com/api-reference/v2/execute-saved-chart) (`POST /api/v2/projects/{projectUuid}/query/chart`) to start the query, then [Get results](https://docs.lightdash.com/api-reference/v2/get-results) to fetch rows. See also [Cancel query](https://docs.lightdash.com/api-reference/v2/cancel-query) and [Download results](https://docs.lightdash.com/api-reference/v2/download-results). # Unverify chart Source: https://docs.lightdash.com/api-reference/charts/unverify-chart https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/saved/{chartUuid}/verification Remove verification from a chart # Verify chart Source: https://docs.lightdash.com/api-reference/charts/verify-chart https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/saved/{chartUuid}/verification Verify a chart # Create comment Source: https://docs.lightdash.com/api-reference/comments/create-comment https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/comments/dashboards/{dashboardUuid}/{dashboardTileUuid} Creates a comment on a dashboard tile # Delete comment Source: https://docs.lightdash.com/api-reference/comments/delete-comment https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/comments/dashboards/{dashboardUuid}/{commentId} Deletes a comment on a dashboard # Get comments Source: https://docs.lightdash.com/api-reference/comments/get-comments https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/comments/dashboards/{dashboardUuidOrSlug} Gets all comments for a dashboard # Resolve comment Source: https://docs.lightdash.com/api-reference/comments/resolve-comment https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/comments/dashboards/{dashboardUuid}/{commentId} Resolves or unresolves a comment on a dashboard # Commit router decision Source: https://docs.lightdash.com/api-reference/commit-router-decision https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/org/aiRouter/decisions/{decisionUuid}/commit Commit a router decision once the user has resolved it (router auto-routed and the thread is created, or the user picked an agent from the picker). Decisions left uncommitted indicate the user abandoned the flow. # Bulk move content Source: https://docs.lightdash.com/api-reference/content/bulk-move-content https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v2/content/bulk-action/{projectUuid}/move Move multiple items (Charts, Dashboards, Spaces) to another space # Get favorites Source: https://docs.lightdash.com/api-reference/content/get-favorites https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/favorites Get the current user's favorite items in a project # Get pinned items Source: https://docs.lightdash.com/api-reference/content/get-pinned-items https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/pinned-lists/{pinnedListUuid}/items Get pinned items # Move content Source: https://docs.lightdash.com/api-reference/content/move-content https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v2/content/{projectUuid}/move Move a single item (Chart, Dashboard, Space) to another space # Toggle favorite Source: https://docs.lightdash.com/api-reference/content/toggle-favorite https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/projects/{projectUuid}/favorites Toggle a favorite item for the current user # Update pinned items order Source: https://docs.lightdash.com/api-reference/content/update-pinned-items-order https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/projects/{projectUuid}/pinned-lists/{pinnedListUuid}/items/order Update pinned items order # Create agent document Source: https://docs.lightdash.com/api-reference/create-agent-document https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/documents Create a knowledge document scoped to this project and agent. # Create AI agent document Source: https://docs.lightdash.com/api-reference/create-ai-agent-document https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/aiAgents/documents Create a knowledge document. The projectUuid and agentAccess body fields are deprecated: scope the document by creating it on the agent route instead. Without them the document is available to every agent. # Create AI agent review item Source: https://docs.lightdash.com/api-reference/create-ai-agent-review-item https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/aiAgents/admin/review-items Create a manual AI agent issue # Create AI agent review item writeback PR Source: https://docs.lightdash.com/api-reference/create-ai-agent-review-item-writeback-pr https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/aiAgents/admin/review-items/{fingerprint}/writeback Open a writeback pull request for a review item (semantic-layer or project-context root cause) # Create GitHub repository Source: https://docs.lightdash.com/api-reference/create-github-repository https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/github/repos Create a new GitHub repository via the installed app # Create dashboard scheduler Source: https://docs.lightdash.com/api-reference/dashboards/create-dashboard-scheduler https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/dashboards/{dashboardUuidOrSlug}/schedulers Create a scheduler for a dashboard # Get dashboard history Source: https://docs.lightdash.com/api-reference/dashboards/get-dashboard-history https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/dashboards/{dashboardUuidOrSlug}/history Get dashboard version history # Get dashboard promotion diff Source: https://docs.lightdash.com/api-reference/dashboards/get-dashboard-promotion-diff https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/dashboards/{dashboardUuidOrSlug}/promoteDiff Get diff from dashboard to promote # Get dashboard version Source: https://docs.lightdash.com/api-reference/dashboards/get-dashboard-version https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/dashboards/{dashboardUuidOrSlug}/version/{versionUuid} Get specific dashboard version # List dashboard schedulers Source: https://docs.lightdash.com/api-reference/dashboards/list-dashboard-schedulers https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/dashboards/{dashboardUuidOrSlug}/schedulers Get schedulers for a dashboard # Promote dashboard Source: https://docs.lightdash.com/api-reference/dashboards/promote-dashboard https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/dashboards/{dashboardUuidOrSlug}/promote Promote dashboard to its upstream project # Rollback dashboard version Source: https://docs.lightdash.com/api-reference/dashboards/rollback-dashboard-version https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/dashboards/{dashboardUuidOrSlug}/rollback/{versionUuid} Rollback dashboard to a previous version # Unverify dashboard Source: https://docs.lightdash.com/api-reference/dashboards/unverify-dashboard https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/dashboards/{dashboardUuidOrSlug}/verification Remove verification from a dashboard # Verify dashboard Source: https://docs.lightdash.com/api-reference/dashboards/verify-dashboard https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/dashboards/{dashboardUuidOrSlug}/verification Verify a dashboard # Delete agent document Source: https://docs.lightdash.com/api-reference/delete-agent-document https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/documents/{documentUuid} Delete a knowledge document this agent can use. # Delete AI agent document Source: https://docs.lightdash.com/api-reference/delete-ai-agent-document https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/aiAgents/documents/{documentUuid} Delete a knowledge document anywhere in the organization. # Delete apiv1projects aiagents Source: https://docs.lightdash.com/api-reference/delete-apiv1projects-aiagents https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/projects/{projectUuid}/aiAgents/{agentUuid} # Delete apiv1projects aiagents evaluations Source: https://docs.lightdash.com/api-reference/delete-apiv1projects-aiagents-evaluations https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/evaluations/{evalUuid} # Delete apiv1projects aiagentspreferences Source: https://docs.lightdash.com/api-reference/delete-apiv1projects-aiagentspreferences https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/projects/{projectUuid}/aiAgents/preferences # Run metric query Source: https://docs.lightdash.com/api-reference/exploring/run-metric-query https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/explores/{exploreId}/runQuery Deprecated — use the v2 Execute metric query endpoint instead. This endpoint was deprecated on 20 March 2025 and is past its sunset date (30 April 2025) — it may be removed at any time. Migrate to the v2 async query flow: Execute metric query, then Get results. **This endpoint is deprecated and past its sunset date (30 April 2025) — it may be removed at any time.** Migrate to the v2 async query flow: [Execute metric query](https://docs.lightdash.com/api-reference/v2/execute-metric-query) (`POST /api/v2/projects/{projectUuid}/query/metric-query`) to start the query, then [Get results](https://docs.lightdash.com/api-reference/v2/get-results) to fetch rows. See also [Cancel query](https://docs.lightdash.com/api-reference/v2/cancel-query) and [Download results](https://docs.lightdash.com/api-reference/v2/download-results). # Run SQL query Source: https://docs.lightdash.com/api-reference/exploring/run-sql-query https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/sqlQuery Deprecated — use the v2 Execute SQL query endpoint instead. This endpoint was deprecated on 17 February 2025 and is past its sunset date (17 May 2025) — it may be removed at any time. Migrate to the v2 async query flow: Execute SQL query, then Get results. **This endpoint is deprecated and past its sunset date (17 May 2025) — it may be removed at any time.** Migrate to the v2 async query flow: [Execute SQL query](https://docs.lightdash.com/api-reference/v2/execute-sql-query) (`POST /api/v2/projects/{projectUuid}/query/sql`) to start the query, then [Get results](https://docs.lightdash.com/api-reference/v2/get-results) to fetch rows. See also [Cancel query](https://docs.lightdash.com/api-reference/v2/cancel-query) and [Download results](https://docs.lightdash.com/api-reference/v2/download-results). # Run underlying data query Source: https://docs.lightdash.com/api-reference/exploring/run-underlying-data-query https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/explores/{exploreId}/runUnderlyingDataQuery Deprecated — use the v2 Execute underlying data endpoint instead. This endpoint was deprecated on 20 March 2025 and is past its sunset date (30 April 2025) — it may be removed at any time. Migrate to the v2 async query flow: Execute underlying data, then Get results. **This endpoint is deprecated and past its sunset date (30 April 2025) — it may be removed at any time.** Migrate to the v2 async query flow: [Execute underlying data](https://docs.lightdash.com/api-reference/v2/execute-underlying-data) (`POST /api/v2/projects/{projectUuid}/query/underlying-data`) to start the query, then [Get results](https://docs.lightdash.com/api-reference/v2/get-results) to fetch rows. See also [Cancel query](https://docs.lightdash.com/api-reference/v2/cancel-query) and [Download results](https://docs.lightdash.com/api-reference/v2/download-results). # Get export status Source: https://docs.lightdash.com/api-reference/exports/get-export-status https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/csv/{jobId} Get the status/URL of a Google Sheets export job # Get file Source: https://docs.lightdash.com/api-reference/files/get-file https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/file/{fileId} Get a persistent file download. Streams the file body through the backend so self-hosted deployments don't need to expose their internal S3-compatible storage endpoint to browsers. # Get event names Source: https://docs.lightdash.com/api-reference/funnel/get-event-names https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/funnel/event-names Get distinct event names from a dimension for funnel step selection. Scans the last 30 days of data to limit query cost. # Run funnel query Source: https://docs.lightdash.com/api-reference/funnel/run-funnel-query https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/funnel/query Execute a funnel analysis query and return conversion metrics # Get AI agent review item activity Source: https://docs.lightdash.com/api-reference/get-ai-agent-review-item-activity https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/aiAgents/admin/review-items/{fingerprint}/activity Get the remediation activity feed for a review item # Get AI agent review item by preview thread Source: https://docs.lightdash.com/api-reference/get-ai-agent-review-item-by-preview-thread https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/aiAgents/admin/review-items/by-preview-thread/{threadUuid} Get the review item linked to a remediation preview work thread # Get AI agent review item PR diff Source: https://docs.lightdash.com/api-reference/get-ai-agent-review-item-pr-diff https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/aiAgents/admin/review-items/{fingerprint}/pr-diff Get the file diff of the pull request linked to a review item # Get AI agent thread pull request Source: https://docs.lightdash.com/api-reference/get-ai-agent-thread-pull-request https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/threads/{threadUuid}/pull-request Get the writeback pull request associated with a thread — the PR the agent opened in this thread, or the PR a verification thread verifies. # Get AI review notification settings Source: https://docs.lightdash.com/api-reference/get-ai-review-notification-settings https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/aiAgents/admin/review-notification-settings Get AI review notification settings # Get AI router config Source: https://docs.lightdash.com/api-reference/get-ai-router-config https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/org/aiRouter Get the AI router configuration for the organization. Returns 404 when the router has not been configured yet — clients use this to detect first-use. # Get AI router instruction Source: https://docs.lightdash.com/api-reference/get-ai-router-instruction https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/org/aiRouter/instructions/{projectUuid} Get the active routing instruction for a project. Returns null when no instruction has been written for the project yet. # Get AI settings Source: https://docs.lightdash.com/api-reference/get-ai-settings https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/aiAgents/admin/settings Get AI organization settings # Get apiv1aiagentsadminreview signals Source: https://docs.lightdash.com/api-reference/get-apiv1aiagentsadminreview-signals https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/aiAgents/admin/review-signals # Get apiv1projects aiagents Source: https://docs.lightdash.com/api-reference/get-apiv1projects-aiagents https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/aiAgents # Get apiv1projects aiagents 1 Source: https://docs.lightdash.com/api-reference/get-apiv1projects-aiagents-1 https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/aiAgents/{agentUuid} # Get apiv1projects aiagents artifacts Source: https://docs.lightdash.com/api-reference/get-apiv1projects-aiagents-artifacts https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/artifacts/{artifactUuid} # Get apiv1projects aiagents artifacts versions Source: https://docs.lightdash.com/api-reference/get-apiv1projects-aiagents-artifacts-versions https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/artifacts/{artifactUuid}/versions/{versionUuid} # Get apiv1projects aiagents artifacts versions charts viz query Source: https://docs.lightdash.com/api-reference/get-apiv1projects-aiagents-artifacts-versions-charts-viz-query https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/artifacts/{artifactUuid}/versions/{versionUuid}/charts/{chartIndex}/viz-query # Get apiv1projects aiagents artifacts versions viz query Source: https://docs.lightdash.com/api-reference/get-apiv1projects-aiagents-artifacts-versions-viz-query https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/artifacts/{artifactUuid}/versions/{versionUuid}/viz-query # Get apiv1projects aiagents evaluations Source: https://docs.lightdash.com/api-reference/get-apiv1projects-aiagents-evaluations https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/evaluations # Get apiv1projects aiagents evaluations 1 Source: https://docs.lightdash.com/api-reference/get-apiv1projects-aiagents-evaluations-1 https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/evaluations/{evalUuid} # Get apiv1projects aiagents evaluations runs Source: https://docs.lightdash.com/api-reference/get-apiv1projects-aiagents-evaluations-runs https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/evaluations/{evalUuid}/runs # Get apiv1projects aiagents evaluations runs 1 Source: https://docs.lightdash.com/api-reference/get-apiv1projects-aiagents-evaluations-runs-1 https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/evaluations/{evalUuid}/runs/{runUuid} # Get apiv1projects aiagents mcpservers Source: https://docs.lightdash.com/api-reference/get-apiv1projects-aiagents-mcpservers https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/mcpServers # Get apiv1projects aiagents mcpservers tools Source: https://docs.lightdash.com/api-reference/get-apiv1projects-aiagents-mcpservers-tools https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/mcpServers/{mcpServerUuid}/tools # Get apiv1projects aiagents models Source: https://docs.lightdash.com/api-reference/get-apiv1projects-aiagents-models https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/models # Get apiv1projects aiagents suggestions Source: https://docs.lightdash.com/api-reference/get-apiv1projects-aiagents-suggestions https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/suggestions # Get apiv1projects aiagents threads Source: https://docs.lightdash.com/api-reference/get-apiv1projects-aiagents-threads https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/threads # Get apiv1projects aiagents threads 1 Source: https://docs.lightdash.com/api-reference/get-apiv1projects-aiagents-threads-1 https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/threads/{threadUuid} # Get apiv1projects aiagents verified artifacts Source: https://docs.lightdash.com/api-reference/get-apiv1projects-aiagents-verified-artifacts https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/verified-artifacts # Get apiv1projects aiagents verified questions Source: https://docs.lightdash.com/api-reference/get-apiv1projects-aiagents-verified-questions https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/verified-questions # Get apiv1projects aiagentsmcpservers Source: https://docs.lightdash.com/api-reference/get-apiv1projects-aiagentsmcpservers https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/aiAgents/mcpServers # Get apiv1projects aiagentsmcpservers tools Source: https://docs.lightdash.com/api-reference/get-apiv1projects-aiagentsmcpservers-tools https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/aiAgents/mcpServers/{mcpServerUuid}/tools # Get apiv1projects aiagentsmcpserversgithubavailability Source: https://docs.lightdash.com/api-reference/get-apiv1projects-aiagentsmcpserversgithubavailability https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/aiAgents/mcpServers/github/availability # Get apiv1projects aiagentspreferences Source: https://docs.lightdash.com/api-reference/get-apiv1projects-aiagentspreferences https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/aiAgents/preferences # Get apiv1projects aiagentsthreads Source: https://docs.lightdash.com/api-reference/get-apiv1projects-aiagentsthreads https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/aiAgents/threads # Get GitHub App configuration Source: https://docs.lightdash.com/api-reference/get-github-app-configuration https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/github/config Get GitHub App configuration for the organization # Get linked GitHub account Source: https://docs.lightdash.com/api-reference/get-linked-github-account https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/github/user Get the authenticated user's linked GitHub account, if any # Get MCP activity stats Source: https://docs.lightdash.com/api-reference/get-mcp-activity-stats https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/aiAgents/admin/mcp-activity/stats Get aggregated MCP tool call stats for admin # Get project AI agent prompt activity Source: https://docs.lightdash.com/api-reference/get-project-ai-agent-prompt-activity https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/aiAgents/admin/projects/{projectUuid}/prompt-activity Get prompt activity for one project # Create branch Source: https://docs.lightdash.com/api-reference/git-files/create-branch https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/git/branches Create a new branch from a source branch # Create pull request Source: https://docs.lightdash.com/api-reference/git-files/create-pull-request https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/git/branches/{branch}/pull-request Create a pull request from a branch to the default branch # Delete file Source: https://docs.lightdash.com/api-reference/git-files/delete-file https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/projects/{projectUuid}/git/branches/{branch}/files Delete a file from the repository # Get file or directory Source: https://docs.lightdash.com/api-reference/git-files/get-file-or-directory https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/git/branches/{branch}/files Get file content or directory listing. Returns directory entries if path is a directory, file content if path is a file. # List branches Source: https://docs.lightdash.com/api-reference/git-files/list-branches https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/git/branches List branches for the connected repository # Save file Source: https://docs.lightdash.com/api-reference/git-files/save-file https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json put /api/v1/projects/{projectUuid}/git/branches/{branch}/files Create or update a file. Provide sha to update existing file, omit for new file. # Create file PR Source: https://docs.lightdash.com/api-reference/git-integration/create-file-pr https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/git-integration/pull-requests/file-change Create a pull request with arbitrary file changes # Create PR for custom dimensions Source: https://docs.lightdash.com/api-reference/git-integration/create-pr-for-custom-dimensions https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/git-integration/pull-requests/custom-dimensions Create a pull request for custom dimensions # Create PR for custom metrics Source: https://docs.lightdash.com/api-reference/git-integration/create-pr-for-custom-metrics https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/git-integration/pull-requests/custom-metrics Create a pull request for custom metrics # Get explore file Source: https://docs.lightdash.com/api-reference/git-integration/get-explore-file https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/git-integration/explores/{exploreName}/files Get the YAML file for an explore's base table # Get explore file path Source: https://docs.lightdash.com/api-reference/git-integration/get-explore-file-path https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/git-integration/explores/{exploreName}/file-path Get the file path for an explore's YAML file (without fetching content) # GitHub OAuth callback Source: https://docs.lightdash.com/api-reference/github-oauth-callback https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/github/oauth/callback Callback URL for GitHub App Authorization also used for GitHub App Installation with combined Authorization # GitLab OAuth callback Source: https://docs.lightdash.com/api-reference/gitlab-oauth-callback https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/gitlab/oauth/callback GitLab OAuth callback handler # Start impersonation Source: https://docs.lightdash.com/api-reference/impersonation/start-impersonation https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/impersonation/start Start impersonating a user # Stop impersonation Source: https://docs.lightdash.com/api-reference/impersonation/stop-impersonation https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/impersonation/stop Stop impersonating a user # Install GitHub App Source: https://docs.lightdash.com/api-reference/install-github-app https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/github/install Install the Lightdash GitHub App and link to an organization # Install GitLab integration Source: https://docs.lightdash.com/api-reference/install-gitlab-integration https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/gitlab/install Initiate GitLab OAuth integration # Check Slack OpenID link status Source: https://docs.lightdash.com/api-reference/integrations/check-slack-openid-link-status https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/slack/is-authenticated Check if the user has an OpenID identity for Slack # Delete Slack installation Source: https://docs.lightdash.com/api-reference/integrations/delete-slack-installation https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/slack Delete the Slack installation for the organization # Get Google Drive access token Source: https://docs.lightdash.com/api-reference/integrations/get-google-drive-access-token https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/gdrive/get-access-token Get access token for google drive # Get Slack card image Source: https://docs.lightdash.com/api-reference/integrations/get-slack-card-image https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/slack/card-image/{id} Get a Slack AI agent card image. Falls back to a placeholder image if the image is not found. Intentionally public (no auth): Slack's unfurl bot fetches preview images without user credentials. Access is guarded by an unguessable 21-char nanoid (only minted server-side and shared with Slack during the unfurl of a resource the user already has access to), strict `{id}` validation, and no-store / noindex response headers. # Get Slack channels Source: https://docs.lightdash.com/api-reference/integrations/get-slack-channels https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/slack/channels Get slack channels # Get Slack image Source: https://docs.lightdash.com/api-reference/integrations/get-slack-image https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/slack/image/{nanoId} Get a Slack image by nanoId # Get Slack installation Source: https://docs.lightdash.com/api-reference/integrations/get-slack-installation https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/slack Get Slack installation details for the organization # Get Slack preview Source: https://docs.lightdash.com/api-reference/integrations/get-slack-preview https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/slack/preview/{id} Get a Slack unfurl preview image via redirect to a fresh signed URL. Falls back to a placeholder image if the preview is not found. # Install Slack Source: https://docs.lightdash.com/api-reference/integrations/install-slack https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/slack/install Start the Slack installation flow # Lookup channel Source: https://docs.lightdash.com/api-reference/integrations/lookup-channel https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/slack/channels/{channelId} Look up a single Slack channel by ID. Used for on-demand fetching when user pastes a channel ID not in the cache. # Update Slack custom settings Source: https://docs.lightdash.com/api-reference/integrations/update-slack-custom-settings https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json put /api/v1/slack/custom-settings Update slack notification channel to send notifications to scheduled jobs fail # Upload rows to Google Sheet Source: https://docs.lightdash.com/api-reference/integrations/upload-rows-to-google-sheet https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/gdrive/upload-gsheet-from-rows Upload client-supplied rows to a new Google Sheet (data apps). # Upload to Google Sheet Source: https://docs.lightdash.com/api-reference/integrations/upload-to-google-sheet https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/gdrive/upload-gsheet Upload results from query to Google Sheet # Link GitHub account Source: https://docs.lightdash.com/api-reference/link-github-account https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/github/user/authorize Link the authenticated user's personal GitHub account so write-backs can be authored as them instead of the Lightdash GitHub App # List agent documents Source: https://docs.lightdash.com/api-reference/list-agent-documents https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/documents List the knowledge documents this agent can use: the organization level documents plus the ones granted to this agent in this project. # List AI agent documents Source: https://docs.lightdash.com/api-reference/list-ai-agent-documents https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/aiAgents/documents List every knowledge document in the organization. # List AI agent review items Source: https://docs.lightdash.com/api-reference/list-ai-agent-review-items https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/aiAgents/admin/review-items Get AI agent classifier review items for admin # List AI agent review signals Source: https://docs.lightdash.com/api-reference/list-ai-agent-review-signals https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/aiAgents/admin/review-items/{fingerprint} Get AI agent classifier review signals for admin debugging # List AI agent thread pull requests Source: https://docs.lightdash.com/api-reference/list-ai-agent-thread-pull-requests https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/threads/{threadUuid}/pull-requests List every pull request the coding agent has opened in this thread (its workstreams), each enriched with live PR state where available. A thread can drive several PRs across one or more repos. # List AI agent threads Source: https://docs.lightdash.com/api-reference/list-ai-agent-threads https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/aiAgents/admin/threads Get all AI agent threads for admin # List AI agents Source: https://docs.lightdash.com/api-reference/list-ai-agents https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/aiAgents/admin/agents Get all AI agents for admin # List GitHub repositories Source: https://docs.lightdash.com/api-reference/list-github-repositories https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/github/repos/list List GitHub repositories accessible via the installed app # List GitLab projects Source: https://docs.lightdash.com/api-reference/list-gitlab-projects https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/gitlab/repos/list List GitLab projects accessible via the integration # List MCP activity Source: https://docs.lightdash.com/api-reference/list-mcp-activity https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/aiAgents/admin/mcp-activity Get MCP tool call activity for admin # List router decisions Source: https://docs.lightdash.com/api-reference/list-router-decisions https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/org/aiRouter/decisions List recent routing decisions for the org's router. # Proxy GeoJSON Source: https://docs.lightdash.com/api-reference/map/proxy-geojson https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/geojson-proxy Proxies external GeoJSON files to bypass CORS restrictions # Compile metric total query Source: https://docs.lightdash.com/api-reference/metrics-explorer/compile-metric-total-query https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/metricsExplorer/{explore}/{metric}/compileMetricTotalQuery Compile the metric total query SQL # Run metric total query Source: https://docs.lightdash.com/api-reference/metrics-explorer/run-metric-total-query https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/metricsExplorer/{explore}/{metric}/runMetricTotal Run a metric total query with comparison # Complete Redshift AWS SSO login Source: https://docs.lightdash.com/api-reference/my-account/complete-redshift-aws-sso-login https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/user/warehouseCredentials/redshift/aws-sso/complete Complete Redshift AWS SSO login # Create email one-time passcode Source: https://docs.lightdash.com/api-reference/my-account/create-email-one-time-passcode https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json put /api/v1/user/me/email/otp Create a new one-time passcode for the current user's primary email. The user will receive an email with the passcode. # Create personal access token Source: https://docs.lightdash.com/api-reference/my-account/create-personal-access-token https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/user/me/personal-access-tokens Create personal access token # Create warehouse credentials Source: https://docs.lightdash.com/api-reference/my-account/create-warehouse-credentials https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/user/warehouseCredentials Create user warehouse credentials # Delete avatar Source: https://docs.lightdash.com/api-reference/my-account/delete-avatar https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/user/me/avatar Remove the current user's uploaded avatar. # Delete personal access token Source: https://docs.lightdash.com/api-reference/my-account/delete-personal-access-token https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/user/me/personal-access-tokens/{personalAccessTokenUuid} Delete personal access token # Delete user Source: https://docs.lightdash.com/api-reference/my-account/delete-user https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/user/me Delete user # Delete warehouse credentials Source: https://docs.lightdash.com/api-reference/my-account/delete-warehouse-credentials https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/user/warehouseCredentials/{uuid} Delete user warehouse credentials # Get account Source: https://docs.lightdash.com/api-reference/my-account/get-account https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/user/account Get account information # Get authenticated user Source: https://docs.lightdash.com/api-reference/my-account/get-authenticated-user https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/user Get authenticated user # Get email verification status Source: https://docs.lightdash.com/api-reference/my-account/get-email-verification-status https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/user/me/email/status Get the verification status for the current user's primary email # Get login options Source: https://docs.lightdash.com/api-reference/my-account/get-login-options https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/user/login-options Get login options # Get user avatar Source: https://docs.lightdash.com/api-reference/my-account/get-user-avatar https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/users/{userUuid}/avatar/{contentHash} Serve a user's avatar image. Content-addressed by hash, so responses are immutable and cached by the browser indefinitely. # Join organization Source: https://docs.lightdash.com/api-reference/my-account/join-organization https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/user/me/joinOrganization/{organizationUuid} Add the current user to an organization that accepts users with a verified email domain. This will fail if the organization email domain does not match the user's primary email domain. # Leave organization Source: https://docs.lightdash.com/api-reference/my-account/leave-organization https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/user/me/leaveOrganization Remove the current user from their organization. Fails if the caller is the only admin remaining. The user record is preserved so they can join another organization later. # List available organizations Source: https://docs.lightdash.com/api-reference/my-account/list-available-organizations https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/user/me/allowedOrganizations List the organizations that the current user can join. This is based on the user's primary email domain and the organization's allowed email domains. # List personal access tokens Source: https://docs.lightdash.com/api-reference/my-account/list-personal-access-tokens https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/user/me/personal-access-tokens List personal access tokens # List warehouse credentials Source: https://docs.lightdash.com/api-reference/my-account/list-warehouse-credentials https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/user/warehouseCredentials Get user warehouse credentials # Register user Source: https://docs.lightdash.com/api-reference/my-account/register-user https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/user Register user # Rotate personal access token Source: https://docs.lightdash.com/api-reference/my-account/rotate-personal-access-token https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/user/me/personal-access-tokens/{personalAccessTokenUuid}/rotate Rotate personal access token # Start Redshift AWS SSO login Source: https://docs.lightdash.com/api-reference/my-account/start-redshift-aws-sso-login https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/user/warehouseCredentials/redshift/aws-sso/start Start Redshift AWS SSO login # Update warehouse credentials Source: https://docs.lightdash.com/api-reference/my-account/update-warehouse-credentials https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/user/warehouseCredentials/{uuid} Update user warehouse credentials # Upload avatar Source: https://docs.lightdash.com/api-reference/my-account/upload-avatar https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json put /api/v1/user/me/avatar Upload a profile avatar. Send raw image bytes as the body with an image/png, image/jpeg or image/webp Content-Type. The image is center-cropped, resized and re-encoded server-side. # Get notifications Source: https://docs.lightdash.com/api-reference/notifications/get-notifications https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/notifications Gets notifications for a user based on the type # Update notification Source: https://docs.lightdash.com/api-reference/notifications/update-notification https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/notifications/{notificationId} Update notification # Create warehouse credentials Source: https://docs.lightdash.com/api-reference/organization-warehouse-credentials/create-warehouse-credentials https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/org/warehouse-credentials Create new warehouse credentials for the organization # Delete warehouse credentials Source: https://docs.lightdash.com/api-reference/organization-warehouse-credentials/delete-warehouse-credentials https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/org/warehouse-credentials/{credentialsUuid} Delete warehouse credentials # Get warehouse credential Source: https://docs.lightdash.com/api-reference/organization-warehouse-credentials/get-warehouse-credential https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/org/warehouse-credentials/{credentialsUuid} Get a specific warehouse credential by UUID # List warehouse credentials Source: https://docs.lightdash.com/api-reference/organization-warehouse-credentials/list-warehouse-credentials https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/org/warehouse-credentials Get all warehouse credentials for the current organization # Update warehouse credentials Source: https://docs.lightdash.com/api-reference/organization-warehouse-credentials/update-warehouse-credentials https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/org/warehouse-credentials/{credentialsUuid} Update existing warehouse credentials # Clear default organization design Source: https://docs.lightdash.com/api-reference/organizations/clear-default-organization-design https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/org/designs/default Clear whichever design is currently the organization default. Idempotent — succeeds when no default is set. NOTE: This literal `/default` route MUST stay registered before `Delete('/{designUuid}')` below so Express routes a request to `DELETE /api/v1/org/designs/default` here rather than treating "default" as a `designUuid` path param. # Confirm domain verification Source: https://docs.lightdash.com/api-reference/organizations/confirm-domain-verification https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/org/domains/confirm Confirms a domain verification passcode. On success the domain is marked verified for the organization. # Create color palette Source: https://docs.lightdash.com/api-reference/organizations/create-color-palette https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/org/color-palettes Create a new color palette # Create group Source: https://docs.lightdash.com/api-reference/organizations/create-group https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/org/groups Creates a new group in the current user's organization # Create invite link Source: https://docs.lightdash.com/api-reference/organizations/create-invite-link https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/invite-links Invite a new user to the organization and create an invite link for them. If the email already belongs to a pending user, a new invite link is generated for them. Only available to organization admins. # Create organization Source: https://docs.lightdash.com/api-reference/organizations/create-organization https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json put /api/v1/org Creates a new organization, the current user becomes the Admin of the new organization. This is only available to users that are not already in an organization. # Create organization design Source: https://docs.lightdash.com/api-reference/organizations/create-organization-design https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/org/designs Create a new organization design. Starts empty — upload files separately. # Create project Source: https://docs.lightdash.com/api-reference/organizations/create-project https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/org/projects Create a new project in the organization # Delete Azure AD SSO configuration Source: https://docs.lightdash.com/api-reference/organizations/delete-azure-ad-sso-configuration https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/org/sso/azuread Removes the current organization's Azure AD SSO configuration. # Delete color palette Source: https://docs.lightdash.com/api-reference/organizations/delete-color-palette https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/org/color-palettes/{colorPaletteUuid} Delete a color palette # Delete email sending domain Source: https://docs.lightdash.com/api-reference/organizations/delete-email-sending-domain https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/org/{organizationUuid}/email-whitelabel Removes the sending domain and reverts the organization to the Lightdash sending identity. # Delete file from organization design Source: https://docs.lightdash.com/api-reference/organizations/delete-file-from-organization-design https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/org/designs/{designUuid}/files/{fileUuid} Delete a single file from an organization design. # Delete generic OIDC SSO configuration Source: https://docs.lightdash.com/api-reference/organizations/delete-generic-oidc-sso-configuration https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/org/sso/oidc Removes the current organization's generic OIDC SSO configuration. # Delete Google SSO configuration Source: https://docs.lightdash.com/api-reference/organizations/delete-google-sso-configuration https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/org/sso/google Removes the current organization's Google SSO policy, reverting to the instance default (Google enabled). # Delete Okta SSO configuration Source: https://docs.lightdash.com/api-reference/organizations/delete-okta-sso-configuration https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/org/sso/okta Removes the current organization's Okta SSO configuration. # Delete OneLogin SSO configuration Source: https://docs.lightdash.com/api-reference/organizations/delete-onelogin-sso-configuration https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/org/sso/oneLogin Removes the current organization's OneLogin SSO configuration. # Delete organization Source: https://docs.lightdash.com/api-reference/organizations/delete-organization https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/org/{organizationUuid} Deletes an organization and all users inside that organization # Delete organization design Source: https://docs.lightdash.com/api-reference/organizations/delete-organization-design https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/org/designs/{designUuid} Delete an organization design and all its files (cascades S3). # Delete organization member Source: https://docs.lightdash.com/api-reference/organizations/delete-organization-member https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/org/user/{userUuid} Deletes a user from the current user's organization # Delete verified domain Source: https://docs.lightdash.com/api-reference/organizations/delete-verified-domain https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/org/domains/{domain} Removes a verified domain and strips it from any SSO provider that routed to it. # Download file from organization design Source: https://docs.lightdash.com/api-reference/organizations/download-file-from-organization-design https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/org/designs/{designUuid}/files/{fileUuid} Download a single file from an organization design. Streams the S3 object body back with the stored Content-Type and a sensible Content-Disposition. # Enable or disable email sending domain Source: https://docs.lightdash.com/api-reference/organizations/enable-or-disable-email-sending-domain https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/org/{organizationUuid}/email-whitelabel Enables or disables sending from the verified domain. Can only be enabled once both DKIM and return-path are verified. # Get Azure AD SSO configuration Source: https://docs.lightdash.com/api-reference/organizations/get-azure-ad-sso-configuration https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/org/sso/azuread Returns the current organization's Azure AD SSO configuration (sensitive fields are not included). # Get current organization Source: https://docs.lightdash.com/api-reference/organizations/get-current-organization https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/org Get the current user's organization # Get email whitelabel configuration Source: https://docs.lightdash.com/api-reference/organizations/get-email-whitelabel-configuration https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/org/{organizationUuid}/email-whitelabel Returns the organization's email sending domain configuration, or null if none has been set up. # Get generic OIDC SSO configuration Source: https://docs.lightdash.com/api-reference/organizations/get-generic-oidc-sso-configuration https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/org/sso/oidc Returns the current organization's generic OIDC SSO configuration (sensitive fields are not included). # Get Google SSO configuration Source: https://docs.lightdash.com/api-reference/organizations/get-google-sso-configuration https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/org/sso/google Returns the current organization's Google SSO policy. Google is enabled by default using the shared instance OAuth app; a configuration only exists when the org has set an explicit policy (e.g. disabled Google). `null` means no explicit policy — Google follows the instance default. # Get impersonation settings Source: https://docs.lightdash.com/api-reference/organizations/get-impersonation-settings https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/org/impersonation Get the impersonation setting for the current organization # Get invite link Source: https://docs.lightdash.com/api-reference/organizations/get-invite-link https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/invite-links/{inviteLinkCode} Get an invite link by its code. Public endpoint used by the invite acceptance page. # Get Okta SSO configuration Source: https://docs.lightdash.com/api-reference/organizations/get-okta-sso-configuration https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/org/sso/okta Returns the current organization's Okta SSO configuration (sensitive fields are not included). # Get OneLogin SSO configuration Source: https://docs.lightdash.com/api-reference/organizations/get-onelogin-sso-configuration https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/org/sso/oneLogin Returns the current organization's OneLogin SSO configuration (sensitive fields are not included). # Get organization brand Source: https://docs.lightdash.com/api-reference/organizations/get-organization-brand https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/org/brand Get the organization's brand profile, previously fetched from Brandfetch. Returns null if no brand profile has been fetched yet. # Get organization design Source: https://docs.lightdash.com/api-reference/organizations/get-organization-design https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/org/designs/{designUuid} Get a single organization design with its files. # Get organization member by email Source: https://docs.lightdash.com/api-reference/organizations/get-organization-member-by-email https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/org/users/email/{email} Get the member profile for a user in the current user's organization by email # Get organization member by UUID Source: https://docs.lightdash.com/api-reference/organizations/get-organization-member-by-uuid https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/org/users/{userUuid} Get the member profile for a user in the current user's organization by uuid # Get organization settings Source: https://docs.lightdash.com/api-reference/organizations/get-organization-settings https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/org/settings Returns the current organization's settings. Defaults are returned when no settings have been saved. # Get user schedulers Source: https://docs.lightdash.com/api-reference/organizations/get-user-schedulers https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/org/user/{userUuid}/schedulers-summary Gets a summary of scheduled deliveries owned by a user across all projects # List allowed email domains Source: https://docs.lightdash.com/api-reference/organizations/list-allowed-email-domains https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/org/allowedEmailDomains Gets the allowed email domains for the current user's organization # List color palettes Source: https://docs.lightdash.com/api-reference/organizations/list-color-palettes https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/org/color-palettes List all color palettes in the organization # List organization designs Source: https://docs.lightdash.com/api-reference/organizations/list-organization-designs https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/org/designs List all organization design assets. # List organization groups Source: https://docs.lightdash.com/api-reference/organizations/list-organization-groups https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/org/groups Gets all the groups in the current user's organization # List organization members Source: https://docs.lightdash.com/api-reference/organizations/list-organization-members https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/org/users Gets all the members of the current user's organization # List organization projects Source: https://docs.lightdash.com/api-reference/organizations/list-organization-projects https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/org/projects Gets all projects of the current user's organization # List verified domains Source: https://docs.lightdash.com/api-reference/organizations/list-verified-domains https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/org/domains Lists the domains the current organization has verified ownership of. # Reassign schedulers Source: https://docs.lightdash.com/api-reference/organizations/reassign-schedulers https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/org/user/{userUuid}/reassign-schedulers Reassigns all scheduled deliveries from one user to another # Request domain verification Source: https://docs.lightdash.com/api-reference/organizations/request-domain-verification https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/org/domains/verify Sends a one-time passcode to an address at the domain to begin verifying ownership. The domain must not be a public email provider and must not already be verified by another organization. # Revoke all invite links Source: https://docs.lightdash.com/api-reference/organizations/revoke-all-invite-links https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/invite-links Revoke all invite links in the organization. Only available to organization admins. # Set active color palette Source: https://docs.lightdash.com/api-reference/organizations/set-active-color-palette https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/org/color-palettes/{colorPaletteUuid}/active Set a color palette as the active palette # Set default organization design Source: https://docs.lightdash.com/api-reference/organizations/set-default-organization-design https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/org/designs/{designUuid}/default Mark this design as the organization's default. Clears any previous default. # Set up email sending domain Source: https://docs.lightdash.com/api-reference/organizations/set-up-email-sending-domain https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json put /api/v1/org/{organizationUuid}/email-whitelabel Sets up (or replaces) the organization's sending domain and returns the DNS records to publish. Does not start sending — the domain must be verified and enabled first. # Update allowed email domains Source: https://docs.lightdash.com/api-reference/organizations/update-allowed-email-domains https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/org/allowedEmailDomains Updates the allowed email domains for the current user's organization # Update color palette Source: https://docs.lightdash.com/api-reference/organizations/update-color-palette https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/org/color-palettes/{colorPaletteUuid} Update a color palette # Update current organization Source: https://docs.lightdash.com/api-reference/organizations/update-current-organization https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/org Update the current user's organization # Update impersonation settings Source: https://docs.lightdash.com/api-reference/organizations/update-impersonation-settings https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/org/impersonation Update the impersonation setting for the current organization # Update organization brand Source: https://docs.lightdash.com/api-reference/organizations/update-organization-brand https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/org/brand Fetch the brand profile for a domain from Brandfetch and store it on the organization. Requires the Brandfetch API key to be configured on the instance. # Update organization design Source: https://docs.lightdash.com/api-reference/organizations/update-organization-design https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/org/designs/{designUuid} Update an organization design's name or description. # Update organization settings Source: https://docs.lightdash.com/api-reference/organizations/update-organization-settings https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/org/settings Updates the current organization's settings. Only the provided fields are changed. # Upload file to organization design Source: https://docs.lightdash.com/api-reference/organizations/upload-file-to-organization-design https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/org/designs/{designUuid}/files Upload a file into a design. Send raw bytes as the body with the appropriate Content-Type and Content-Length headers. Pass `kind` and `filename` as query parameters. Mirrors the data-app image upload pattern — no multipart wrapping required. # Upsert Azure AD SSO configuration Source: https://docs.lightdash.com/api-reference/organizations/upsert-azure-ad-sso-configuration https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json put /api/v1/org/sso/azuread Creates or updates the current organization's Azure AD SSO configuration. Omit `oauth2ClientSecret` to preserve the previously stored secret on updates. # Upsert generic OIDC SSO configuration Source: https://docs.lightdash.com/api-reference/organizations/upsert-generic-oidc-sso-configuration https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json put /api/v1/org/sso/oidc Creates or updates the current organization's generic OIDC SSO configuration. Omit `clientSecret` to preserve the previously stored secret on updates. # Upsert Google SSO configuration Source: https://docs.lightdash.com/api-reference/organizations/upsert-google-sso-configuration https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json put /api/v1/org/sso/google Creates or updates the current organization's Google SSO policy. Google has no per-org credentials — only the `enabled` / domain / password flags are stored. # Upsert Okta SSO configuration Source: https://docs.lightdash.com/api-reference/organizations/upsert-okta-sso-configuration https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json put /api/v1/org/sso/okta Creates or updates the current organization's Okta SSO configuration. Omit `oauth2ClientSecret` to preserve the previously stored secret on updates. # Upsert OneLogin SSO configuration Source: https://docs.lightdash.com/api-reference/organizations/upsert-onelogin-sso-configuration https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json put /api/v1/org/sso/oneLogin Creates or updates the current organization's OneLogin SSO configuration. Omit `oauth2ClientSecret` to preserve the previously stored secret on updates. # Verify email sending domain Source: https://docs.lightdash.com/api-reference/organizations/verify-email-sending-domain https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/org/{organizationUuid}/email-whitelabel/verify Triggers verification of the DNS records with the email provider and returns the refreshed status. Safe to call repeatedly while DNS propagates. # Patch apiv1projects aiagents Source: https://docs.lightdash.com/api-reference/patch-apiv1projects-aiagents https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/projects/{projectUuid}/aiAgents/{agentUuid} # Patch apiv1projects aiagents artifacts versions saveddashboard Source: https://docs.lightdash.com/api-reference/patch-apiv1projects-aiagents-artifacts-versions-saveddashboard https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/artifacts/{artifactUuid}/versions/{versionUuid}/savedDashboard # Patch apiv1projects aiagents artifacts versions verified Source: https://docs.lightdash.com/api-reference/patch-apiv1projects-aiagents-artifacts-versions-verified https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/artifacts/{artifactUuid}/versions/{versionUuid}/verified # Patch apiv1projects aiagents evaluations Source: https://docs.lightdash.com/api-reference/patch-apiv1projects-aiagents-evaluations https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/evaluations/{evalUuid} # Patch apiv1projects aiagents mcpservers tools Source: https://docs.lightdash.com/api-reference/patch-apiv1projects-aiagents-mcpservers-tools https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/mcpServers/{mcpServerUuid}/tools # Patch apiv1projects aiagents threads messages feedback Source: https://docs.lightdash.com/api-reference/patch-apiv1projects-aiagents-threads-messages-feedback https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/threads/{threadUuid}/messages/{messageUuid}/feedback # Patch apiv1projects aiagents threads messages savedquery Source: https://docs.lightdash.com/api-reference/patch-apiv1projects-aiagents-threads-messages-savedquery https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/threads/{threadUuid}/messages/{messageUuid}/savedQuery # Post apiv1projects aiagents Source: https://docs.lightdash.com/api-reference/post-apiv1projects-aiagents https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/aiAgents # Post apiv1projects aiagents append instruction Source: https://docs.lightdash.com/api-reference/post-apiv1projects-aiagents-append-instruction https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/append-instruction # Post apiv1projects aiagents avatar Source: https://docs.lightdash.com/api-reference/post-apiv1projects-aiagents-avatar https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/avatar # Post apiv1projects aiagents evaluatereadiness Source: https://docs.lightdash.com/api-reference/post-apiv1projects-aiagents-evaluatereadiness https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/evaluateReadiness # Post apiv1projects aiagents evaluations Source: https://docs.lightdash.com/api-reference/post-apiv1projects-aiagents-evaluations https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/evaluations # Post apiv1projects aiagents evaluations append Source: https://docs.lightdash.com/api-reference/post-apiv1projects-aiagents-evaluations-append https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/evaluations/{evalUuid}/append # Post apiv1projects aiagents evaluations run Source: https://docs.lightdash.com/api-reference/post-apiv1projects-aiagents-evaluations-run https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/evaluations/{evalUuid}/run # Post apiv1projects aiagents threads Source: https://docs.lightdash.com/api-reference/post-apiv1projects-aiagents-threads https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/threads # Post apiv1projects aiagents threads clone Source: https://docs.lightdash.com/api-reference/post-apiv1projects-aiagents-threads-clone https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/threads/{threadUuid}/clone/{promptUuid} # Post apiv1projects aiagents threads generate Source: https://docs.lightdash.com/api-reference/post-apiv1projects-aiagents-threads-generate https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/threads/{threadUuid}/generate # Post apiv1projects aiagents threads generate title Source: https://docs.lightdash.com/api-reference/post-apiv1projects-aiagents-threads-generate-title https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/threads/{threadUuid}/generate-title # Post apiv1projects aiagents threads messages Source: https://docs.lightdash.com/api-reference/post-apiv1projects-aiagents-threads-messages https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/threads/{threadUuid}/messages # Post apiv1projects aiagents threads messages interrupt Source: https://docs.lightdash.com/api-reference/post-apiv1projects-aiagents-threads-messages-interrupt https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/threads/{threadUuid}/messages/{messageUuid}/interrupt # Post apiv1projects aiagents threads messages revert change Source: https://docs.lightdash.com/api-reference/post-apiv1projects-aiagents-threads-messages-revert-change https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/threads/{threadUuid}/messages/{promptUuid}/revert-change # Post apiv1projects aiagents threads messages steers Source: https://docs.lightdash.com/api-reference/post-apiv1projects-aiagents-threads-messages-steers https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/threads/{threadUuid}/messages/{messageUuid}/steers # Post apiv1projects aiagents threads shares Source: https://docs.lightdash.com/api-reference/post-apiv1projects-aiagents-threads-shares https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/threads/{threadUuid}/shares # Post apiv1projects aiagents threads stream Source: https://docs.lightdash.com/api-reference/post-apiv1projects-aiagents-threads-stream https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/threads/{threadUuid}/stream # Post apiv1projects aiagents threads tool calls sql approval Source: https://docs.lightdash.com/api-reference/post-apiv1projects-aiagents-threads-tool-calls-sql-approval https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/threads/{threadUuid}/tool-calls/{toolCallId}/sql-approval # Post apiv1projects aiagentsexplore access summary Source: https://docs.lightdash.com/api-reference/post-apiv1projects-aiagentsexplore-access-summary https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/aiAgents/explore-access-summary # Post apiv1projects aiagentsmcpservers Source: https://docs.lightdash.com/api-reference/post-apiv1projects-aiagentsmcpservers https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/aiAgents/mcpServers # Post apiv1projects aiagentsmcpservers credential Source: https://docs.lightdash.com/api-reference/post-apiv1projects-aiagentsmcpservers-credential https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/aiAgents/mcpServers/{mcpServerUuid}/credential # Post apiv1projects aiagentsmcpservers oauthdisconnect Source: https://docs.lightdash.com/api-reference/post-apiv1projects-aiagentsmcpservers-oauthdisconnect https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/aiAgents/mcpServers/{mcpServerUuid}/oauth/disconnect # Post apiv1projects aiagentsmcpservers oauthstart Source: https://docs.lightdash.com/api-reference/post-apiv1projects-aiagentsmcpservers-oauthstart https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/aiAgents/mcpServers/{mcpServerUuid}/oauth/start # Post apiv1projects aiagentsmcpservers toolsrefresh Source: https://docs.lightdash.com/api-reference/post-apiv1projects-aiagentsmcpservers-toolsrefresh https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/aiAgents/mcpServers/{mcpServerUuid}/tools/refresh # Post apiv1projects aiagentsmcpserversgithubconnect Source: https://docs.lightdash.com/api-reference/post-apiv1projects-aiagentsmcpserversgithubconnect https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/aiAgents/mcpServers/github/connect # Post apiv1projects aiagentspreferences Source: https://docs.lightdash.com/api-reference/post-apiv1projects-aiagentspreferences https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/aiAgents/preferences # Post apiv1projects aiagentsthread shares clone Source: https://docs.lightdash.com/api-reference/post-apiv1projects-aiagentsthread-shares-clone https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/aiAgents/thread-shares/{aiThreadShareUuid}/clone # Preview AI agent review item writeback diff Source: https://docs.lightdash.com/api-reference/preview-ai-agent-review-item-writeback-diff https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/aiAgents/admin/review-items/{fingerprint}/writeback-preview Preview the file change a writeback PR would make, without opening it. Only project_context findings have a deterministic diff. # Add deploy batch Source: https://docs.lightdash.com/api-reference/project/add-deploy-batch https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v2/projects/{projectUuid}/deploy/{sessionUuid}/batch Add a batch of explores to an existing deploy session # Finalize deploy Source: https://docs.lightdash.com/api-reference/project/finalize-deploy https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v2/projects/{projectUuid}/deploy/{sessionUuid}/finalize Finalize a deploy session and commit all staged explores to the project # Start deploy session Source: https://docs.lightdash.com/api-reference/project/start-deploy-session https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v2/projects/{projectUuid}/deploy Start a new deploy session for batched explore uploads # Add dbt source Source: https://docs.lightdash.com/api-reference/projects/add-dbt-source https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/dbt-sources Add an additional dbt source to a project. # Calculate subtotals from query Source: https://docs.lightdash.com/api-reference/projects/calculate-subtotals-from-query https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/calculate-subtotals Calculate subtotals from a metricQuery # Calculate total from query Source: https://docs.lightdash.com/api-reference/projects/calculate-total-from-query https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/calculate-total Calculate all metric totals from a metricQuery # Check BigQuery authentication Source: https://docs.lightdash.com/api-reference/projects/check-bigquery-authentication https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/bigquery/sso/is-authenticated Check if user is authenticated with BigQuery # Check Databricks OAuth authentication Source: https://docs.lightdash.com/api-reference/projects/check-databricks-oauth-authentication https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/databricks/sso/is-authenticated Check if user is authenticated with Databricks OAuth # Check pre-aggregate Source: https://docs.lightdash.com/api-reference/projects/check-pre-aggregate https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/explores/{exploreId}/preAggregateCheck Check pre-aggregate availability for a metric query # Check Snowflake SSO authentication Source: https://docs.lightdash.com/api-reference/projects/check-snowflake-sso-authentication https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/snowflake/sso/is-authenticated Check if the user is authenticated with Snowflake SSO # Compile query Source: https://docs.lightdash.com/api-reference/projects/compile-query https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/explores/{exploreId}/compileQuery Compile a metric query for an explore # Create dashboard Source: https://docs.lightdash.com/api-reference/projects/create-dashboard https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/dashboards Create a new dashboard in a project # Create dashboard with charts Source: https://docs.lightdash.com/api-reference/projects/create-dashboard-with-charts https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/dashboards/with-charts Create a new dashboard with embedded charts # Create project preview Source: https://docs.lightdash.com/api-reference/projects/create-project-preview https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/createPreview Create a preview project # Create tag Source: https://docs.lightdash.com/api-reference/projects/create-tag https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/tags Create a new tag in a project # Delete tag Source: https://docs.lightdash.com/api-reference/projects/delete-tag https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/projects/{projectUuid}/tags/{tagUuid} Delete a tag from a project # Dismiss validation error Source: https://docs.lightdash.com/api-reference/projects/dismiss-validation-error https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/projects/{projectUuid}/validate/{validationIdOrUuid} Deletes a single validation error. # Download user activity CSV Source: https://docs.lightdash.com/api-reference/projects/download-user-activity-csv https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/analytics/user-activity/{projectUuid}/download Download user activity as CSV # Get apiv1projects colorpalette Source: https://docs.lightdash.com/api-reference/projects/get-apiv1projects-colorpalette https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/colorPalette # Get BigQuery datasets Source: https://docs.lightdash.com/api-reference/projects/get-bigquery-datasets https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/bigquery/sso/datasets Get BigQuery datasets for a project # Get BigQuery projects Source: https://docs.lightdash.com/api-reference/projects/get-bigquery-projects https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/bigquery/sso/projects Get BigQuery projects accessible by the user # Get chart fields for rename Source: https://docs.lightdash.com/api-reference/projects/get-chart-fields-for-rename https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/rename/chart/{chartUuid}/fields Get a list of fields for this chart's explore to be used when renaming a chart in the UI # Get compilation log for a specific job Source: https://docs.lightdash.com/api-reference/projects/get-compilation-log-for-a-specific-job https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/compile-logs/job/{jobUuid} Get compilation log by job UUID # Get dashboard fields for rename Source: https://docs.lightdash.com/api-reference/projects/get-dashboard-fields-for-rename https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/rename/dashboard/{dashboardUuid}/fields Get a list of fields from explores referenced by the dashboard's filters # Get dbt source Source: https://docs.lightdash.com/api-reference/projects/get-dbt-source https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/dbt-sources/{projectDbtSourceUuid} Get a single dbt source including its connection, with credentials stripped — used to pre-fill the edit form. # Get download activity log Source: https://docs.lightdash.com/api-reference/projects/get-download-activity-log https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/analytics/user-activity/{projectUuid}/download-activity Get download activity log for a project, ordered by most recent first. Two pagination modes are supported: - Offset mode: pass `page` (1-indexed) and `pageSize`. Response includes `page`/`totalResults`/`totalPageCount`. - Cursor mode: pass `cursor` (from a previous response's `nextCursor`) and `pageSize`. `page` is ignored when `cursor` is provided. Avoids the count query so `page`/`totalResults`/`totalPageCount` are null in the response. # Get explore Source: https://docs.lightdash.com/api-reference/projects/get-explore https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/explores/{exploreId} Get a specific explore # Get preview expiration settings Source: https://docs.lightdash.com/api-reference/projects/get-preview-expiration-settings https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/previews-config Get preview project expiration settings for a project # Get project Source: https://docs.lightdash.com/api-reference/projects/get-project https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid} Get a project of an organiztion # Get project color palette Source: https://docs.lightdash.com/api-reference/projects/get-project-color-palette https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/table-groups Get the resolved color palette for a project, walking the chart -> dashboard -> space -> project -> organization fallback chain (matches saved-chart resolution). The optional UUIDs let unsaved renderers (Explore, AI viz, sql runner) opt into deeper layers as they become available. # Get project compilation logs Source: https://docs.lightdash.com/api-reference/projects/get-project-compilation-logs https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/compile-logs Get compilation logs for a project # Get SQL charts as code Source: https://docs.lightdash.com/api-reference/projects/get-sql-charts-as-code https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/sqlCharts/code Gets SQL charts in code representation # Get upstream diff Source: https://docs.lightdash.com/api-reference/projects/get-upstream-diff https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/upstreamDiff Diff a preview project against the project it was copied from, using the catalog index. Detects added/removed fields and label changes; does not detect SQL-only field changes. # Get user activity Source: https://docs.lightdash.com/api-reference/projects/get-user-activity https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/analytics/user-activity/{projectUuid} Get user activity for a project # Get user warehouse credentials preference Source: https://docs.lightdash.com/api-reference/projects/get-user-warehouse-credentials-preference https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/user-credentials Get the user's warehouse credentials preference for a project # Get validation results Source: https://docs.lightdash.com/api-reference/projects/get-validation-results https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/validate Get validation results for a project. This will return the results of the latest validation job. # Handle dbt Cloud webhook Source: https://docs.lightdash.com/api-reference/projects/handle-dbt-cloud-webhook https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/dbt-cloud/webhook Handle dbt Cloud webhook for job completion # List chart summaries in project Source: https://docs.lightdash.com/api-reference/projects/list-chart-summaries-in-project https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/chart-summaries List all charts summaries in a project # List charts as code Source: https://docs.lightdash.com/api-reference/projects/list-charts-as-code https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/charts/code Get charts in code representation # List charts by explore Source: https://docs.lightdash.com/api-reference/projects/list-charts-by-explore https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/explores/{exploreId}/charts List charts referencing a given explore # List charts in project Source: https://docs.lightdash.com/api-reference/projects/list-charts-in-project https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/charts List all charts in a project # List custom metrics Source: https://docs.lightdash.com/api-reference/projects/list-custom-metrics https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/custom-metrics Get all custom metrics in a project # List dashboards Source: https://docs.lightdash.com/api-reference/projects/list-dashboards https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/dashboards Get all dashboards in a project # List dashboards as code Source: https://docs.lightdash.com/api-reference/projects/list-dashboards-as-code https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/dashboards/code Get dashboards in code representation # List dbt sources Source: https://docs.lightdash.com/api-reference/projects/list-dbt-sources https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/dbt-sources List the dbt sources connected to a project (the primary source plus any additional sources), without credentials. # List explores Source: https://docs.lightdash.com/api-reference/projects/list-explores https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/explores Get all explores for a project # List project group accesses Source: https://docs.lightdash.com/api-reference/projects/list-project-group-accesses https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/groupAccesses List group access for projects # List project user warehouse credentials Source: https://docs.lightdash.com/api-reference/projects/list-project-user-warehouse-credentials https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/user-warehouse-credentials Get user warehouse credentials available for a project # List spaces in project Source: https://docs.lightdash.com/api-reference/projects/list-spaces-in-project https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/spaces List all spaces in a project # List tags Source: https://docs.lightdash.com/api-reference/projects/list-tags https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/tags Get all tags in a project # List verified content Source: https://docs.lightdash.com/api-reference/projects/list-verified-content https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/content-verification List all verified content (charts and dashboards) in a project # Preview data timezone Source: https://docs.lightdash.com/api-reference/projects/preview-data-timezone https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/preview-data-timezone Preview how the warehouse disambiguates "now" under a data timezone # Preview rename Source: https://docs.lightdash.com/api-reference/projects/preview-rename https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/rename/preview Preview which resources would be affected by a bulk rename # Refresh pre-aggregate by definition name Source: https://docs.lightdash.com/api-reference/projects/refresh-pre-aggregate-by-definition-name https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/pre-aggregates/definitions/{preAggregateDefinitionName}/refresh Refresh a single pre-aggregate by its definition name # Refresh project Source: https://docs.lightdash.com/api-reference/projects/refresh-project https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/refresh Refresh a project by recompiling dbt # Refresh project pre-aggregates Source: https://docs.lightdash.com/api-reference/projects/refresh-project-pre-aggregates https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/pre-aggregates/refresh Refresh all pre-aggregates in a project # Remove dbt source Source: https://docs.lightdash.com/api-reference/projects/remove-dbt-source https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/projects/{projectUuid}/dbt-sources/{projectDbtSourceUuid} Remove an additional dbt source from a project. The primary source cannot be removed. # Rename chart Source: https://docs.lightdash.com/api-reference/projects/rename-chart https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/rename/chart/{chartUuid} Rename a chart and its fields # Rename dashboard filter Source: https://docs.lightdash.com/api-reference/projects/rename-dashboard-filter https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/rename/dashboard/{dashboardUuid} Rename a dashboard filter's field or model reference # Rename resources Source: https://docs.lightdash.com/api-reference/projects/rename-resources https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/rename Rename resources in a project # Replace project table groups Source: https://docs.lightdash.com/api-reference/projects/replace-project-table-groups https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json put /api/v1/projects/{projectUuid}/table-groups Replace project-level table-group definitions. Sent by the CLI on deploy/preview so labels & descriptions from `table_groups` in `lightdash.config.yml` are applied. Pass an empty object to clear. # Replace YAML tags Source: https://docs.lightdash.com/api-reference/projects/replace-yaml-tags https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json put /api/v1/projects/{projectUuid}/tags/yaml Replace all YAML-defined tags in a project # Set explores Source: https://docs.lightdash.com/api-reference/projects/set-explores https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json put /api/v1/projects/{projectUuid}/explores Set explores for a project # Update dashboards Source: https://docs.lightdash.com/api-reference/projects/update-dashboards https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/projects/{projectUuid}/dashboards Update multiple dashboards # Update dbt source Source: https://docs.lightdash.com/api-reference/projects/update-dbt-source https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/projects/{projectUuid}/dbt-sources/{projectDbtSourceUuid} Update an additional dbt source's name or connection. # Update default user spaces setting Source: https://docs.lightdash.com/api-reference/projects/update-default-user-spaces-setting https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/projects/{projectUuid}/hasDefaultUserSpaces Toggle default user spaces for a project. When enabled, creates personal spaces for all eligible users. # Update preview expiration settings Source: https://docs.lightdash.com/api-reference/projects/update-preview-expiration-settings https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/projects/{projectUuid}/previews-config Update preview project expiration settings for a project # Update project color palette Source: https://docs.lightdash.com/api-reference/projects/update-project-color-palette https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/projects/{projectUuid}/colorPalette Set the project's color palette to one of its organization's palettes, or null to inherit from the organization's active palette. # Update project metadata Source: https://docs.lightdash.com/api-reference/projects/update-project-metadata https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/projects/{projectUuid}/metadata Update project metadata like upstreamProjectUuid we don't trigger a compile, so not for updating warehouse or credentials # Update query timezone settings Source: https://docs.lightdash.com/api-reference/projects/update-query-timezone-settings https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/projects/{projectUuid}/queryTimezoneSettings Update query timezone settings for a project # Update scheduler settings Source: https://docs.lightdash.com/api-reference/projects/update-scheduler-settings https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/projects/{projectUuid}/schedulerSettings Update scheduler settings for a project # Update tag Source: https://docs.lightdash.com/api-reference/projects/update-tag https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/projects/{projectUuid}/tags/{tagUuid} Update a tag in a project # Update user warehouse credentials preference Source: https://docs.lightdash.com/api-reference/projects/update-user-warehouse-credentials-preference https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/projects/{projectUuid}/user-credentials/{userWarehouseCredentialsUuid} Update the user's warehouse credentials preference for a project # Upsert chart as code Source: https://docs.lightdash.com/api-reference/projects/upsert-chart-as-code https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/charts/{slug}/code Upsert a chart from code representation # Upsert dashboard as code Source: https://docs.lightdash.com/api-reference/projects/upsert-dashboard-as-code https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/dashboards/{slug}/code Upsert a dashboard from code representation # Upsert SQL chart as code Source: https://docs.lightdash.com/api-reference/projects/upsert-sql-chart-as-code https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/sqlCharts/{slug}/code Upserts an SQL chart from code representation # Validate formula Source: https://docs.lightdash.com/api-reference/projects/validate-formula https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/explores/{exploreId}/validateFormula Validate a spreadsheet formula against the explore's fields # Validate project Source: https://docs.lightdash.com/api-reference/projects/validate-project https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/validate Validate content inside a project. This will start a validation job and return the job id. Validation jobs scan all charts and dashboards inside a project to find any broken references to metrics or dimensions that aren't available. Results are available after the job is completed. # Validate specific chart Source: https://docs.lightdash.com/api-reference/projects/validate-specific-chart https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/validate/chart/{chartUuid} Validates a specific chart and updates validation entries in database. # Validate specific dashboard Source: https://docs.lightdash.com/api-reference/projects/validate-specific-dashboard https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/validate/dashboard/{dashboardUuid} Validates a specific dashboard and updates validation entries in database. # List pull requests Source: https://docs.lightdash.com/api-reference/pull-requests/list-pull-requests https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/pull-requests List the pull requests that have been created by write-backs for a project # Reorder AI agent review items on the board Source: https://docs.lightdash.com/api-reference/reorder-ai-agent-review-items-on-the-board https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/aiAgents/admin/review-items/reorder Persist the board's manual card order for one lane. Declared before the `{fingerprint}` route so "reorder" isn't matched as a fingerprint. # Retest an AI agent review remediation Source: https://docs.lightdash.com/api-reference/retest-an-ai-agent-review-remediation https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/aiAgents/admin/review-items/{fingerprint}/retest Re-verify a remediation after its PR changed: recompiles the existing preview and re-runs the Test-fix verification thread. # Create space Source: https://docs.lightdash.com/api-reference/roles-&-permissions/create-space https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/spaces Create a new space inside a project # Get project member access Source: https://docs.lightdash.com/api-reference/roles-&-permissions/get-project-member-access https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/user/{userUuid} Get a project explicit member's access. There may be users that have access to the project via their organization membership. # Grant group access to space Source: https://docs.lightdash.com/api-reference/roles-&-permissions/grant-group-access-to-space https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/spaces/{spaceUuid}/group/share Grant a group access to a space # Grant project access to user Source: https://docs.lightdash.com/api-reference/roles-&-permissions/grant-project-access-to-user https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/access Grant a user access to a project # Grant user access to space Source: https://docs.lightdash.com/api-reference/roles-&-permissions/grant-user-access-to-space https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/spaces/{spaceUuid}/share Grant a user access to a space # List project access Source: https://docs.lightdash.com/api-reference/roles-&-permissions/list-project-access https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/access Get access list for a project. This is a list of users that have been explictly granted access to the project. There may be other users that have access to the project via their organization membership. # Revoke group access to space Source: https://docs.lightdash.com/api-reference/roles-&-permissions/revoke-group-access-to-space https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/projects/{projectUuid}/spaces/{spaceUuid}/group/share/{groupUuid} Remove a group's access to a space # Revoke project access for user Source: https://docs.lightdash.com/api-reference/roles-&-permissions/revoke-project-access-for-user https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/projects/{projectUuid}/access/{userUuid} Remove a user's access to a project # Revoke user access to space Source: https://docs.lightdash.com/api-reference/roles-&-permissions/revoke-user-access-to-space https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/projects/{projectUuid}/spaces/{spaceUuid}/share/{userUuid} Remove a user's access to a space # Update organization member Source: https://docs.lightdash.com/api-reference/roles-&-permissions/update-organization-member https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/org/users/{userUuid} Updates the membership profile for a user in the current user's organization # Update project access for user Source: https://docs.lightdash.com/api-reference/roles-&-permissions/update-project-access-for-user https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/projects/{projectUuid}/access/{userUuid} Update a user's access to a project # Update space Source: https://docs.lightdash.com/api-reference/roles-&-permissions/update-space https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/projects/{projectUuid}/spaces/{spaceUuid} Update a space in a project # Route prompt Source: https://docs.lightdash.com/api-reference/route-prompt https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/org/aiRouter/route Route a user prompt to the best candidate agent in the current project. # Delete scheduler Source: https://docs.lightdash.com/api-reference/schedulers/delete-scheduler https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/schedulers/{schedulerUuid} Delete a scheduler # Delete scheduler AI augmentation Source: https://docs.lightdash.com/api-reference/schedulers/delete-scheduler-ai-augmentation https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/schedulers/{schedulerUuid}/ai-augmentation Remove the AI augmentation from a scheduled delivery. # Get run logs Source: https://docs.lightdash.com/api-reference/schedulers/get-run-logs https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/schedulers/runs/{runId}/logs Get detailed logs for a specific scheduler run # Get scheduled jobs Source: https://docs.lightdash.com/api-reference/schedulers/get-scheduled-jobs https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/schedulers/{schedulerUuid}/jobs Get scheduled jobs # Get scheduler Source: https://docs.lightdash.com/api-reference/schedulers/get-scheduler https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/schedulers/{schedulerUuid} Get a scheduler # Get scheduler AI augmentation Source: https://docs.lightdash.com/api-reference/schedulers/get-scheduler-ai-augmentation https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/schedulers/{schedulerUuid}/ai-augmentation Get the AI augmentation attached to a scheduled delivery, or null. # Get scheduler job status Source: https://docs.lightdash.com/api-reference/schedulers/get-scheduler-job-status https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/schedulers/job/{jobId}/status Get a generic job status This method can be used when polling from the frontend # Get scheduler logs Source: https://docs.lightdash.com/api-reference/schedulers/get-scheduler-logs https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/schedulers/{projectUuid}/logs Get scheduled logs # List scheduler runs Source: https://docs.lightdash.com/api-reference/schedulers/list-scheduler-runs https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/schedulers/{projectUuid}/runs Get paginated scheduler runs with aggregated child job counts # List schedulers Source: https://docs.lightdash.com/api-reference/schedulers/list-schedulers https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/schedulers/{projectUuid}/list List all schedulers with pagination, search, sorting, and filtering # List user schedulers Source: https://docs.lightdash.com/api-reference/schedulers/list-user-schedulers https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/schedulers/user-schedulers List all schedulers for the current user across all projects with pagination, search, sorting, and filtering # Reassign scheduler owner Source: https://docs.lightdash.com/api-reference/schedulers/reassign-scheduler-owner https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/schedulers/{projectUuid}/reassign-owner Reassign ownership of multiple schedulers # Send scheduler Source: https://docs.lightdash.com/api-reference/schedulers/send-scheduler https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/schedulers/send Send a scheduler now before saving it # Send scheduler by uuid Source: https://docs.lightdash.com/api-reference/schedulers/send-scheduler-by-uuid https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/schedulers/{schedulerUuid}/send Send an existing scheduler now by its uuid # Update scheduler Source: https://docs.lightdash.com/api-reference/schedulers/update-scheduler https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/schedulers/{schedulerUuid} Update a scheduler # Update scheduler enabled status Source: https://docs.lightdash.com/api-reference/schedulers/update-scheduler-enabled-status https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/schedulers/{schedulerUuid}/enabled Set scheduler enabled # Upsert scheduler AI augmentation Source: https://docs.lightdash.com/api-reference/schedulers/upsert-scheduler-ai-augmentation https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json put /api/v1/schedulers/{schedulerUuid}/ai-augmentation Attach or replace the AI augmentation on a scheduled delivery. # Create group Source: https://docs.lightdash.com/api-reference/scim/create-group https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/scim/v2/Groups Create a new group in the SCIM application # Create user Source: https://docs.lightdash.com/api-reference/scim/create-user https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/scim/v2/Users Create a new user # Delete group Source: https://docs.lightdash.com/api-reference/scim/delete-group https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/scim/v2/Groups/{id} Delete a specific group by its SCIM ID # Delete user Source: https://docs.lightdash.com/api-reference/scim/delete-user https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/scim/v2/Users/{userUuid} Delete a user by ID # Get group Source: https://docs.lightdash.com/api-reference/scim/get-group https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/scim/v2/Groups/{id} Get a specific group by its SCIM ID # Get resource type Source: https://docs.lightdash.com/api-reference/scim/get-resource-type https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/scim/v2/ResourceTypes/{resourceTypeId} Get individual SCIM resource type # Get role Source: https://docs.lightdash.com/api-reference/scim/get-role https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/scim/v2/Roles/{roleId} Get a SCIM role by ID # Get schema Source: https://docs.lightdash.com/api-reference/scim/get-schema https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/scim/v2/Schemas/{schemaId} Get individual SCIM schema # Get user Source: https://docs.lightdash.com/api-reference/scim/get-user https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/scim/v2/Users/{userUuid} Get a SCIM user by ID # List groups Source: https://docs.lightdash.com/api-reference/scim/list-groups https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/scim/v2/Groups Get a list of groups within an organization # List resource types Source: https://docs.lightdash.com/api-reference/scim/list-resource-types https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/scim/v2/ResourceTypes Get SCIM resource types # List roles Source: https://docs.lightdash.com/api-reference/scim/list-roles https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/scim/v2/Roles Get a list of roles within an organization # List schemas Source: https://docs.lightdash.com/api-reference/scim/list-schemas https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/scim/v2/Schemas Get SCIM schemas # List users Source: https://docs.lightdash.com/api-reference/scim/list-users https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/scim/v2/Users List SCIM users in the organization # Patch group Source: https://docs.lightdash.com/api-reference/scim/patch-group https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/scim/v2/Groups/{id} Partially updates a group’s attributes (e.g., add or remove members). # Patch user Source: https://docs.lightdash.com/api-reference/scim/patch-user https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/scim/v2/Users/{userUuid} Patch a user by ID (SCIM PATCH) # Provider config Source: https://docs.lightdash.com/api-reference/scim/provider-config https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/scim/v2/ServiceProviderConfig Get SCIM service provider configuration # Replace group Source: https://docs.lightdash.com/api-reference/scim/replace-group https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json put /api/v1/scim/v2/Groups/{id} Update a group's attributes completely # Replace user Source: https://docs.lightdash.com/api-reference/scim/replace-user https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json put /api/v1/scim/v2/Users/{userUuid} Update a user by ID (SCIM PUT) # Root check Source: https://docs.lightdash.com/api-reference/scim/root-check https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/scim/v2 Root SCIM endpoint for validating SCIM configuration # Create share URL Source: https://docs.lightdash.com/api-reference/share-links/create-share-url https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/share Given a full URL generates a short url id that can be used for sharing # Get share URL Source: https://docs.lightdash.com/api-reference/share-links/get-share-url https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/share/{nanoId} Get a share url from a short url id # Delete space Source: https://docs.lightdash.com/api-reference/spaces/delete-space https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/projects/{projectUuid}/spaces/{spaceUuid} Delete a space from a project # Get delete impact Source: https://docs.lightdash.com/api-reference/spaces/get-delete-impact https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/spaces/{spaceUuid}/delete-impact Get the impact of deleting a space (affected child spaces, charts, dashboards) # Get space Source: https://docs.lightdash.com/api-reference/spaces/get-space https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/spaces/{spaceUuid} Get details for a space in a project # Get spotlight table config Source: https://docs.lightdash.com/api-reference/spotlight/get-spotlight-table-config https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/spotlight/table/config Get spotlight table configuration # Reset spotlight table config Source: https://docs.lightdash.com/api-reference/spotlight/reset-spotlight-table-config https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/projects/{projectUuid}/spotlight/table/config Reset spotlight table configuration to defaults # Update spotlight table config Source: https://docs.lightdash.com/api-reference/spotlight/update-spotlight-table-config https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/spotlight/table/config Create or update spotlight table configuration # Create SQL chart Source: https://docs.lightdash.com/api-reference/sql-runner/create-sql-chart https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/sqlRunner/saved Create sql chart # Create SQL chart scheduler Source: https://docs.lightdash.com/api-reference/sql-runner/create-sql-chart-scheduler https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/sqlRunner/saved/{savedSqlUuid}/schedulers Create a scheduler for a SQL chart # Create virtual view Source: https://docs.lightdash.com/api-reference/sql-runner/create-virtual-view https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/sqlRunner/virtual-view Create a virtual-view # Create write back PR Source: https://docs.lightdash.com/api-reference/sql-runner/create-write-back-pr https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/sqlRunner/pull-request Write back from SQL runner # Delete SQL chart Source: https://docs.lightdash.com/api-reference/sql-runner/delete-sql-chart https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/projects/{projectUuid}/sqlRunner/saved/{uuid} Delete sql chart # Delete virtual view Source: https://docs.lightdash.com/api-reference/sql-runner/delete-virtual-view https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/projects/{projectUuid}/sqlRunner/virtual-view/{name} Delete a virtual-view # Get SQL chart Source: https://docs.lightdash.com/api-reference/sql-runner/get-sql-chart https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/sqlRunner/saved/{uuid} Get saved sql chart # Get SQL chart by slug Source: https://docs.lightdash.com/api-reference/sql-runner/get-sql-chart-by-slug https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/sqlRunner/saved/slug/{slug} Get saved sql chart # Get SQL chart promotion diff Source: https://docs.lightdash.com/api-reference/sql-runner/get-sql-chart-promotion-diff https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/sqlRunner/saved/{uuid}/promoteDiff Get diff from SQL chart to promote # Get SQL chart results job Source: https://docs.lightdash.com/api-reference/sql-runner/get-sql-chart-results-job https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/sqlRunner/saved/slug/{slug}/results-job Schedules a job to get its results # Get SQL chart results job by UUID Source: https://docs.lightdash.com/api-reference/sql-runner/get-sql-chart-results-job-by-uuid https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/sqlRunner/saved/{uuid}/results-job Schedules a job to get its results # Get stored results Source: https://docs.lightdash.com/api-reference/sql-runner/get-stored-results https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/sqlRunner/results/{fileId} Get results from a file stored locally # Get table fields Source: https://docs.lightdash.com/api-reference/sql-runner/get-table-fields https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/sqlRunner/fields Get fields for a warehouse table # List SQL chart schedulers Source: https://docs.lightdash.com/api-reference/sql-runner/list-sql-chart-schedulers https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/sqlRunner/saved/{savedSqlUuid}/schedulers Get all schedulers for a SQL chart # List warehouse tables Source: https://docs.lightdash.com/api-reference/sql-runner/list-warehouse-tables https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/projects/{projectUuid}/sqlRunner/tables Get warehouse tables for a project # Preview write back Source: https://docs.lightdash.com/api-reference/sql-runner/preview-write-back https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/sqlRunner/preview Preview write back from SQL runner # Promote SQL chart Source: https://docs.lightdash.com/api-reference/sql-runner/promote-sql-chart https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/sqlRunner/saved/{uuid}/promote Promote SQL chart to upstream project # Refresh catalog cache Source: https://docs.lightdash.com/api-reference/sql-runner/refresh-catalog-cache https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/sqlRunner/refresh-catalog Refresh the catalog cache # Run SQL pivot query Source: https://docs.lightdash.com/api-reference/sql-runner/run-sql-pivot-query https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/sqlRunner/runPivotQuery Run a SQL pivot query # Run SQL query Source: https://docs.lightdash.com/api-reference/sql-runner/run-sql-query https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/projects/{projectUuid}/sqlRunner/run Run a SQL query # Update SQL chart Source: https://docs.lightdash.com/api-reference/sql-runner/update-sql-chart https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/projects/{projectUuid}/sqlRunner/saved/{uuid} Update sql chart # Update virtual view Source: https://docs.lightdash.com/api-reference/sql-runner/update-virtual-view https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json put /api/v1/projects/{projectUuid}/sqlRunner/virtual-view/{name} Update a virtual view # Create SSH key pair Source: https://docs.lightdash.com/api-reference/ssh-keypairs/create-ssh-key-pair https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/ssh/key-pairs Create a new SSH key pair # Uninstall GitHub App Source: https://docs.lightdash.com/api-reference/uninstall-github-app https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/github/uninstall Uninstall the GitHub App from the organization # Uninstall GitLab integration Source: https://docs.lightdash.com/api-reference/uninstall-gitlab-integration https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/gitlab/uninstall Uninstall GitLab integration from the organization # Unlink GitHub account Source: https://docs.lightdash.com/api-reference/unlink-github-account https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/github/user Unlink the authenticated user's GitHub account and revoke its token # Update agent document Source: https://docs.lightdash.com/api-reference/update-agent-document https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/projects/{projectUuid}/aiAgents/{agentUuid}/documents/{documentUuid} Choose whether the full knowledge document is included in every prompt. # Update AI agent review item assignee Source: https://docs.lightdash.com/api-reference/update-ai-agent-review-item-assignee https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/aiAgents/admin/review-items/{fingerprint}/assignee Set the assignee on an AI agent review item # Update AI agent review item priority Source: https://docs.lightdash.com/api-reference/update-ai-agent-review-item-priority https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/aiAgents/admin/review-items/{fingerprint}/priority Set the priority on an AI agent review item # Update AI agent review item status Source: https://docs.lightdash.com/api-reference/update-ai-agent-review-item-status https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/aiAgents/admin/review-items/{fingerprint} Update the status of an AI agent review item (e.g. dismiss it) # Update AI review notification settings Source: https://docs.lightdash.com/api-reference/update-ai-review-notification-settings https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json put /api/v1/aiAgents/admin/review-notification-settings Update AI review notification settings # Update AI settings Source: https://docs.lightdash.com/api-reference/update-ai-settings https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/aiAgents/admin/settings Update AI organization settings # Upsert AI router config Source: https://docs.lightdash.com/api-reference/upsert-ai-router-config https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json put /api/v1/org/aiRouter Upsert the AI router configuration. Creates the row lazily on first save. # Upsert AI router instruction Source: https://docs.lightdash.com/api-reference/upsert-ai-router-instruction https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json put /api/v1/org/aiRouter/instructions/{projectUuid} Write a new routing-instruction version for a project. Versions are append-only; the latest one is the active instruction. # Create user attribute Source: https://docs.lightdash.com/api-reference/user-attributes/create-user-attribute https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/org/attributes Creates new user attribute # Delete user attribute Source: https://docs.lightdash.com/api-reference/user-attributes/delete-user-attribute https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/org/attributes/{userAttributeUuid} Remove a user attribute # List user attributes Source: https://docs.lightdash.com/api-reference/user-attributes/list-user-attributes https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/org/attributes Get all user attributes # Update user attribute Source: https://docs.lightdash.com/api-reference/user-attributes/update-user-attribute https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json put /api/v1/org/attributes/{userAttributeUuid} Updates a user attribute # Add project access to group Source: https://docs.lightdash.com/api-reference/user-groups/add-project-access-to-group https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v1/groups/{groupUuid}/projects/{projectUuid} Add project access to a group # Add user to group Source: https://docs.lightdash.com/api-reference/user-groups/add-user-to-group https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json put /api/v1/groups/{groupUuid}/members/{userUuid} Add a Lightdash user to a group # Delete group Source: https://docs.lightdash.com/api-reference/user-groups/delete-group https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/groups/{groupUuid} Delete a group # Get group Source: https://docs.lightdash.com/api-reference/user-groups/get-group https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/groups/{groupUuid} Get group details # Get group members Source: https://docs.lightdash.com/api-reference/user-groups/get-group-members https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v1/groups/{groupUuid}/members View members of a group # Remove project access from group Source: https://docs.lightdash.com/api-reference/user-groups/remove-project-access-from-group https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/groups/{groupUuid}/projects/{projectUuid} Remove project access from a group # Remove user from group Source: https://docs.lightdash.com/api-reference/user-groups/remove-user-from-group https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v1/groups/{groupUuid}/members/{userUuid} Remove a user from a group # Update group Source: https://docs.lightdash.com/api-reference/user-groups/update-group https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/groups/{groupUuid} Update a group # Update project access for group Source: https://docs.lightdash.com/api-reference/user-groups/update-project-access-for-group https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v1/groups/{groupUuid}/projects/{projectUuid} Update project access for a group # Lightdash API Source: https://docs.lightdash.com/api-reference/v1/introduction [Support](https://docs.lightdash.com/help-and-contact/contact/contact-info): [support@lightdash.com](mailto:support@lightdash.com) | License: [MIT](#) ## Open API documentation for all public Lightdash API endpoints. Before you get started, you might need to create a Personal Access Token to authenticate via the API. You can create a token by following this guide: [https://docs.lightdash.com/references/workspace/personal-tokens](https://docs.lightdash.com/references/workspace/personal-tokens) # Recipes Source: https://docs.lightdash.com/api-reference/v1/recipes A collection of practical, copy-paste examples showing how to combine Lightdash API endpoints to achieve common workflows. ## What are API recipes? The Lightdash API is intentionally modular: most endpoints return small, focused pieces of information. While this keeps the API flexible, some real-world tasks require calling multiple endpoints together or assembling responses in a certain order. For example, Lightdash doesn’t provide a single endpoint that returns “SQL for every chart,” but you *can* accomplish this by combining the chart-listing endpoint with the metric-query endpoint. Follow the recipes below. **API recipes** are short guides that show you *how to do exactly that*. Each recipe walks through: * **What you’re trying to accomplish** (e.g., fetch SQL for all charts in a project) * **Which endpoints to call and in what order** * **Example requests** in `curl` * **Optional scripts** in JS/Python when useful ## When should you use recipes? Use a recipe when: * You want to automate a workflow that spans multiple endpoints * You need to query Lightdash programmatically but aren’t sure which calls to chain * You want real examples of authentication, pagination, or interpreting metric queries * You’re building internal tooling or dashboards powered by the Lightdash API This page includes a few of the most common API recipes, but it’s not a complete list. For all available recipes, see the full collection [here](https://github.com/lightdash/lightdash-api-examples). ## Before you run any recipe You will need: * Python 3.9+ installed * A [Personal Access Token (PAT)](https://docs.lightdash.com/references/workspace/personal-tokens#personal-access-tokens) * Your Lightdash instance URL * The project UUID you want to modify ## Extract SQL from a saved Lightdash chart using the API This recipe shows how to fetch the underlying SQL for any saved chart. You can use this to debug queries, run them directly in your warehouse, or automate data pulls outside of Lightdash. ### Step 1: Fetch the saved chart (You must first create a Personal Access Token (PAT)) ``` curl -H "Authorization: ApiKey ldpat_{{your_personal_access_token}}" \ https://{{your.lightdash.instance}}/api/v1/saved/{{your_chart_uuid}} ``` ### Step 2: Extract the `metricQuery` JSON ``` curl -s \ -H "Authorization: ApiKey ldpat_{{your_personal_access_token}}" \ https://{{your.lightdash.instance}}/api/v1/saved/{{your_chart_uuid}} \ | jq '.results.metricQuery' > metricQuery.json ``` This writes the chart’s semantic query definition to `metricQuery.json`. ### Step 3: Compile the `metricQuery` into SQL ``` curl -s -X POST \ -H "Authorization: ApiKey ldpat_{{your_personal_access_token}}" \ -H "Content-Type: application/json" \ -d @metricQuery.json \ https://{{your.lightdash.instance}}/api/v1/projects/{{your_project_uuid}}/explores/{{your_explore_name}}/compileQuery \ | jq '.results.query' ``` ### One-Step Solution ``` curl -s -H "Authorization: ApiKey ldpat_{{your_personal_access_token}}" \ https://{{your.lightdash.instance}}/api/v1/savedc/{{your_chart_uuid}} \ | jq '.results.metricQuery' \ | curl -s -X POST \ -H "Authorization: ApiKey ldpat_{{your_personal_access_token}}" \ -H "Content-Type: application/json" \ -d @- \ https://{{your.lightdash.instance}}/api/v1/projects/{{your_project_uuid}}/explores/{{your_explore_name}}/compileQuery \ | jq '.results.query' ``` ## Dashboard cleanup & usage audit for a project This Python script helps you **clean up dashboards** in a specific Lightdash project. It uses the v2 Content API and can export results to CSV, Excel, or JSON for deeper analysis. This script provides: * A complete list of all dashboards with metadata for that project * View counts and first viewed dates * Creation and last modification dates * Dashboard organization by spaces * Cleanup recommendations based on usage patterns (never viewed, low engagement, stale, no description, etc.) ### Before you run this script You will need: * A copy of [find\_dashboards.py](https://github.com/lightdash/lightdash-api-examples/blob/main/python/find_dashboards.py) ### Step 1: Install dependencies You can run this script with **poetry** or plain Python: ``` poetry install # OR pip install -r requirements.txt ``` (Dependencies include `requests` and `pandas`.) ### Step 2: Update script configuration Open the script and update these fields: ``` API_URL = 'https://{YOUR_INSTANCE_URL}.lightdash.cloud' # Your Lightdash instance API_KEY = '' # Your Personal Access Token PROJECT_UUID = '' # Project you want to analyze (REQUIRED) EXPORT_METHOD = 'csv' # 'csv', 'excel', or 'json' ``` ### Step 3: Run the script Using poetry: ``` poetry run python find_dashboards.py ``` Or directly: ``` python find_dashboards.py ``` ## Export all users in your organization This Python script fetches **all users in your Lightdash organization** using the `/api/v1/org/users` endpoint. This is useful for **audits**, **access reviews**, and **governance**. It returns: * Full name * Email * Role * Group membership * Optional Excel or CSV export ### Before you run this script You will need: * A copy of [get\_all\_organization\_users.py](https://github.com/lightdash/lightdash-api-examples/blob/main/python/get_all_organization_users.py) ### Step 1: Install dependencies ``` pip install requests pandas ``` (or add them to your environment of choice) ### Step 2: Update script configuration Open the script and replace: ``` API_URL = 'https://.lightdash.cloud/api/v1/org/users' API_KEY = '' EXPORT_METHOD = 'excel' # or 'csv' ``` ### Step 3: Run the script ``` python get_all_organization_users.py ``` ## Assign or update project access for a list of users This Python script assigns Lightdash **project roles** to a list of users from a CSV file, and upgrades roles when needed. This is useful for **large-scale onboarding**, **role synchronization**, or **managing customer/partner access**. This script handles: * Bulk granting of project access * Automatic role upgrades (e.g., viewer → editor) * Skipping users who already have equal or higher access * Checking whether users exist in the organization * Merging org users, project access, and your CSV into one unified dataset ### Before you run this script You will need: * A CSV file of users with desired roles * A copy of [assign\_project\_access\_to\_user\_list.py](https://github.com/lightdash/lightdash-api-examples/blob/main/python/assign_project_access_to_user_list.py) ### Step 1: Prepare your CSV file Your CSV should contain **two columns**: ``` email,role user1@example.com,viewer user2@example.com,editor user3@example.com,developer ``` Valid roles: ``` viewer, interactive_viewer, editor, developer, admin ``` ### Step 2: Install dependencies ``` pip install pandas lightdash-api-client ``` (or via poetry) ### Step 3: Update script configuration Open the script and update: ``` TARGET_URL = 'https://app.lightdash.cloud/api/v1/' TARGET_API_KEY = '' TARGET_PROJECT_ID = '' USER_PERMS_FILEPATH = '~/Documents/user_permission_list.csv' ``` ### Step 4: Run the script ``` python assign_project_access_to_user_list.py ``` ## Filter metrics by tag using the data catalog API The `/api/v2/projects/{projectUuid}/dataCatalog/metrics-with-time-dimensions` endpoint returns metrics from your project's data catalog. You can filter the results by field-level tags using the `tags` query parameter, which makes it possible to retrieve only the metrics relevant to a specific workflow — such as a headless metrics store pipeline or a semantic layer integration. Field-level tags are set in your dbt YAML under individual metrics and dimensions. See the [metrics reference](/references/metrics#tags) and [dimensions reference](/references/dimensions#tags) for syntax details. ### Step 1: Tag your metrics in dbt Add tags to specific metrics in your dbt YAML: ```yaml theme={null} models: - name: orders columns: - name: amount meta: metrics: total_order_amount: type: sum tags: ["core", "finance"] average_order_amount: type: average tags: ["core"] ``` ```yaml theme={null} models: - name: orders columns: - name: amount config: meta: metrics: total_order_amount: type: sum tags: ["core", "finance"] average_order_amount: type: average tags: ["core"] ``` ```yaml theme={null} type: model name: orders metrics: total_order_amount: type: sum sql: ${TABLE}.amount tags: ["core", "finance"] average_order_amount: type: average sql: ${TABLE}.amount tags: ["core"] ``` ### Step 2: Fetch metrics filtered by tag Use the `tags` query parameter to retrieve only metrics with matching tags. You can pass multiple `tags` parameters to filter by more than one tag (OR logic — metrics matching **any** of the provided tags are returned). ```bash theme={null} curl -H "Authorization: ApiKey ldpat_{{your_personal_access_token}}" \ "https://{{your.lightdash.instance}}/api/v2/projects/{{your_project_uuid}}/dataCatalog/metrics-with-time-dimensions?page=1&pageSize=10&sort=label&order=asc&tags=core&tags=finance" ``` ### Example response Each metric in the response includes a `tags` array showing all tags assigned to it: ```json theme={null} { "status": "ok", "results": { "data": [ { "name": "total_order_amount", "label": "Total order amount", "tags": ["core", "finance"], "categories": [], "tableName": "orders", "tableLabel": "Orders", ... }, { "name": "average_order_amount", "label": "Average order amount", "tags": ["core"], "categories": [], "tableName": "orders", "tableLabel": "Orders", ... } ] } } ``` ### Supported query parameters | Parameter | Type | Description | | :--------- | :----- | :------------------------------------------------------------------------- | | `page` | number | Page number for pagination (starts at 1) | | `pageSize` | number | Number of results per page | | `sort` | string | Field to sort by (e.g., `label`) | | `order` | string | Sort order: `asc` or `desc` | | `tags` | string | Filter by tag. Repeat the parameter to filter by multiple tags (OR logic). | Tags are a backend-only mechanism — they are **not** displayed as Spotlight categories in the Lightdash UI. This makes them suitable for controlling API-driven workflows without affecting the end-user experience. # Add scopes to role Source: https://docs.lightdash.com/api-reference/v2/add-scopes-to-role https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v2/orgs/{orgUuid}/roles/{roleUuid}/scopes Add scopes to role # Assign organization role to user Source: https://docs.lightdash.com/api-reference/v2/assign-organization-role-to-user https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v2/orgs/{orgUuid}/roles/assignments/user/{userId} Assign system or organization-level custom role to user at organization level # Assign project role to group Source: https://docs.lightdash.com/api-reference/v2/assign-project-role-to-group https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v2/projects/{projectId}/roles/assignments/group/{groupId} Create or update project role assignment for group (upsert) # Assign project role to user Source: https://docs.lightdash.com/api-reference/v2/assign-project-role-to-user https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v2/projects/{projectId}/roles/assignments/user/{userId} Create or update project role assignment for user (upsert) # Calculate totals Source: https://docs.lightdash.com/api-reference/v2/calculate-totals https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v2/projects/{projectUuid}/query/{queryUuid}/calculate-total Calculates totals for a previously-executed query, referenced by its queryUuid. Re-runs the source query's MetricQuery against the warehouse so totals are correct for every metric type (count distinct, average, ratio, etc.) — unlike client-side cell summation, which only works for sum/count. The requested `kind` selects which totals to compute. # Cancel query Source: https://docs.lightdash.com/api-reference/v2/cancel-query https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v2/projects/{projectUuid}/query/{queryUuid}/cancel Cancels a running async query and discards any partial results # Create custom role Source: https://docs.lightdash.com/api-reference/v2/create-custom-role https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v2/orgs/{orgUuid}/roles Create a new role in organization # Delete chart Source: https://docs.lightdash.com/api-reference/v2/delete-chart https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v2/projects/{projectUuid}/saved/{chartUuidOrSlug} Delete a saved chart by uuid or slug within a project # Delete custom role Source: https://docs.lightdash.com/api-reference/v2/delete-custom-role https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v2/orgs/{orgUuid}/roles/{roleUuid} Delete role from organization # Delete dashboard Source: https://docs.lightdash.com/api-reference/v2/delete-dashboard https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v2/projects/{projectUuid}/dashboards/{dashboardUuidOrSlug} Delete a dashboard by uuid or slug within a project # Download results Source: https://docs.lightdash.com/api-reference/v2/download-results https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v2/projects/{projectUuid}/query/{queryUuid}/download Downloads query results in various formats with custom formatting options # Download results Source: https://docs.lightdash.com/api-reference/v2/download-results-1 https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v2/projects/{projectUuid}/query/{queryUuid}/schedule-download Downloads query results in various formats with custom formatting options # Duplicate role Source: https://docs.lightdash.com/api-reference/v2/duplicate-role https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v2/orgs/{orgUuid}/roles/{roleId}/duplicate Duplicate a role # Execute dashboard chart Source: https://docs.lightdash.com/api-reference/v2/execute-dashboard-chart https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v2/projects/{projectUuid}/query/dashboard-chart Executes a chart within a dashboard context asynchronously with inherited dashboard filters # Execute dashboard SQL chart Source: https://docs.lightdash.com/api-reference/v2/execute-dashboard-sql-chart https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v2/projects/{projectUuid}/query/dashboard-sql-chart Executes a SQL chart within a dashboard context asynchronously with inherited filters # Execute metric query Source: https://docs.lightdash.com/api-reference/v2/execute-metric-query https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v2/projects/{projectUuid}/query/metric-query Executes a metric query asynchronously against your data warehouse using dimensions, metrics, filters, and sorts # Execute saved chart Source: https://docs.lightdash.com/api-reference/v2/execute-saved-chart https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v2/projects/{projectUuid}/query/chart Executes a saved chart query asynchronously with optional parameter overrides # Execute SQL chart Source: https://docs.lightdash.com/api-reference/v2/execute-sql-chart https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v2/projects/{projectUuid}/query/sql-chart Executes a saved SQL chart query asynchronously with optional chart configurations # Execute SQL query Source: https://docs.lightdash.com/api-reference/v2/execute-sql-query https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v2/projects/{projectUuid}/query/sql Executes a raw SQL query asynchronously against your data warehouse for custom queries # Execute underlying data Source: https://docs.lightdash.com/api-reference/v2/execute-underlying-data https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v2/projects/{projectUuid}/query/underlying-data Executes a query to retrieve underlying raw data for drilling down into aggregated values # Export dashboard content Source: https://docs.lightdash.com/api-reference/v2/export-dashboard-content https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v2/dashboards/{dashboardUuid}/exports Export dashboard content # Get chart Source: https://docs.lightdash.com/api-reference/v2/get-chart https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v2/projects/{projectUuid}/saved/{chartUuidOrSlug} Get a saved chart by uuid or slug within a project # Get comments Source: https://docs.lightdash.com/api-reference/v2/get-comments https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v2/projects/{projectUuid}/dashboards/{dashboardUuidOrSlug}/comments Gets all comments for a dashboard within a project # Get custom role Source: https://docs.lightdash.com/api-reference/v2/get-custom-role https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v2/orgs/{orgUuid}/roles/{roleUuid} Get custom role by uuid # Get dashboard Source: https://docs.lightdash.com/api-reference/v2/get-dashboard https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v2/projects/{projectUuid}/dashboards/{dashboardUuidOrSlug} Get a dashboard by uuid or slug within a project # Get dashboard pre-aggregate audit Source: https://docs.lightdash.com/api-reference/v2/get-dashboard-pre-aggregate-audit https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v2/projects/{projectUuid}/pre-aggregates/dashboards/{dashboardUuidOrSlug}/audit Audits pre-aggregate hit/miss coverage for every tile on a dashboard without executing the queries. Returns a per-tile breakdown grouped by tab, suitable for CI coverage checks and pre-aggregate tuning. # Get feature flag Source: https://docs.lightdash.com/api-reference/v2/get-feature-flag https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v2/feature-flag/{featureFlagId} Get feature flag # Get organization roles Source: https://docs.lightdash.com/api-reference/v2/get-organization-roles https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v2/orgs/{orgUuid}/roles Get roles for organization # Get pre-aggregate materializations Source: https://docs.lightdash.com/api-reference/v2/get-pre-aggregate-materializations https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v2/projects/{projectUuid}/pre-aggregates/materializations Retrieves pre-aggregate definitions with their latest materialization status # Get pre-aggregate stats Source: https://docs.lightdash.com/api-reference/v2/get-pre-aggregate-stats https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v2/projects/{projectUuid}/pre-aggregates/stats Retrieves aggregated pre-aggregate hit/miss statistics for a project # Get project defaults Source: https://docs.lightdash.com/api-reference/v2/get-project-defaults https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v2/projects/{projectUuid}/defaults Get project defaults configuration # Get project parameters Source: https://docs.lightdash.com/api-reference/v2/get-project-parameters https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v2/projects/{projectUuid}/parameters Get project parameters by names # Get results Source: https://docs.lightdash.com/api-reference/v2/get-results https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v2/projects/{projectUuid}/query/{queryUuid} Retrieves paginated results from a previously executed async query using its UUID # Get validation result Source: https://docs.lightdash.com/api-reference/v2/get-validation-result https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v2/projects/{projectUuid}/validate/{validationIdOrUuid} Get a single validation result. # List chart scheduler runs Source: https://docs.lightdash.com/api-reference/v2/list-chart-scheduler-runs https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v2/saved/{chartUuid}/schedulers/{schedulerUuid}/runs Get the run history of a single scheduler on a chart # List chart schedulers Source: https://docs.lightdash.com/api-reference/v2/list-chart-schedulers https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v2/saved/{chartUuid}/schedulers Get all schedulers for a saved chart # List content Source: https://docs.lightdash.com/api-reference/v2/list-content https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v2/content Get content (charts, dashboards, spaces) # List dashboard scheduler runs Source: https://docs.lightdash.com/api-reference/v2/list-dashboard-scheduler-runs https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v2/dashboards/{dashboardUuid}/schedulers/{schedulerUuid}/runs Get the run history of a single scheduler on a dashboard # List dashboard schedulers Source: https://docs.lightdash.com/api-reference/v2/list-dashboard-schedulers https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v2/dashboards/{dashboardUuid}/schedulers Get all schedulers for a dashboard # List deleted content Source: https://docs.lightdash.com/api-reference/v2/list-deleted-content https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v2/content/deleted Get deleted content (soft-deleted charts, dashboards, etc.) # List metrics with time dimensions Source: https://docs.lightdash.com/api-reference/v2/list-metrics-with-time-dimensions https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v2/projects/{projectUuid}/dataCatalog/metrics-with-time-dimensions Get paginated metrics that have time dimensions available # List organization role assignments Source: https://docs.lightdash.com/api-reference/v2/list-organization-role-assignments https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v2/orgs/{orgUuid}/roles/assignments List organization role assignments # List project parameters Source: https://docs.lightdash.com/api-reference/v2/list-project-parameters https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v2/projects/{projectUuid}/parameters/list Get a paginated list of project parameters with search and sorting capabilities. # List project role assignments Source: https://docs.lightdash.com/api-reference/v2/list-project-role-assignments https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v2/projects/{projectId}/roles/assignments List project role assignments # List role assignees Source: https://docs.lightdash.com/api-reference/v2/list-role-assignees https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v2/orgs/{orgUuid}/roles/{roleUuid}/assignees List the users, groups, and service accounts currently assigned to a role. Used by the delete-confirmation modal to explain why a role cannot be deleted while still in use. # List validation results Source: https://docs.lightdash.com/api-reference/v2/list-validation-results https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json get /api/v2/projects/{projectUuid}/validate Get paginated validation results for a project with search, filter, and sort support. # Permanently delete content Source: https://docs.lightdash.com/api-reference/v2/permanently-delete-content https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v2/content/{projectUuid}/permanent Permanently delete a soft-deleted item (chart, dashboard, etc.) # Remove project role from group Source: https://docs.lightdash.com/api-reference/v2/remove-project-role-from-group https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v2/projects/{projectId}/roles/assignments/group/{groupId} Delete project role assignment for group # Remove project role from user Source: https://docs.lightdash.com/api-reference/v2/remove-project-role-from-user https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v2/projects/{projectId}/roles/assignments/user/{userId} Delete project role assignment for user # Remove scope from role Source: https://docs.lightdash.com/api-reference/v2/remove-scope-from-role https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json delete /api/v2/orgs/{orgUuid}/roles/{roleUuid}/scopes/{scopeName} Remove scope from role # Replace project defaults Source: https://docs.lightdash.com/api-reference/v2/replace-project-defaults https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json put /api/v2/projects/{projectUuid}/defaults Replace project defaults configuration # Replace project parameters Source: https://docs.lightdash.com/api-reference/v2/replace-project-parameters https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json put /api/v2/projects/{projectUuid}/parameters Replace all project parameters # Restore content Source: https://docs.lightdash.com/api-reference/v2/restore-content https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v2/content/{projectUuid}/restore Restore a soft-deleted item (chart, dashboard, etc.) # Run dashboard pre-aggregate audit Source: https://docs.lightdash.com/api-reference/v2/run-dashboard-pre-aggregate-audit https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v2/projects/{projectUuid}/pre-aggregates/dashboards/{dashboardUuidOrSlug}/audit Audit pre-aggregate hit/miss coverage with runtime filter overrides # Search field values Source: https://docs.lightdash.com/api-reference/v2/search-field-values https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json post /api/v2/projects/{projectUuid}/query/field-values Searches for unique field values asynchronously, returning a query UUID to poll for results # Update custom role Source: https://docs.lightdash.com/api-reference/v2/update-custom-role https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v2/orgs/{orgUuid}/roles/{roleUuid} Update role in organization # Update dashboard Source: https://docs.lightdash.com/api-reference/v2/update-dashboard https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v2/projects/{projectUuid}/dashboards/{dashboardUuidOrSlug} Update a dashboard by uuid or slug within a project # Update project group role Source: https://docs.lightdash.com/api-reference/v2/update-project-group-role https://raw.githubusercontent.com/lightdash/lightdash/refs/heads/main/packages/backend/src/generated/swagger.json patch /api/v2/projects/{projectId}/roles/assignments/group/{groupId} Update project role assignment for group # The Lightdash way: data access Source: https://docs.lightdash.com/best-practice/lightdash-way Our mission at Lightdash is to enable everybody in your company to answer their own questions using data. Lightdash is where the data team (the builders) and the rest of the business (the consumers) come together to make better data-driven decisions. We have some pretty strong opinions about how this relationship between data builders and data consumers should work. So, we thought it would be useful to explain the principles that make up The Lightdash Way. The Lightdash Way isn't just semantics - it's about the entire experience of enabling everybody in your company to answer their own data questions. But, we'll start off slow and just go through one of the principles for now: > How should you serve data to people who want to answer their own data questions? ** The Lightdash Way:** **Give end users meaningful building blocks to answer their own data questions.** Let me explain what we mean... ## We've come across three ways to let people answer their questions using data: *I hope it's obvious which one is our fave* 1. You give everyone access to the raw data. 2. If you have a data question, you ask the data builders, and they just give you complete answers. ** The Lightdash Way:** 3. The data builders give you meaningful building blocks to answer your own data questions. ### 1. You give everyone access to the raw data. If everybody in your organization knows SQL and everyone has the context they need to query the raw data (...and unicorns were real 🦄...), then giving everyone access to the raw data wouldn't be that bad. But, if a single person doesn't know SQL then they're totally dependent on someone helping them with a data question...no bueno. : very flexible, totally self-serve (as long as everyone knows SQL) : everybody has to know sql, everybody needs context of raw data, duplicated work, bound to be errors ### 2. If you have a data question, you ask the data builders, and they just give you complete answers. If nobody knows SQL or they aren't willing to explore data themselves, then dedicated team members (probably data analysts) will be completely responsible for exploring data. Everybody relies on the data team for answer questions. : only analysts have to have data skills, fewer errors (since only data experts are answering data questions) : doesn't scale, analysts become a bottleneck, this kind of work sort of sucks :( ### 3. The data builders give you meaningful building blocks to answer your own data questions. ** The Lightdash Way:** We give your data team the tools they need to build metrics + dimensions that everyone else can use in a user-friendly interface. With this approach, you leave the SQL to the experts: your data team. They become force-multipliers when they create these pre-defined metrics + dimensions in SQL because anybody in the business can combine, segment, and filter them to answer their own questions. The downside is that the data team need to spend some time defining and maintaining the library of metrics. But, a small set of metrics can power a huge amount of different analyses, enabling the rest of your team to answer their own data questions. : you only need a few SQL experts, anyone can ask questions using the data, fewer errors, scaleable : you need a data team, this system needs maintenance ## When we aggregate data, we add value. Giving data consumers useful building blocks makes it easier for them to self-serve and answer their own questions. We believe that this way of sharing data insights is a core part of the experience of everyone being able to answer their own data questions. It's the foundation of a healthy, happy relationship between data builders and data consumers 👯‍♀️. # Planning your dashboard: the Who, What and How of building great dashboards. Source: https://docs.lightdash.com/best-practice/planning-your-dashboard For those of you who are just getting started with building dashboards, it it can be useful to do some planning before you get your hands dirty and actually start building the thing. So, we thought we'd give you a few tips to help you get comfortable with planning your dashboard build. Specifically, we're going to answer three questions before we build our dashboard: “who? what? and how?” Check out our 5 minute video tutorial here: ``` ### Parameterized chart Display a chart with pre-set parameter values: ```javascript theme={null} // Chart is saved with a parameter for "region" // Pass parameter value in the chart configuration const token = jwt.sign({ content: { type: 'chart', contentId: 'sales-by-region-uuid', canExportCsv: true, }, }, LIGHTDASH_EMBED_SECRET, { expiresIn: '1h' }); ``` Parameter values are set when the chart is saved. Chart embeds display the chart with its saved parameter configuration. ## Advanced features ### User metadata for analytics Pass user information to track who's viewing your embedded charts. ```javascript theme={null} { user: { externalId: 'user-123', // Your internal user ID email: 'user@example.com', // User's email } } ``` This metadata appears in [query tags](/references/workspace/usage-analytics#query-tags) in Lightdash usage analytics. ### Custom styling (SDK only) Apply custom styling to match your application's design. ```tsx theme={null} ``` ### Localization (SDK only) Translate embedded charts using the `contentOverrides` prop. See [React SDK localization](/references/react-sdk#localization) for details. ## Next steps Embed multiple charts with filters and interactivity Complete iframe URL patterns and HTML embedding Complete JWT structure documentation Complete SDK component documentation # How to Embed Dashboards Source: https://docs.lightdash.com/guides/embedding/dashboards Complete guide to embedding Lightdash dashboards with full configuration options for both iframe and React SDK methods Embedding is available to all Lightdash Cloud users and Enterprise On-Prem customers. [Get in touch](https://lightdash.typeform.com/to/BujU5wg5) to have this feature enabled in your account. ## Overview Dashboard embedding allows you to display full Lightdash dashboards in your application with multiple visualizations, filters, and interactive features. This is ideal when you want to provide comprehensive analytics views to your users. ### When to use dashboard embedding * **Executive dashboards**: Display multiple KPIs and metrics in admin panels * **Customer-facing analytics**: Provide analytics portals for SaaS customers * **Embedded reporting**: Integrate comprehensive data views into your workflows * **Multi-chart views**: Show related visualizations together with shared filters ### Key features * Multiple chart tiles, including saved charts and SQL Runner charts * Markdown, loom, and heading tiles * Dashboard-level filters (interactive if enabled) * Multiple tabs for organizing content * Parameters support * Export options (CSV, images, PDF) * Date zoom for time-series charts * "Explore from here" to navigate to query builder * View underlying data for any visualization SQL Runner chart tiles are authorized through dashboard-tile membership, so they work with existing embed JWTs — you do not need to regenerate tokens or change embed URLs to render them. SQL charts remain embeddable only as part of a dashboard; chart-scoped JWTs (`type: 'chart'`) cannot embed a SQL chart on its own. ## Setup ### Configure allowed dashboards Only dashboards explicitly added to the "allowed dashboards" list can be embedded. Navigate to **Settings → Embed** and add your dashboard. Add allowed dashboards Alternatively, toggle "Allow all dashboards" to enable embedding for any dashboard in your project. ## Configuring interactivity Control what users can do with your embedded dashboard by configuring interactivity options. These options work for both iframe and React SDK embedding methods and are set in the JWT. While the SDK options are configured via React props, iframe options are configured in the admin UI where you setup the embedding: Configure iframe interactivity ### Dashboard filters Dashboard filters allow users to slice and filter data across all charts in the dashboard. You can control whether users can interact with these filters, which filters they can modify, and whether the filter UI is visible. All interactivity options like `dashboardFiltersInteractivity`, `canExportCsv`, `canExplore`, etc. must be placed **inside the `content` object** in your JWT payload — not at the top level. See the [complete configuration example](#complete-configuration-example) for the full structure. **Configure in JWT:** ```javascript theme={null} { content: { type: 'dashboard', dashboardUuid: 'your-dashboard-uuid', dashboardFiltersInteractivity: { enabled: 'all', // 'all', 'some', or 'none' }, } } ``` **Options:** * `'all'` - All dashboard filters are interactive and visible * `'some'` - Only specified filters are interactive (use `allowedFilters` array) * `'none'` - Filters are applied but not visible or editable **Allow specific filters only:** ```javascript theme={null} { content: { type: 'dashboard', dashboardUuid: 'your-dashboard-uuid', dashboardFiltersInteractivity: { enabled: 'some', allowedFilters: ['filter-uuid-1', 'filter-uuid-2'], }, } } ``` **Hide filter UI:** ```javascript theme={null} { content: { type: 'dashboard', dashboardUuid: 'your-dashboard-uuid', dashboardFiltersInteractivity: { enabled: 'all', hidden: true, // Filters work but UI is hidden }, } } ``` **Let viewers add their own filters:** Set `canAddFilters: true` to render an **Add filter** button in the embedded filter bar. Viewers can add temporary filters over any filterable field in the dashboard's explores — the filters live in session state (and the temp-filter deep-link parameter) and are not saved to the dashboard. Opening a fresh embed URL starts with a clean filter bar. ```javascript theme={null} { content: { type: 'dashboard', dashboardUuid: 'your-dashboard-uuid', dashboardFiltersInteractivity: { enabled: 'all', // or 'some' with a non-empty allowedFilters canAddFilters: true, // shows the "Add filter" button }, } } ``` The Add filter button only renders when filter interactivity is enabled — either `enabled: 'all'`, or `enabled: 'some'` with a non-empty `allowedFilters` array. JWTs without `canAddFilters` behave exactly as before (button hidden), so this change is backwards compatible. Metric filters in the picker still require the `metric-dashboard-filters` feature flag on your organization. Dimension filters are always available. ### Parameters Parameters are dynamic values that can be referenced in your queries and filters. When enabled, users can modify parameter values to change what data is displayed across the dashboard. **Configure in JWT:** ```javascript theme={null} { content: { type: 'dashboard', dashboardUuid: 'your-dashboard-uuid', parameterInteractivity: { enabled: true, }, } } ``` ### Export options Allow users to export data and visualizations from the embedded dashboard. You can control which export formats are available. **Configure in JWT:** ```javascript theme={null} { content: { type: 'dashboard', dashboardUuid: 'your-dashboard-uuid', canExportCsv: true, // Export chart data as CSV canExportImages: true, // Export charts as PNG/images canExportPagePdf: true, // Export entire dashboard page as PDF } } ``` **Available export options:** * **CSV** - Download raw data from individual charts * **Images** - Export charts as PNG images * **PDF** - Export the entire dashboard page as a PDF document ### Date zoom Date zoom allows users to dynamically change the time granularity of time-series visualizations (e.g., view by day, week, month, quarter, year) without modifying the underlying query. When enabled, the embed renders the dashboard's configured date zoom controls (the Default zoom plus any named controls), matching what viewers see in Lightdash. **Configure in JWT:** ```javascript theme={null} { content: { type: 'dashboard', dashboardUuid: 'your-dashboard-uuid', canDateZoom: true, } } ``` ### Explore from here "Explore from here" allows users to navigate from a dashboard chart into the full query builder interface, where they can modify dimensions, metrics, filters, and create ad-hoc analyses starting from the chart's configuration. **Configure in JWT:** ```javascript theme={null} { content: { type: 'dashboard', dashboardUuid: 'your-dashboard-uuid', canExplore: true, } } ``` When enabled, users see an "Explore from here" option on chart tiles that opens the explore interface. ### Save charts from Explore By default, embedded users can explore but cannot save their changes. If you want to let them save a new chart from the Explore view — or edit and build dashboards through the [React SDK](/references/react-sdk) — add a `writeActions` claim to the JWT. Lightdash will perform the save on behalf of a configured actor (a service account or a specific user) and place the new content into a fixed destination space. **Configure in JWT:** ```javascript theme={null} { content: { type: 'dashboard', dashboardUuid: 'your-dashboard-uuid', canExplore: true, }, writeActions: { serviceAccountUserUuid: 'service-account-user-uuid', spaceUuid: 'destination-space-uuid', }, } ``` Set up the actor and destination space from **Settings → Embedding**. See [Write actions](/references/embedding#write-actions) for the full claim reference, including using a regular user as the actor. Newly saved charts are not added to the embed allowlist, so they won't be re-embeddable unless you add them explicitly. ### View underlying data View underlying data shows users the raw data table behind any visualization, making it easy to inspect the actual values and records that create the chart. **Configure in JWT:** ```javascript theme={null} { content: { type: 'dashboard', dashboardUuid: 'your-dashboard-uuid', canViewUnderlyingData: true, } } ``` ### View data apps [Data app](/guides/data-apps) tiles run their own metric queries, so they need to be explicitly authorized before they render in an embedded dashboard. When `canViewDataApps` is off (the default), data app tiles show a placeholder and no queries run. When it's on, the data app loads inside the embed and uses the same user attributes and filters as the rest of the dashboard. **Configure in JWT:** ```javascript theme={null} { content: { type: 'dashboard', dashboardUuid: 'your-dashboard-uuid', canViewDataApps: true, } } ``` Only turn this on for audiences you trust to see the data the app can query. The data app inherits the embed JWT's user attributes, so row-level filters defined on your tables still apply. ### Complete configuration example ```javascript theme={null} import jwt from 'jsonwebtoken'; const token = jwt.sign({ content: { type: 'dashboard', projectUuid: 'your-project-uuid', dashboardUuid: 'your-dashboard-uuid', // Filter controls dashboardFiltersInteractivity: { enabled: 'all', }, // Parameter controls parameterInteractivity: { enabled: true, }, // Export capabilities canExportCsv: true, canExportImages: true, canExportPagePdf: true, // Interactive features canDateZoom: true, canExplore: true, canViewUnderlyingData: true, canViewDataApps: true, }, // User information (for analytics) user: { externalId: 'user-123', email: 'user@example.com', }, // User attributes (for row-level filtering) userAttributes: { tenant_id: 'tenant-abc', }, }, LIGHTDASH_EMBED_SECRET, { expiresIn: '1h' }); ``` ## iframe embedding iframe embedding is the simplest way to embed dashboards. No special libraries or dependencies required. ### URL structure ``` https://your-instance.lightdash.cloud/embed/{projectUuid}#{jwtToken} ``` The `dashboardUuid` is passed inside the JWT payload as `content.dashboardUuid` (see [Generate JWT](#generate-jwt) below). The JWT itself is passed in the URL hash fragment for security. ### Generate JWT ```javascript Node.js theme={null} import jwt from 'jsonwebtoken'; const LIGHTDASH_EMBED_SECRET = process.env.LIGHTDASH_EMBED_SECRET; const projectUuid = 'your-project-uuid'; const token = jwt.sign({ content: { type: 'dashboard', dashboardUuid: 'your-dashboard-uuid', }, }, LIGHTDASH_EMBED_SECRET, { expiresIn: '1h' }); const embedUrl = `https://app.lightdash.cloud/embed/${projectUuid}#${token}`; ``` ```python Python theme={null} import jwt import datetime LIGHTDASH_EMBED_SECRET = os.getenv('LIGHTDASH_EMBED_SECRET') project_uuid = 'your-project-uuid' payload = { 'content': { 'type': 'dashboard', 'dashboardUuid': 'your-dashboard-uuid', }, 'exp': datetime.datetime.utcnow() + datetime.timedelta(hours=1) } token = jwt.encode(payload, LIGHTDASH_EMBED_SECRET, algorithm='HS256') embed_url = f"https://app.lightdash.cloud/embed/{project_uuid}#{token}" ``` ```ruby Ruby theme={null} require 'jwt' lightdash_embed_secret = ENV['LIGHTDASH_EMBED_SECRET'] project_uuid = 'your-project-uuid' payload = { content: { type: 'dashboard', dashboardUuid: 'your-dashboard-uuid' }, exp: Time.now.to_i + 3600 } token = JWT.encode(payload, lightdash_embed_secret, 'HS256') embed_url = "https://app.lightdash.cloud/embed/#{project_uuid}##{token}" ``` ### Embed in HTML ```html theme={null} ``` ### Theming You can customize the appearance of iframe embeds using optional URL query parameters. These are added **before** the hash fragment in the embed URL. | Parameter | Description | Values | Default | | ----------------- | ------------------------------------- | -------------------------------- | ------- | | `theme` | Color scheme for the embed | `light`, `dark` | `light` | | `backgroundColor` | Custom background color (hex, no `#`) | e.g. `121212`, `FFF`, `FF000080` | none | `backgroundColor` only accepts hex color codes without the `#` prefix. Named colors, `rgb()`, and other CSS formats are not supported. **Example with dark theme and custom background:** ``` https://app.lightdash.cloud/embed/project-uuid?theme=dark&backgroundColor=1c1c1c#jwt-token ``` Both parameters are optional — existing embed URLs without them continue to work unchanged. See the [iframe embedding reference](/references/iframe-embedding#url-parameters) for full details and code examples. ## React SDK The React SDK provides seamless integration with additional features like programmatic filters, callbacks, and styling. See the [React SDK reference](/references/react-sdk) for installation, setup, and complete configuration options. ### Basic usage ```tsx theme={null} import Lightdash from '@lightdash/sdk'; function MyDashboard() { return ( ); } ``` ### Component props ```typescript theme={null} type DashboardProps = { instanceUrl: string; // Required: Your Lightdash instance URL token: string | Promise; // Required: JWT styles?: { backgroundColor?: string; // Dashboard background color or 'transparent' fontFamily?: string; // Font family for text }; filters?: SdkFilter[]; // Apply filters programmatically contentOverrides?: LanguageMap; // Translation/localization overrides onExplore?: (options: { chart: SavedChart }) => void; // Callback when user navigates to explore }; ``` ### Advanced example with filters ```tsx theme={null} import Lightdash, { FilterOperator } from '@lightdash/sdk'; { console.log('User exploring chart:', chart.name); }} /> ``` ## Advanced features ### User metadata for analytics Pass user information to track who's viewing your embedded dashboards. ```javascript theme={null} { user: { externalId: 'user-123', // Your internal user ID email: 'user@example.com', // User's email } } ``` This metadata appears in [query tags](/references/workspace/usage-analytics#query-tags) in Lightdash usage analytics. ### Custom styling (SDK only) Apply custom styling to match your application's design. ```tsx theme={null} ``` For overrides the `styles` prop doesn't cover, embedded dashboards expose stable CSS classnames (e.g. `ld-dashboard-header`) you can target from your own stylesheet. See [CSS class overrides](/references/react-sdk#css-class-overrides). ### Localization (SDK only) Translate embedded dashboards using the `contentOverrides` prop. See [React SDK localization](/references/react-sdk#localization) for details. ### Row-level security with user attributes Filter data based on the viewing user's properties. See the [user attributes reference](/references/workspace/user-attributes) for complete details. ## Next steps Embed individual charts for focused displays Show different data to different users Complete iframe URL patterns and HTML embedding Complete JWT structure documentation # How to embed data apps Source: https://docs.lightdash.com/guides/embedding/data-apps Embed a Lightdash data app as standalone content in an iframe using a JWT-scoped preview token. Embedding is available to all Lightdash Cloud users and Enterprise On-Prem customers. [Get in touch](https://lightdash.typeform.com/to/BujU5wg5) to have this feature enabled in your account. ## Overview Standalone data app embedding lets you render a [data app](/guides/data-apps) on its own — no dashboard, no surrounding chrome — inside an iframe in your application. The app runs in the same sandboxed environment as it does in Lightdash, with every metric query proxied through Lightdash and authorized against the embed JWT. Use standalone embedding when you want to surface an entire data app as a feature in your product (for example, a customer-facing report or interactive narrative) rather than embedding it as one tile on a Lightdash dashboard. ### How it compares to other embed types | | Standalone data app | Data app tile on an embedded dashboard | Embedded chart | | --------------------- | ------------------------------------ | ---------------------------------------- | --------------- | | Content | One data app, full screen | One data app inside a dashboard | One saved chart | | JWT `content.type` | `dataApp` | `dashboard` with `canViewDataApps: true` | `chart` | | URL path | `/embed/{projectUuid}/app/{appUuid}` | `/embed/{projectUuid}` | React SDK only | | Filters / tile chrome | None | Dashboard filters and tile chrome | None | For tile-based embedding inside a dashboard, see [View data apps in dashboards](/guides/embedding/dashboards#view-data-apps). ## Setup ### 1. Enable the data app in embed settings Open **Settings → Embedding** for your project and use the **Allowed content** section to authorize the data apps you want to embed: * Toggle **Allow all data apps** to permit any app in the project, or * Add specific data apps to the allowlist. Standalone embedding is denied for any app that isn't on the allowlist (or covered by the "allow all" switch). This is enforced server-side regardless of what your JWT contains. ### 2. Mint a data app JWT Sign a JWT with `content.type: 'dataApp'` and the `appUuid` of the data app you want to embed. The JWT must be signed with your project's embed secret. ```javascript theme={null} import jwt from 'jsonwebtoken'; const token = jwt.sign( { content: { type: 'dataApp', projectUuid: 'your-project-uuid', appUuid: 'your-app-uuid', }, user: { externalId: 'user-123', email: 'user@example.com', }, userAttributes: { tenant_id: 'tenant-abc', }, }, LIGHTDASH_EMBED_SECRET, { expiresIn: '1h' }, ); ``` A `dataApp` token can only render the app named in its `appUuid` claim. It cannot be reused to render any other data app, chart, or dashboard. ### 3. Construct the embed URL Data app embeds use the path `/embed/{projectUuid}/app/{appUuid}` with the JWT in the URL hash fragment: ``` https://your-instance.lightdash.cloud/embed/{projectUuid}/app/{appUuid}#{token} ``` The hash fragment is never sent to the server or stored in browser history. ### 4. Render the iframe ```html theme={null} ``` You can copy ready-to-use Node, Python, and Go snippets from **Settings → Embedding → Preview → Data apps** in Lightdash. ## How access works A `dataApp` JWT is intentionally narrow: it authorizes the named app for the named project and nothing else. In practice, this means: * The token grants the embed user permission to **view the specified data app only**. * The data app can run arbitrary metric queries across the project's tables. Embedding an app means you are accepting project-wide column access for that token. * **Row-level filtering still applies.** User attributes on the JWT are enforced inside every query, just like they are for dashboard and chart embeds. SQL filters defined on your tables continue to apply. * A `dataApp` token **cannot** be used to load dashboards, charts, or the explore page. Each embed token is scoped to a single content type. Because the token grants project-wide column access for the app's queries, only mint `dataApp` tokens for audiences you trust with that data. Use [user attributes](/references/workspace/user-attributes) to enforce row-level access. ## Limitations * Standalone data app embedding is iframe-only. There is no React SDK component for it yet. * The standalone embed has no filter bar or tile chrome — the app is rendered in isolation. * Interactivity options like `canExportCsv`, `canExplore`, and `dashboardFiltersInteractivity` do not apply to `dataApp` tokens. ## See also * [Data apps overview](/guides/data-apps) * [Embedding reference (JWT structure)](/references/embedding) * [iframe embedding reference](/references/iframe-embedding) * [Embed dashboards with data app tiles](/guides/embedding/dashboards#view-data-apps) # How to embed content Source: https://docs.lightdash.com/guides/embedding/how-to-embed-content Lightdash allows you to embed your content using expirable URLs and tokens. This is a great way to enable self-serve analytics in your own application and platform by leveraging the insights you've got in Lightdash and making them available to your own users. Embedding is available to all Lightdash Cloud users and Enterprise On-Prem customers. [Get in touch](https://lightdash.typeform.com/to/BujU5wg5) to have this feature enabled in your account. ## What can you embed? Lightdash supports embedding three types of content, each designed for different use cases: ### Dashboards Embed complete dashboards with multiple visualizations, filters, and tabs. Perfect for providing comprehensive analytics views in your application. **Use cases:** * Executive dashboards in admin panels * Customer-facing analytics portals * Embedded reporting for SaaS applications [Learn more about embedding dashboards →](/guides/embedding/dashboards) ### Charts Embed individual saved charts for focused, single-metric displays. Charts provide a minimal UI for clean integration. **Use cases:** * Single KPI widgets in applications * Embedded metrics in marketing pages * Focused analytics in workflows Chart embedding requires the React SDK. iframe embedding is only available for dashboards. [Learn more about embedding charts →](/guides/embedding/charts) ### AI agents Embed a Lightdash AI agent so customers can chat with their data and generate charts without leaving your product. Each embed is scoped to a single agent and space. **Use cases:** * "Chat with your data" experiences inside customer-facing apps * Self-serve analytics where customers can ask ad-hoc questions * Scoped AI access where each customer can only see their own content AI agent embedding requires the React SDK. iframe embedding is not supported for AI agents. [Learn more about embedding AI agents →](/guides/embedding/ai-agents) ### Data apps Embed a [data app](/guides/data-apps) as standalone content in an iframe — the full app, no dashboard or surrounding chrome. Useful when you want to surface an entire AI-generated app as a feature in your product. **Use cases:** * Customer-facing interactive reports * Embedded narratives or slide-show apps in your product * Self-serve analytics views built on your semantic layer [Learn more about embedding data apps →](/guides/embedding/data-apps) ## How can you share or embed content? Lightdash offers three ways to share embedded content. The choice depends on whether you need to embed content in your own application or simply share a link. **Shareable URL** is the simplest option. Lightdash can generate a standalone URL that anyone can open directly in their browser — no iframe, no SDK, and no Lightdash account required. This is useful when you want to share a dashboard with users outside your organisation (e.g., clients, partners, or stakeholders) without embedding it in an application. The URL uses the same JWT-based security as the other methods, so it expires after the time you set and can include user attributes for row-level filtering. **[iframe embedding](/references/iframe-embedding)** lets you embed a dashboard inside your own web page. You generate a JWT, construct a URL, and add it to an ` ``` ### Recommended attributes ```html theme={null} ``` **Attributes explained:** * `width="100%"` - Makes iframe responsive to container width * `height="600"` - Fixed height (adjust based on content) * `frameborder="0"` - Removes default border (legacy) * `style="border: none;"` - Removes border (modern CSS) * `loading="lazy"` - Defers loading until iframe is visible * `title="..."` - Accessibility: Describes iframe content for screen readers * `allowfullscreen` - Enables fullscreen mode (if your dashboard uses it) ### Responsive iframes To make iframes maintain aspect ratio and scale responsively: **Method 1: Aspect ratio wrapper (16:9)** ```html theme={null}
``` **Method 2: Modern CSS aspect-ratio (16:9)** ```html theme={null} ``` **Method 3: Fixed viewport percentage** ```html theme={null} ``` ### Dynamic height iframes have fixed height by default. For dynamic height based on content: Lightdash embeds do not currently support automatic height adjustment via postMessage. Use a fixed height or viewport-based height (e.g., `80vh`). Recommended approach for dashboards with unknown content: ```html theme={null} ``` ### Security considerations iframes provide natural security isolation, but you can add additional restrictions: ```html theme={null} ``` **sandbox attributes:** * `allow-scripts` - Required for Lightdash to function * `allow-same-origin` - Required for Lightdash to function * `allow-forms` - Required for filter interactions * `allow-downloads` - Required if you enable CSV/image exports The `sandbox` attribute provides additional security but may restrict functionality. Test thoroughly if you use it. ## Common patterns ### Server-side rendering Generate embed URLs in your server-side templates: **Express (Node.js)** ```javascript theme={null} app.get('/dashboard', authenticateUser, async (req, res) => { const user = await getUser(req.user.id); const token = jwt.sign({ content: { type: 'dashboard', dashboardUuid: 'dashboard-uuid', }, userAttributes: { tenant_id: user.tenantId, }, }, process.env.LIGHTDASH_EMBED_SECRET, { expiresIn: '1h' }); const embedUrl = `https://app.lightdash.cloud/embed/${projectUuid}#${token}`; res.render('dashboard', { embedUrl }); }); ``` **Template (EJS)** ```html theme={null}
``` ### Single-page apps (SPA) Generate URLs via API when component mounts: **React example** ```jsx theme={null} function EmbeddedDashboard() { const [embedUrl, setEmbedUrl] = useState(null); useEffect(() => { fetch('/api/dashboard-embed-url') .then(res => res.json()) .then(data => setEmbedUrl(data.url)); }, []); if (!embedUrl) return
Loading...
; return ( '; } add_shortcode('lightdash', 'lightdash_embed_shortcode'); ``` ## Token refresh JWTs expire after the time specified in `expiresIn`. Handle token expiration: ### Option 1: Long-lived tokens For public or semi-public dashboards, use longer expiration: ```javascript theme={null} jwt.sign(payload, secret, { expiresIn: '7d' }) // 7 days ``` Long-lived tokens are convenient but less secure. Use only when appropriate for your use case. ### Option 2: Regenerate URL on expiration Detect when iframe shows "Token expired" error and reload with new URL: ```javascript theme={null} function refreshEmbed() { fetch('/api/dashboard-embed-url') .then(res => res.json()) .then(data => { document.getElementById('dashboard-iframe').src = data.url; }); } // Refresh before expiration (e.g., every 50 minutes for 1-hour tokens) setInterval(refreshEmbed, 50 * 60 * 1000); ``` ### Option 3: Backend proxy Create a backend endpoint that serves a static iframe URL but generates fresh tokens: ```javascript theme={null} app.get('/embed-proxy/dashboard/:dashboardUuid', authenticateUser, (req, res) => { const token = jwt.sign({ content: { type: 'dashboard', dashboardUuid: req.params.dashboardUuid, }, }, process.env.LIGHTDASH_EMBED_SECRET, { expiresIn: '1h' }); const embedUrl = `https://app.lightdash.cloud/embed/${projectUuid}#${token}`; // Redirect to actual embed URL res.redirect(embedUrl); }); ``` Then use: ```html theme={null} ``` ## Troubleshooting ### Token not working **Issue:** iframe shows "Invalid token" or "Token expired" **Solutions:** * Verify embed secret matches between token generation and Lightdash * Check token hasn't expired (`expiresIn` in jwt.sign) * Ensure JWT payload structure matches [embedding reference](/references/embedding#jwt-token-structure) * Test token expiration: `jwt.decode(token)` and check `exp` field ### Content not displaying **Issue:** iframe is blank or shows loading indefinitely **Solutions:** * Check browser console for errors * Verify dashboard/chart UUID is correct * Ensure content is added to "allowed dashboards/charts" in Lightdash settings * Check project UUID is correct * Try accessing embed URL directly in browser to see error message ### CORS errors **Issue:** Browser console shows CORS errors **Solution:** * iframes should NOT have CORS issues (CORS only affects React SDK) * If you see CORS errors with iframes, you may be using fetch/XHR to load content instead of iframe * Use standard iframe src attribute, not JavaScript-based loading ### URL encoding issues **Issue:** JWT or URL appears malformed **Solutions:** * Don't URL-encode the JWT in the hash fragment * If constructing URLs in templates, ensure proper escaping: ```html theme={null} ``` ### Dashboard filters not working **Issue:** Users can't interact with filters despite `dashboardFiltersInteractivity: { enabled: 'all' }` **Solutions:** * Verify JWT includes correct interactivity settings * Check browser console for JavaScript errors * Ensure iframe isn't using `sandbox` attribute without `allow-forms` ## See also JWT structure and configuration options Alternative: React component embedding Step-by-step dashboard embedding guide Step-by-step chart embedding guide Row-level security with user attributes # Lightdash Integration Reference Docs Source: https://docs.lightdash.com/references/integrations Reference docs for all integrations available on Lightdash. You can easily make changes in... Below is everything you need... Syncs # dbt Projects Source: https://docs.lightdash.com/references/integrations/dbt-projects You can easily make changes in dbt and see them updated in your Lightdash project. Lightdash supports dbt v1.4.0 and above. If you are using an older version of dbt, you will need to upgrade to sync your project to Lightdash. ## Syncing your dbt project to Lightdash There are five ways to sync changes from dbt into Lightdash. They differ in **where the code comes from**, **where compilation happens**, **which `profiles.yml` / target governs the result**, and **whether they respect the project's UI Connection Settings**. For ready-to-use workflow templates, see the [`lightdash/cli-actions`](https://github.com/lightdash/cli-actions) repo. ### Sync mechanisms Compiles the dbt project locally and pushes the resulting `manifest.json` to Lightdash. | Property | Value | | --------------------------------- | ------------------------------------------------------------------------- | | dbt code source | Local working copy (uncommitted changes included) | | Compile location | Laptop | | `profiles.yml` source | Local (`~/.dbt/profiles.yml` by default, or `--profiles-dir`) | | Target | Default in that `profiles.yml`, overridden by `--target` | | UI Connection Settings respected? | No | | Auth | `lightdash login` session or `LIGHTDASH_API_KEY` env var | | Prerequisites | Lightdash CLI installed; dbt installed; warehouse creds reachable locally | | Remote git connection required? | No | **Use cases:** initial project setup, debugging, one-off manual deploys. **Trade-offs:** bypasses PR review; relies on per-developer `profiles.yml`; high footgun risk if a developer's prod target accidentally points at a non-prod warehouse. Same as #1, but runs inside a CI workflow (GitHub Actions, GitLab CI, Azure Pipelines, Bitbucket Pipelines, etc.) with credentials stored as CI secrets. | Property | Value | | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | | dbt code source | CI runner's checkout of the repo | | Compile location | CI runner | | `profiles.yml` source | Provided by the workflow — either committed as an `env_var()` template, or written to disk from a CI secret at runtime | | Target | Default in the CI `profiles.yml`, overridden by `--target` | | UI Connection Settings respected? | No | | Auth | `LIGHTDASH_API_KEY` from CI secrets | | Prerequisites | Lightdash CLI + dbt installed in the workflow; warehouse creds available to CI; valid `profiles.yml` produced at runtime | | Remote git connection required? | No | | Workflow template | [`deploy.yml`](https://github.com/lightdash/cli-actions) in `lightdash/cli-actions` (GitHub Actions example) | **Use cases:** automated production deploys gated by PR merge; PR preview workflows (`lightdash start-preview` + `lightdash validate`). **Trade-offs:** requires duplicating warehouse credentials into CI on top of what's already in Lightdash; needs dbt available in the runner. Never commit a `profiles.yml` with plaintext credentials. Either use an `env_var()` template committed to the repo, or write the file to disk at runtime from a CI secret. Lightdash fetches the dbt code from the configured remote, compiles it server-side, and updates the project. | Property | Value | | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | | dbt code source | Lightdash pulls from the remote git source configured in Project Settings (GitHub, GitLab, Azure DevOps, Bitbucket, dbt Cloud) | | Compile location | Lightdash servers | | `profiles.yml` source | Lightdash synthesises one from Project Settings → Connection Settings | | Target | UI Project Settings → Connection Settings → Target name | | UI Connection Settings respected? | Yes | | Auth | Logged-in user in the UI | | Prerequisites | Project must have a remote git source connected | | Remote git connection required? | Yes | **Use cases:** ad-hoc refresh after a merge; quick UI-driven sync without leaving the browser. **Trade-offs:** manual; relies on a human remembering to click it. Calls the same endpoint as the "Refresh dbt" button, but programmatically from CI (GitHub Actions, GitLab CI, Azure Pipelines, Bitbucket Pipelines, etc.). Lightdash does the work server-side using the project's UI Connection Settings. | Property | Value | | --------------------------------- | ------------------------------------------------------------------------------------------------------------- | | dbt code source | Lightdash pulls from the remote git source (configured in Project Settings) | | Compile location | Lightdash servers | | `profiles.yml` source | Synthesised by Lightdash from UI Connection Settings | | Target | UI Project Settings → Connection Settings → Target name | | UI Connection Settings respected? | Yes | | Auth | `LIGHTDASH_API_KEY` from CI secrets | | Prerequisites | Project must have a remote git source connected; Lightdash CLI installed in the workflow | | Remote git connection required? | Yes | | Workflow template | [`refresh.yml`](https://github.com/lightdash/cli-actions) in `lightdash/cli-actions` (GitHub Actions example) | **Use cases:** automated post-merge sync to production when the project is already git-connected. **Trade-offs:** can't push uncommitted changes (only what's in the connected branch); won't catch issues pre-merge — pair with a separate `lightdash validate` PR workflow if you want that. Same as #4, but bypasses the Lightdash CLI entirely — just a `curl` to the API. Works from any CI system (GitHub Actions, GitLab CI, Azure Pipelines, Bitbucket Pipelines, etc.). | Property | Value | | --------------------------------- | --------------------------------------------------------------------------- | | dbt code source | Lightdash pulls from the remote git source (configured in Project Settings) | | Compile location | Lightdash servers | | `profiles.yml` source | Synthesised by Lightdash from UI Connection Settings | | Target | UI Project Settings → Connection Settings → Target name | | UI Connection Settings respected? | Yes | | Auth | `LIGHTDASH_API_KEY` from CI secrets | | Prerequisites | Project must have a remote git source connected | | Remote git connection required? | Yes | | Lightdash CLI required? | No | | Endpoint | `POST /api/v1/projects/{projectUuid}/refresh` | **Use cases:** the simplest possible automated refresh — no dependencies to install. Useful for teams who don't want a Node toolchain in CI. **Trade-offs:** same as #4. The refresh is async (returns a `jobUuid`); for stronger guarantees, poll `GET /api/v1/jobs/{jobUuid}` to confirm completion before exiting the workflow. ### Decision matrix | | #1 `lightdash deploy` — local CLI | #2 `lightdash deploy` — CI | #3 "Refresh dbt" — UI button | #4 `lightdash refresh` — CI | #5 `POST /refresh` API — CI | | -------------------------------------- | --------------------------------- | ----------------------------------------------------- | ---------------------------- | ----------------------------- | --------------------------------- | | Automated? | No | Yes | No | Yes | Yes | | Pushes uncommitted local changes? | Yes | No | No | No | No | | Needs dbt + warehouse creds in CI? | N/A | Yes | No | No | No | | Needs Lightdash CLI installed? | Yes | Yes | No | Yes | No | | Respects UI Target name? | No | No | Yes | Yes | Yes | | Works without a remote git connection? | Yes | Yes | No | No | No | | Catches breaking changes pre-merge? | With `--select` + `validate` | If used in a PR workflow | No | No | No | | Best for | Initial setup, debugging | PR previews; CI deploys with no remote git connection | Ad-hoc UI refresh | Post-merge sync (recommended) | Post-merge sync, minimal-CI shops | ### Recommended setups **Most teams** (Lightdash connected to GitHub, GitLab, Azure DevOps, Bitbucket, or dbt Cloud): * **PR workflow** → `lightdash start-preview` + `lightdash validate` (mechanism #2 with `start-preview`) * **Post-merge to `main`** → `lightdash refresh` (#4) or the refresh API (#5) * **Manual UI refresh** (#3) available for ad-hoc syncs **Teams without a remote git connection** (project loaded via local CLI only): * **Production sync** → `lightdash deploy` in CI (#2) * **Previews** → `lightdash start-preview` in CI **Teams just getting started:** * Local `lightdash deploy` (#1) for first-time setup, then graduate to one of the automated patterns above as soon as the project is stable. Not sure whether to use `lightdash deploy` or `lightdash refresh`? Read about the [differences between the two commands](/references/lightdash-cli#lightdash-deploy-vs-lightdash-refresh) in the CLI reference. ### Things to know **`lightdash deploy` does NOT use the UI "Target name" setting.** It uses the local `profiles.yml` default, or whatever `--target` overrides it with. Only mechanisms #3, #4, and #5 respect the UI Target name. **`lightdash refresh` requires a remote git connection.** It will fail with a `ParameterError` if the project's `dbtConnection.type` is `NONE`. **Refresh is async.** Both #4 and #5 return a `jobUuid` and the work continues server-side. If your CI needs to know the refresh succeeded, poll `GET /api/v1/jobs/{jobUuid}` before exiting the workflow. **Never commit `profiles.yml` with credentials.** For mechanism #2, use either a secret-written-to-file approach or an `env_var()` template — but never check in plaintext credentials. Mechanisms #4 and #5 are underused. Most existing CI examples lead with `lightdash deploy`, which is the heaviest option in CI (requires dbt + warehouse credentials duplicated into the runner). The refresh-based patterns are simpler and often a better fit when the project is git-connected. ### How to trigger each sync #### Click "Refresh dbt" in Lightdash The button can be found on the Query from tables page. screenshot-refresh-dbt *If you're using a git connection (like GitHub, GitLab, or Bitbucket), you'll need to push + merge your changes to the branch that your Lightdash project is connected to before you press `Refresh dbt`.* If you've made any changes to the underlying data (for example, adding a new column in your `model.sql` file or changing the SQL logic of a dimension), then you need to run `dbt run -m yourmodel` before you click `Refresh dbt` in Lightdash. #### Push code from the CLI If you're using the [Lightdash CLI](/guides/cli/how-to-install-the-lightdash-cli), you can use `lightdash deploy` to deploy your changes to Lightdash. [Read more about how to use `lightdash deploy`](/guides/cli/how-to-use-lightdash-deploy). We don't recommend using `lightdash deploy` from your local environment as the primary way you update Lightdash since small mistakes can lead to production issues. #### Set up continuous deployment [Read how to do that and check out our example workflow files](/guides/cli/how-to-use-lightdash-deploy#automatically-deploy-your-changes-to-lightdash-using-a-github-action). ## dbt project settings For more information about dbt connection types (Github, Gitlab, Bitbucket, etc.) and the fields required for each type, [read the dbt project section in our connection guide](/get-started/setup-lightdash/connect-project#2-import-a-dbt-project). Below are details about the universal fields for all connected dbt projects. ### dbt selector This setting is found under Advanced configuration options You can filter out models in your dbt project that you don't want to see in Lightdash. This is useful if you have a large dbt project and you want to speed up the sync process. Unlike [table selection](/get-started/develop-in-lightdash/adding-tables-to-lightdash#limiting-the-tables-in-lightdash-using-dbt-tags), this selector is applied to the dbt models, so it will skip the entire compilation process for the models that you don't want to see in Lightdash. To do this, you can add a **dbt selector** to your project settings. This is a JSON object that contains the models you want to include in Lightdash. For example, if you only want to include the `my_model` and all models with the `lightdash` tag in Lightdash, you can add the following to your dbt project settings: ```console theme={null} my_model tag:lightdash ``` We support all dbt selectors. [Read more about selectors in the dbt docs](https://docs.getdbt.com/reference/node-selection/syntax#combining-state-and-result-selectors). ## dbt targets ### What is a dbt target? A **dbt target** is an environment configuration in your dbt project that defines where and how dbt should run. In dbt Core, targets are defined in your `profiles.yml` file and typically include settings like: * Database connection details * Schema/dataset names * Warehouse specifications * Other environment-specific configurations Most teams have multiple targets for different environments: * `dev` - for development work * `prod` - for production deployments * `staging` - for testing before production Each target can have different connection settings which are stored in your profiles.yml file. The example `profiles.yml` file below shows different connection settings for the dev and prod targets. Note that on line 3 `target: dev` indicates that the dev target is the default target for this project. ```yaml theme={null} # example profiles.yml file jaffle_shop: target: dev outputs: dev: type: postgres host: localhost user: alice password: port: 5432 dbname: jaffle_shop schema: dbt_alice threads: 4 prod: # additional prod target type: postgres host: prod.db.example.com user: alice password: port: 5432 dbname: jaffle_shop schema: analytics threads: 8 ``` ### Configuring your target in Lightdash **Target** contains information about your dbt connection to your warehouse. By default, we set this to be the same value as you have as the default in your `profiles.yml` file when you run `lightdash deploy` (if that's how you created or recently deployed your project). If you want to update this, you can enter the target of your choice in the project settings (for example `prod` or `analytics`). [Read more about dbt targets in the dbt docs.](https://docs.getdbt.com/reference/dbt-jinja-functions/target) ### How targets work with dbt macros When Lightdash connects to your dbt project, it compiles a `profiles.yml` file based on the connection settings you configure in the Lightdash UI or the connection settings from your profiles.yml if you deployed your project from the CLI using `lightdash deploy`. This means that any dbt macros in your project that use target settings will be executed by Lightdash and resolved according to those settings. #### Why use targets in macros? You might want dbt to behave differently depending on the target/environment you're running in. Common use cases include: * Using different schema naming conventions in dev vs. production * Configuring different warehouse sizes (small for dev, large for prod) * Adjusting query performance settings per environment * Loading different amounts of data (sample data in dev, full data in prod) * Applying different data retention policies Let's look at a common example: customizing schema names based on your target. #### Example: Schema naming based on target By default, dbt appends your custom schema names to your target schema. For example, if your target schema is `analytics` and you configure a model with `schema='staging'`, dbt creates it in `analytics_staging`. This default behavior is useful in development because it prevents developers from overwriting each other's work - each developer can have their own target schema like `dbt_jane` or `dbt_john`, resulting in separated schemas like `dbt_jane_staging` and `dbt_john_staging`. However, in production, you typically want cleaner schema names. Instead of `analytics_staging`, you just want `staging`. This is where customizing the `generate_schema_name` macro based on the target becomes helpful. **Default behavior:** ```sql theme={null} {% macro generate_schema_name(custom_schema_name, node) -%} {%- set default_schema = target.schema -%} {%- if custom_schema_name is none -%} {{ default_schema }} {%- else -%} {{ default_schema }}_{{ custom_schema_name | trim }} {%- endif -%} {%- endmacro %} ``` **Modified behavior for production:** ```sql theme={null} {% macro generate_schema_name(custom_schema_name, node) -%} {%- set default_schema = target.schema -%} {%- if custom_schema_name is none -%} {{ default_schema }} {%- elif target.name == 'prod' -%} {{ custom_schema_name | trim }} {%- else -%} {{ default_schema }}_{{ custom_schema_name | trim }} {%- endif -%} {%- endmacro %} ``` This macro says: "If we're in production (`target.name == 'prod'`), use just the custom schema name. Otherwise, use the default behavior of prefixing it." **How this works in Lightdash:** If your Lightdash connection settings specify: * **Target name:** `prod` * **Dataset/Schema:** `analytics` And you have a model configured with: ```sql theme={null} {{ config(schema='staging') }} ``` Then Lightdash will create/query this model in the `staging` schema - not `analytics_staging` - because `target.name == 'prod'`. This gives you clean, professional schema names in production (`staging`, `marts`, `reporting`) while maintaining developer isolation in development environments (`dbt_jane_staging`, `dbt_john_staging`). The `generate_schema_name` macro is a default dbt macro and its behavior can be overridden by adding a macro to dbt with the same name. If this macro is not showing up in your dbt project, it means that your project is using the default macro. It is a good idea to check your project for custom macros which can alter your project's configurations. **Example: Warehouse configuration** Similarly, if you have a macro that dynamically configures settings: ```sql theme={null} {% macro get_warehouse() %} {% if target.name == 'prod' %} {{ return('LARGE_WAREHOUSE') }} {% elif target.name == 'dev' %} {{ return('SMALL_WAREHOUSE') }} {% endif %} {% endmacro %} ``` And use it in your models: ```sql theme={null} {{ config(snowflake_warehouse=get_warehouse()) }} ``` Lightdash will use the configuration that corresponds to the target name you've configured in your Lightdash connection settings. ### Differences between dbt Core and dbt Cloud In dbt Core, teams commonly use targets to manage different environments. In dbt Cloud, targets are replaced by environments, and custom logic such as `if target.name = dev then...` is commonly swapped out using env vars to become 'if env\_var = development then...' or similar. ## dbt environment variables ### What are environment variables? Environment variables allow you to set dynamic values that your dbt macros can reference. This is particularly useful if your dbt project uses environment variables to control behavior (common in dbt Cloud setups). ### Configuring environment variables in Lightdash This setting is found under Advanced configuration options If your dbt project uses [environment variables in your dbt `profiles.yml` file](https://docs.getdbt.com/reference/dbt-jinja-functions/env%5Fvar), you can add these to Lightdash in your project settings. For each environment variable, you'll need to add the `key` + `value` pair for the item. You'll normally find these values in a file called `.env` in your dbt project directory. For example, you might have something like: ```yaml theme={null} profile: target: prod outputs: prod: type: postgres host: 127.0.0.1 user: "{{ env_var('DBT_USER') }}" .... ``` Then a `.env` file like: ```yaml theme={null} export DBT_USER="myspecialuser" ``` So, in Lightdash, you'd add a new environment variable and put `key` as `DBT_USER` and `value` as `myspecialuser`. ### Reserved and blocked variable names When you create or update a project, Lightdash validates each environment variable key and rejects values that could change how dbt or its child processes execute. Names must contain only letters, numbers, and underscores, and cannot start with a number. The following keys are blocked: * `GIT_ASKPASS`, `GIT_SSH`, `GIT_SSH_COMMAND`, and any name starting with `GIT_CONFIG_` * `LD_AUDIT`, `LD_LIBRARY_PATH`, `LD_PRELOAD`, and any name starting with `DYLD_` * `NODE_OPTIONS`, `NODE_PATH` * `PATH`, `SHELL` * `PERL5OPT`, `PYTHONHOME`, `PYTHONPATH`, `RUBYOPT` * `SSH_ASKPASS` * Any name starting with `LIGHTDASH_DBT_PROFILE_VAR_` (reserved for internal use) If you have an existing project that already uses one of these keys, project compilation will continue to work — the check only runs when you save changes to your connection settings. Rename the variable in your dbt project and save the updated settings to clear the validation error. ### How environment variables work with dbt macros When Lightdash compiles your dbt project, any environment variables you configure will be available to your dbt macros through the `env_var()` function. For example, if you have a macro that checks an environment variable: ```sql theme={null} {% macro get_schema() %} {% if env_var('DBT_ENV') == 'production' %} {{ return('prod_analytics') }} {% else %} {{ return('dev_analytics') }} {% endif %} {% endmacro %} ``` You would set `DBT_ENV=production` as an environment variable in your Lightdash connection settings to ensure the macro resolves to `prod_analytics`. **Key points about environment variables:** * They're available to all macros in your dbt project via the `env_var()` function * They're particularly important if your dbt project was built for dbt Cloud, which relies heavily on environment variables * Make sure to set any environment variables your macros depend on in Lightdash to match your production dbt environment ## Key takeaways * Lightdash compiles your dbt project using the target name and other settings you configure in the connection settings * Any macros that use `target.name`, environment variables, or other profile settings will resolve according to your Lightdash configuration * Make sure your Lightdash target name matches the target you use for your production dbt runs to ensure Lightdash behaves consistently with your dbt project * If you have custom macros that depend on target settings or environment variables, ensure those settings are configured correctly in your Lightdash connection settings If you're experiencing unexpected behavior with how Lightdash compiles your dbt project, check that your target name in Lightdash matches what your dbt macros expect, and verify any environment variables your macros depend on are properly set. # Google Sheets Source: https://docs.lightdash.com/references/integrations/google-sheets Syncs let you send your chart results to a Google Sheet in your Google Drive on a schedule. ## Syncs You can set up as many syncs as you like, and if you make any changes to the content, Lightdash will update the syncs the next time they’re sent. ## Creating a Sync All users with editor access or above can create Syncs. To do this, open your chart in view or edit mode, click the three-dot menu in the top-right corner, then click on `Google Sheets Sync`. The pop-up shows you a list of any existing Syncs for the saved chart, you also have the option to `Create new Sync`. Clicking `Create new Sync` takes you to the configuration screen to setup a new Google Sheets Sync. When you create a Sync, Lightdash also creates a special tab in your Google Sheet called metadata which includes information on when the sheet was last updated and the frequency interval. This allows users to easily understand how often data is refreshed inside their Google Sheet. By default, data will be synced to the first tab in your Google Sheet and it will overwrite all the content. If you want to select a specific tab, use the **Save in new tab option**. ## Sync options * **Name**: this is the name of your Sync in Lightdash * **Frequency**: this is how often your Google Sheet will be synced. You can make this hourly, daily, weekly, monthly, or custom - each frequency has its own options. For example, with a monthly schedule, you set the day of the month and the time that you want your Sync to be happen. The custom frequency lets you write out your own custom Cron expression if you need something more specific than our standard options. All times for the scheduler are in UTC. * **Select Google Sheet**: Use the file picker to select the Google Sheet that you'd like to sync your chart results to. Note: You need to sync to an existing Google Sheet, so ensure you have created it before you can select it here. * **Save in new tab**: when enabled, it lets you set a tab name that will be used to store your sync data. The tab will be created if it doesn't exist yet in the sheet. This will avoid overwriting the first tab of the sheet. Once you've set up all of your Sync options, you can click `Sync`. ## Overview of your Syncs Users who have an admin role in your project can access an overview of your Syncs in the Project Settings. In the `Syncs & Scheduled deliveries` overview page, you can see a list of all of your Syncs (along with your Scheduled Deliveries), their most recent delivery status, and a history of all of the previous deliveries in your project. To access the overview page, just head to your Project Settings, then to the `Syncs & Scheduled deliveries` tab. Here, you can also click on the three-dot-menu beside each Sync to edit or delete it. Editing a Sync from the overview page will bring you to the same configuration screen as when you create a new Sync. Deleting a Sync from the overview page will remove it from your chart. ## Google API Services User Data Policy Lightdash's use and transfer of information received from Google APIs adhere to [Google API Services User Data Policy](https://developers.google.com/terms/api-services-user-data-policy), including the Limited Use requirements. # Lightdash MCP Source: https://docs.lightdash.com/references/integrations/lightdash-mcp Available to all Lightdash Cloud users. The [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) enables AI assistants (e.g. ChatGPT, Claude, OpenAI Codex) and custom agents to directly interact with your Lightdash data. This integration allows MCP clients to explore your data models, search for metrics and dimensions, and provide data-driven insights - all through natural conversation. You can use MCP with existing AI assistants or integrate it into your own custom agents and automated workflows. MCP uses secure OAuth authentication and respects all your existing access controls, ensuring data remains protected. With MCP, your AI assistant becomes a data analyst that can: * Browse and understand your data models * Find relevant metrics and dimensions * Run queries and generate visualizations * Discover existing charts and dashboards, including verified content * Create and edit charts and dashboards using content-as-code * Leverage your AI agents' domain expertise and verified answers * Switch between different projects seamlessly * Respect your data governance and access controls MCP respects all your existing Lightdash permissions and user attributes. MCP clients can only access the data that your user account has permission to view. ## Get started Setting up MCP is quick and straightforward. You can connect your AI assistant to your Lightdash instance in just a few minutes. ### Prerequisites * A Lightdash Cloud account or Enterprise account with MCP enabled * An MCP-compatible AI assistant (e.g., Claude.ai, Claude Desktop, ChatGPT, OpenAI Codex) ### Network requirements If your organization uses a corporate firewall, VPN, or internet security tool, the following domains must be allowlisted for MCP to work correctly: | Domain | Purpose | | -------------------------------------- | ---------------------------------------------------------------------------- | | `.lightdash.cloud` | Lightdash API and OAuth authentication | | `claudemcpcontent.com` | Used by Claude to render visual content (charts, tables) from MCP connectors | If `claudemcpcontent.com` is blocked, Claude will still return query results as text but will not be able to display Lightdash visual charts. You may see the error: *"Failed to set up MCP app. Check that claudemcpcontent.com is not blocked by your network or browser."* If you're having trouble, try opening Claude in an incognito/private browser window to rule out browser extensions (like ad blockers) that may be blocking these domains. ### Installation #### Claude.ai (Web & Desktop Apps) Set up MCP in the [Claude.ai](https://claude.ai) web app, and it will automatically sync to your Claude Desktop app after restart. 1. **Access Settings in Claude.ai** Navigate to your profile menu (bottom-left corner) and select Settings. Navigate to profile menu in bottom-left corner and click Settings 2. **Add Custom Connector** In the Settings menu, select "Connectors" from the sidebar, then click "Add custom connector". Select Connectors from the sidebar menu, then click Add custom connector button 3. **Configure Connection** Fill in the connection details with your Lightdash instance information. Enter Lightdash as the name and your instance MCP URL in the configuration form * **Name:** Lightdash (or any name you prefer) * **URL:** `https://.lightdash.cloud/api/v1/mcp` 4. **Connect and Authenticate** Click the "Connect" button to initiate the authentication process. Click the Connect button to start OAuth authentication with Lightdash 5. **Complete OAuth Flow** Log in to your Lightdash account and approve the connection when prompted. Login to Lightdash with your credentials and approve the OAuth connection request 6. **Configure Permissions (Optional)** Optionally configure which MCP tools Claude can access and set any additional permissions. Optional: Configure MCP tool access and permissions for your Claude assistant #### ChatGPT (Web App) ChatGPT support for MCP is coming soon! Stay tuned for updates. #### OpenAI Codex 1. **Navigate to Settings** Go to **Settings > MCP Servers** and click **Add Server**. 2. **Configure Connection** Select **Streamable HTTP** as the transport type and enter your Lightdash MCP URL. Select Streamable HTTP and enter your Lightdash instance MCP URL * **URL:** `https://.lightdash.cloud/api/v1/mcp` 3. **Authenticate** Once the server is created, an **Authenticate** option will appear in the MCP Servers list. Click it to complete the OAuth flow with your Lightdash account. Click Authenticate next to the Lightdash server to complete the OAuth flow #### Claude Code CLI For developers using Claude Code CLI: ```bash theme={null} claude mcp add lightdash https://.lightdash.cloud/api/v1/mcp -t http ``` Replace `` with your actual Lightdash instance name. 1. **Use the /mcp command in Claude Code** Type /mcp to see available MCP connections 2. **Select Lightdash from the list** Navigate to Lightdash using arrow keys 3. **Authenticate with Lightdash** Select Authenticate and hit Enter 4. **Complete OAuth Flow** Complete the OAuth flow via Lightdash 5. **Start using MCP** Start prompting after successful authentication After authentication, you can start asking questions about your Lightdash data directly in Claude Code! #### Cursor Editor Navigate to **Cursor Settings > MCP & Integrations** Clean Shot2025 08 28at17 42 54@2x Pn #### Custom Integration (For Developers) If you're building your own agents or automated workflows, you can integrate directly with Lightdash MCP: * **Transport**: Lightdash MCP exposes a StreamableHTTP transport endpoint at `https://.lightdash.cloud/api/v1/mcp` * **Debugging**: Use `@modelcontextprotocol/inspector` to inspect and debug the MCP connection * **Authentication**: For interactive setups use OAuth 2.0. For headless agents and automated workflows, you can authenticate with a Personal Access Token by passing `Authorization: ApiKey ` instead. Create the token under **Settings → Personal access tokens** for the user whose permissions and attributes you want the integration to use. Service account tokens are also supported on plans that include them. * **Documentation**: See the [MCP specification](https://modelcontextprotocol.io/docs) for implementation details * **Pin a project (optional)**: pass `X-Lightdash-Project: ` to scope the MCP session to a specific project, skipping the `set_project` step. See [details below](#pin-a-project-with-the-x-lightdash-project-header). * **Override user attributes per request (optional)**: pass `X-Lightdash-User-Attributes: ` to override the authenticated user's attributes for that request (useful for row-level security when an agent acts on behalf of different end-users). See [details below](#override-user-attributes). ##### Pin a project with the `X-Lightdash-Project` header By default, MCP clients use `set_project` to choose an active project, and the selection is stored as a per-user context. If you're building an integration that should always operate against a single project, you can pre-select the project by sending the `X-Lightdash-Project` header on every request to `/api/v1/mcp`. When the header is set: * The project UUID in the header is used as the active project for that request, overriding any project previously set with `set_project`. * The `list_projects` and `set_project` tools are hidden from `tools/list`, so the AI assistant can't change the project for the request. * Access to the project is still enforced by your user, API key, or service account's permissions — the header can't be used to access projects the caller can't already see. This is useful when you want each integration, workspace, or environment to be locked to one project (for example, a separate connector per project) without relying on the AI assistant to call `set_project` first. The header value must be a valid project UUID. You can find the project UUID in the Lightdash URL when viewing a project (`/projects//...`). ```json Cursor (.cursor/mcp.json) theme={null} { "mcpServers": { "lightdash-sales": { "url": "https://.lightdash.cloud/api/v1/mcp", "headers": { "X-Lightdash-Project": "00000000-0000-0000-0000-000000000000" } } } } ``` ```bash curl theme={null} curl https://.lightdash.cloud/api/v1/mcp \ -H "Authorization: Bearer " \ -H "X-Lightdash-Project: 00000000-0000-0000-0000-000000000000" \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' ``` If the header value isn't a valid UUID, it's ignored and the request falls back to the user's stored project context. Permissions are always checked against the resolved project, so a header for a project the caller can't view will return a "no access" error. ##### Override user attributes with the `X-Lightdash-User-Attributes` header The `X-Lightdash-User-Attributes` header overrides the authenticated user's Lightdash user attributes for that specific MCP request. This is designed for agents that act on behalf of multiple end-users with row-level security: one PAT (or service account) user handles all requests, and per-request RLS scoping is applied via the header. The PAT or service account user must have the **org admin** role to use this header. Non-admins will receive a `ForbiddenError`. The header value must be a JSON object where each value is either a string or an array of strings. For example: * `{"user_id": "abc123"}` * `{"user_id": ["abc123", "def456"]}` If the agent user already has a value set for an attribute, the header can only **narrow** that value (set a subset of the pre-configured values), not expand access. If no value is pre-configured for the attribute on the agent user, any value can be set via the header. ```bash curl theme={null} curl https://.lightdash.cloud/api/v1/mcp \ -H 'Authorization: ApiKey ' \ -H 'X-Lightdash-User-Attributes: {"user_id": "abc123"}' \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' ``` ```json Cursor (.cursor/mcp.json) theme={null} { "mcpServers": { "lightdash-agent": { "url": "https://.lightdash.cloud/api/v1/mcp", "headers": { "X-Lightdash-User-Attributes": "{"user_id": "abc123"}" } } } } ``` Setting the header statically in an MCP client config is suitable for development and testing. For production, where the attribute needs to change per end-user, the calling application must set the `X-Lightdash-User-Attributes` header programmatically on each request. ## What it can do ### Core capabilities MCP provides AI assistants with powerful tools to interact with your Lightdash data: #### Project management * **List projects** - View all accessible projects in your organization * **Set active project** - Switch context between different projects (required before accessing any data). Accepts an optional `tags` array to filter the explores and fields visible in the session to those matching the given tags — the same tag-based filtering used by [AI agents](/guides/ai-agents/data-access#limiting-access-to-specific-explores-and-fields), but available directly in an MCP session without needing an agent. Useful when tags work in the Lightdash UI but you also want to scope an MCP session to a specific domain (e.g., `["sales"]`). * **Get current project** - Check which project is currently active An active project must be set before MCP can retrieve any data. Your AI assistant will typically handle this automatically by listing available projects and asking you to select one. #### Data exploration * **List explores** - See all available data models in the current project at a glance * **Find explores** - Search for relevant data models using natural language (e.g., "customer orders") * **Find fields** - Search for specific metrics and dimensions by business terms (e.g., "total revenue", "order date") * **Search field values** - Look up valid values for a field, useful for building filters * **Find content** - Search for existing spaces, charts, and dashboards by name or description. Results include space breadcrumbs and direct links. Optionally scope the search to a single space (and its descendants) by passing a space slug. * **List content** - Browse accessible content as a hierarchy. By default it returns root-level spaces; pass a space slug to list the charts, dashboards, and nested spaces directly inside that space. Use this when you want the agent to walk space → content rather than search by keyword. * **List verified content** - Discover charts and dashboards that admins have marked as verified, so agents can reference trusted, canonical patterns when building new content. If you want your agent to prefer verified patterns, ask it to in your prompt (e.g. *"Use verified charts as the reference for any new chart you build."*). #### Query execution * **Run metric query** - Execute queries using your semantic layer's metrics and dimensions. Completed results include a best-effort `exploreUrl` so you can open the query in Lightdash to keep exploring. * **Render chart** - Render a visualization (tables, bar charts, line charts, pie charts, and more) for a completed metric query result in MCP App-capable clients (e.g., Claude). Call this after a metric query finishes when you want a visual chart; the query is not re-executed. SQL Runner results are not supported by `render_chart`. * **Run SQL** - Execute arbitrary SQL queries directly against the project's data warehouse. Useful for ad-hoc analysis or queries that don't fit the explore-based model. Returns up to 500 rows by default (configurable up to 5,000). Completed results include a best-effort `sqlRunnerUrl` so you can open the compiled SQL in [SQL Runner](/guides/developer/sql-runner). * **Get query result** - Poll for the result of a long-running query. If `run_metric_query` or `run_sql` doesn't finish within its wait window, the tool returns a `queryUuid` and the assistant polls `get_query_result` until the warehouse completes the query — so long queries don't time out the session. **Run SQL** requires the `manage SqlRunner` permission. The SQL is executed directly against your warehouse, so use the appropriate SQL dialect for your connection (e.g., PostgreSQL, BigQuery, Snowflake). When you call `run_sql` from a custom MCP client or live artifact, the tool returns both a CSV text payload and a `structuredContent` object. Prefer `structuredContent.rows` over parsing the CSV — values arrive as JSON-serializable primitives (numbers, strings, booleans, ISO date strings, or `null`), so you don't need `parseFloat` or `parseInt` on numeric columns. **Response envelope:** ```json theme={null} { "content": [ { "type": "text", "text": "" } ], "structuredContent": { "rows": [ { "status": "completed", "n": 94, "total_amount": 2397 } ], "columns": ["status", "n", "total_amount"], "rowCount": 1, "sqlRunnerUrl": "https://.lightdash.cloud/projects//sql-runner?..." } } ``` **Example usage:** ```ts theme={null} const result = await callMcpTool('run_sql', { sql, limit }); const rows = result.structuredContent.rows; // [{ status: 'completed', n: 94, ... }, ...] const columns = result.structuredContent.columns; // ['status', 'n', 'total_amount'] const sqlRunnerUrl = result.structuredContent.sqlRunnerUrl; // shareable link to inspect/edit the SQL in SQL Runner, or null ``` **Notes:** * Empty results still return `structuredContent` as `{ rows: [], columns, rowCount: 0, sqlRunnerUrl }` — distinct from a parse failure. * `sqlRunnerUrl` is best-effort and may be `null` if the share link cannot be created. It points to the compiled SQL that was executed, which may differ slightly from the SQL you submitted. * On error, the response has `isError: true` and `content[0].text` contains the error message; `structuredContent` is omitted. * `content[0].text` continues to carry the raw CSV, so existing clients that parse the text payload keep working. **Security best practice:** Ensure the database credentials configured in your Lightdash connection have **read-only (viewer) access** to your warehouse. Since `run_sql` executes arbitrary SQL, a connection with write permissions could allow AI agents to modify or delete warehouse data. #### Editing content MCP can read, create, and edit Lightdash charts and dashboards using the same [content-as-code](/guides/developer/dashboards-as-code) payloads that the Lightdash CLI uses. This lets agents make targeted edits to existing content or build new charts and dashboards directly in a conversation, without downloading YAML files locally. * **Read content** (`read_content`) - Fetch a chart or dashboard as JSON by slug. Call this before editing so the agent can see the current state. * **Edit content** (`edit_content`) - Apply an [RFC 6902 JSON Patch](https://datatracker.ietf.org/doc/html/rfc6902) to an existing chart or dashboard, then validate and persist. Use this for surgical changes (e.g. rename a field, add a filter, swap a chart color) without rewriting the whole object. * **Create content** (`create_content`) - Create a new chart or dashboard from a full chart-as-code or dashboard-as-code object. Returns the persisted slug and URL. These tools reuse the same permissions, validation, and project context as the [Lightdash CLI](/guides/cli/how-to-install-the-lightdash-cli) `download` and `upload` commands, so the user driving the MCP session needs the same access required to manage that content in Lightdash. **Admin kill-switch.** Organization admins can disable content writes across all MCP clients from **Settings → Ask AI → General** by turning off **Allow content changes via MCP**. When this is off, `create_content` and `edit_content` are not registered for any MCP client in the organization — reading content over MCP is unaffected, and per-user permissions still apply when it's on. The toggle is **on by default**. When prompting an agent to build content, ask it to use [verified content](#data-exploration) as a reference. The agent can call `find_content` and `read_content` on a verified chart, then use that JSON as the template for `create_content` — giving you new content that follows the patterns your team has already approved. **Example prompt:** *"Read the `weekly-revenue` chart, then create a copy called `weekly-revenue-by-region` that adds `customers_region` as a pivot dimension."* The assistant will call `read_content` to fetch the source chart, modify the JSON to add the pivot, and call `create_content` to save the new chart — returning a link to open it in Lightdash. For bulk edits across many dashboards or as part of a CI/CD pipeline, the [download-edit-upload workflow](/guides/developer/editing-dashboards-with-agents) using the Lightdash CLI is still the recommended approach. MCP content tools are best for interactive edits inside an AI assistant. #### Agent context * **Route agent** - Automatically select and activate the best agent for a user prompt within the active project. This is the preferred way to pick an agent — it mirrors the [AI Router](/guides/ai-agents/ai-router) experience in the Lightdash app, so MCP sessions get the same automatic agent selection. * **List agents** - Discover available AI agents and their areas of expertise * **Set agent** - Manually activate an agent to scope your session to its explores, instructions, and verified answers. Use this when you want to override automatic routing. * **Get current agent** - Check which agent is active and view its full context * **Clear agent** - Remove agent scoping and return to the full project context These tools are covered in detail in the [Using AI agent context](#using-ai-agent-context) section below. When an agent is active, its scope applies to the whole session: data exploration is limited to the agent's explores, and content tools (find, list, read, create, and edit) only see spaces the agent has access to. #### Built-in skills Lightdash ships built-in skills (such as `developing-in-lightdash`) that give AI assistants guidance for working with Lightdash — for example, conventions for writing dbt models, charts, and dashboards. These skills are exposed as MCP resources, which most clients consume automatically. For MCP clients that don't read resources directly (e.g. Claude Code), three fallback tools let the assistant discover and load the same content: * **List skills** (`list_skills`) - Return the available built-in skills along with their supporting resource files * **Read skill** (`read_skill`) - Read the main `SKILL.md` instructions for a skill by name (e.g. `developing-in-lightdash`) * **Read skill resource** (`read_skill_resource`) - Read a supporting resource file for a skill by name and resource path (e.g. `resources/dashboard-best-practices.md`) You don't need to call these tools explicitly — when relevant, the assistant will call `list_skills` to discover what's available and then load the skill content it needs. If your client already supports MCP resources, you can ignore these tools; both paths return the same content. The Lightdash MCP server exposes its built-in skills as MCP resources, so any MCP-compatible client can discover and load them at runtime — no CLI install required. This is useful for custom agents that want to dynamically fetch Lightdash's guidance on building dashboards, charts, and semantic layer configuration. The server advertises support via the `io.modelcontextprotocol/skills` extension capability returned from `initialize`. Clients that don't recognize the extension can still list and read the resources directly. **Available resources:** | URI | Type | Description | | ------------------------------------------------- | ------------------ | --------------------------------------------------------------------------------------------------- | | `skill://index.json` | `application/json` | Discovery index listing every built-in skill and its supporting files. | | `skill://lightdash//SKILL.md` | `text/markdown` | A skill's instructions and frontmatter (e.g. `skill://lightdash/developing-in-lightdash/SKILL.md`). | | `skill://lightdash//resources/` | `text/markdown` | Supporting reference files for a skill. | **Example: list and read a skill via JSON-RPC** ```json theme={null} // List available resources { "jsonrpc": "2.0", "id": 1, "method": "resources/list", "params": {} } // Read the discovery index { "jsonrpc": "2.0", "id": 2, "method": "resources/read", "params": { "uri": "skill://index.json" } } // Read a specific skill { "jsonrpc": "2.0", "id": 3, "method": "resources/read", "params": { "uri": "skill://lightdash/developing-in-lightdash/SKILL.md" } } ``` If you're working in Claude Code, Cursor, or another supported editor, you can also [install skills via the CLI](/guides/developer/agent-skills#installing-skills) — it ships the same files to your local agent without requiring an MCP round trip. ### Example conversations Here are some examples of how you can interact with AI assistants using MCP: #### Example 1: Verifying your MCP connection After connecting, verify that the MCP integration is working by asking your AI assistant to list available tools. **Prompt:** *"What Lightdash tools do you have access to?"* The assistant will confirm the connection and list the available MCP tools, such as `list_projects`, `find_fields`, `run_metric_query`, `run_sql`, and others. This is a quick way to verify that authentication succeeded and the MCP server is reachable. Verifying MCP connection and listing available tools #### Example 2: Setting up a project and finding dashboards Before querying data, you need to set an active project. Then you can search for existing dashboards and charts. **Prompt:** *"What projects do I have access to? Set the Jaffle Shop project, then show me all dashboards related to revenue."* The assistant will: 1. Call `list_projects` to show your available projects 2. Call `set_project` to activate "Jaffle Shop" 3. Call `find_content` with your search term to find matching dashboards and charts **Expected output:** A list of dashboards and charts matching "revenue", including their names, descriptions, and direct links to view them in Lightdash. Setting up project context and finding dashboards #### Example 3: Exploring data and running a metric query Once a project is active, you can explore data models and run queries using your semantic layer. **Prompt:** *"What metrics do we have for orders? Show me total revenue by month for the last 6 months as a bar chart."* The assistant will: 1. Call `find_fields` to search for order-related metrics and dimensions (e.g., `orders_total_revenue`, `orders_order_date`) 2. Call `run_metric_query` with the appropriate explore, metrics, dimensions, filters, and sort order to fetch the data and render a visualization **Expected output:** A bar chart showing monthly revenue for the last 6 months, along with the underlying data table. The query uses your semantic layer definitions, so metric calculations and joins are handled automatically. Finding explores and fields, then executing metric queries to analyze data ## Using AI agent context If your organization has [Lightdash AI agents](/guides/ai-agents) configured, you can reuse their configuration in your MCP sessions — so you get consistent guidance regardless of where you're working. ### How is this different from Lightdash AI agents? [Lightdash AI agents](/guides/ai-agents) are a fully managed experience inside Lightdash and Slack. They handle everything end-to-end: interpreting your question, picking the right data, running queries, and presenting results. With MCP, you can use Lightdash data in other contexts, but the AI assistant driving an MCP session doesn't have the same specialized tuning that Lightdash AI agents provide out of the box. Agent context via MCP bridges that gap: it brings your agents' domain knowledge into any MCP session. ### What you get from agent context When you activate an agent in your MCP session, your AI assistant receives: * **[Specialized content](/guides/ai-agents/best-practices#think-specialized-not-general)**: only the data models relevant to that agent's domain * **[Verified answers](/guides/ai-agents/verified-answers#how-verified-answers-work)**: curated example queries that demonstrate correct usage of the data model * **[Custom instructions](/guides/ai-agents/getting-started#instructions)**: domain-specific rules like *"Always filter orders by status = 'completed'"* ### Example workflow 1. **Set your project** with `set_project` 2. **Let the router pick an agent** with `route_agent` — pass the user's prompt and Lightdash activates the best-fit agent automatically. Use `list_agents` + `set_agent` only when you want to inspect candidates or override the choice manually. 3. **Ask your questions** — the agent's context automatically guides queries `route_agent` chooses between agents the user can already access — it never widens permissions. If only one agent is accessible, it activates that agent directly; if none are accessible, it returns an error so the assistant can fall back to the unscoped project context. **Prompt:** *"What AI agents are available?"* Listing available AI agents in a project **Prompt:** *"Use the Sales Analyst agent."* Setting an AI agent and viewing its available explores Once an agent is active, your queries automatically follow its instructions. For example, with a Sales Analyst agent configured with these instructions: ``` You are a Sales analyst for Jaffle Shop. Your role is to answer questions about revenue, orders, customers and subscriptions. Key guidelines: - Use the orders explore as the starting point for revenue and order volume questions. - Always include a time dimension when showing trends. Default to monthly granularity unless the user specifies otherwise. - Format currency values in CAD. ``` **Prompt:** *"Can you show me revenue so far?"* The assistant will automatically use the `orders` explore, include a monthly time dimension, and format values in CAD — all without you specifying these details, because the agent's instructions guide the query. Asking a question with agent context applied for better results ## Built-in prompt The Lightdash MCP server includes a built-in **`lightdash-analyst`** prompt with guidelines for querying data effectively. MCP clients that support prompts can use this automatically, so you don't need to configure custom instructions manually. When an [AI agent](#using-ai-agent-context) is active, the prompt automatically adapts to include the agent's context. ## Best practices To get the most value from MCP, ensure your Lightdash data is well-organized and documented. See our [AI agents best practices guide](/guides/ai-agents#best-practices) for detailed recommendations on: * Organizing and naming your data models * Writing effective documentation and AI hints * Optimizing for AI assistant performance * Security and permissions considerations *** ## Lightdash Docs MCP In addition to the Lightdash data MCP above, we also offer a **Docs MCP endpoint** that gives AI coding agents access to the complete Lightdash documentation. This is free for everyone—including open source users and all cloud tiers. ### Benefits The Docs MCP helps AI agents: * Understand Lightdash concepts, configuration, and best practices * Generate accurate YAML configurations for metrics and dimensions * Troubleshoot issues using official documentation * Stay up-to-date with the latest Lightdash features For the best experience building and maintaining your semantic layer, we recommend using [agent skills](/guides/developer/agent-skills) instead. Skills provide more targeted context for AI coding agents and are optimized for code generation tasks. ### Setup The Docs MCP endpoint is available at `https://docs.lightdash.com/mcp`. Add it to your AI coding tool: Add to your `.cursor/mcp.json`: ```json theme={null} { "mcpServers": { "lightdash-docs": { "url": "https://docs.lightdash.com/mcp" } } } ``` Run the following command: ```bash theme={null} claude mcp add lightdash-docs https://docs.lightdash.com/mcp -t http ``` Add to your `~/.codeium/windsurf/mcp_config.json`: ```json theme={null} { "mcpServers": { "lightdash-docs": { "serverUrl": "https://docs.lightdash.com/mcp" } } } ``` ### Availability The Docs MCP is free for everyone: * Open source users * Cloud Pro * Cloud Enterprise No authentication required. ## FAQ **Q: Does Lightdash MCP store my data or query results?** A: No, Lightdash MCP does not store any query results, conversation responses, or data. MCP acts as a bridge that allows AI assistants to access your Lightdash metadata and execute queries in real-time. The MCP consumer (your AI assistant) is responsible for any data storage. Depending on which AI assistant you use, data might be shared with third parties according to their privacy policies. **Q: Can multiple team members use MCP?** A: Yes, each team member can set up their own MCP connection with their individual Lightdash credentials. Each connection respects that user's specific permissions and access controls. **Q: Can MCP modify my data or dashboards?** A: MCP can create and edit Lightdash charts and dashboards via the [content-as-code tools](#editing-content) when your user account has the required permissions. MCP cannot modify your underlying warehouse data — query execution is read-only (metric queries and SQL `SELECT` only). All write operations respect your existing Lightdash permissions and project access controls. **Q: Claude returns data as text but no visual chart is displayed. What's wrong?** A: Claude uses the domain `claudemcpcontent.com` to render visual content from MCP connectors. If this domain is blocked by your corporate firewall, VPN, internet security tool, or a browser extension (like an ad blocker), Claude will fall back to text-only output. See [Network requirements](#network-requirements) above for the full list of domains to allowlist. # Slack integration Source: https://docs.lightdash.com/references/integrations/slack-integration Below is everything you need to know about the Lightdash Slack integration. For walk through videos, check out our guides on [adding the Slack integration](/references/workspace/adding-slack-integration) and [using the Slack integration](/guides/using-slack-integration). ## Required permissions The Lightdash Slack app will request permission for these scopes: * **`[links:read]` for lightdash.cloud** : Links to lightdash.cloud will be sent to our App so we can make an internal request and fetch information from charts and dashboards so we can later share it in slack. * **`[links:write]`** : This allows us to unfurl the URL previously mentioned. No other content will be shared from your workspace. ## Settings After installing the app you'll see these settings: ### Select a notification channel Here you may choose a Slack channel where Lightdash will send alerts when any scheduled deliveries fail in your organization. You must add the Lightdash app into that organization for notifications to work properly. ### Slack bot avatar You can customize the avatar for your Lightdash slack app by adding an image URL in the Profile photo URL field. Slack recommends these images be square with a minimum of 512x512 pixels, but no larger than 1024x1024 pixels. ### AI Agents configuration Configure how AI Agents interact with your Slack workspace. You can control whether AI Agents can access thread messages when mentioned and require OAuth authentication for AI Agent usage. For details on Slack channel limitations and multi-agent support, see [Slack channel limitations](/guides/ai-agents/getting-started#slack-channel-limitations). #### User attribution and OAuth By default, all AI agent conversations in Slack are attributed to the user who installed the Slack app (or created the agent). This means every Slack user's questions will appear as if they came from that single user, and all queries will run with that user's permissions. To have each Slack user properly identified and use their own permissions, enable the **AI Agents OAuth requirement** toggle in these settings. When enabled: * Each Slack user must authenticate with Lightdash before using the AI agent * Conversations are attributed to the individual user asking the question * Queries respect each user's own [user attributes and permissions](/guides/ai-agents/data-access#user-attributes-and-permissions) We recommend enabling OAuth if your organization uses row-level or column-level security through user attributes, or if you need an audit trail of which users are asking which questions. ## Using Lightdash in private channels Lightdash supports private Slack channels, but because Slack doesn't allow apps to see private channels by default, you'll need to manually add the Lightdash app to your private channel first. To add Lightdash to a private channel, you can either: * **Use the invite command** - Type `/invite @Lightdash` in the channel * **Use channel settings** - Click on the channel name, go to **Integrations** > **Add an app**, then search for and add Lightdash Once the app is added, you can find the channel in Lightdash by either: * **Refreshing the channel list** in the Lightdash UI * **Looking up the channel by ID** - You can find your channel ID in Slack by right-clicking on the channel name, selecting "View channel details", then copying the Channel ID from the bottom of the modal. In Lightdash, paste the channel ID into the Channels input field and select the "Look up channel ID" option to find your private channel. ## Unfurl Lightdash links After installing the Slack app it will automatically unfurl links you share in Slack from your Lightdash project. The Lightdash app must be invited to a channel before it will unfurl links in that channel. Chart and dashboard links unfurl for links copied from the URL field and also "share" links copied by clicking the link icon. When generating link previews, queries are executed using the credentials of the user who installed the Slack app. This means the preview will reflect that user's data access permissions, not the permissions of the person sharing the link. If the installer's warehouse session expires, link previews will fail until they re-authenticate. Here's what an individual chart looks like unfurled: And an unfurled dashboard: ## Scheduled deliveries Once Slack is added to your Lightdash organization you can use it as a destination for scheduled deliveries. You can schedule refreshes for either Charts or Dashboards and push the results into a Slack channel or DM. The result will look like this for charts if you choose to attach an image of the chart: And like this for dashboards if you chose *not* to include an image: ## Saved Chart Alerts in Slack In addition to scheduled deliveries, you can also set up [alerts on saved charts](/guides/how-to-create-alerts) that only send to slack if certain criteria are met. ## AI analyst agents The Slack integration is also used by AI analyst agents to chat with your data and build charts in Slack. Once you have access to AI analysts you can give them access to Slack threads in your integration settings. To trigger AI responses, mention the Lightdash app in your message. There's only one Lightdash Slack app name to mention - you don't need to specify a particular agent. Lightdash automatically routes your question to the most appropriate agent. If it's unclear which agent should respond, you'll be prompted to choose. By default, all Slack AI agent conversations are attributed to the user who installed the Slack app. To have conversations attributed to individual Slack users (and respect their data permissions), enable the **AI Agents OAuth requirement** in your [Slack integration settings](#ai-agents-configuration). # Snowflake Cortex Source: https://docs.lightdash.com/references/integrations/snowflake-cortex Operate your BI layer agentically by pairing Lightdash with Snowflake's Cortex Code agent. [Cortex Code](https://www.snowflake.com/) is Snowflake's coding agent, with Snowflake-native tools and RBAC governance built in. Pair it with Lightdash and you can operate your BI layer agentically. For broader guidance on using AI coding agents with Lightdash, see [Editing dashboards with agents](/guides/developer/editing-dashboards-with-agents). ## Integration options There are three ways to integrate Cortex with Lightdash: | Method | Best for | Auth required | Where it works | | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------- | ------------------------------- | | [Skills](#skills) | Operating Lightdash as an expert: building your semantic layer, developing charts and dashboards, shipping [dashboards as code](/guides/developer/dashboards-as-code), and vibe coding dashboards | None | Locally (via the Lightdash CLI) | | [Lightdash MCP](#lightdash-mcp) | Searching your semantic layer and executing queries | Lightdash login | Locally and in Snowsight Cortex | | [Docs MCP](#docs-mcp) | Looking up anything in the Lightdash docs | None (public) | Anywhere | You can use any combination of these together. ## Skills Skills are the best way to get Cortex operating Lightdash as an expert. They teach the agent how to: * Build your [semantic layer](/guides/developer/dashboards-as-code) * Develop charts and dashboards * Ship [dashboards as code](/guides/developer/dashboards-as-code) * Vibe code dashboards Skills are powered by the [Lightdash CLI](/guides/cli/how-to-install-the-lightdash-cli). Install skills for Cortex in your project: ```bash theme={null} lightdash install-skills --agent cortex ``` Or install them globally so they're available across all your projects: ```bash theme={null} lightdash install-skills --agent cortex --global ``` For more details, see the [Agent skills guide](/guides/developer/agent-skills). ## Lightdash MCP The [Lightdash MCP](/references/integrations/lightdash-mcp) is best for searching through your semantic layer and executing queries. Unlike skills, the MCP also works in Snowsight Cortex — not just locally. It requires you to log in to Lightdash. Add the Lightdash MCP to Cortex: ```bash theme={null} cortex mcp add lightdash https://.lightdash.cloud/api/v1/mcp ``` Replace `` with your Lightdash instance name. ## Docs MCP The [Docs MCP](/references/integrations/lightdash-mcp#lightdash-docs-mcp) is public and requires no login. It lets Cortex look up anything in the Lightdash documentation — generally very useful alongside the other integrations. Add the Docs MCP to Cortex: ```bash theme={null} cortex mcp add lightdash https://docs.lightdash.com ``` # Joins reference Source: https://docs.lightdash.com/references/joins Joins let you connect different models to each other so that you can explore more than one model at the same time in Lightdash and see how different parts of your data relate to each other. **Performance Best Practice:** For optimal query performance, we recommend using wide tables wherever possible and minimising joins in the BI layer. While we offer advanced features like fanout protection to help with complex relationships, handling data transformations and complex logic directly in your SQL models will generally yield better performance than relying heavily on joins at query time. Consider pre-joining related data during your data modeling process rather than joining tables on-the-fly in dashboards and reports. ## Adding joins in your models Joins are defined at the same level as the model parameters in your YAML file. ```yaml theme={null} models: - name: accounts meta: primary_key: id joins: - join: deals type: left sql_on: ${accounts.id} = ${deals.account_id} fields: [unique_deals, new_deals, won_deals, lost_deals, stage] relationship: one-to-many ``` ```yaml theme={null} models: - name: accounts config: meta: primary_key: id joins: - join: deals type: left sql_on: ${accounts.id} = ${deals.account_id} fields: [unique_deals, new_deals, won_deals, lost_deals, stage] relationship: one-to-many ``` ```yaml theme={null} type: model name: accounts primary_key: id joins: - join: deals type: left sql_on: ${accounts.id} = ${deals.account_id} fields: [unique_deals, new_deals, won_deals, lost_deals, stage] relationship: one-to-many ``` When you open Lightdash, the dimensions and metrics from your joined model will appear below the ones in your selected model. screenshot-joined-table * Omit `fields` to include all metrics and dimensions defined in the joined table. * When joined fields reference other fields, those other fields must be included. * The `sql_on` statement can include references to [user attributes](/references/workspace/user-attributes) for row-level filtering. ## Rename a joined model When joining tables, you may want to rename for readability. This can be done with the `label` tag, for example on the `messages` model it makes sense to rename the joined `users` table as "Sender": ```yaml theme={null} models: - name: messages meta: joins: - join: users label: Sender sql_on: ${messages.sent_by} = ${users.user_id} ``` ```yaml theme={null} models: - name: messages config: meta: joins: - join: users label: Sender sql_on: ${messages.sent_by} = ${users.user_id} ``` ```yaml theme={null} type: model name: messages joins: - join: users label: Sender sql_on: ${messages.sent_by} = ${users.user_id} ``` You can also override the description of the joined table by providing a `description` field: ```yaml theme={null} models: - name: messages meta: joins: - join: users label: Sender description: User who sent the message sql_on: ${messages.sent_by} = ${users.user_id} ``` ```yaml theme={null} models: - name: messages config: meta: joins: - join: users label: Sender description: User who sent the message sql_on: ${messages.sent_by} = ${users.user_id} ``` ```yaml theme={null} type: model name: messages joins: - join: users label: Sender description: User who sent the message sql_on: ${messages.sent_by} = ${users.user_id} ``` ## Join the same table multiple times If you need to join a table multiple times, you can use an `alias` to distinguish between the different tables. A common use case is joining a user table multiple times to another table depending on the type of user. For example this `messages` model has both a sender and a recipient: ```yaml theme={null} models: - name: messages meta: joins: - join: users alias: sender sql_on: ${messages.sent_by} = ${sender.user_id} - join: users alias: recipient sql_on: ${messages.sent_to} = ${recipient.user_id} ``` ```yaml theme={null} models: - name: messages config: meta: joins: - join: users alias: sender sql_on: ${messages.sent_by} = ${sender.user_id} - join: users alias: recipient sql_on: ${messages.sent_to} = ${recipient.user_id} ``` ```yaml theme={null} type: model name: messages joins: - join: users alias: sender sql_on: ${messages.sent_by} = ${sender.user_id} - join: users alias: recipient sql_on: ${messages.sent_to} = ${recipient.user_id} ``` We recommend using `alias` values that are all lowercase and do not include spaces to avoid unexpected issues. Note the following important differences when using alias in joins: 1. You must reference the fields in the model using the new alias. Notice that the joins above use `${sender.user_id}` rather than `${users.user_id}`. 2. Because of the above, any fields in the base model or joined model that reference any field `${users.*}` will fail to compile. Be careful of aliasing tables that are used in the base model. 3. Joined models are automatically relabelled with the alias but you may also customise this using the `label:` field as above. ## Specify your join type If you want to specify the type of join to be used in your SQL query, use the `type` field in your YAML configuration file. Set its value to one of the following: `inner`, `left`, `right`, or `full`. This will determine how the tables are joined in your query, aligning with SQL's inner join, left outer join, right outer join, or full outer join respectively. Here's an example of how to specify a join type: ```yaml theme={null} models: - name: messages meta: joins: - join: users type: inner sql_on: ${messages.sent_by} = ${users.user_id} ``` ```yaml theme={null} models: - name: messages config: meta: joins: - join: users type: inner sql_on: ${messages.sent_by} = ${users.user_id} ``` ```yaml theme={null} type: model name: messages joins: - join: users type: inner sql_on: ${messages.sent_by} = ${users.user_id} ``` By default, if no `type` is specified, Lightdash will use a `left join`. Here's a table to help you understand what each join type means and how it translates to SQL: | Join Type | Generated SQL | Description | | :-------------- | :--------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [inner](#inner) | inner join | Returns rows that have matching values in both tables. | | [left](#left) | left outer join | Returns all rows from the left table, and the matching rows from the right table. Non-matching rows will have NULL for right table's columns. | | [right](#right) | right outer join | Returns all rows from the right table, and the matching rows from the left table. Non-matching rows will have NULL for left table's columns. | | [full](#full) | full outer join | Returns all rows when there is a match in either the left or right table records. Non-matching rows will have NULL for columns of the table that lacks a match. | ### inner An inner join returns rows that have matching values in both tables. For example, if you have a `users` table and a `subscriptions` table, an inner join would return only the users who have a subscription. Here's an example of how to specify an inner join: ```yaml theme={null} models: - name: users meta: joins: - join: subscriptions sql_on: ${users.user_id} = ${subscriptions.user_id} type: inner ``` ```yaml theme={null} models: - name: users config: meta: joins: - join: subscriptions sql_on: ${users.user_id} = ${subscriptions.user_id} type: inner ``` ```yaml theme={null} type: model name: users joins: - join: subscriptions sql_on: ${users.user_id} = ${subscriptions.user_id} type: inner ``` ### left A left join returns all rows from the left table (i.e. the model where you're adding the `join` to), and the matching rows from the right table (i.e. the model you've specified in `- join:`). Non-matching rows will have `NULL` for right table's columns. For example, if you have a `users` table and a `subscriptions` table, a left join would return all users, and the subscription information for users who have a subscription. Here's an example of how to specify a left join: ```yaml theme={null} models: - name: users meta: joins: - join: subscriptions sql_on: ${users.user_id} = ${subscriptions.user_id} type: left # you can omit this, as left is the default ``` ```yaml theme={null} models: - name: users config: meta: joins: - join: subscriptions sql_on: ${users.user_id} = ${subscriptions.user_id} type: left # you can omit this, as left is the default ``` ```yaml theme={null} type: model name: users joins: - join: subscriptions sql_on: ${users.user_id} = ${subscriptions.user_id} type: left # you can omit this, as left is the default ``` ### right A right join returns all rows from the right table (i.e. the model you've specified in `- join: `), and the matching rows from the left table (i.e. the model where you're adding the `join` to). Non-matching rows will have `NULL` for left table's columns. For example, if you have a `users` table and a `subscriptions` table, a right join would return all subscriptions, and the user information for users who have a subscription. Here's an example of how to specify a right join: ```yaml theme={null} models: - name: users meta: joins: - join: subscriptions sql_on: ${users.user_id} = ${subscriptions.user_id} type: right ``` ```yaml theme={null} models: - name: users config: meta: joins: - join: subscriptions sql_on: ${users.user_id} = ${subscriptions.user_id} type: right ``` ```yaml theme={null} type: model name: users joins: - join: subscriptions sql_on: ${users.user_id} = ${subscriptions.user_id} type: right ``` ### full A full join returns all rows when there is a match in either the left or right table records. Non-matching rows will have `NULL` for columns of the table that lacks a match. For example, if you have a `users` table and a `subscriptions` table, a full join would return all users and all subscriptions, and the subscription information for users who have a subscription. ## Defining join relationships You can define the relationship between tables in your joins to help Lightdash show warnings and generate the appropriate SQL. This is especially useful for preventing SQL fanouts issues described in the [SQL fanouts](#sql-fanouts) section. To define a relationship, add the `relationship` field to your join configuration. ```yaml theme={null} models: - name: users meta: primary_key: user_id joins: - join: orders sql_on: ${users.user_id} = ${orders.user_id} relationship: one-to-many ``` ```yaml theme={null} models: - name: users config: meta: primary_key: user_id joins: - join: orders sql_on: ${users.user_id} = ${orders.user_id} relationship: one-to-many ``` ```yaml theme={null} type: model name: users primary_key: user_id joins: - join: orders sql_on: ${users.user_id} = ${orders.user_id} relationship: one-to-many ``` Make sure that you consider the direction of the join when defining the relationship. If you incorreclty define the join relationship, your will be affected by fanouts. ##### The following join relationships are supported: * `one-to-many` - Starting table has 1 record, joined table has many matches * `many-to-one` - Starting table has many records, joined table has 1 match * `one-to-one` - Starting table has 1 record, joined table has 1 match * `many-to-many` - Multiple records in the starting table match multiple records in the joined table #### Step 1: Identify your starting table Which table are you joining FROM? Direction matters: `Accounts` joining to `Users` (one-to-many) is completely different from users joining to accounts (many-to-one), even though it's the same data. #### Step 2: Count the expected matches and name the join relationship For any record in your starting table, ask: "How many matching records will I find in the table I'm joining to and vice versa?" Refer to the supported join relationships listed above. The examples below detail some more complex join relationships: ##### Chained Join Example Don't try to figure out `Accounts` → `Users` → `Tracks` all at once. Analyze each join separately: * First: `Accounts` → `Users` (one-to-many) * Then: `Users` → `Tracks` (one-to-many) * Overall result: `Accounts` → `Tracks` (one-to-many) The `accounts.yml` file will look like this: ```yaml theme={null} models: - name: accounts meta: primary_key: account_id description: List of all customer and prospective customer Accounts pulled from our CRM joins: - join: users relationship: one-to-many sql_on: ${accounts.account_id} = ${users.account_id} type: left - join: tracks relationship: one-to-many sql_on: ${users.user_id} = ${tracks.user_id} type: left ``` ```yaml theme={null} models: - name: accounts config: meta: primary_key: account_id description: List of all customer and prospective customer Accounts pulled from our CRM joins: - join: users relationship: one-to-many sql_on: ${accounts.account_id} = ${users.account_id} type: left - join: tracks relationship: one-to-many sql_on: ${users.user_id} = ${tracks.user_id} type: left ``` ```yaml theme={null} type: model name: accounts primary_key: account_id description: List of all customer and prospective customer Accounts pulled from our CRM joins: - join: users relationship: one-to-many sql_on: ${accounts.account_id} = ${users.account_id} type: left - join: tracks relationship: one-to-many sql_on: ${users.user_id} = ${tracks.user_id} type: left ``` The above setup will consider both `Accounts` and `Users` as being susceptible to fanouts and these would be handled accordingly. When you chain two one-to-many relationships, you get a one-to-many relationship from your starting table to your final table (`Accounts` can have many `Tracks`). Note that if I wanted to join `Users` and `Accounts` onto the `Tracks`, where `Tracks` is the starting model, the direction of the relationship would look different: The `tracks.yml` model would look like this: ```yaml theme={null} models: - name: tracks meta: primary_key: account_id description: List of all customer and prospective customer Accounts pulled from our CRM joins: - join: users relationship: many-to-one sql_on: ${users.user_id} = ${tracks.user_id} type: right - join: accounts relationship: many-to-one sql_on: ${users.account_id} = ${accounts.account_id} type: right ``` ```yaml theme={null} models: - name: tracks config: meta: primary_key: account_id description: List of all customer and prospective customer Accounts pulled from our CRM joins: - join: users relationship: many-to-one sql_on: ${users.user_id} = ${tracks.user_id} type: right - join: accounts relationship: many-to-one sql_on: ${users.account_id} = ${accounts.account_id} type: right ``` ```yaml theme={null} type: model name: tracks primary_key: account_id description: List of all customer and prospective customer Accounts pulled from our CRM joins: - join: users relationship: many-to-one sql_on: ${users.user_id} = ${tracks.user_id} type: right - join: accounts relationship: many-to-one sql_on: ${users.account_id} = ${accounts.account_id} type: right ``` ##### Complex Join Example We want to see all `Accounts` and all `Deals`, but we only want to see `Users` (and their associated event `Tracks`) for `Accounts` that have at least one `Deal` in the "Won" stage. This join example is covered in our Demo site [here](https://demo.lightdash.com/projects/d496d901-a76d-4916-9eae-b81bc7337013/dashboards/471bc4ac-ef14-4efc-b972-7f8f0be18d18/view). This requires a complex join that involves 4 different tables. * First: `Accounts` → `Deals` (one-to-many) * Next: `Accounts` and `Deals` → `Users` (many-to-many) - each `Account`+ `Deal` combination can be associated with many `Users` and each user can be associated with multiple `Deals`. * Then: `Users` → `Tracks` (one-to-many) A normal SQL join that does not account for fanouts would look like this: ```sql theme={null} select * from accounts left join deals on accounts.account_id = deals.account_id left join users on accounts.account_id = users.account_id and deals.stage ='Won' left join tracks on users.user_id = tracks.user_id ``` And the `accounts.yml` would look like this: ```yaml theme={null} models: - name: accounts meta: primary_key: account_id description: List of all customer and prospective customer Accounts pulled from our CRM joins: - join: deals relationship: one-to-many sql_on: ${accounts.account_id} = ${deals.account_id} type: left - join: users relationship: many-to-many sql_on: ${accounts.account_id} = ${users.account_id} and ${deals.stage} = 'Won' type: left - join: tracks relationship: one-to-many sql_on: ${users.user_id} = ${tracks.user_id} type: left ``` ```yaml theme={null} models: - name: accounts config: meta: primary_key: account_id description: List of all customer and prospective customer Accounts pulled from our CRM joins: - join: deals relationship: one-to-many sql_on: ${accounts.account_id} = ${deals.account_id} type: left - join: users relationship: many-to-many sql_on: ${accounts.account_id} = ${users.account_id} and ${deals.stage} = 'Won' type: left - join: tracks relationship: one-to-many sql_on: ${users.user_id} = ${tracks.user_id} type: left ``` ```yaml theme={null} type: model name: accounts primary_key: account_id description: List of all customer and prospective customer Accounts pulled from our CRM joins: - join: deals relationship: one-to-many sql_on: ${accounts.account_id} = ${deals.account_id} type: left - join: users relationship: many-to-many sql_on: ${accounts.account_id} = ${users.account_id} and ${deals.stage} = 'Won' type: left - join: tracks relationship: one-to-many sql_on: ${users.user_id} = ${tracks.user_id} type: left ``` In this case, the fanout protection logic will consider metrics from all models to be susceptible to fanouts. #### Step 3: Check for conditional joins Look for any AND conditions in your join logic (like and `${deals.stage} = 'Won'`). These can change your relationship from what you'd expect - a typical one-to-many might become many-to-many when you add conditions. #### Step 4: Validate with sample data Pick one record from your starting table and manually trace through the joins. Count how many final records you get - this helps catch relationship mistakes before they cause problems. ## Always join a table If you need a table to always be joined, you can set the `always` field to `true`. ```yaml theme={null} models: - name: messages meta: joins: - join: users sql_on: ${messages.sent_by} = ${users.user_id} always: true ``` ```yaml theme={null} models: - name: messages config: meta: joins: - join: users sql_on: ${messages.sent_by} = ${users.user_id} always: true ``` ```yaml theme={null} type: model name: messages joins: - join: users sql_on: ${messages.sent_by} = ${users.user_id} always: true ``` This will make sure that even when you don't select any of the fields from the joined table it will still be joined in the query. ## Only select a subset of fields from a join Use the `fields` tag to select a subset of fields from a join. This is useful if you want to join a model but only a few of its fields are useful in the joined context. For example this `messages` model only needs the `name` and`email` fields from the `users` model. Note we must also include the `user_id` field since it's needed for the join. ```yaml theme={null} models: - name: messages meta: joins: - join: users sql_on: ${messages.sent_by} = ${users.user_id} fields: [user_id, email, name] ``` ```yaml theme={null} models: - name: messages config: meta: joins: - join: users sql_on: ${messages.sent_by} = ${users.user_id} fields: [user_id, email, name] ``` ```yaml theme={null} type: model name: messages joins: - join: users sql_on: ${messages.sent_by} = ${users.user_id} fields: [user_id, email, name] ``` ## Using joined dimensions or metrics in your YAML Once you've joined a model, you can reference the metrics and dimensions from your joined model in your configurations. For example, I can filter one of my metrics using a dimension from my joined model, like this: ```yaml theme={null} models: - name: users meta: joins: - join: web_sessions sql_on: ${web_sessions.user_id} = ${users.user_id} - join: subscriptions sql_on: ${subscriptions.user_id} = ${users.user_id} AND ${subscriptions.is_active} columns: - name: user_id meta: metrics: num_unique_premium_user_ids: type: count_distinct filters: - subscriptions.plan: premium ``` ```yaml theme={null} models: - name: users config: meta: joins: - join: web_sessions sql_on: ${web_sessions.user_id} = ${users.user_id} - join: subscriptions sql_on: ${subscriptions.user_id} = ${users.user_id} AND ${subscriptions.is_active} columns: - name: user_id config: meta: metrics: num_unique_premium_user_ids: type: count_distinct filters: - subscriptions.plan: premium ``` ```yaml theme={null} type: model name: users joins: - join: web_sessions sql_on: ${web_sessions.user_id} = ${users.user_id} - join: subscriptions sql_on: ${subscriptions.user_id} = ${users.user_id} AND ${subscriptions.is_active} dimensions: - name: user_id metrics: num_unique_premium_user_ids: type: count_distinct sql: ${TABLE}.user_id filters: - subscriptions.plan: premium ``` You can also reference joined metrics and dimensions in custom sql, like this: ```yaml theme={null} models: - name: users meta: joins: - join: web_sessions sql_on: ${web_sessions.user_id} = ${users.user_id} - join: subscriptions sql_on: ${subscriptions.user_id} = ${users.user_id} AND ${subscriptions.is_active} columns: - name: user_id meta: dimension: sql: IF(${subscriptions.plan} IS NULL, NULL, ${user_id}) metrics: num_unique_premium_user_ids: type: count_distinct sql: IF(${subscriptions.plan} = 'premium', ${user_id}, NULL) ``` ```yaml theme={null} models: - name: users config: meta: joins: - join: web_sessions sql_on: ${web_sessions.user_id} = ${users.user_id} - join: subscriptions sql_on: ${subscriptions.user_id} = ${users.user_id} AND ${subscriptions.is_active} columns: - name: user_id config: meta: dimension: sql: IF(${subscriptions.plan} IS NULL, NULL, ${user_id}) metrics: num_unique_premium_user_ids: type: count_distinct sql: IF(${subscriptions.plan} = 'premium', ${user_id}, NULL) ``` ```yaml theme={null} type: model name: users joins: - join: web_sessions sql_on: ${web_sessions.user_id} = ${users.user_id} - join: subscriptions sql_on: ${subscriptions.user_id} = ${users.user_id} AND ${subscriptions.is_active} dimensions: - name: user_id sql: IF(${subscriptions.plan} IS NULL, NULL, ${user_id}) metrics: num_unique_premium_user_ids: type: count_distinct sql: IF(${subscriptions.plan} = 'premium', ${user_id}, NULL) ``` If you get the following error: `Model "TABLE" has a metric reference: ${TABLE.DIMENSION} which matches no metric` - you likely have a mismatch in metric category. Read more about metric categories [here](/references/metrics#metric-categories). **Every joined field that you reference in a YAML file adds a dependency that you'll have to include in all future references to that model.** For example, you might define `deals.unique_enterprise_deals` by using a joined field in a filter: `${accounts.segment} = 'Enterprise'`. Then later you need to join `deals` to a `marketing_attribution` model. The `unique_enterprise_deals` metric must be excluded from the join unless you also join `accounts` to get the `accounts.segment` field. Check out our [dimensions](/references/dimensions) and [metrics](/references/metrics) reference docs to see all of the other configurations you can use with your joined fields. ## Joins are not transitive Joins defined on one model are **not automatically available** when that model is joined to another model. Each explore only knows about the joins explicitly defined on the model you are exploring from. For example, if `accounts` joins `deals` and `users` joins `accounts`, the `deals` join is **not** carried over to the `users` explore. Any dimension or metric on `accounts` that references a `deals` field (like `${deals.stage}`) will fail to compile when exploring from `users`. ``` users → accounts ✅ works users → accounts → deals ❌ not automatic ``` This commonly surfaces when you define a metric on one model using a dimension from a joined table, and then join that model elsewhere. The metric references a field that doesn't exist in the new context. ### How to resolve cross-join field references There are three approaches, depending on your use case: **Option 1: Materialize the field in dbt (recommended)** Compute the value as a real column in your dbt model so it has no cross-model dependency. This is the cleanest approach and avoids the issue entirely. ```sql theme={null} -- in your dbt model for accounts SELECT *, (SELECT COUNT(*) FROM deals WHERE deals.account_id = accounts.id AND deals.stage = 'Won') AS won_deals_count FROM accounts ``` **Option 2: Add a chained join to the other explore** Explicitly add the missing table as a [chained join](#chained-join-example) on any explore that needs it. This makes the referenced fields available in that context. ```yaml theme={null} models: - name: users meta: joins: - join: accounts sql_on: ${users.account_id} = ${accounts.id} - join: deals sql_on: ${accounts.id} = ${deals.account_id} ``` ```yaml theme={null} models: - name: users config: meta: joins: - join: accounts sql_on: ${users.account_id} = ${accounts.id} - join: deals sql_on: ${accounts.id} = ${deals.account_id} ``` ```yaml theme={null} type: model name: users joins: - join: accounts sql_on: ${users.account_id} = ${accounts.id} - join: deals sql_on: ${accounts.id} = ${deals.account_id} ``` **Option 3: Exclude the dependent metrics with `fields`** Use the [`fields` tag](#only-select-a-subset-of-fields-from-a-join) on the join to omit metrics that depend on unavailable tables. The metric won't be accessible in the explore, but the error is suppressed. ```yaml theme={null} models: - name: users meta: joins: - join: accounts sql_on: ${users.account_id} = ${accounts.id} fields: [id, name] # omit metrics that reference deals ``` ```yaml theme={null} models: - name: users config: meta: joins: - join: accounts sql_on: ${users.account_id} = ${accounts.id} fields: [id, name] # omit metrics that reference deals ``` ```yaml theme={null} type: model name: users joins: - join: accounts sql_on: ${users.account_id} = ${accounts.id} fields: [id, name] # omit metrics that reference deals ``` ## Hide joined tables Sometimes, you need to use an intermediate model to join two models together and don't want to show its columns in the list of available metrics/dimensions. You can add a `hidden: true` tag to joins, like this to hide these intermediate models: ```yaml theme={null} models: - name: users meta: joins: - join: map_users_organizations sql_on: users.user_id = map_users_organizations.user_id hidden: true - join: organizations sql_on: organizations.organization_id = map_users_organizations.organization_id ``` ```yaml theme={null} models: - name: users config: meta: joins: - join: map_users_organizations sql_on: users.user_id = map_users_organizations.user_id hidden: true - join: organizations sql_on: organizations.organization_id = map_users_organizations.organization_id ``` ```yaml theme={null} type: model name: users joins: - join: map_users_organizations sql_on: users.user_id = map_users_organizations.user_id hidden: true - join: organizations sql_on: organizations.organization_id = map_users_organizations.organization_id ``` Using just the `hidden` tag in the join and changing nothing else will remove the joined table from the sidebar of metrics/dimensions in `users`, but it will still appear in the Tables list as a table to explore on its own. You can adjust which tables show up in the Tables list by adjusting your tables configuration under project settings, [read the guide here](/get-started/develop-in-lightdash/adding-tables-to-lightdash#configuring-which-tables-appear-in-your-lightdash-project). ## SQL fanouts When joining tables in SQL, it can accidentally inflate your metrics if those tables have one-to-many relationships. Understanding when this happens helps you know which metrics need special handling. When dealing with joins that might cause metric inflation, certain types of calculations remain safe to use. ### Safe vs. risky metrics These metrics stay accurate even when the data contains duplicates: * **min and max:** `min(order_total)` and `max(order_total)` give you the same answer whether you have duplicates or not, because they're looking for the extreme values, not counting or adding things up. The maximum value in a set doesn't change just because that value appears multiple times. * **`Aggregate functions with distinct:`** `count(distinct user_id)` ensures each user is counted only once, regardless of how many times they appear in the joined result. These metrics can give you the wrong answers: * `sum`, `count`, `avg` without using distinct * Custom calculations that treat duplicated rows as separate data points ### Common scenarios and what gets affected **Example:** When you join an `organization` table to a `users` table, each organization can have multiple users. In this scenario: ✅ **User metrics remain accurate** Since each user appears exactly once in the joined result, any metrics calculated on the user level (like average user age or total user count) will be correct. ❌ **Organization metrics become inflated** - Each organization will appear multiple times in the result set (once for each associated user). This means organization-level metrics will be counted multiple times, leading to inflated results. For example, if "ABC Corp" has 2 users, its org\_total\_users metric cannot be summed because it will be duplicated twice. **Raw tables** `organizations` table | organization\_id | organization\_name | org\_total\_users | | :--------------- | :----------------- | :---------------- | | 1 | ABC Corp | 2 | | 2 | XYZ Ltd | 3 | `users` table | organization\_id | user\_id | user\_age | | :--------------- | :------- | :-------- | | 1 | 100 | 57 | | 1 | 200 | 13 | | 2 | 300 | 20 | | 2 | 400 | 30 | | 2 | 500 | 19 | **Joined Output** Organizations are multiplied by the number of users | user\_id | organization\_id | org\_total\_users | user\_age | | :------- | :--------------- | :---------------- | :-------- | | 100 | 1 | 2 | 57 | | 200 | 1 | 2 | 13 | | 300 | 2 | 3 | 20 | | 400 | 2 | 3 | 30 | | 500 | 2 | 3 | 19 | We cannot sum org\_total\_users on this joined table because it will be incorrect. **Example:** When you create a chain of one-to-many relationships by joining `users` to their `orders`, and then `orders` to their support `tickets`. In this scenario: ✅ **Ticket metrics remain accurate** - The final table (`tickets`) in the chain will have accurate metrics because each ticket appears exactly once in the result set. ❌ **Upstream tables experience compounding inflation** - The further up the chain you go, the worse the inflation gets: * **Order metrics become inflated** by the number of tickets per order. If Order #1001 has 3 support tickets, any metrics for this order (like order value) will be counted 3 times. * **User metrics suffer even more inflation** as they're multiplied by the total number of tickets. If a user has 2 orders with 3 tickets each, user-level metrics (like lifetime value) will be counted 6 times in aggregate calculations. For example, if the user Alice has 2 orders and each of these orders have 3 tickets, after joining `users` → `orders` → `tickets`, the result would look like: **Raw tables** `users` table | user\_id | user\_name | user\_age | | :------- | :--------- | :-------- | | 1 | Alice | 23 | `orders` table | order\_id | user\_id | order\_total\_items | | :-------- | :------- | :------------------ | | 1001 | 1 | 5 | | 2001 | 1 | 2 | `tickets` Table | order\_id | ticket\_id | ticket\_time\_to\_first\_response\_mins | | :-------- | :--------- | :-------------------------------------- | | 1001 | A | 8 | | 1001 | B | 62 | | 1001 | C | 47 | | 2001 | D | 5 | | 2001 | E | 1 | | 2001 | F | 89 | **Joined output** Step 1: First Join users to orders | user\_name | user\_age | order\_id | order\_total\_items | | :--------- | :-------- | :-------- | :------------------ | | Alice | 23 | 1001 | 5 | | Alice | 23 | 2001 | 2 | Step 2: Join the result of step 1 to tickets | user\_name | order\_id | ticket\_id | user\_age | order\_total\_items | ticket\_time\_to\_first\_response\_mins | | :--------- | :-------- | :--------- | :-------- | :------------------ | :-------------------------------------- | | Alice | 1001 | A | 23 | 5 | 8 | | Alice | 1001 | B | 23 | 5 | 62 | | Alice | 1001 | C | 23 | 5 | 47 | | Alice | 2001 | D | 23 | 2 | 5 | | Alice | 2001 | E | 23 | 2 | 1 | | Alice | 2001 | F | 23 | 2 | 89 | Note that `users` and `orders` are duplicated but `tickets` are not, which means we can only safely apply aggregates to metrics on the `tickets` table. **Example:** When you join `users` → `orders` AND `users` → `tickets` (both `orders` and `tickets` relate to `users`, but not directly to each other) This creates the most problematic data situation, when you join multiple one-to-many relationships that branch from the same table but aren't directly related to each other. In this scenario: ❌ **EVERY aggregate metric gets inflated due to the cartesian product effect** * **User metrics become massively inflated** by the product of `orders` × `tickets`. If a user has 5 orders and 10 support tickets, each user-level metric will be counted 50 times! * **Order metrics get inflated** by the number of tickets the user has. * **Ticket metrics get inflated** by the number of orders the user has. For example, if the user Alice has 2 orders and 3 tickets, after joining `users` to both `orders` and `tickets` separately, the result would look like: **Raw tables** `users` table | user\_id | user\_name | user\_credit\_amount | | :------- | :--------- | :------------------- | | 1 | Alice | 100 | `orders` table | user\_id | order\_id | order\_total\_items | | :------- | :-------- | :------------------ | | 1 | 1001 | 5 | | 1 | 2001 | 2 | `tickets` Table | user\_id | ticket\_id | ticket\_time\_to\_first\_response\_mins | | :------- | :--------- | :-------------------------------------- | | 1 | A | 8 | | 1 | B | 62 | | 1 | C | 47 | **The cartesian product** - (every record is joined to every other record) of users, orders and tickets. | user\_name | order\_id | ticket\_id | user\_credit\_amount | order\_total\_items | ticket\_time\_to\_first\_response\_mins | | :--------- | :-------- | :--------- | :------------------- | :------------------ | :-------------------------------------- | | Alice | 1001 | A | 100 | 5 | 8 | | Alice | 1001 | B | 100 | 5 | 62 | | Alice | 1001 | C | 100 | 5 | 47 | | Alice | 2001 | A | 100 | 2 | 8 | | Alice | 2001 | B | 100 | 2 | 62 | | Alice | 2001 | C | 100 | 2 | 47 | Note that there is duplication in `users`, `orders` and `tickets` records. We cannot apply aggregates on any metrics without deduplicating records. This creates the worst-case scenario where no aggregate metric (`sum`, `count`, `avg`) is safe without explicit deduplication techniques. ### Handling fanouts Lightdash can automatically handle deduplicating metrics that are inflated due to fanouts if join relationships are specified in YAML as described [in Defining join relationships, above](#defining-join-relationships). **For example:** ```yaml theme={null} models: - name: users meta: primary_key: user_id joins: - join: organizations sql_on: ${organizations.organization_id} = ${users.organization_id} relationship: many-to-one - join: orders sql_on: ${users.user_id} = ${orders.user_id} relationship: one-to-many ``` ```yaml theme={null} models: - name: users config: meta: primary_key: user_id joins: - join: organizations sql_on: ${organizations.organization_id} = ${users.organization_id} relationship: many-to-one - join: orders sql_on: ${users.user_id} = ${orders.user_id} relationship: one-to-many ``` ```yaml theme={null} type: model name: users primary_key: user_id joins: - join: organizations sql_on: ${organizations.organization_id} = ${users.organization_id} relationship: many-to-one - join: orders sql_on: ${users.user_id} = ${orders.user_id} relationship: one-to-many ``` Specifying a `primary_key` and the join `relationship` allows Lightdash to: * Understand the **intended row-level granularity** * Prevent metric inflation by deduplicating joined rows Once you've included primary keys and a join relationship, Lightdash will add CTEs to the compiled SQL query that ensure metrics are not inflated. #### How Lightdash solves SQL fanouts Lightdash uses a pattern of Common Table Expressions (CTEs) to solve the fanout problem. Here's how it works: 1. **cte\_keys**: Contains dimensions (like payment\_method, order\_id) that define the grain of your final results and the primary keys. Any field you want to GROUP BY in your final output should be included here. 2. **cte\_metrics**: Performs calculations on metrics while maintaining the correct grain established by the keys CTE. This prevents double-counting when aggregating across related tables. 3. **cte\_unaffected**: Calculates all metrics that are not affected by fanouts. This includes metrics that exclude duplicates by definition (i.e. `MIN()`, `MAX()` and `COUNT(DISTINCT)`) as well as metrics that are calculated on the table that is on the `many` side of an `one-to-many` or `many-to-one` join relationship. For example, if you have joined `accounts` to `deals` using a `one-to-many` join relationship, `SUM(deals.amount)` would be calculated in this unaffected\_cte because the `deals` data is not susceptible to fanouts. 4. **final**: Join the metrics CTEs together to create the complete result set. Lightdash creates a separate cte\_keys and cte\_metrics for each table that contains metrics with fanouts. This is why you'll see names like "cte\_keys\_orders" and "cte\_metrics\_orders" in the example below, indicating they're specific to the orders table. ##### Examples ```sql theme={null} # Step 1: Create cte_keys that determine the final grain of your results i.e. whatever we will group by. # Exclude fields that we use in aggregations to calculate metrics e.g. `"orders".amount` WITH cte_keys_orders AS ( SELECT DISTINCT "orders".status AS "orders_status", -- grouping dimension "orders".order_id AS "pk_order_id" -- primary key FROM "postgres"."jaffle"."payments" AS "payments" LEFT OUTER JOIN "postgres"."jaffle"."orders" AS "orders" ON ("orders".order_id) = ("payments".order_id) ), # Step 2: Calculate metrics that are affected by fanouts cte_metrics_orders AS ( SELECT cte_keys_orders."orders_status", SUM("orders".amount) AS "orders_total_order_amount" -- order metric (affected by fanout) FROM cte_keys_orders LEFT JOIN "postgres"."jaffle"."orders" AS "orders" ON cte_keys_orders."pk_order_id" = "orders".order_id -- join with primary keys GROUP BY 1 -- Note orders_status are grouping dimensions ), # Step 3: Calculate metrics that are not affected by fanouts cte_unaffected AS ( SELECT "orders".status AS "orders_status", COUNT(DISTINCT "payments".payment_id) AS "payments_unique_payment_count" -- payment metric (NOT affected by fanout) FROM "postgres"."jaffle"."payments" AS "payments" LEFT OUTER JOIN "postgres"."jaffle"."orders" AS "orders" ON ("orders".order_id) = ("payments".order_id) GROUP BY 1 -- Note orders_status are grouping dimensions ) # Step 4: Join the metrics CTEs together to create the final result with properly calculated metrics SELECT cte_unaffected.*, cte_metrics_orders."orders_total_order_amount" AS "orders_total_order_amount" FROM cte_unaffected INNER JOIN cte_metrics_orders ON ( cte_unaffected."orders_status" = cte_metrics_orders."orders_status" OR ( cte_unaffected."orders_status" IS NULL AND cte_metrics_orders."orders_status" IS NULL ) ) ORDER BY "orders_total_order_amount" DESC LIMIT 500 ``` ### Known limitations There are a few situations where Lightdash doesn't currently handle inflated metrics: When a metric in one table references a dimension from a joined table, Lightdash's fanout handling may not correctly deduplicate the results. **Example** References in metric `sql` ```yaml theme={null} metrics: total_amount: type: sum sql: ${amount}+${expenses.amount} ``` **Recommendation** To avoid this limitation, consider moving this logic to your dbt models. By transforming your data in dbt first, you can pre-calculate these dimensions without needing to reference dimensions from joined tables in Lightdash. Metrics that include filters based on dimensions from joined tables can also cause issues with Lightdash's fanout handling. **Example** ```yaml theme={null} metrics: count_users: type: count_distinct filters: - web_sessions.is_bot_user: false ``` **Recommendation** To avoid this limitation, consider moving this logic to your dbt models. By applying these filters in your dbt transformations, you can create pre-filtered metrics that don't require referencing dimensions from joined tables in Lightdash. Metrics that involve multiple levels of references or dependencies can be particularly challenging for Lightdash's fanout handling. **Example** ```yaml theme={null} # orders.yml metrics: total_amount: type: number sql: ${amount}+${expenses.total_amount} # expenses.yml metrics: total_amount: type: number sql: ${amount}+${tariffs.amount} ``` **Recommendation** To avoid this limitation, consider moving this complex logic to your dbt models. By pre-calculating these metrics in dbt, you can flatten the dependency chain and avoid the need for multi-level references between joined tables in Lightdash. Rolledup metrics are pre-aggregated metrics that have already been calculated at a specific granularity in your data warehouse. When these metrics are used in queries that involve joins creating fanouts, they can become inflated because the pre-aggregated values get duplicated across the fanned-out rows. **Example: Orders and payments analysis** Consider a scenario where you have an orders table with total\_amount and a payments table with payment methods. For each order, you can have multiple payments with different methods: **orders table:** | order\_id | total\_amount | | :-------- | :------------ | | 1001 | 100.00 | | 1002 | 250.00 | **payments table:** | payment\_id | order\_id | payment\_method | amount | | :---------- | :-------- | :-------------- | :----- | | 1 | 1001 | cash | 60.00 | | 2 | 1001 | card | 40.00 | | 3 | 1002 | card | 250.00 | If you select payment method and average orders total\_amount, the results are wrong because total\_amount is a rolledup metric that can't be split by method: | payment\_method | avg\_order\_total | | :-------------- | :---------------- | | cash | 100.00 | | card | 175.00 | This is incorrect because: * The cash average should reflect that cash was only used for part of order 1001 (\$100), but the query shows \$100 as if cash paid for the entire order * The card average shows \$175 (average of \$100 and \$250), but this doesn't represent the actual relationship between card payments and order totals The issue is that `total_amount` is a rolledup metric at the order level, but when joined with payments, it gets duplicated across payment methods, making it impossible to correctly analyze the relationship between payment methods and order totals. **Best practices for rolledup metrics** To avoid issues with rolledup metrics in joins that create fanouts: * **Avoid rolledup metrics when possible:** Instead of using pre-aggregated values, use the underlying detail-level data. For example, instead of using a pre-calculated `total_amount` at the order level, use individual payment amounts that can be properly aggregated. * **Name rolledup metrics clearly:** If you must use rolledup metrics, give them descriptive names that indicate their pre-aggregated nature and limitations. * **Provide clear descriptions:** Always include detailed descriptions in your dbt model's YAML that explain the metric's granularity and any limitations when used with joins. ```yaml theme={null} models: - name: orders columns: - name: total_amount meta: metrics: total_order_amount: type: sum description: 'Pre-aggregated total amount per order. Cannot be meaningfully split by payment method or other transaction-level dimensions.' ``` ```yaml theme={null} models: - name: orders columns: - name: total_amount config: meta: metrics: total_order_amount: type: sum description: 'Pre-aggregated total amount per order. Cannot be meaningfully split by payment method or other transaction-level dimensions.' ``` ```yaml theme={null} type: model name: orders dimensions: - name: total_amount metrics: total_order_amount: type: sum sql: ${TABLE}.total_amount description: 'Pre-aggregated total amount per order. Cannot be meaningfully split by payment method or other transaction-level dimensions.' ``` In some business scenarios, fanouts are actually desired and represent real data relationships. A common example is when you need to calculate per-user fees or charges. **Example: Per-user billing** Consider a scenario with accounts, users, and per-user fees where different accounts pay different rates: **accounts table:** | account\_id | account\_name | | :---------- | :------------ | | 1 | TechCorp | | 2 | StartupXYZ | **users table:** | user\_id | account\_id | user\_name | | :------- | :---------- | :--------- | | 101 | 1 | Alice | | 102 | 1 | Bob | | 201 | 2 | David | **fees table:** | account\_id | fee\_type | per\_user\_amount | | :---------- | :----------- | :---------------- | | 1 | Support Fee | 80.00 | | 1 | Training Fee | 120.00 | | 2 | Support Fee | 50.00 | | 2 | Training Fee | 75.00 | When you join these tables: ```sql theme={null} SELECT a.account_name, u.user_name, f.fee_type, f.per_user_amount FROM accounts a LEFT JOIN users u ON a.account_id = u.account_id LEFT JOIN fees f ON a.account_id = f.account_id; ``` The resulting fanout is exactly what you want for billing: | account\_name | user\_name | fee\_type | per\_user\_amount | | :------------ | :--------- | :----------- | :---------------- | | TechCorp | Alice | Support Fee | 80.00 | | TechCorp | Alice | Training Fee | 120.00 | | TechCorp | Bob | Support Fee | 80.00 | | TechCorp | Bob | Training Fee | 120.00 | | StartupXYZ | David | Support Fee | 50.00 | | StartupXYZ | David | Training Fee | 75.00 | In this case, each row represents a real charge, and the total billing (TechCorp pays \$400, StartupXYZ pays \$125) is correctly calculated by summing all rows. **Handling intentional fanouts** Lightdash does not currently provide a built-in way to explicitly handle intentional fanouts. Using intentional fanouts can cause issues when defining other table relationships and may conflict with Lightdash's automatic fanout handling. We recommend always use fanout protection for joins. When you actually want a fanout (like per-user billing), create a dedicated dbt model that handles the logic and gets your data to the right granularity first. Then use that model in Lightdash. # Lightdash CLI reference Source: https://docs.lightdash.com/references/lightdash-cli The Lightdash CLI is the recommended way to develop your Lightdash project. It makes development faster and easier, as well as giving you options for building more powerful automation to manage your Lightdash projects. For installation instructions, see [How to install the Lightdash CLI](/guides/cli/how-to-install-the-lightdash-cli). ## Dependencies The Lightdash CLI requires Node, NPM, and the [dbt core](https://docs.getdbt.com/docs/core/installation-overview) or [dbt cloud](https://docs.getdbt.com/docs/cloud/cloud-cli-installation) CLI to be installed and available under the `dbt` command. ### Known limitations when using dbt cloud CLI **Warehouse credentials dependency for some commands** Affected commands: `lightdash generate`, `lightdash preview` and `lightdash start-preview` These commands rely on the warehouse credentials from the active project, as the dbt Cloud CLI does not expose credentials directly. Ensure the project's credentials have access to all development and staging schemas for a seamless experience. **Empty warehouse credentials for new projects** Affected commands: `lightdash deploy --create` When using this command to create a new project that is not a preview, the warehouse credentials will not be populated automatically. Users must update the warehouse credentials manually in the project settings page after the project is created. ## Global options There are three global options that can be used with any Lightdash CLI command: [version](#version), [help](#help), and [verbose](#verbose). ### Version `--version` or `-V` Ignores the preceding command and shows the installed CLI version. Usually it's used right after `lightdash`, like this: ```bash theme={null} lightdash --version ``` If you need to upgrade your version of the Lightdash CLI, run one of the following in your terminal depending on how you installed it: ```bash theme={null} npm install -g @lightdash/cli lightdash --version ``` ```bash theme={null} brew update && brew upgrade lightdash lightdash --version ``` ### Help `--help` or `-h` Tells you what the preceding command does and lists all command-specific options. You can view the Lightdash CLI help like this: ```console theme={null} lightdash --help ``` That returns the Lightdash CLI help menu: When you use the `--help` or `-h` option with a speific command: ```console theme={null} lightdash validate -h ``` That returns details and examples for the command itself: lightdash validate help CLI results ### Verbose `--verbose` Defaults to OFF. When included, each step will print logs as it progresses through the command. For example, here's a `--verbose` version of `lightdash generate-exposures`: lightdash generate-exposures verbose example ## Commands The table below includes a complete list of all commands available in the Lightdash CLI. For examples and command-specific options, click through the command in the table for docs, or install the Lightdash CLI and use the [global help option](#help). | Command | Description | | -------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | | [`lightdash login`](/references/lightdash-cli#lightdash-login) | Log in to a Lightdash instance using email/password or a token | | [`lightdash config set-project`](/references/lightdash-cli#lightdash-config-set-project) | Choose or set the Lightdash project you are working on | | [`lightdash config get-project`](/references/lightdash-cli#lightdash-config-get-project) | Get the current active project | | [`lightdash config list-projects`](/references/lightdash-cli#lightdash-config-list-projects) | List all non-preview projects in your organization | | [`lightdash compile`](/references/lightdash-cli#lightdash-compile) | Compile lightdash resources using your local project files | | [`lightdash preview`](/references/lightdash-cli#lightdash-preview) | Create a temporary preview project, then wait for a keypress to stop | | [`lightdash start-preview`](/references/lightdash-cli#lightdash-start-preview) | Create a preview project that stays open until it is stopped | | [`lightdash stop-preview`](/references/lightdash-cli#lightdash-stop-preview) | Shut down an open preview project | | [`lightdash deploy`](/references/lightdash-cli#lightdash-deploy) | Compile and deploy a Lightdash project using your local project and credentials | | [`lightdash refresh`](/references/lightdash-cli#lightdash-refresh) | Refresh Lightdash project with remote repository | | [`lightdash validate`](/references/lightdash-cli#lightdash-validate) | Validate content from your active project against your local project files | | [`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 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 | | [`lightdash lint`](/references/lightdash-cli#lightdash-lint) | Validate Lightdash Code files against JSON schemas | | [`lightdash pre-aggregate-audit`](/references/lightdash-cli#lightdash-pre-aggregate-audit) | Audit pre-aggregate hit/miss coverage for one or every dashboard | *** ### `lightdash login` Log in to a Lightdash instance using email and password or a token. ```console theme={null} lightdash login [URL] ``` **Argument:** * `[URL]` * The URL for your Lightdash instance (see examples below) **Options:** * `--token ` * For logging in with an access token (common for SSO users) * Exclude this to log in with email and password * `--project ` * Select a project by UUID after login (must be valid UUID) **Examples:** Log in to Lightdash Cloud US instance (for most Starter customers): ```bash theme={null} lightdash login https://app.lightdash.cloud ``` Log in to Lightdash Cloud EU instance while showing detailed logs of login process: ```bash theme={null} lightdash login https://eu1.lightdash.cloud --verbose ``` Log in to a custom domain with a personal access token (exclude `--token` to log in with email and password): ```bash theme={null} lightdash login https://custom.lightdash.domain --token bv6105f53cb127087189cfib180a3131 ``` ### `lightdash config set-project` Choose the project you're developing in so the CLI knows which project content to look at for other commands like `lightdash validate` and `lightdash preview`. If your organization only has one project you won't need to use this! ```bash theme={null} lightdash config set-project ``` This command will bring up an interactive list of projects in your organization to choose from. If you need to set the project non-interactively, you can use one of the two optional arguments below. **Options:** * `--name` * Set the project non-interactively by passing an explicit project name * `--uuid` * Set the project non-interactively by passing an explicit project UUID **Examples:** Set project to "Healthcare Demo": ```bash theme={null} lightdash config set-project --name "Healthcare Demo" ``` Set project to the one with this UUID: ```bash theme={null} lightdash config set-project --uuid "d75379bc-f6e9-4e52-86b2-d897cabacd0c" ``` ### `lightdash config get-project` Get the current active project that the CLI is configured to use. ```bash theme={null} lightdash config get-project ``` This command displays the project that is currently set for CLI operations. Use this to verify which project will be affected by commands like `lightdash validate`, `lightdash preview`, and `lightdash deploy`. ### `lightdash config list-projects` List all non-preview projects in your organization. ```bash theme={null} lightdash config list-projects ``` This command displays all available projects (excluding preview projects) that you can select using `lightdash config set-project`. ### `lightdash compile` Compile Lightdash resources using your local project and database credentials. dbt gets compiled first, then your Lightdash explores. If you use [dbt node selection](#dbt-node-selection) to only compile a subset of models, Lightdash will also compile models joined to those models to ensure no field references are broken. All standard [dbt options](#dbt-options) work with `lightdash compile`. **Options:** * `--skip-dbt-compile` * (default: false) * Skip `dbt compile` and deploy from the existing ./target/manifest.json * `--skip-warehouse-catalog` * (default: false) * Skip fetch warehouse catalog and use types defined in the YAML * `--no-warehouse-credentials` * (default: false) * Compile without any warehouse credentials. Skips dbt compile + warehouse catalog * `--disable-timestamp-conversion [true|false]` * (default: false) * Snowflake only. Disable converting timestamps to UTC during compilation. Only use this if your timestamp values are already in UTC. **Examples:** Compile the whole project: ```bash theme={null} lightdash compile ``` Compile only the `accounts` dbt model, then your Lightdash explores: ```bash theme={null} lightdash compile -s accounts ``` Compile your project, but skip `dbt compile` and warehouse catalog: ```bash theme={null} lightdash compile --no-warehouse-credentials ``` ### `lightdash preview` Spin up a temporary preview project using your local project files and content (charts and dashboards) copied from your [selected project](#lightdash-config-set-project). All standard [dbt options](#dbt-options) work with `lightdash preview`. **Options:** * `--name [preview name]` * Custom name for the preview project. If a name is not provided, a unique, randomly generated name will be created * `--start-of-week [number]` * Specifies the first day of the week (used by week-related date functions) * 0 (Monday) to 6 (Sunday) * `--skip-dbt-compile` * (default: false) * Skip `dbt compile` and deploy from the existing ./target/manifest.json * `--skip-warehouse-catalog` * (default: false) * Skip fetch warehouse catalog and use types defined in the YAML * `--no-warehouse-credentials` * (default: false) * Compile without any warehouse credentials. Skips dbt compile + warehouse catalog * `--use-dbt-list [true/false]` * (default: true) * Use `dbt list` instead of `dbt compile` to generate dbt manifest.json * `--ignore-errors` * (default: false) * Allows deploy with errors on compile * `--table-configuration [prod/all]` * (default: all) * If set to 'prod' it will copy the table configuration from the source project * `--skip-copy-content` * (default: false) * Skip copying content from the source project * `--combine-manifest ` * Path or http(s) URL to an additional dbt `manifest.json`. Models present in this file but missing from the preview-generated manifest are merged in so the preview reflects the full project even when dbt was only run on a subset of models. The preview-generated manifest always wins on conflicts. URLs (for example, a presigned S3 URL) are fetched at runtime so the manifest does not need to be downloaded first. * `--use-batched-deploy` * (default: false) * Deploy explores in batches instead of a single request. Useful for large projects that exceed payload size limits * `--batch-size [number]` * (default: 50) * Number of explores to include in each batch when using batched deploy * `--parallel-batches [number]` * (default: 1) * Number of batches to upload in parallel when using batched deploy. Use with caution as higher values may overwhelm the server * `--expires-in ` * (default: the upstream project's configured default, or 720 if there is no upstream project) * Number of hours until the preview project auto-expires. Values above the upstream project's [maximum preview expiration](/guides/developer/preview-projects#preview-expiration) are silently capped to the maximum. * `--disable-timestamp-conversion [true|false]` * (default: false) * Snowflake only. Disable converting timestamps to UTC. Applied and persisted when creating the preview project. When updating an existing preview, the flag is ignored with a warning and the saved project setting is used instead. **Examples:** Create a temporary preview project with the name **PR: Add Revenue Metric** and ignore validation errors while spinning it up: ```bash theme={null} lightdash preview --name "PR: Add Revenue Metric" --ignore errors ``` Create a temporary preview project with a random name and set the start of week to Monday, only include models with the dbt tag of `marketing`: ```bash theme={null} lightdash preview --start-of-week=0 --select "tag:marketing" ``` ### `lightdash start-preview` Create a persistent preview project using your local project files and content (charts and dashboards) copied from your [selected project](#lightdash-config-set-project). All standard [dbt options](#dbt-options) work with `lightdash start-preview`. **Required argument:** * `--name [preview name]` * Name for the preview project. If a preview project with this name already exists, it will be updated, otherwise it will create a new preview project. **Options:** * `--start-of-week [number]` * Specifies the first day of the week (used by week-related date functions) * 0 (Monday) to 6 (Sunday) * `--skip-dbt-compile` * (default: false) * Skip `dbt compile` and deploy from the existing ./target/manifest.json * `--skip-warehouse-catalog` * (default: false) * Skip fetch warehouse catalog and use the types defined in YAML * `--use-dbt-list [true/false]` * (default: true) * Use `dbt list` instead of `dbt compile` to generate dbt manifest.json * `--ignore-errors` * (default: false) * Allows deploy with errors on compile * `--table-configuration [prod/all]` * (default: all) * If set to 'prod' it will copy the table configuration from the source project * `--skip-copy-content` * (default: false) * Skip copying content from the source project * `--combine-manifest ` * Path or http(s) URL to an additional dbt `manifest.json`. Models present in this file but missing from the preview-generated manifest are merged in so the preview reflects the full project even when dbt was only run on a subset of models. The preview-generated manifest always wins on conflicts. URLs (for example, a presigned S3 URL) are fetched at runtime so the manifest does not need to be downloaded first. * `--use-batched-deploy` * (default: false) * Deploy explores in batches instead of a single request. Useful for large projects that exceed payload size limits * `--batch-size [number]` * (default: 50) * Number of explores to include in each batch when using batched deploy * `--parallel-batches [number]` * (default: 1) * Number of batches to upload in parallel when using batched deploy. Use with caution as higher values may overwhelm the server * `--expires-in ` * (default: the upstream project's configured default, or 720 if there is no upstream project) * Number of hours until the preview project auto-expires. Values above the upstream project's [maximum preview expiration](/guides/developer/preview-projects#preview-expiration) are silently capped to the maximum. * `--disable-timestamp-conversion [true|false]` * (default: false) * Snowflake only. Disable converting timestamps to UTC. Applied and persisted when creating the preview project. When updating an existing preview, the flag is ignored with a warning and the saved project setting is used instead. ### `lightdash stop-preview` Shuts down a project that was created with . This command does not support using dbt options. **Required argument:** * `--name [preview name]` * Name of the preview project to be deleted. **Example:** Shut down the preview project named **neon unicorn**. ```bash theme={null} lightdash stop-preview "neon unicorn" ``` ### `lightdash deploy` Compiles and deploys the current project to your [selected Lightdash Cloud project](#lightdash-config-set-project). **`lightdash deploy` pushes directly to your production project.** Running this command from a local branch will overwrite your production semantic layer with whatever is compiled locally, including any dev or staging targets from your `profiles.yml`. This can break dashboards for all users. **Use [`lightdash preview`](#lightdash-preview) for local development and testing.** Preview creates a temporary, isolated project that won't affect production. For production deploys, we recommend using [CI/CD with GitHub Actions](/guides/cli/how-to-use-lightdash-deploy#automatically-deploy-your-changes-to-lightdash-using-a-github-action). All standard [dbt options](#dbt-options) work with `lightdash deploy`. **Options:** * `--create [project_name]` * Create a new project. If a project name is not provided, you'll be prompted for one on creation * `--ignore-errors` * (default: false) * Allows deploy with errors on compile * `--start-of-week [number]` * Specifies the first day of the week (used by week-related date functions) * 0 (Monday) to 6 (Sunday) * `--skip-dbt-compile` * (default: false) * Skip `dbt compile` and deploy from the existing ./target/manifest.json * `--skip-warehouse-catalog` * (default: false) * Skip fetch warehouse catalog and use types defined in the YAML * `--no-warehouse-credentials` * (default: false) * Compile without any warehouse credentials. Skips dbt compile + warehouse catalog * `--use-dbt-list [true|false]` * (default: true) * Use `dbt list` instead of `dbt compile` to generate dbt manifest.json * `--combine-manifest ` * Path or http(s) URL to an additional dbt `manifest.json`. Models present in this file but missing from the deploy-generated manifest are merged in so the deploy reflects the full project even when dbt was only run on a subset of models. The deploy-generated manifest always wins on conflicts. URLs (for example, a presigned S3 URL) are fetched at runtime so the manifest does not need to be downloaded first. * `--use-batched-deploy` * (default: false) * Deploy explores in batches instead of a single request. Useful for large projects that exceed payload size limits * `--batch-size [number]` * (default: 50) * Number of explores to include in each batch when using batched deploy * `--parallel-batches [number]` * (default: 1) * Number of batches to upload in parallel when using batched deploy. Use with caution as higher values may overwhelm the server * `--disable-timestamp-conversion [true|false]` * (default: false) * Snowflake only. Disable converting timestamps to UTC. Only honored together with `--create`; the value is persisted to the new project. When deploying to an existing project, the flag is ignored with a warning and the saved project setting is used instead. **Examples:** Create a new project that uses the `production` credentials from your local dbt `profiles.yml`: ```bash theme={null} lightdash deploy --create --target production ``` Deploy a large project with many explores using batched deploy: ```bash theme={null} lightdash deploy --use-batched-deploy ``` Deploy with custom batch settings for very large projects: ```bash theme={null} lightdash deploy --use-batched-deploy --batch-size 100 --parallel-batches 3 ``` ### `lightdash refresh` Refreshes your hosted Lightdash project using the latest code from your linked Github repository. This is equivalent to pressing **Refresh dbt** in the UI as an admin. This command does not support using dbt options. ### `lightdash deploy` vs `lightdash refresh` The two CLI commands above (`lightdash deploy` and `lightdash refresh`) are often confused. Here's the quick difference: | | `lightdash deploy` | `lightdash refresh` | | ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **What it does** | Pushes your local dbt project to a Lightdash project. Runs `dbt compile` (or `dbt list`) locally to produce a fresh `manifest.json`, then sends the compiled models/explores to the Lightdash server. | Tells the Lightdash server to re-pull from the connected git remote and recompile, server-side. No local dbt run, no local files involved — it's the API-driven equivalent of clicking **Refresh dbt** in the UI. | | **Where compilation happens** | Locally (laptop or CI runner) | Lightdash servers | | **Requires a remote git connection?** | No | Yes | | **Flags** | Many (`--project`, `--select`, `--full-refresh`, `--create`, `--use-batched-deploy`, etc.) | Essentially none (just `--verbose`) | | **Use when** | You've changed dbt models or Lightdash YAML metadata locally and want those changes to land in a Lightdash project. | Lightdash already points at a git repo and you just want it to pull the latest. | **Rule of thumb:** * Local dbt code you want to push → `deploy` * Lightdash already points at a git repo and you just want it to pull the latest → `refresh` ### `lightdash validate` Validates a project by comparing the content in your currently selected project against your local project files. Returns all charts and dashboards that have errors. All standard [dbt options](#dbt-options) work with `lightdash validate`. **Options:** * `--project [project uuid]` * Project UUID to validate, if not provided, the last preview will be used * `--preview` * (default: false) * Validate the last preview if available * `--skip-dbt-compile` * (default: false) * Skip `dbt compile` and deploy from the existing ./target/manifest.json * `--skip-warehouse-catalog` * (default: false) * Skip fetch warehouse catalog and use types defined in the YAML * `--use-dbt-list [true/false]` * (default: true) * Use `dbt list` instead of `dbt compile` to generate dbt manifest.json * `--only [elems...]` * (default: \["charts","dashboards","tables"]) * Specify project elements to validate **Example:** Validate only dashboards and use the existing compiled dbt manifest: ```bash theme={null} lightdash validate --only ["dashboards"] --skip-dbt-compile ``` ### `lightdash generate` Generates a new `schema.yml` file or updates existing `schema.yml` for selected model(s). Use this command to auto-generate Lightdash-ready YAML schema files from your database columns so your dbt models appear as tables in Lightdash. All standard [dbt options](#dbt-options) work with `lightdash generate`. **Options:** * `-y` or `--assume-yes` * (default: false) * assume yes to prompts * `--exclude-meta` * (default: false) * exclude Lightdash metadata from the generated .yml * `--preserve-column-case` * (default: false) * preserve original casing of column names in generated schema files * `--skip-existing` * (default: false) * skip files that already exist **Example:** Generate or update YAML file for a single dbt model to cover all columns in the database: ```bash theme={null} lightdash generate -s mymodel ``` ### `lightdash generate-exposures` Generates a `schema.yml` file for Lightdash exposures. This command is still in beta and may be removed or updated without warning. Only Project Admins can execute this command, since it requires access to all spaces (including private ones). This command does not support using dbt options. **Options:** * `--project-dir [path]` * (default: ".") * The directory of the dbt project * `--output [path]` * The path where the output exposures YAML file will be written **Example:** Create or update YAML file called `lightdash-exposures.yml` in the current directory with all exposures in Lightdash: ```bash theme={null} lightdash generate-exposures --output ./lightdash-exposures.yml ``` ### `lightdash dbt run` Runs dbt and then generates or updates `schema.yml` file(s) for models that have columns missing or changed from the existing `schema.yml` files. Any dbt option that works with `dbt run` will also work with `lightdash dbt run`. That includes all the [Lightdash dbt options](#dbt-options), and more ([see dbt run docs](https://docs.getdbt.com/reference/commands/run)). **Options:** * `--exclude-meta` * (default: false) * exclude Lightdash metadata from the generated .yml * `--assume-yes` or `-y` * assume yes to prompts (default: false) * `--assume-no` or `-no` * assume no to prompts (default: false) * `--preserve-column-case` * (default: false) * preserve original casing of column names in generated schema files **Example:** Run a single model and create or update its `schema.yml` file: ```bash theme={null} 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. 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`). You can make changes to the code and upload these changes back to your Lightdash project. Content that's been downloaded as code can still be managed in the Lightdash UI. **Options:** * `--charts` or `-c` * 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 * `--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 ` * download all charts and dashboards from a specific project. You can find the project UUID for a project from a Lightdash URL. E.g. here, the project UUID is `123-project-uuid` `https://app.lightdash.cloud/projects/123-project-uuid/` * `--language-map` or `-l` * (default: false) * generate `.language.map.yml` for the downloaded charts and dashboards with all translatable text from charts and dashboards * `--nested` * (default: false) * split downloaded content into sub-folders matching the spaces in your project * `--strip-pivot-series` * (default: false) * strip per-value pivot series config from chart YAML so it's portable across projects. Cartesian chart series that are tied to specific pivot field values are rewritten to reference only the underlying x/y fields, and duplicates collapsed into a single entry. Use this when the source project's pivot values don't exist in the target project (for example, when reusing chart YAML as a template), so the upload doesn't fail or render with the original project's hardcoded series. Only applies to regular charts; SQL charts and dashboards are unaffected. * `--apps ` * opt-in flag to also download specific [data apps](/guides/data-apps#data-apps-as-code) as code (enterprise only). Pass one or more app UUIDs to download just those apps — this is the only way to download apps that haven't been added to a space. Each app is written to `lightdash/apps//` as a locally buildable project: `lightdash-app.yml` manifest, the app's `src/` tree, `package.json`, a read-only `.lightdash/context/` snapshot of the project's semantic layer, and agent skill files. The built output is not included — the server rebuilds it on upload. * `--include-apps` * (default: false) * opt-in flag to download every [data app](/guides/data-apps#data-apps-as-code) in the project that has been added to a space (enterprise only), capped at the first 10. Use `--apps ` to reach apps that aren't in a space, or to download more than 10. * `--apps-only` * (default: false) * download only data apps, skipping charts, dashboards, and space files (implies `--skip-charts --skip-dashboards --skip-spaces`). Requires `--apps ` or `--include-apps`. Recommended for app-focused checkouts. * `--skip-charts` * (default: false) * skip downloading charts (including SQL charts) * `--skip-dashboards` * (default: false) * skip downloading dashboards **Examples:** Download all charts and dashboards from your project. ```bash theme={null} lightdash download ``` Download a specific dashboard from your Lightdash project. ```bash theme={null} lightdash download -d https://app.lightdash.cloud/my-dashboard-url ``` Download all content from a project to the directory `/Users/katiehindson/lightdash/lightdash-analytics/` ```bash theme={null} lightdash download -p /Users/katiehindson/lightdash/lightdash-analytics/ ``` This will create: `/Users/katiehindson/lightdash/lightdash-analytics/charts/` and `/Users/katiehindson/lightdash/lightdash-analytics/dashboards` and save the content to these new folders. You can also use relative paths like: ```bash theme={null} lightdash download -p ../ ``` Download all charts and dashboards organized by space. ```bash theme={null} lightdash download --nested ``` Download all charts and dashboards from a specific project with language maps. ```bash theme={null} lightdash download --project 21eef0b9-5bae-40f3-851e-9554588e71a6 -l ``` Download charts with portable, pivot-value-free YAML (handy when reusing charts as templates in projects that don't share the same pivot values). ```bash theme={null} lightdash download --strip-pivot-series ``` Download all charts and dashboards, plus every data app in a space (up to the first 10). ```bash theme={null} lightdash download --include-apps ``` Download specific data apps by UUID (charts and dashboards are still downloaded as usual). Required for apps that are not in a space. ```bash theme={null} lightdash download --apps 8f2b1c4d-1111-2222-3333-444455556666 a1b2c3d4-5555-6666-7777-888899990000 ``` Download just one data app and nothing else. ```bash theme={null} lightdash download --apps-only --apps 8f2b1c4d-1111-2222-3333-444455556666 ``` ### `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). 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. `lightdash upload` preserves empty dashboard filters — active filters with no values on operators that require values (for example, `equals` or `greaterThan`). These act as an "unset default" control: at runtime they render as `is any value` in the filter bar and do not override chart-level filters on the same field until a viewer picks a value. Value-less relative-date operators (`inTheCurrent`, `notInTheCurrent`) are compiled from `settings.unitOfTime` rather than `values`, so they are not treated as empty and continue to apply as before. See [Empty default dashboard filters](/guides/limiting-data-using-filters#empty-default-dashboard-filters). **Options:** * `--force` * if you've created new content as code that doesn't exist in your Lightdash project yet, you need to run `lightdash upload --force` to create the new charts and dashboards—otherwise, `lightdash upload` only uploads updates to existing content * `--charts` or `-c` * 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 * `--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 ` * upload all charts and dashboards from a specific project. You can find the project UUID for a project from a Lightdash URL. E.g. here, the project UUID is `123-project-uuid` `https://app.lightdash.cloud/projects/123-project-uuid/` * `--skip-space-create` * (default: false) * Skip space creation if it does not exist * `--include-charts` * (default: false) * Include charts updates when uploading dashboards * `--public` * (default: false) * Creates new spaces as public instead of private * `--validate` * (default: false) * Validate charts and dashboards after upload and display any validation errors * `--nested` * (default: false) * expect content to be organized in sub-folders matching the spaces in your project (use this if content was downloaded with `--nested`) * `--apps [appUuids...]` * opt-in flag to also upload [data apps](/guides/data-apps#data-apps-as-code) as code (enterprise only). Bare `--apps` uploads every app folder under `lightdash/apps/`. Pass one or more app UUIDs to upload just those apps. The CLI posts each app's `src/` tree and returns immediately — the destination rebuilds the app in its sandbox and publishes a new version. The app shows a `building` status in the UI until the build finishes. Uploading to the same project appends a new version and applies any edits to the manifest's `name` or `description`; uploading to a different project prompts for confirmation (in non-interactive shells the app is skipped with an error unless you also pass `--create-new`) and creates a new app in the target. After any create, the CLI prints the new app's URL and offers to retarget the local `lightdash-app.yml` (updating `appUuid`, `projectUuid`, and `version`) so future uploads update the new app. * `--create-new` * (default: false) * always create a new data app from the uploaded source instead of appending a new version to the app referenced by `lightdash-app.yml`. Combine with `--apps` and `--project` when copying an app to a different project or instance in a non-interactive shell. **Examples:** Upload all charts and dashboards in code from your `lightdash/` directory to your Lightdash project. ```bash theme={null} lightdash upload ``` Upload a specific dashboard to your Lightdash project. ```bash theme={null} lightdash upload -d my-dashboard-slug ``` Upload a specific dashboard and include any chart changes referenced by that dashboard. ```bash theme={null} lightdash upload -d my-dashboard-slug --include-charts ``` Upload content from the directory `/Users/katiehindson/lightdash/lightdash-analytics/` ```bash theme={null} lightdash upload -p /Users/katiehindson/lightdash/lightdash-analytics/ ``` This will upload all content from: `/Users/katiehindson/lightdash/lightdash-analytics/charts/` and `/Users/katiehindson/lightdash/lightdash-analytics/dashboards` and save the content to these new folders. You can also use relative paths like: ```bash theme={null} lightdash upload -p ../ ``` Upload all charts and dashboards from your `lightdash/` directory to a specific project. ```bash theme={null} lightdash upload --project 21eef0b9-5bae-40f3-851e-9554588e71a6 ``` Upload all charts and dashboards and validate them after upload to check for errors. ```bash theme={null} lightdash upload --validate ``` Upload all charts, dashboards, and data app folders under `lightdash/apps/`. ```bash theme={null} lightdash upload --apps ``` Upload only specific data apps by UUID. ```bash theme={null} lightdash upload --apps 8f2b1c4d-1111-2222-3333-444455556666 ``` Copy a data app to a different project as a brand-new app (non-interactive). ```bash theme={null} lightdash upload --apps --project 21eef0b9-5bae-40f3-851e-9554588e71a6 --create-new ``` ### `lightdash rename` Rename model or field names across all content in your Lightdash project. This command will do a full find and replace on a field or table so all references in chart fields, dashboard filters, table calculations, custom metrics, etc. can be changed at once. **Arguments:** * `--type` * Specify what you're renaming * Accepted values: `field` or `model` * `--from` * The current name of the table or field you want to change (this is the slug from your YAML definition, i.e. `num_users`) * `--to` * The new name you want to use (must match the new slug in your YAML for this field or table, i.e. `count_distinct_user_id`) **Options:** * `--project`, `-p` * Project UUID to target a specific project * (default: The most recent project you set with `lightdash config set-project`) * `--model`, `-m` * The model to target for field renaming. This is only needed if the current field name is not unique in your project * `--dry-run` * List all content the rename action will change, no changes will be made * `--list` * List all charts and dashboards that were renamed after the command is complete * `--assume-yes`, `-y` * Assume yes to all prompts. **Examples:** Rename the field `num_users` to `count_distinct_user_id`. ```bash theme={null} lightdash rename --type field --from num_users --to count_distinct_user_id ``` Do a dry run of changing the table reference from `users_mart_v1` to `users`. ```bash theme={null} lightdash rename --type model --from users_mart_v1 --to users --dry-run ``` Rename the field `count` to `count_distinct_order_id` in the `orders` model and list all affected content when complete: ```bash theme={null} lightdash rename --type field --model orders --from count --to count_distinct_order_id --list ``` ### `lightdash diagnostics` Shows diagnostic information about the CLI environment. This is useful for debugging issues with the CLI or sharing information with the Lightdash support team. ```console theme={null} lightdash diagnostics ``` **Options:** * `--dbt` * Include dbt debug information in the output * `--project-dir ` * dbt project directory (used with --dbt flag) * `--profiles-dir ` * dbt profiles directory (used with --dbt flag) * `--defer` * dbt defer option (used with --dbt flag) * `--no-defer` * dbt no-defer option (used with --dbt flag) **Information displayed:** * CLI version * Node.js version and optimization status * Authentication status (API key, server URL, organization, project) * dbt debug output (if --dbt flag provided) **Examples:** Show basic diagnostic information: ```bash theme={null} lightdash diagnostics ``` Show diagnostic information including dbt debug output: ```bash theme={null} lightdash diagnostics --dbt ``` Show diagnostic information with dbt debug for a specific project directory: ```bash theme={null} lightdash diagnostics --dbt --project-dir ./my-dbt-project ``` ### `lightdash sql` Run a raw SQL query against your data warehouse using the credentials from your currently selected project. Results are exported to a CSV file. ```console theme={null} lightdash sql -o ``` **Required argument:** * `` * The SQL query to execute **Required option:** * `-o, --output ` * Output file path for CSV results **Options:** * `--limit ` * Maximum number of rows to return from the query * `--page-size ` * Number of rows per page (default: 500, max: 5000) * `--verbose` * (default: false) * Show detailed output **Examples:** Run a simple query and save results to a CSV file: ```bash theme={null} lightdash sql "SELECT * FROM users LIMIT 100" -o users.csv ``` Run a query with a row limit: ```bash theme={null} lightdash sql "SELECT * FROM orders" -o orders.csv --limit 1000 ``` Run a query with verbose output to see detailed progress: ```bash theme={null} lightdash sql "SELECT customer_id, SUM(amount) FROM orders GROUP BY 1" -o revenue.csv --verbose ``` ### `lightdash lint` Validates Lightdash Code files (models, charts, dashboards) against JSON schemas. This command checks that your YAML files conform to the expected structure before you deploy. ```console theme={null} lightdash lint [options] ``` This command does not support using dbt options. **Options:** * `-p, --path ` * Path to a file or directory to lint * (default: current directory) * `--verbose` * (default: false) * Show detailed validation output including all validated files * `-f, --format ` * Output format: `cli` (default) or `json` (SARIF format) * (default: "cli") **Validated file types:** The lint command validates three types of Lightdash Code files: | File type | Schema | Description | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------- | | Models | [model-as-code-1.0.json](https://github.com/lightdash/lightdash/blob/main/packages/common/src/schemas/json/model-as-code-1.0.json) | Lightdash YAML model definitions | | Charts | [chart-as-code-1.0.json](https://github.com/lightdash/lightdash/blob/main/packages/common/src/schemas/json/chart-as-code-1.0.json) | Charts downloaded as code | | Dashboards | [dashboard-as-code-1.0.json](https://github.com/lightdash/lightdash/blob/main/packages/common/src/schemas/json/dashboard-as-code-1.0.json) | Dashboards downloaded as code | **Examples:** Validate all Lightdash Code files in the current directory: ```bash theme={null} lightdash lint ``` Validate a single chart file: ```bash theme={null} lightdash lint --path ./lightdash/charts/my-chart.yml ``` Validate files in a specific directory: ```bash theme={null} lightdash lint --path ./lightdash ``` Show detailed validation output: ```bash theme={null} lightdash lint --verbose ``` Output results in SARIF JSON format (useful for CI/CD integration): ```bash theme={null} lightdash lint --format json ``` **Errors and warnings:** Lint results are reported at two severities: * **Errors** (`✗`, red) — schema validation failures. The command exits with a non-zero status, failing CI. * **Warnings** (`⚠`, yellow) — non-fatal issues that don't block deployment but signal a configuration likely to behave unexpectedly. Warnings don't change the exit code. See [How to use lightdash lint](/guides/cli/how-to-use-lightdash-lint#errors-vs-warnings) for details. ### `lightdash pre-aggregate-audit` Reports pre-aggregate hit/miss coverage for one dashboard or every dashboard in the project. Use it to find gaps in your pre-aggregate YAML or to gate CI on dashboard coverage. ```console theme={null} lightdash pre-aggregate-audit [options] ``` This command does not support using dbt options. **Options:** * `--dashboard ` * Audit a specific dashboard. Required unless `--all` is set. * `--all` * Audit every dashboard in the project. * `--project ` * Override the active project. Falls back to `LIGHTDASH_PROJECT_UUID`, then to the CLI config. * `--json` * Emit machine-readable JSON instead of human-friendly text. * `--fail-on-miss` * Exit 1 if any eligible tile misses. Ineligible tiles do not trigger a failure. * `--verbose` * Include ineligible tiles (and their reason) in the human output. See [Auditing pre-aggregates from the CLI](/references/pre-aggregates/cli-audit) for the full guide, including miss-reason → YAML-fix mappings and CI examples. *** ## dbt options These are options from the dbt Core CLI that also work with some Lightdash CLI commands. ### dbt node selection You can select a subset of your dbt models by using the following options on any Lightdash commands that support dbt options. **Node selection:** * `--select [models...]` or `-s [models...]` * [Read the dbt docs on select](https://docs.getdbt.com/reference/node-selection/syntax#shorthand) * `--exclude [models...]` * [Read the dbt docs on exclude](https://docs.getdbt.com/reference/node-selection/exclude) * `--selector [selector_name]` * [Read the dbt docs on selector](https://docs.getdbt.com/reference/node-selection/yaml-selectors) ### dbt flags These dbt flags work with Lightdash commands that support dbt options. [Read the dbt docs on global config flags](https://docs.getdbt.com/reference/global-configs/about-global-configs#available-flags) for details. * `--project-dir [path]` * `--profiles-dir [path]` * `--profile [name]` * `--target [name]` * `--no-version-check` * `--state [state]` * `--full-refresh` * `--defer` (works with `lightdash preview` and `lightdash compile`) #### `--defer` `--defer` is commonly paired with `--state` and `--select state:modified+` to limit a preview to changed models. The behavior below is specific to how Lightdash builds the explore list and differs from a plain `dbt build --defer`. * **`--defer` only resolves Lightdash-joined upstream models against the prod state manifest.** It does not promote arbitrary unmodified models from the state manifest into the preview as standalone explores. With `--select state:modified+`, the preview contains the modified models (compiled to the dev/CI schema), their downstream models, and any models referenced through Lightdash join configs (deferred to the prod relations). Standalone `tag:lightdash` models that are not joined to a modified model will not appear. This is the scope of the fix shipped in [lightdash/lightdash#20672](https://github.com/lightdash/lightdash/pull/20672). * **Do not pass `--favor-state` to preview workflows.** `--favor-state` makes selected nodes prefer the prod relation over the freshly built dev relation, which silently routes the modified model back to stale prod data — the opposite of the intent of a PR preview. * **The comma in dbt's `--select` is `AND`, not `OR`.** `--select 'tag:lightdash,state:modified+'` resolves to "modified models that are also tagged `lightdash`", which usually narrows to one or two explores rather than the broader set most users expect. Use space-separated arguments (`--select tag:lightdash state:modified+`) for `OR`. ### dbt project variables You can set dbt project variables in Lightdash commands that support dbt options. [Read the dbt docs on project variables](https://docs.getdbt.com/docs/build/project-variables) for details. `--vars [vars]` ### dbt threads You can set the number of threads for dbt in Lightdash commands that support dbt options. [Read the dbt docs on threads](https://docs.getdbt.com/docs/running-a-dbt-project/using-threads) for details. `--threads [number]` *** ## Environment Variables The Lightdash CLI supports various environment variables that can be used to configure its behavior. These are especially useful in CI/CD environments where you want to avoid interactive prompts or need to set credentials programmatically. ### Core Lightdash Configuration * **`LIGHTDASH_API_KEY`** * API access token for authentication * Overrides the API key stored in the config file (`~/.config/lightdash/config.yaml`) * Useful for CI/CD pipelines where you don't want to store credentials in files * **`LIGHTDASH_URL`** * Lightdash server URL (e.g., `https://app.lightdash.cloud`) * Overrides the server URL in the config file * **`LIGHTDASH_PROJECT`** * Project UUID to use for CLI commands * Overrides the project UUID in the config file * Useful when you want to target a specific project without using `--project` flag * **`LIGHTDASH_PROXY_AUTHORIZATION`** * Proxy authorization header for proxied access * Use this if your Lightdash instance is behind a proxy that requires authentication ### CI/CD Environment * **`CI`** * Set to `CI=true` to disable interactive prompts and run commands non-interactively in CI/CD environments * When enabled, the CLI will: * Silence all interactive prompts (including confirmation dialogs) * Assume default values or fail if required input is missing * Skip certain version checks * Adjust behavior for non-interactive execution * Automatically detected by most CI/CD platforms (GitHub Actions, GitLab CI, CircleCI, etc.) * **Usage:** Prefix any Lightdash command with `CI=true` to silence prompts: ```bash theme={null} CI=true lightdash deploy CI=true lightdash preview CI=true lightdash generate -s mymodel ``` ### dbt Configuration These environment variables are passed through to dbt and can be used to configure dbt behavior: * **`DBT_PROJECT_DIR`** * Directory of dbt project * Default: current directory (`.`) * Can also be set using `--project-dir` flag * **`DBT_PROFILES_DIR`** * Directory of dbt profiles * Default: `~/.dbt` * Can also be set using `--profiles-dir` flag ### Example: Using Environment Variables in CI/CD Here's an example of how to use environment variables in a GitHub Actions workflow: ```yaml theme={null} name: Deploy to Lightdash on: push: branches: - main jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Install Lightdash CLI run: npm install -g @lightdash/cli - name: Deploy to Lightdash env: LIGHTDASH_API_KEY: ${{ secrets.LIGHTDASH_API_KEY }} LIGHTDASH_URL: https://app.lightdash.cloud LIGHTDASH_PROJECT: ${{ secrets.LIGHTDASH_PROJECT_UUID }} CI: true run: lightdash deploy ``` In this example: * `LIGHTDASH_API_KEY` is stored as a GitHub secret and passed to the CLI * `LIGHTDASH_URL` specifies which Lightdash instance to connect to * `LIGHTDASH_PROJECT` specifies which project to deploy to * `CI=true` ensures the CLI runs in non-interactive mode # lightdash.config.yml reference Source: https://docs.lightdash.com/references/lightdash-config-yml The lightdash.config.yml file allows you to configure project-wide settings for your Lightdash project, including Metrics Catalog, parameters, and defaults. ## What is lightdash.config.yml? The `lightdash.config.yml` file is an **optional** configuration file that allows you to define project-wide settings for your Lightdash project. Think of it as a way to customize and enhance your Lightdash experience beyond the basic setup. `lightdash.config.yml` is **not supported** when your project is connected directly to dbt Cloud. This file only works with projects that use direct git connections or deploy with the CLI (either from local dbt projects and/or continuous deployment). ## Do I need this file? You **don't need** `lightdash.config.yml` to get started with Lightdash! This file is for users who want to: * **Organize metrics in the [Metrics Catalog](/guides/metrics-catalog)** with custom categories and visibility settings * **Create parameters** that users can change to modify data across multiple charts and dashboards If you're just getting started with Lightdash, you can skip this file and come back to it later when you want these advanced features. ## Getting started Before creating a `lightdash.config.yml` file, make sure you have: 1. ✅ A working Lightdash project (completed the [getting started guide](/get-started/setup-lightdash/intro)) 2. ✅ A local dbt project (not connected to dbt Cloud) 3. ✅ The [Lightdash CLI](/get-started/setup-lightdash/get-project-lightdash-ready#step-1-install-the-lightdash-cli-tool) installed and configured Create a new file called `lightdash.config.yml` in the **root directory of your dbt project** - this is the same folder where your `dbt_project.yml` file is located. ```bash theme={null} # Navigate to your dbt project directory cd /path/to/your/dbt/project # Create the config file touch lightdash.config.yml ``` Start with a simple configuration. Here's a basic example that sets up Metrics Catalog categories: ```yaml theme={null} # Basic lightdash.config.yml example spotlight: default_visibility: "show" categories: finance: label: "Finance" color: "green" marketing: label: "Marketing" color: "blue" ``` After creating or updating your `lightdash.config.yml` file, deploy the changes to your Lightdash project: ```bash theme={null} lightdash deploy ``` That's it! Your configuration is now active in your Lightdash project. ## Configuration options The `lightdash.config.yml` file supports the following top-level configuration options: ```yaml theme={null} # Configuration for project-wide spotlight settings spotlight: # ... # Configuration for project-wide parameters parameters: # ... # Configuration for project-wide defaults defaults: # ... # Configuration for custom date granularities custom_granularities: # ... # Configuration for table groups in the sidebar table_groups: # ... ``` ## Metrics Catalog configuration The `spotlight` section allows you to configure project-wide Metrics Catalog settings. `spotlight` is the YAML namespace that covers everything about how your metrics show up across the [Metrics experience](/guides/metrics-catalog#the-spotlight-config) — here you set the project-wide defaults, and you can override them per model or metric in your model `.yml` files. This section is required in the lightdash.config.yml file. ```yaml theme={null} spotlight: default_visibility: "show" categories: finance: label: "Finance" color: "green" user_engagement: label: "User Engagement" color: "blue" ``` | Property | Required | Value | Description | | :------------------- | :------- | :---------- | :------------------------------------------------------------------------------------------------ | | `default_visibility` | No | string enum | The default visibility of Metrics Catalog metrics. Defaults to `show`, can also be set to `hide`. | | `categories` | No | Object | Define the categories that can be used in the Metrics Catalog on your model yml files. | Each category in the `categories` object requires the following properties: | Property | Required | Value | Description | | :------- | :------- | :---------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `label` | Yes | string | The label of the category as it will be displayed in the Metrics Catalog. | | `color` | No | string enum | The color of the category. If not provided, it will be set to gray. Allowed values: `gray`, `violet`, `red`, `orange`, `green`, `blue`, `indigo`, `pink`, `yellow`. | ## Parameters configuration The `parameters` section allows you to define project-wide parameters that can be referenced in various parts of your Lightdash project. ```yaml theme={null} parameters: region: label: "Region" description: "Filter data by region" options: - "EMEA" - "AMER" - "APAC" default: ["EMEA", "AMER"] multiple: true min_revenue: label: "Minimum Revenue" description: "Filter for minimum revenue threshold" type: "number" options: - 1000 - 5000 - 10000 default: 5000 custom_date_range_start: label: "Custom date range - start" description: "The start date for a custom date range filter" type: "date" custom_date_range_end: label: "Custom date range - end" description: "The end date for a custom date range filter" type: "date" department: label: "Department" description: "Filter data by department" options_from_dimension: model: "employees" dimension: "department" ``` Each parameter is defined as a key-value pair where the key is the parameter name (must be alphanumeric with underscores or hyphens) and the value is an object with the following properties: | Property | Required | Value | Description | | :----------------------- | :------- | :------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------- | | `label` | Yes | string | A user-friendly label for the parameter as it will be displayed in the UI. | | `description` | No | string | A description of the parameter. | | `type` | No | "string", "number", or "date" | The type of the parameter. Defaults to "string" if not specified. | | `options` | No | Array of strings, numbers, or `{ label, value }` objects | A list of possible values for the parameter. | | `default` | No | string, number, or Array of strings/numbers | The default value(s) for the parameter. When using labeled options, the default must match a `value`, not a `label`. | | `multiple` | No | boolean | Whether the parameter input will be a multi-select. | | `allow_custom_values` | No | boolean | Whether users can input custom values beyond predefined options. | | `options_from_dimension` | No | Object | Get parameter options from a dimension in a model. Requires `model` and `dimension` arguments (see below). | If using `options_from_dimension`, the object requires the following properties: | Property | Required | Value | Description | | :---------- | :------- | :----- | :---------------------------------- | | `model` | Yes | string | The model containing the dimension. | | `dimension` | Yes | string | The dimension to get options from. | #### Labeled options Static `options` can be authored as either plain values or `{ label, value }` objects. ```yaml theme={null} parameters: status: label: "Status" description: "Filter data by status" options: - label: "Active" value: "active_id_1" - label: "Inactive" value: "inactive_id_2" default: "active_id_1" ``` Plain string/number arrays continue to work and remain the simplest form when the label and value are the same. ### Using parameters in your project Parameters defined in the `lightdash.config.yml` file can be referenced in various parts of your Lightdash project using the syntax `${lightdash.parameters.parameter_name}` or the shorter alias `${ld.parameters.parameter_name}`. For example, to reference a parameter named `region`: ```yaml theme={null} ${lightdash.parameters.region} ``` Or using the shorter alias: ```yaml theme={null} ${ld.parameters.region} ``` See the [Parameters guide](/guides/developer/using-parameters) for more information on how to use parameters. ### Reserved parameter names A small set of parameter names are **reserved** by Lightdash and resolve automatically from the query context — you don't need to declare them in `lightdash.config.yml` or in a model. | Reserved name | Resolves to | | :------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------- | | `date_zoom` | The currently selected [date zoom](/guides/date-zoom) granularity, lowercased (e.g. `day`, `week`, `month`). Empty string when no date zoom is selected. | If you define a user parameter with one of these names, your user parameter shadows the reserved one. See [Reserved parameters](/guides/developer/using-parameters#reserved-parameters) for usage details. ## Defaults configuration The `defaults` section allows you to set project-wide default settings that apply across all explores and dimensions. These defaults can be overridden at the explore or dimension level. ```yaml theme={null} defaults: case_sensitive: false column_totals: false additional_time_intervals: date: ['fiscal_quarter'] timestamp: ['HOUR'] granularity_labels: week: "Week starting Monday" ``` | Property | Required | Value | Description | | :-------------------------- | :------- | :----------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `case_sensitive` | No | boolean | Default case sensitivity for string filters across the project. When `false`, all string filters will be case insensitive by default. Defaults to `true`. | | `column_totals` | No | boolean | Default behavior for column totals in the explorer results table. When `false`, Lightdash skips the extra warehouse query that calculates column totals for new queries. Charts that explicitly enable "Show column totals" still calculate them. Defaults to `true`. | | `additional_time_intervals` | No | Object | Extra time intervals appended to the built-in defaults for `date` and `timestamp` dimensions that don't declare their own `time_intervals`. See [Additional time intervals](#additional-time-intervals) below. | | `granularity_labels` | No | Object (string → string) | Override the display label of standard granularities (e.g. `week`, `month`) project-wide. Applied to dimension labels in the Explorer, the Explorer sidebar tree, the date zoom dropdown, and chart axis labels. See [Granularity label overrides](#granularity-label-overrides) below. | ### Disabling column totals by default Every time you run a query in the explorer, Lightdash runs an additional warehouse query to calculate column totals for the results table footer. For cost-conscious users, setting `column_totals: false` skips this extra query by default, which can reduce warehouse spend on busy projects. ```yaml theme={null} defaults: column_totals: false ``` This is a default, not a kill switch — charts that explicitly enable "Show column totals" still calculate totals as expected. You can also toggle this default via the API: ```http theme={null} PUT /api/v2/projects/{projectUuid}/defaults { "column_totals": false } ``` ### Case sensitivity hierarchy The `case_sensitive` setting follows a hierarchy where more specific settings override broader ones: 1. **Dimension-level** (highest priority) - Set on individual dimensions 2. **Explore/table-level** - Set on the explore or table 3. **Project-level** - Set in `lightdash.config.yml` defaults 4. **Default behavior** - Case sensitive (`true`) if nothing is specified This allows you to set organization-wide defaults while maintaining the flexibility to override them for specific explores or dimensions as needed. **Example**: Set case insensitivity as the project default, but override for a specific table: ```yaml theme={null} # lightdash.config.yml defaults: case_sensitive: false # Project-wide default ``` ```yaml theme={null} # In your model yml file - override for a specific table models: - name: case_sensitive_table meta: case_sensitive: true # Override: this table uses case sensitive filters ``` See [Tables reference](/references/tables#case-sensitive) for explore-level configuration and [Dimensions reference](/references/dimensions#case-sensitive) for dimension-level configuration. ### Additional time intervals By default, Lightdash exposes a fixed set of time intervals on date and timestamp dimensions: * **Date dimensions:** `DAY`, `WEEK`, `MONTH`, `QUARTER`, `YEAR` * **Timestamp dimensions:** `RAW`, `DAY`, `WEEK`, `MONTH`, `QUARTER`, `YEAR` The `additional_time_intervals` setting lets you append extra intervals (standard granularities or [custom granularity](#custom-granularities-configuration) keys) to those built-in defaults project-wide, so you don't have to repeat `time_intervals` on every column. ```yaml theme={null} defaults: additional_time_intervals: date: - fiscal_quarter # custom_granularities key timestamp: - HOUR # standard granularity - fiscal_quarter # custom_granularities key ``` | Property | Required | Value | Description | | :---------- | :------- | :--------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------- | | `date` | No | Array of strings | Extra intervals appended to the date defaults. Values may be standard granularities or [custom granularity](#custom-granularities-configuration) keys. | | `timestamp` | No | Array of strings | Extra intervals appended to the timestamp defaults. Values may be standard granularities or custom granularity keys. | **How it works:** * **Additive only** — the built-in defaults are always included; values listed here are appended after them and de-duplicated. * **Fallback-only** — if a dimension declares its own `time_intervals` in its model `.yml`, the per-column list wins and `additional_time_intervals` is ignored for that dimension. * **Validation** — values are validated once at project compile time. Standard granularities are accepted case-insensitively. Sub-day grains (`RAW`, `MILLISECOND`, `SECOND`, `MINUTE`, `HOUR`) are not valid under `date` and are dropped with a warning. Unknown names that don't match a standard grain or a defined `custom_granularities` key are also dropped with a warning. **Example**: Add `HOUR` to every timestamp dimension and a `fiscal_quarter` custom granularity to both: ```yaml theme={null} # lightdash.config.yml custom_granularities: fiscal_quarter: label: "Fiscal Quarter" sql: "DATE_TRUNC('quarter', ${COLUMN} + INTERVAL '1 month')" type: date defaults: additional_time_intervals: date: ['fiscal_quarter'] timestamp: ['HOUR', 'fiscal_quarter'] ``` A column that overrides this default still works as before: ```yaml theme={null} # In your model yml file - this column ignores the project default columns: - name: created_at meta: dimension: type: timestamp time_intervals: ['DAY', 'WEEK'] # explicit list wins ``` See [Dimensions reference](/references/dimensions#time-intervals) for per-dimension configuration and the [Custom granularities](#custom-granularities-configuration) section below for defining custom granularity keys. ### Granularity label overrides The `granularity_labels` setting lets you replace how standard granularities are displayed across the project. This is useful when your business uses a non-default convention — for example, a week that starts on Monday — and you want the UI to reflect that everywhere a granularity is shown. ```yaml theme={null} defaults: granularity_labels: week: "Week starting Monday" month: "Calendar month" ``` | Property | Required | Value | Description | | :---------------------------- | :------- | :----- | :---------------------------------------------------------------------------------------------------------------------------------------------------------- | | `` (e.g. `week`) | No | string | The full replacement label used for this grain wherever the grain name is shown. The configured string is used verbatim, not appended to the built-in name. | Supported keys are the standard Lightdash `TimeFrames` values, written in lowercase or uppercase, for example `week`, `month`, or `hour`. Unknown keys are ignored with a warning at project compile time. **Where the override is applied:** * **Explorer dimension labels** — the configured string replaces the built-in grain segment of the auto-generated dimension label. For example, with `week: "Week starting Monday"`, the `Order date Week` dimension becomes `Order date Week starting Monday`. * **Explorer sidebar tree** — the same relabeling is shown in the dimension tree. * **Date zoom dropdown** — the configured string is used verbatim as the option label (e.g. `Week starting Monday` instead of `Week`). * **Chart axis labels** — axis labels that reflect the active grain pick up the override automatically. **How it works:** * **Full replacement** — the configured string replaces the grain label outright. Provide the complete label you want users to see (e.g. `"Week starting Monday"`), not just a suffix. * **Standard granularities only** — to relabel non-standard time periods (e.g. fiscal quarters), define a [custom granularity](#custom-granularities-configuration) instead. * **Project-wide** — applies to every date and timestamp dimension in the project; there is no per-dimension override. **Example**: Make every weekly grain advertise its week-start convention: ```yaml theme={null} # lightdash.config.yml defaults: granularity_labels: week: "Week starting Monday" ``` With this config, a `created_at` timestamp dimension exposes `Created at Week starting Monday` in the Explorer, sidebar tree, and chart axis labels, and `Week starting Monday` appears in the date zoom dropdown. ## Custom granularities configuration **Availability:** Custom granularities are a [Beta](/references/workspace/feature-maturity-levels) feature. The `custom_granularities` section allows you to define reusable custom time granularities that appear in the date zoom dropdown alongside standard options (Day, Week, Month, Quarter, Year). This is useful for business-specific time periods like fiscal quarters, Monday-to-Sunday weeks, or other custom date groupings. ```yaml theme={null} custom_granularities: fiscal_quarter: label: "Fiscal Quarter" sql: "DATE_TRUNC('quarter', ${COLUMN} + INTERVAL '1 month')" type: date week_monday: label: "Week (Mon-Sun)" sql: "DATE_TRUNC('week', ${COLUMN})" type: date fiscal_year: label: "Fiscal Year" sql: "EXTRACT(YEAR FROM ${COLUMN} + INTERVAL '1 month')" type: string ``` Each custom granularity is defined as a key-value pair where the key is the granularity name (must be alphanumeric with underscores) and the value is an object with the following properties: | Property | Required | Value | Description | | :------- | :------- | :------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `label` | Yes | string | A user-friendly label for the granularity as it will be displayed in the date zoom dropdown. | | `sql` | Yes | string | SQL expression that defines how to truncate/transform the date. Use `${COLUMN}` as a placeholder for the actual date column - it will be replaced with the column's SQL at runtime. | | `type` | No | `date`, `timestamp`, or `string` | The output type of the SQL expression. Use `date` for truncated dates, `timestamp` for truncated timestamps, or `string` for formatted text output (e.g., fiscal year labels). Defaults to `date` if not specified. | ### How custom granularities work Custom granularities are defined at the project level in `lightdash.config.yml` and become available on date dimensions through the `time_intervals` property. The `${COLUMN}` template in the SQL expression is automatically replaced with the actual column SQL when generating queries. **Example**: Define a fiscal quarter granularity and use it on a dimension: ```yaml theme={null} # lightdash.config.yml custom_granularities: fiscal_quarter: label: "Fiscal Quarter" sql: "DATE_TRUNC('quarter', ${COLUMN} + INTERVAL '1 month')" type: date ``` ```yaml theme={null} # In your model yml file columns: - name: order_date meta: dimension: type: date time_intervals: ['DAY', 'WEEK', 'MONTH', 'fiscal_quarter', 'YEAR'] ``` The custom granularity `fiscal_quarter` will now appear in the date zoom dropdown for `order_date`, alongside the standard intervals. Custom granularities inherit `requiredAttributes` and `anyAttributes` from the parent dimension, so access controls are automatically applied. See the [Date zoom guide](/guides/date-zoom) for information on configuring which granularities appear in the dropdown and setting defaults. ### Use cases * **Fiscal calendars**: Define fiscal quarters or years that don't align with calendar quarters * **Week start customization**: Create weeks that start on Monday or any other day * **Custom periods**: Define business-specific time periods like "retail weeks" or "academic terms" See [Dimensions reference](/references/dimensions#time-intervals) for more information on configuring time intervals on dimensions, including how to reference custom granularities. ## Table groups configuration The `table_groups` section defines display labels and descriptions for the group keys referenced by your models in their `meta.groups` array. These groups are used to render nested table groups in the Explore sidebar (up to 3 levels of nesting). ```yaml theme={null} table_groups: mobile: label: 'Mobile App' description: 'Tables related to the mobile app' engagement: label: 'Engagement' finance: label: 'Finance' description: 'Revenue, billing, and accounting tables' ``` Each entry in `table_groups` is keyed by the group identifier you reference from a model's `meta.groups`, and supports the following properties: | Property | Required | Value | Description | | :------------ | :------- | :----- | :------------------------------------------------------- | | `label` | Yes | string | Display label shown in the sidebar for this table group. | | `description` | No | string | Optional description of this table group. | Group keys must match the pattern `^[a-zA-Z0-9_-]+$`. If a key referenced from a model's `meta.groups` is not defined in `table_groups`, the key itself is used as the label. When you run `lightdash deploy` or `lightdash preview`, the CLI only syncs table groups if the `table_groups` key is present in your config. To clear all previously deployed table groups, set `table_groups: {}` explicitly — omitting the key leaves the server-side groups unchanged. To assign a table to a group, use the `groups` property on the model's `meta`: ```yaml theme={null} models: - name: users meta: groups: ['mobile', 'engagement'] ``` See [Tables reference](/references/tables#groups) for more information on grouping tables in the sidebar. # Metrics reference Source: https://docs.lightdash.com/references/metrics A metric is a value that describes or summarizes features from a collection of data points. For example: count of total number of user IDs, or sum of revenue. In Lightdash, metrics are used to summarize dimensions or, sometimes, other metrics. ## Adding metrics to your project using the `meta` tag. ### 1. Using the column `meta` tag To add a metric to Lightdash using the `meta` tag, you define it in your dbt project under the dimension name you're trying to describe/summarize. ```yaml theme={null} models: - name: orders_model columns: - name: user_id # dimension your metric is aggregating meta: metrics: distinct_user_ids: # name of your metric type: count_distinct # metric type - name: revenue # dimension your metric is aggregating meta: metrics: sum_revenue: # name of your metric type: sum # metric type ``` ```yaml theme={null} models: - name: orders_model columns: - name: user_id # dimension your metric is aggregating config: meta: metrics: distinct_user_ids: # name of your metric type: count_distinct # metric type - name: revenue # dimension your metric is aggregating config: meta: metrics: sum_revenue: # name of your metric type: sum # metric type ``` ```yaml theme={null} type: model name: orders_model dimensions: - name: user_id # dimension your metric is aggregating - name: revenue # dimension your metric is aggregating metrics: distinct_user_ids: # name of your metric type: count_distinct # metric type sql: ${TABLE}.user_id sum_revenue: # name of your metric type: sum # metric type sql: ${TABLE}.revenue ``` Once you've got the hang of what these metrics look like, read more about the [metric types you can use below.](#metric-types) ### 2. Using the model `meta` tag Sometimes a metric references multiple columns, in these cases you can define the metric at the model level: ```yaml theme={null} models: - name: orders_model meta: metrics: revenue_per_user: type: number sql: ${sum_revenue} / ${distinct_user_ids} sum_total_paid: type: sum sql: ${revenue} + ${taxes_paid} ``` ```yaml theme={null} models: - name: orders_model config: meta: metrics: revenue_per_user: type: number sql: ${sum_revenue} / ${distinct_user_ids} sum_total_paid: type: sum sql: ${revenue} + ${taxes_paid} ``` ```yaml theme={null} type: model name: orders_model metrics: revenue_per_user: type: number sql: ${sum_revenue} / ${distinct_user_ids} sum_total_paid: type: sum sql: ${revenue} + ${taxes_paid} ``` **Non-aggregate metrics** (`number`, `boolean`, etc.) can only reference other metrics in `sql:` since they are inserted directly into the generated SQL query without being wrapped in an aggregate function. **Aggregate metrics** (`sum`, `count_distinct`, etc.) can only reference dimensions since they are wrapped in an aggregate function before being added to the generated SQL query. Wrapping an aggregate function in another aggregate function will cause an error. **Post calculation metrics** (`percent_of_previous`, `percent_of_total`, `running_total`) are computed after other metrics. They can reference aggregate and non-aggregate metrics only (they cannot reference dimensions or other post calculation metrics). Read on to learn more about aggregate vs non-aggregate metrics! ## Metric Categories Each metric type falls into one of these categories. The metric categories tell you whether the metric type is an aggregation and what type of fields the metric can reference: ### Aggregate metrics Aggregate metric types perform (surprise, surprise) aggregations. Sums and averages are examples of aggregate metrics: they are measurements summarizing a collection of data points. Aggregate metrics can *only* reference dimensions, not other metrics. ### Non-aggregate metrics Non-aggregate metrics are metric types that, you guessed it, do *not* perform aggregations. Numbers and booleans are examples of non-aggregate metrics. These metric types perform a calculation on a single data point, so they can only reference aggregate metrics. They *cannot* reference dimensions. ### Post calculation metrics Post calculation metrics are computed after aggregate and non-aggregate metrics in the query. Because they run after the main aggregations, they can use window functions. Post calculation metrics: * Can only reference aggregate and non-aggregate metrics (they cannot reference dimensions or other post calculation metrics) * Can be referenced in table calculations like any other metric * Do not support the `filters` YML property **Experimental:** Post calculation metrics are currently in the Experimental phase. Learn what this means in our Feature Maturity Levels guide: [Feature Maturity Levels](/references/workspace/feature-maturity-levels). ## Metric configuration You can customize your metrics in your dbt model's YAML file. Here's an example of the properties used in defining a metric: ```yaml theme={null} models: - name: sales_stats meta: joins: - join: web_sessions sql_on: ${web_sessions.date} = ${sales_stats.date} group_details: product_details: label: Product Details description: 'Fields that have information about the products in the basket.' item_details: label: Item Details description: 'Fields that have information about the items in the basket.' columns: - name: revenue description: 'Total estimated revenue in GBP based on forecasting done by the finance team.' meta: metrics: total_revenue: label: 'Total revenue GBP' type: SUM description: 'Total revenue in GBP' sql: 'IF(${revenue} IS NULL, 10, ${revenue})' groups: ['product_details', 'item_details'] # this would add the metric to a nested group: `product details` --> `item details` hidden: false format: '[$£]#,##0.00' # GBP rounded to two decimal points show_underlying_values: - revenue - forecast_date - web_sessions.session_id # field from joined table filters: - is_adjusted: true ``` ```yaml theme={null} models: - name: sales_stats config: meta: joins: - join: web_sessions sql_on: ${web_sessions.date} = ${sales_stats.date} group_details: product_details: label: Product Details description: 'Fields that have information about the products in the basket.' item_details: label: Item Details description: 'Fields that have information about the items in the basket.' columns: - name: revenue description: 'Total estimated revenue in GBP based on forecasting done by the finance team.' config: meta: metrics: total_revenue: label: 'Total revenue GBP' type: SUM description: 'Total revenue in GBP' sql: 'IF(${revenue} IS NULL, 10, ${revenue})' groups: ['product_details', 'item_details'] # this would add the metric to a nested group: `product details` --> `item details` hidden: false format: '[$£]#,##0.00' # GBP rounded to two decimal points show_underlying_values: - revenue - forecast_date - web_sessions.session_id # field from joined table filters: - is_adjusted: true ``` ```yaml theme={null} type: model name: sales_stats joins: - join: web_sessions sql_on: ${web_sessions.date} = ${sales_stats.date} group_details: product_details: label: Product Details description: 'Fields that have information about the products in the basket.' item_details: label: Item Details description: 'Fields that have information about the items in the basket.' dimensions: - name: revenue description: 'Total estimated revenue in GBP based on forecasting done by the finance team.' metrics: total_revenue: label: 'Total revenue GBP' type: SUM description: 'Total revenue in GBP' sql: 'IF(${revenue} IS NULL, 10, ${revenue})' groups: ['product_details', 'item_details'] # this would add the metric to a nested group: `product details` --> `item details` hidden: false format: '[$£]#,##0.00' # GBP rounded to two decimal points show_underlying_values: - revenue - forecast_date - web_sessions.session_id # field from joined table filters: - is_adjusted: true ``` Here are all of the properties you can customize: | Property | Required | Value | Description | | :-------------------------------------------------- | :------: | :----------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | label | No | string | Custom label. This is what you'll see in Lightdash instead of the metric name. | | [type](#metric-types) | Yes | metric type | Metrics must be one of the supported types. | | [description](#description) | No | string | Description of the metric that appears in Lightdash. A default description is created by Lightdash if this isn't included | | [sql](#custom-sql-in-aggregate-metrics) | No | string | Custom SQL used to define the metric. | | hidden | No | boolean | If set to true, the metric is hidden from Lightdash. By default, this is set to false if you don't include this property. | | [compact](#compact) | No | string | This option will compact the number value (e.g. 1,500 to 1.50K). Currently supports one of the following: \['thousands', 'millions', 'billions', 'trillions', 'kilobytes', 'megabytes', 'gigabytes', 'terabytes', 'petabytes', 'kibibytes', 'mebibytes', 'gibibytes', 'tebibytes', 'pebibytes'] | | [format](#format) | No | string | This option will format the output value on the results table and CSV export. Supports spreadsheet-style formatting (e.g. #,##0.00). Use [this website](https://customformats.com) to help build your custom format. | | [separator](#separator) | No | string | This option controls the grouping and decimal characters used when rendering numbers (e.g. `1.234.567,50` for European locales). One of: `default`, `commaPeriod`, `spacePeriod`, `periodComma`, `noSeparatorPeriod`, `apostrophePeriod`. | | [groups](#groups) | No | string or string\[] | If you set this property, the metric will be grouped in the sidebar with other metrics with the same group label. | | [urls](/references/dimensions#urls) | No | array | Adding urls to a metric allows your users to click metric values in the UI and take actions, like opening an external tool with a url, or open at a website. You can use liquid templates to customise the link based on the value of the dimension. | | [richText](#rich-text) | No | string | Rich text template for displaying formatted content in table cells. Supports Markdown, HTML, and LiquidJS templating. | | [show\_underlying\_values](#show-underlying-values) | No | Array of dimension names | You can limit which dimensions or metrics are shown for a field when a user clicks View underlying data. The list must only include dimension/metric names from the base model or from any joined models. If not defined, we show all model dimensions. | | [filters](#filters) | No | array | You can add filter logic to limit the values included in the metric calculation. You can add many filters. See which filter types are supported [here](#filters). | | [tags](#tags) | No | string\[] | An array of string tags for categorizing and filtering metrics programmatically. Tags can be used by AI agents, API filters, and other backend workflows. See [tags](#tags). | ## Metric types | Type | Category | Description | | :-------------------------------------------- | :------------------------------ | :------------------------------------------------------------------------------ | | [percentile](#percentile) | Aggregate | Generates a percentile of values within a column | | [median](#median) | Aggregate | Generates the 50th percentile of values within a column | | [average](#average) | Aggregate | Generates an average (mean) of values within a column | | [boolean](#boolean) | Non-aggregate | For fields that will show if something is true or false | | [count](#count) | Aggregate | Counts the total number of values in the dimension | | [count\_distinct](#count%5Fdistinct) | Aggregate | Counts the total unique number of values in the dimension | | [date](#date) | Non-aggregate | For adding calculations to metrics that return dates. | | [max](#max) | Aggregate | Generates the maximum value within a numeric column | | [min](#min) | Aggregate | Generates the minimum value within a numeric column | | [number](#number) | Non-aggregate | For adding calculations to metrics that return numbers. | | [string](#string) | Non-aggregate | For metrics that contain letters or special characters | | [sum](#sum) | Aggregate | Generates a sum of values within a column | | [sum\_distinct](#sum_distinct) | Aggregate (Beta) | Generates a sum of values, deduplicating by specified keys | | [average\_distinct](#average_distinct) | Aggregate (Beta) | Generates an average of values, deduplicating by specified keys | | [percent\_of\_previous](#percent_of_previous) | Post calculation (Experimental) | Current value as a percentage of the previous row's value | | [percent\_of\_total](#percent_of_total) | Post calculation (Experimental) | Current value as a percentage of the total across the result set (or partition) | | [running\_total](#running_total) | Post calculation (Experimental) | Cumulative total | ### percentile Takes the percentile of the values in the given field. Like SQL's `PERCENTILE_CONT` function. The `percentile` metric can be used on any numeric dimension or, [for custom SQL](#using-custom-sql-in-aggregate-metrics), any valid SQL expression that gives a numeric table column. For example, this creates a metric `median_price` by taking the 50% percentile of the `item_price` dimension: ```yaml theme={null} columns: - name: item_price meta: metrics: median_price: type: percentile percentile: 50 ``` ```yaml theme={null} columns: - name: item_price config: meta: metrics: median_price: type: percentile percentile: 50 ``` ```yaml theme={null} type: model name: my_model dimensions: - name: item_price metrics: median_price: type: percentile percentile: 50 sql: ${TABLE}.item_price ``` ### median Takes the 50th percentile of the values in the given field. Like SQL's `PERCENTILE_CONT(0.5)` function. The `median` metric can be used on any numeric dimension or, [for custom SQL](#using-custom-SQL-in-aggregate-metrics), any valid SQL expression that gives a numeric table column. For example, this creates a metric `median_price` by taking the 50% percentile of the `item_price` dimension: ```yaml theme={null} columns: - name: item_price meta: metrics: median_price: type: median ``` ```yaml theme={null} columns: - name: item_price config: meta: metrics: median_price: type: median ``` ```yaml theme={null} type: model name: my_model dimensions: - name: item_price metrics: median_price: type: median sql: ${TABLE}.item_price ``` ### average Takes the average (mean) of the values in the given field. Like SQL's `AVG` function. The `average` metric can be used on any numeric dimension or, [for custom SQL](#using-custom-SQL-in-aggregate-metrics), any valid SQL expression that gives a numeric table column. For example, this creates a metric `avg_price` by taking the average of the `item_price` dimension: ```yaml theme={null} columns: - name: item_price meta: metrics: avg_price: type: average ``` ```yaml theme={null} columns: - name: item_price config: meta: metrics: avg_price: type: average ``` ```yaml theme={null} type: model name: my_model dimensions: - name: item_price metrics: avg_price: type: average sql: ${TABLE}.item_price ``` ### boolean Tells you whether something is True or False. The `boolean` metric can be used on any valid SQL expression that gives you a `TRUE` or `FALSE` value. It can only be used on aggregations, which means either aggregate metrics *or* [custom SQL that references other metrics](#using-custom-sql-in-non-aggregate-metrics). You cannot build a `boolean` metric by referencing other unaggregated dimensions from your model. `boolean` metrics don't do any aggregations; they just reference other aggregations. For example, the `avg_price` metric below is an average of all of the `item_price` values in our product table. A second metric called `is_avg_price_above_20` is a `boolean` type metric. The `is_avg_price_above_20` metric has a custom SQL expression that tells us whether the `avg_price` value is greater than 20. ```yaml theme={null} columns: - name: item_price meta: metrics: avg_price: type: average is_avg_price_above_20: type: boolean sql: 'IF(${avg_price} > 20, TRUE, FALSE)' ``` ```yaml theme={null} columns: - name: item_price config: meta: metrics: avg_price: type: average is_avg_price_above_20: type: boolean sql: 'IF(${avg_price} > 20, TRUE, FALSE)' ``` ```yaml theme={null} type: model name: my_model dimensions: - name: item_price metrics: avg_price: type: average sql: ${TABLE}.item_price is_avg_price_above_20: type: boolean sql: 'IF(${avg_price} > 20, TRUE, FALSE)' ``` ### count Does a table count, like SQL’s `COUNT` function. The `count` metric can be used on any dimension or, [for custom SQL](#using-custom-SQL-in-aggregate-metrics), any valid SQL expression that gives a set of values. For example, this creates a metric `number_of_users` by counting the number of `user_id` values in the table: ```yaml theme={null} columns: - name: user_id meta: metrics: number_of_users: type: count ``` ```yaml theme={null} columns: - name: user_id config: meta: metrics: number_of_users: type: count ``` ```yaml theme={null} type: model name: my_model dimensions: - name: user_id metrics: number_of_users: type: count sql: ${TABLE}.user_id ``` ### count\_distinct Counts the number of distinct values in a given field. It's like SQL’s `COUNT DISTINCT` function. The `count_distinct` metric can be used on any dimension or, [for custom SQL](#using-custom-SQL-in-aggregate-metrics), any valid SQL expression that gives a set of values. For example, this creates a metric `number_of_unique_users` by counting the number of unique `user_id` values in the table: ```yaml theme={null} columns: - name: user_id meta: metrics: number_of_unique_users: type: count_distinct ``` ```yaml theme={null} columns: - name: user_id config: meta: metrics: number_of_unique_users: type: count_distinct ``` ```yaml theme={null} type: model name: my_model dimensions: - name: user_id metrics: number_of_unique_users: type: count_distinct sql: ${TABLE}.user_id ``` ### date Gives you a date value from an expression. The `date` metric can be used on any valid SQL expression that gives you a date value. It can only be used on aggregations, which means either aggregate metrics *or* [custom SQL that references other metrics](#using-custom-sql-in-non-aggregate-metrics). You cannot build a `date` metric by referencing other unaggregated dimensions from your model. **`Creating a max or min date metric with type: date`** If you want to create a metric of a maximum or minimum date, you can't use `type: max` or of `type: min` metrics because these are only compatible with numeric type fields. Instead, you can calculate a maximum or minimum date by defining a metric of `type: date` and using some custom sql, like this: ```yaml theme={null} columns: - name: created_at_date meta: dimension: type: date metrics: max_created_at_date: type: date sql: MAX(${TABLE}.created_at_date) ``` ```yaml theme={null} columns: - name: created_at_date config: meta: dimension: type: date metrics: max_created_at_date: type: date sql: MAX(${TABLE}.created_at_date) ``` ```yaml theme={null} type: model name: my_model dimensions: - name: created_at_date type: date metrics: max_created_at_date: type: date sql: MAX(${TABLE}.created_at_date) ``` ### max Max gives you the largest value in a given numeric field. It's like SQL’s `MAX` function. The `max` metric can be used on any numeric dimension or, [for custom SQL](#using-custom-SQL-in-aggregate-metrics), any valid SQL expression that gives a numeric value. Because `type: max` metrics only work with numerical fields, you can't use them to find a maximum date. Instead, you can use the `MAX()` function in the `sql` parameter of a metric of `type: date` to get a maximum date (you can see an [example of this in the date section](#date). For example, this creates a metric `max_delivery_cost` by looking at the `delivery_cost` dimension and taking the largest value it finds: ```yaml theme={null} columns: - name: delivery_cost meta: metrics: max_delivery_cost: type: max ``` ```yaml theme={null} columns: - name: delivery_cost config: meta: metrics: max_delivery_cost: type: max ``` ```yaml theme={null} type: model name: my_model dimensions: - name: delivery_cost metrics: max_delivery_cost: type: max sql: ${TABLE}.delivery_cost ``` ### min Min gives you the smallest value in a given numeric field. It's like SQL’s `MIN` function. The `min` metric can be used on any numeric dimension or, [for custom SQL](#using-custom-SQL-in-aggregate-metrics), any valid SQL expression that gives a numeric value. Because `type: min` metrics only work with numerical fields, you can't use them to find a minimum date. Instead, you can use the `MIN()` function in the `sql` parameter of a metric of `type: date` to get a minimum date (you can see an [example of this in the date section](#date). For example, this creates a metric `min_delivery_cost` by looking at the `delivery_cost` dimension and taking the smallest value it finds: ```yaml theme={null} columns: - name: delivery_cost meta: metrics: min_delivery_cost: type: min ``` ```yaml theme={null} columns: - name: delivery_cost config: meta: metrics: min_delivery_cost: type: min ``` ```yaml theme={null} type: model name: my_model dimensions: - name: delivery_cost metrics: min_delivery_cost: type: min sql: ${TABLE}.delivery_cost ``` ### number Used with numbers or integers. A `number` metric doesn't perform any aggregation but can be used to perform simple transformations on other metrics. The `number` metric can be used on any valid SQL expression that gives you a numeric or integer value. It can only be used on aggregations, which means either aggregate metrics *or* [custom SQL that references other metrics](#using-custom-sql-in-non-aggregate-metrics). You cannot build a `number` metric by referencing other unaggregated dimensions from your model. For example, this creates a metric called `total_gross_profit_margin_percentage` based on the `total_sale_price` and `total_gross_profit_margin` aggregate metrics: ```yaml theme={null} columns: - name: sale_price meta: metrics: total_sale_price: type: sum - name: gross_profit_margin meta: metrics: total_gross_profit_margin: type: sum total_gross_profit_margin_percentage: type: number sql: '(${total_gross_profit_margin}/ NULLIF(${total_sale_price},0))' ``` ```yaml theme={null} columns: - name: sale_price config: meta: metrics: total_sale_price: type: sum - name: gross_profit_margin config: meta: metrics: total_gross_profit_margin: type: sum total_gross_profit_margin_percentage: type: number sql: '(${total_gross_profit_margin}/ NULLIF(${total_sale_price},0))' ``` ```yaml theme={null} type: model name: my_model dimensions: - name: sale_price - name: gross_profit_margin metrics: total_sale_price: type: sum sql: ${TABLE}.sale_price total_gross_profit_margin: type: sum sql: ${TABLE}.gross_profit_margin total_gross_profit_margin_percentage: type: number sql: '(${total_gross_profit_margin}/ NULLIF(${total_sale_price},0))' ``` The example above also uses the NULLIF() SQL function to avoid division-by-zero errors. ### sum Adds up the values in a given field. Like SQL's `SUM` function. The `sum` metric can be used on any numeric dimension or, [for custom SQL](#using-custom-SQL-in-aggregate-metrics), any valid SQL expression that gives a numeric table column. For example, this creates a metric `total_revenue` by adding up the values in the `revenue` dimension: ```yaml theme={null} columns: - name: revenue meta: metrics: total_revenue: type: sum ``` ```yaml theme={null} columns: - name: revenue config: meta: metrics: total_revenue: type: sum ``` ```yaml theme={null} type: model name: my_model dimensions: - name: revenue metrics: total_revenue: type: sum sql: ${TABLE}.revenue ``` ### sum\_distinct **Beta:** `sum_distinct` is currently in Beta. Learn what this means in our Feature Maturity Levels guide: [Feature Maturity Levels](/references/workspace/feature-maturity-levels). Adds up the values in a given field while deduplicating data based on one or more specified distinct keys. This is useful when you have wide tables where values are repeated across rows and you need to sum unique values only. Lightdash already supports [SQL fanout protection](/references/joins#handling-fanouts) to remove duplicates when joining tables together. `sum_distinct` allows you to remove duplicates from wide tables where deduplication cannot be handled at the join level. The `sum_distinct` metric requires: * `sql`: The field to sum * `distinct_keys`: An array of one or more fields to deduplicate by The metric orders by the value being summed and takes the first occurrence for each unique combination of distinct keys. If there are different values for the same distinct key combination, the first one encountered will be used. **Example: Summing order shipping costs** Consider a model containing `order_id`, `order_item_id`, and `order_shipping_cost`: | order\_id | order\_item\_id | order\_shipping\_cost | | --------- | --------------- | --------------------- | | 1 🟦 | 1 | 10 | | 1 🟦 | 2 | 10 | | 2 🟩 | 3 | 20 | | 2 🟩 | 4 | 20 | | 2 🟩 | 5 | 20 | | 2 🟩 | 6 | 30 | To sum shipping costs for all orders, you need to deduplicate by `order_id`: * When `order_id` is the distinct key, the first `order_shipping_cost` in ascending order is taken for each order * Order 1 🟦 contributes **10** * Order 2 🟩 contributes **20** (the first value when ordered ascending) * The `order_shipping_cost` of **30** for order 2 is ignored * **Total: 30** If the value you are aggregating is truly distinct based on the distinct key (e.g., each order has only one shipping cost), this won't be a problem. However, if there are multiple different values for the same distinct key, only the first value in ascending order will be used. ```yaml theme={null} models: - name: order_line_items meta: metrics: total_shipping_cost: type: sum_distinct sql: ${order_shipping_cost} distinct_keys: [order_id] description: > Total shipping cost correctly deduped. Each order's shipping cost is summed once, regardless of how many line items the order has. format: usd round: 2 ``` ```yaml theme={null} models: - name: order_line_items config: meta: metrics: total_shipping_cost: type: sum_distinct sql: ${order_shipping_cost} distinct_keys: [order_id] description: > Total shipping cost correctly deduped. Each order's shipping cost is summed once, regardless of how many line items the order has. format: usd round: 2 ``` ```yaml theme={null} type: model name: order_line_items metrics: total_shipping_cost: type: sum_distinct sql: ${TABLE}.order_shipping_cost distinct_keys: [order_id] description: > Total shipping cost correctly deduped. Each order's shipping cost is summed once, regardless of how many line items the order has. format: usd round: 2 ``` **Using multiple distinct keys** When you need to deduplicate by a combination of fields, you can specify multiple distinct keys. A row is considered unique only when the entire combination of key values is unique. For example, warehouse processing fees are charged per warehouse per order. If there are two items from the same warehouse in the same order, the fee should not be counted twice: | order\_id | order\_item\_id | item\_warehouse\_location | warehouse\_processing\_fee\_per\_order | | --------- | --------------- | ------------------------- | -------------------------------------- | | 🟦 1 | 1 | US | 2.5 | | 🟦 1 | 2 | US | 2.5 | | 🟩 2 | 3 | US | 2.5 | | 🟩 2 | 4 | Canada | 3.0 | | 🟩 2 | 5 | Canada | 3.0 | | 🟩 2 | 6 | UK | 4.0 | With `distinct_keys: [order_id, item_warehouse_location]`: * Order 1 🟦: One unique warehouse (US) → 2.5 * Order 2 🟩: Three unique warehouses (US, Canada, UK) → 2.5 + 3.0 + 4.0 = 9.5 * **Total: 12.0** ```yaml theme={null} columns: - name: warehouse_processing_fee_per_order description: warehouse processing fee per order meta: dimension: type: number metrics: total_processing_fee: type: sum_distinct distinct_keys: [order_id, item_warehouse_location] description: > Processing fees are charged per warehouse per order. If there are two items from the same warehouse the fee should not be counted twice. ``` ```yaml theme={null} columns: - name: warehouse_processing_fee_per_order description: warehouse processing fee per order config: meta: dimension: type: number metrics: total_processing_fee: type: sum_distinct distinct_keys: [order_id, item_warehouse_location] description: > Processing fees are charged per warehouse per order. If there are two items from the same warehouse the fee should not be counted twice. ``` ```yaml theme={null} type: model name: order_line_items metrics: total_processing_fee: type: sum_distinct sql: ${TABLE}.warehouse_processing_fee_per_order distinct_keys: [order_id, item_warehouse_location] description: > Processing fees are charged per warehouse per order. If there are two items from the same warehouse the fee should not be counted twice. ``` **How selected dimensions interact with `distinct_keys`** Deduplication is always performed globally on the `distinct_keys` you defined on the metric, regardless of which dimensions you select in a query. * If a selected dimension is also a `distinct_key`, the metric is grouped by that dimension and you get one deduplicated value per group. * If a selected dimension is **not** one of the`distinct_keys`, it does not affect deduplication. The globally deduplicated value is repeated across every row that shares the same `distinct_keys` value. For example, with `distinct_keys: [order_id]`: * Selecting `order_id` returns one deduplicated shipping cost per order. * Selecting an unrelated dimension such as `item_warehouse_location` returns the same global deduplicated total alongside each item\_warehouse\_location row, because `item_warehouse_location` is independent of the `order_id` grain. If you want a per-group total that varies with an unrelated dimension, add that dimension to `distinct_keys` so it becomes part of the dedup grain. ### average\_distinct **Beta:** `average_distinct` is currently in Beta. Learn what this means in our Feature Maturity Levels guide: [Feature Maturity Levels](/references/workspace/feature-maturity-levels). Calculates the average of values in a given field while deduplicating data based on one or more specified distinct keys. This works the same way as [`sum_distinct`](#sum_distinct), but computes an average instead of a sum. Lightdash already supports [SQL fanout protection](/references/joins#handling-fanouts) to remove duplicates when joining tables together. `average_distinct` allows you to remove duplicates from wide tables where deduplication cannot be handled at the join level. The `average_distinct` metric requires: * `sql`: The field to average * `distinct_keys`: An array of one or more fields to deduplicate by The metric orders by the value being averaged and takes the first occurrence for each unique combination of distinct keys. If there are different values for the same distinct key combination, the first one encountered will be used. **Example: Averaging order shipping costs** Consider a model containing `order_id`, `order_item_id`, and `order_shipping_cost`: | order\_id | order\_item\_id | order\_shipping\_cost | | --------- | --------------- | --------------------- | | 1 🟦 | 1 | 10 | | 1 🟦 | 2 | 10 | | 2 🟩 | 3 | 20 | | 2 🟩 | 4 | 20 | | 2 🟩 | 5 | 20 | | 2 🟩 | 6 | 30 | To calculate the average shipping cost per order, you need to deduplicate by `order_id`: * When `order_id` is the distinct key, the first `order_shipping_cost` in ascending order is taken for each order * Order 1 🟦 contributes **10** * Order 2 🟩 contributes **20** (the first value when ordered ascending) * The `order_shipping_cost` of **30** for order 2 is ignored * **Average: (10 + 20) / 2 = 15** Without `average_distinct`, a naive `AVG` on this table would give `(10 + 10 + 20 + 20 + 20 + 30) / 6 = 18.33`, which is incorrect because duplicate rows inflate the result. If the value you are aggregating is truly distinct based on the distinct key (e.g., each order has only one shipping cost), this won't be a problem. However, if there are multiple different values for the same distinct key, only the first value in ascending order will be used. ```yaml theme={null} models: - name: order_line_items meta: metrics: avg_shipping_cost: type: average_distinct sql: ${order_shipping_cost} distinct_keys: [order_id] description: > Average shipping cost per order, correctly deduped. Each order's shipping cost is counted once, regardless of how many line items the order has. format: usd round: 2 ``` ```yaml theme={null} models: - name: order_line_items config: meta: metrics: avg_shipping_cost: type: average_distinct sql: ${order_shipping_cost} distinct_keys: [order_id] description: > Average shipping cost per order, correctly deduped. Each order's shipping cost is counted once, regardless of how many line items the order has. format: usd round: 2 ``` ```yaml theme={null} type: model name: order_line_items metrics: avg_shipping_cost: type: average_distinct sql: ${TABLE}.order_shipping_cost distinct_keys: [order_id] description: > Average shipping cost per order, correctly deduped. Each order's shipping cost is counted once, regardless of how many line items the order has. format: usd round: 2 ``` **Using multiple distinct keys** When you need to deduplicate by a combination of fields, you can specify multiple distinct keys. A row is considered unique only when the entire combination of key values is unique. For example, warehouse processing fees are charged per warehouse per order. To find the average processing fee per warehouse-order combination: | order\_id | order\_item\_id | item\_warehouse\_location | warehouse\_processing\_fee\_per\_order | | --------- | --------------- | ------------------------- | -------------------------------------- | | 🟦 1 | 1 | US | 2.5 | | 🟦 1 | 2 | US | 2.5 | | 🟩 2 | 3 | US | 2.5 | | 🟩 2 | 4 | Canada | 3.0 | | 🟩 2 | 5 | Canada | 3.0 | | 🟩 2 | 6 | UK | 4.0 | With `distinct_keys: [order_id, item_warehouse_location]`: * Order 1 🟦, US → 2.5 * Order 2 🟩, US → 2.5 * Order 2 🟩, Canada → 3.0 * Order 2 🟩, UK → 4.0 * **Average: (2.5 + 2.5 + 3.0 + 4.0) / 4 = 3.0** ```yaml theme={null} columns: - name: warehouse_processing_fee_per_order description: warehouse processing fee per order meta: dimension: type: number metrics: avg_processing_fee: type: average_distinct distinct_keys: [order_id, item_warehouse_location] description: > Average processing fee per warehouse-order combination. Deduplicates so each warehouse-order pair is counted once. ``` ```yaml theme={null} columns: - name: warehouse_processing_fee_per_order description: warehouse processing fee per order config: meta: dimension: type: number metrics: avg_processing_fee: type: average_distinct distinct_keys: [order_id, item_warehouse_location] description: > Average processing fee per warehouse-order combination. Deduplicates so each warehouse-order pair is counted once. ``` ```yaml theme={null} type: model name: order_line_items metrics: avg_processing_fee: type: average_distinct sql: ${TABLE}.warehouse_processing_fee_per_order distinct_keys: [order_id, item_warehouse_location] description: > Average processing fee per warehouse-order combination. Deduplicates so each warehouse-order pair is counted once. ``` `average_distinct` follows the same rules as `sum_distinct` for how selected dimensions interact with `distinct_keys`. See [How selected dimensions interact with `distinct_keys`](#sum_distinct) for details. ### string Used with fields that include letters or special characters. The `string` metric can be used on any valid SQL expression that gives you a string value. It can only be used on aggregations, which means either aggregate metrics *or* [custom SQL that references other metrics](#using-custom-sql-in-non-aggregate-metrics). You cannot build a `string` metric by referencing other unaggregated dimensions from your model. `string` metrics are rarely used because most SQL aggregate functions don't return strings. One common exception is MySQL’s `GROUP_CONCAT` function. For example, this creates a metric `product_name_group` by combining the unique values of a dimension called `product_name`: ```yaml theme={null} columns: - name: product_name meta: metrics: product_name_group: type: string sql: 'GROUP_CONCAT(${TABLE}.product_name)' ``` ```yaml theme={null} columns: - name: product_name config: meta: metrics: product_name_group: type: string sql: 'GROUP_CONCAT(${TABLE}.product_name)' ``` ```yaml theme={null} type: model name: my_model dimensions: - name: product_name metrics: product_name_group: type: string sql: 'GROUP_CONCAT(${TABLE}.product_name)' ``` ### percent\_of\_previous Returns the current value as a percentage of the previous row's value for a referenced metric. For example, to calculate the percent of the previous value of total revenue: ```yaml theme={null} models: - name: orders_model meta: metrics: total_revenue: type: sum revenue_percent_of_previous: type: percent_of_previous sql: ${total_revenue} format: '0.00%' ``` ```yaml theme={null} models: - name: orders_model config: meta: metrics: total_revenue: type: sum revenue_percent_of_previous: type: percent_of_previous sql: ${total_revenue} format: '0.00%' ``` ```yaml theme={null} type: model name: orders_model metrics: total_revenue: type: sum sql: ${TABLE}.revenue revenue_percent_of_previous: type: percent_of_previous sql: ${total_revenue} format: '0.00%' ``` Note: If the previous value is 0 or NULL, the result will be NULL to avoid division-by-zero. **This is a post calculation metric** which is computed after other metrics. It can only reference aggregate and non-aggregate metrics (and cannot reference dimensions or other post calculation metrics). ### percent\_of\_total Returns the current value as a percentage of the total across the result set (or partition) for a referenced metric. For example, to calculate each row's percent of total revenue: ```yaml theme={null} models: - name: orders_model meta: metrics: total_revenue: type: sum revenue_percent_of_total: type: percent_of_total sql: ${total_revenue} format: '0.00%' ``` ```yaml theme={null} models: - name: orders_model config: meta: metrics: total_revenue: type: sum revenue_percent_of_total: type: percent_of_total sql: ${total_revenue} format: '0.00%' ``` ```yaml theme={null} type: model name: orders_model metrics: total_revenue: type: sum sql: ${TABLE}.revenue revenue_percent_of_total: type: percent_of_total sql: ${total_revenue} format: '0.00%' ``` **This is a post calculation metric** which is computed after other metrics. It can only reference aggregate and non-aggregate metrics (and cannot reference dimensions or other post calculation metrics). ### running\_total Returns the cumulative total of a referenced metric according to the query's grouping and sort order. For example, to calculate a running total of revenue: ```yaml theme={null} models: - name: orders_model meta: metrics: total_revenue: type: sum running_total_revenue: type: running_total sql: ${total_revenue} ``` ```yaml theme={null} models: - name: orders_model config: meta: metrics: total_revenue: type: sum running_total_revenue: type: running_total sql: ${total_revenue} ``` ```yaml theme={null} type: model name: orders_model metrics: total_revenue: type: sum sql: ${TABLE}.revenue running_total_revenue: type: running_total sql: ${total_revenue} ``` **This is a post calculation metric** which is computed after other metrics. It can only reference aggregate and non-aggregate metrics (and cannot reference dimensions or other post calculation metrics). ## Description We add default descriptions to all of the metrics you include in your model. But, you can override these using the description parameter when you define your metric. ```yaml theme={null} metrics: num_user_ids: type: count description: 'Total number of user IDs. NOTE: this is NOT counting unique user IDs' ``` ## Format You can use the `format` parameter to have your metrics show in a particular format in Lightdash. Lightdash supports spreadsheet-style format expressions for all metric types. To help you build your format expression, we recommend using [https://customformats.com/](https://customformats.com/). ```yaml theme={null} metrics: total_us_revenue: type: sum description: 'Total revenue in USD, with two decimal places, compacted to thousands' format: '$#,##0.00," K"' # 505,430 will appear as '$505.43 K' percent_of_total_global_revenue: type: number description: 'Percent of total global revenue coming from US revenue.' sql: ${total_us_revenue} / ${total_global_revenue} format: '0.00%' # 0.67895243 will appear as '67.89% ``` ### Example format expressions | Description | Format Expression | Raw Value | Formatted Output | | :--------------------------------------------- | :-------------------- | :------------------- | :-------------------- | | **Adds "km" suffix to the value** | `#,##0.00" km"` | 100000.00 | 100,000.00 km | | | | 15000.25 | 15,000.25 km | | | | 500 | 500.00 km | | **Format date with 12-hour clock** | `m/d/yyyy h:mm AM/PM` | 2023-09-05T15:45:00Z | 9/5/2023 3:45 PM | | | | 2024-01-20T08:30:00Z | 1/20/2024 8:30 AM | | **Display the full name of the day** | `dddd` | 2023-09-05T15:45:00Z | Tuesday | | | | 2024-01-20T08:30:00Z | Saturday | | **Format positive, negative, and zero values** | `"⬆️ "0;"⬇️ "0;0` | -500 | ⬇️ 500 | | | | 200 | ⬆️ 200 | | | | 0 | 0 | | **Text formatting** | `"Delivered in "@` | 2 weeks | Delivered in 2 weeks | | | | 18 hours | Delivered in 18 hours | | **Percentage formatting** | `#,##0.00%` | 0.6758 | 67.58% | | | | 0.1 | 10.00% | | | | 0.002 | 0.20% | | **No formatting** | `0` | 12345232 | 12345232 | | | | 56.7856 | 57 | | **Currency formatting (USD)** | `[$]#,##0.00` | 15430.75436 | \$15,430.75 | | | | 1234.50 | \$1,234.50 | | **Currency formatting (GBP)** | `[$£]#,##0.00` | 15430.75436 | £15,430.75 | | | | 1234.50 | £1,234.50 | | **Compact currency in thousands** | `[$]#,##0,"K"` | 15430.75436 | \$15K | | | | 15430.75436 | \$15.43K | | **Compact currency in millions** | `[$$]#,##0.00,,"M"` | 13334567 | \$13.33M | | | | 120000000 | \$120.00M | Spreadsheet-style format expressions are the recommended way of adding formatting to your metrics in Lightdash. There are legacy formatting options, listed below, which are less flexible than the spreadsheet-style formatting. If you use both legacy and spreadsheet-style formatting options for a single metric, Lightdash will ignore the legacy `format` and `round` options and only apply the spreadsheet-style formatting expression. #### Format (legacy) ```yaml theme={null} models: - name: sales_stats columns: - name: revenue description: 'Total estimated revenue in GBP based on forecasting done by the finance team.' meta: metrics: total_revenue: label: 'Total revenue GBP' type: SUM format: 'gbp' ``` These are the options: | Option | Equivalent format expression | Description | Raw value | Displayed value | | :------ | :--------------------------- | :---------------------------------------------------------------------------------- | :-------- | :-------------- | | km | `'#,##0.00" km"'` | Adds the suffix `km` to your value | 10 | 10 km | | mi | `'#,##0.00" mi"'` | Adds the suffix `mile` to your value | 10 | 10 mi | | usd | `'[\$]#,##0.00'` | Adds the `$` symbol to your number value | 10 | \$10.00 | | gbp | `'[\$£]#,##0.00'` | Adds the `£` symbol to your number value | 10 | £10.00 | | eur | `'[\$€]#,##0.00'` | Adds the `€` symbol to your number value | 10 | €10.00 | | jpy | `'[\$¥]#,##0.00'` | Adds the `¥` symbol to your number value | 10 | ¥10 | | percent | `'#,##0.00%'` | Adds the `%` symbol and multiplies your value by 100 | 0.1 | %10 | | id | `'0'` | Removes commas and spaces from number or string types so that they appear like IDs. | 12389572 | 12389572 | #### Round (legacy) You can round values to appear with a certain number of decimal points. ```yaml theme={null} models: - name: sales columns: - name: revenue meta: metrics: total_revenue: type: sum round: 0 # equivalent format expression: '#,##0.0' ``` ## Compact You can compact values in your YAML. For example, if I wanted all of my revenue values to be shown in thousands (e.g. `1,500` appears as `1.50K`), then I would write something like this in my .yml: ```yaml theme={null} models: - name: sales columns: - name: revenue meta: dimension: compact: thousands # You can also use 'K' ``` | Value | Alias | Equivalent format expression | Example output | | :-------- | :------------------- | :---------------------------------------- | :------------- | | thousands | "K" and "thousand" | `'#,##0," K"'` or `'#,##0.00," K"'` | 1K | | millions | "M" and "million" | `'#,##0,," M"'` or `'#,##0.00,," M"'` | 1M | | billions | "B" and "billion" | `'#,##0,,," B"'` or `'#,##0.00,,," B"'` | 1B | | trillions | "T" and "trillion" | `'#,##0,,,," T"'` or `'#,##0.00,,,," T"'` | 1T | | kilobytes | "KB" and "kilobyte" | | 1KB | | megabytes | "MB" and "megabyte" | | 1MB | | gigabytes | "GB" and "gigabyte" | | 1GB | | terabytes | "TB" and "terabyte" | | 1TB | | petabytes | "PB" and "petabyte" | | 1PB | | kibibytes | "KiB" and "kibibyte" | | 1KiB | | mebibytes | "MiB" and "mebibyte" | | 1MiB | | gibibytes | "GiB" and "gibibyte" | | 1GiB | | tebibytes | "TiB" and "tebibyte" | | 1TiB | | pebibytes | "PiB" and "pebibyte" | | 1PiB | ## Separator You can use the `separator` property to control the grouping and decimal characters used when rendering numbers, so values display correctly for non-US locales (e.g. `1.234.567,50` in Europe or `1'234'567.50` in Switzerland). `separator` only changes the separator characters. It composes with `format` (including spreadsheet-style `format` expressions), `compact`, `round`, and `currency`, which still control the overall shape of the number. ```yaml theme={null} models: - name: sales columns: - name: revenue meta: metrics: total_revenue: type: sum format: '[$€]#,##0.00' separator: periodComma # 1.234.567,50 € ``` These are the supported values: | Value | Example output | Description | | :------------------ | :------------- | :------------------------------------------------------------------------------------------ | | `default` | `1,234,567.50` | Uses the Lightdash default (comma thousands, period decimal). Same as omitting `separator`. | | `commaPeriod` | `1,234,567.50` | Comma thousands separator, period decimal separator. | | `spacePeriod` | `1 234 567.50` | Space thousands separator, period decimal separator. | | `periodComma` | `1.234.567,50` | Period thousands separator, comma decimal separator. | | `noSeparatorPeriod` | `1234567.50` | No thousands separator, period decimal separator. | | `apostrophePeriod` | `1'234'567.50` | Apostrophe thousands separator, period decimal separator (Swiss). | ## Custom SQL in aggregate metrics You can include custom SQL in your metric definition to build more advanced metrics using the sql parameter. Inside the sql parameter, you can reference any other dimension from the given model and any joined models. You **can’t reference other metrics.** You can reference dimensions from the same model like this: `sql: "${dimension_in_this_model}"` Or from joined models like this: `sql: "${other_model.dimension_in_other_model}"` ```yaml theme={null} metrics: num_unique_7d_web_active_user_ids: type: count_distinct # metric type sql: 'IF(${is_7d_web_active}, ${user_id}, NULL)' num_unique_paid_user_ids: type: count_distinct sql: 'IF(${subscriptions.is_active}, ${user_id}, NULL)' ``` ### Referencing time intervals in custom SQL You can reference specific time intervals of dimensions in custom SQL for aggregate metrics. When a dimension has time intervals defined, you can reference the specific interval by appending the interval name to the dimension name. ```yaml theme={null} max_month: type: max sql: ${session_start_month} ``` In this example, the metric references `${session_start_month}`, which is the `MONTH` time interval of the `session_start` dimension. This allows you to perform aggregations on specific time interval versions of your dimensions. ## Using custom SQL in non-aggregate metrics In non-aggregate metrics, you can reference any other metric from the given model and any joined models. You **can’t reference other dimensions.** You can reference metrics from the same model like this: `sql: "${metric_in_this_model}"`Or from joined models like this: `sql: "${other_model.metric_in_other_model}"` ```yaml theme={null} metrics: num_unique_users: type: count_distinct is_num_unique_users_above_100: type: boolean sql: 'IF(${num_unique_users} > 100, TRUE, FALSE)' percentage_user_growth_daily: type: number sql: '(${num_unique_users} - ${growth_model.num_unique_users_lag_1d}) / NULLIF(${growth_model.num_unique_users_lag_1d}, 0)' ``` ## Show underlying values By default, we show all of the dimensions from the Table when you click `View underlying data`. If you have fields from a joined table included in your results table, then we'll also show you all of the fields from the joined Table. You can limit which dimensions are shown, as well as add metrics to be included, for a field when a user clicks `View underlying data` by adding the list of dimensions and/or metrics to your `.yml` files. When `show_underlying_values` is not explicitly defined for a metric, `View underlying data` is capped at the first 50 dimensions from the Table (including joined tables). To show more than 50 dimensions, or to control exactly which fields appear, specify the fields explicitly in `show_underlying_values` (or [`default_show_underlying_values`](#default-show-underlying-values) at the model level) in your `.yml`. Hidden dimensions (with `hidden: true`) cannot be included in drilldowns. If you need a dimension to appear in drilldowns but not in the Explore sidebar, consider using [groups](/references/dimensions#groups) to organize dimensions instead. ```yaml theme={null} models: - name: sales_stats meta: joins: - join: web_sessions sql_on: ${web_sessions.date} = ${sales_stats.date} columns: - name: user_id description: 'Unique ID for users.' meta: dimension: type: string metrics: count_users: type: count_distinct show_underlying_values: - revenue_gbp_total_est - actual_date - web_sessions.session_id # field from joined table ``` ### Default show underlying values You can set a default `show_underlying_values` configuration at the model level using `default_show_underlying_values`. This applies to all metrics in that model, and individual metrics can override it by specifying their own `show_underlying_values`. See [default\_show\_underlying\_values in the Tables reference](/references/tables#default-show-underlying-values) for full details and examples. The list of fields must be made of dimension names (or metrics if you'd like to include them) from the base table or from any joined tables. To reference a field from a joined table, you just need to prefix the field name with the joined table name, like this: `my_joined_table_name.my_dimension`. The order that the fields are listed in `show_underlying_values` is the order that they'll appear in on the `view underlying data` table. ### Referencing time intervals in show underlying values You can reference specific time intervals of dimensions in the `show_underlying_values` list. When a dimension has time intervals defined, you can reference the specific interval by appending the interval name to the dimension name (e.g., `session_start_month`, `session_end_quarter`). ```yaml theme={null} count: type: count show_underlying_values: - session_start_month - session_end_quarter ``` In this example, `session_start_month` and `session_end_quarter` reference the `MONTH` and `QUARTER` time intervals of the `session_start` and `session_end` dimensions respectively. ## Groups You can group your dimensions and metrics in the sidebar using the `groups` parameter. To do this, you need to set up `group_details` in the model's configuration. Then, you can use these groups to organize metrics and dimensions. You can create nested groups up to 2 levels. ```yaml theme={null} models: - name: baskets meta: group_details: product_details: label: Product Details description: 'Fields that have information about the products in the basket.' item_details: label: Item Details description: 'Fields that have information about the items in the basket.' columns: - name: basket_item_id description: 'ID for the product item within the basket.' meta: dimension: groups: ['product_details', 'item_details'] # this would add the dimension to a nested group: `product details` --> `item details` metrics: count_total_basket_items: type: count_distinct groups: ['product_details', 'item_details'] # this would add the metric to a nested group: `product details` --> `item details` - name: product_name description: 'Full name of the product.' meta: dimension: label: 'Product name' groups: ['product_details'] # this would add the dimension under the group label: `product_details` metrics: count_total_product_types: type: count_distinct groups: ['product_details'] # this would add the metric under the group label: `product_details` ``` ```yaml theme={null} models: - name: baskets config: meta: group_details: product_details: label: Product Details description: 'Fields that have information about the products in the basket.' item_details: label: Item Details description: 'Fields that have information about the items in the basket.' columns: - name: basket_item_id description: 'ID for the product item within the basket.' config: meta: dimension: groups: ['product_details', 'item_details'] # this would add the dimension to a nested group: `product details` --> `item details` metrics: count_total_basket_items: type: count_distinct groups: ['product_details', 'item_details'] # this would add the metric to a nested group: `product details` --> `item details` - name: product_name description: 'Full name of the product.' config: meta: dimension: label: 'Product name' groups: ['product_details'] # this would add the dimension under the group label: `product_details` metrics: count_total_product_types: type: count_distinct groups: ['product_details'] # this would add the metric under the group label: `product_details` ``` ```yaml theme={null} type: model name: baskets group_details: product_details: label: Product Details description: 'Fields that have information about the products in the basket.' item_details: label: Item Details description: 'Fields that have information about the items in the basket.' dimensions: - name: basket_item_id description: 'ID for the product item within the basket.' groups: ['product_details', 'item_details'] # this would add the dimension to a nested group: `product details` --> `item details` - name: product_name description: 'Full name of the product.' label: 'Product name' groups: ['product_details'] # this would add the dimension under the group label: `product_details` metrics: count_total_basket_items: type: count_distinct sql: ${TABLE}.basket_item_id groups: ['product_details', 'item_details'] # this would add the metric to a nested group: `product details` --> `item details` count_total_product_types: type: count_distinct sql: ${TABLE}.product_name groups: ['product_details'] # this would add the metric under the group label: `product_details` ``` ## Rich text The `richText` property allows you to define custom HTML/Markdown templates for displaying metric values in table cells. This enables sophisticated data presentation with formatting, styling, conditional logic, and external integrations. Rich text only affects UI display in table cells. It has no impact on value formatting, CSV exports, or the underlying data values. ### Conditional formatting example Use Liquid control flow tags for conditional display based on metric values: ```yaml theme={null} columns: - name: customer_lifetime_value meta: metrics: average_clv: type: average richText: | {% raw %}{% if value.raw >= 100 %} ### 📈 ${ value.formatted } **Excellent** Average CLV {% elsif value.raw >= 50 %} ### 📊 ${ value.formatted } **Good** Average CLV {% else %} ### ⚠️ ${ value.formatted } **Low** Average CLV {% endif %}{% endraw %} ``` ```yaml theme={null} columns: - name: customer_lifetime_value config: meta: metrics: average_clv: type: average richText: | {% raw %}{% if value.raw >= 100 %} ### 📈 ${ value.formatted } **Excellent** Average CLV {% elsif value.raw >= 50 %} ### 📊 ${ value.formatted } **Good** Average CLV {% else %} ### ⚠️ ${ value.formatted } **Low** Average CLV {% endif %}{% endraw %} ``` ```yaml theme={null} metrics: average_clv: type: average sql: ${TABLE}.customer_lifetime_value richText: | {% raw %}{% if value.raw >= 100 %} ### 📈 ${ value.formatted } **Excellent** Average CLV {% elsif value.raw >= 50 %} ### 📊 ${ value.formatted } **Good** Average CLV {% else %} ### ⚠️ ${ value.formatted } **Low** Average CLV {% endif %}{% endraw %} ``` ### Liquid templating in rich text Use templates to configure values dynamically at runtime based on query results. **Available liquid tags** | Tag | Description | | :------------------------------------------ | :------------------------------------------------------------------------------------------ | | `${ value.formatted }` | The exact value of the dimension as seen in the Lightdash UI. For example `$1,427.20` | | `${ value.raw }` | The raw value of the dimension returned from the underlying SQL query. For example `1427.2` | | `${ row.table_name.column_name.formatted }` | The exact value of the column as seen in the Lightdash UI. For example `$1,427.20` | | `${ row.table_name.column_name.raw }` | The raw value of the dimension returned from the underlying SQL query. For example `1427.2` | **Available liquid filters** Filters can be used to make small transformations of your values: * `url_encode`: Encode a string as URL safe, for example it replaces spaces with `%20`. ```liquid theme={null} ${ value.formatted | url_encode } ``` * `downcase`: Convert a string to lowercase. ```liquid theme={null} ${ value.formatted | downcase } ``` * `append`: Append one string to another. ```liquid theme={null} ${ value.formatted | append: ".html" } ``` There are [many more filters available in the Liquid documentation](https://liquidjs.com/filters/overview.html). ## Filters Filters are applied to metrics any time that metric is used in Lightdash. Filters can only be used with [aggregate metric types](#metric-categories). For example, we could add a filter to our users count to make sure it didn't include user IDs with closed accounts, like this: ```yaml theme={null} models: - name: sales_stats columns: - name: user_id description: 'Unique ID for users.' meta: dimension: type: string metrics: count_users: type: count_distinct filters: - is_closed_account: false ``` ```yaml theme={null} models: - name: sales_stats columns: - name: user_id description: 'Unique ID for users.' config: meta: dimension: type: string metrics: count_users: type: count_distinct filters: - is_closed_account: false ``` ```yaml theme={null} type: model name: sales_stats dimensions: - name: user_id description: 'Unique ID for users.' type: string metrics: count_users: type: count_distinct sql: ${TABLE}.user_id filters: - is_closed_account: false ``` These filters do not appear in the `Filters` tab in the Explore view, instead, they are applied automatically in the SQL query that fetches your results. That means filters added using the `filter` parameter can't be removed in the UI and won't be visible to users unless they look at the SQL query. ### Available filter types | Type | Example (in English) | Example (as code) | | :---------------------------- | :--------------------------------------------- | :---------------------------- | | is | User name is equal to katie | `user_name: "katie"` | | is not | User name is not equal to katie | `user_name: "!katie"` | | contains | User name contains katie | `user_name: "%katie%"` | | does not contain | User name does not contain katie | `user_name: "!%katie%"` | | starts with | User name starts with katie | `user_name: "katie%"` | | ends with | User name ends with katie | `user_name: "%katie"` | | is greater than (number) | Number of orders is greater than 4 | `num_orders: "> 4"` | | in the past (date) (interval) | Date is before x (days / months / years) | `date: "inThePast 14 months"` | | in the next (date) (interval) | Date is after x (days / months / years) | `date: "inTheNext 14 days"` | | is greater than or equal to | Number of orders is greater than or equal to 4 | `num_orders: ">= 4"` | | is less than | Number of orders is less than 4 | `num_orders: "< 4"` | | is less than or equal to | Number of orders is less than or equal to 4 | `num_orders: "<= 4"` | | is null | Status is NULL | `status: "null"` | | is not null | Status is not NULL | `status: "!null"` | | is \[boolean] | Is complete is true | `is_complete: "true"` | | is not \[boolean] | Is complete is false or null | `is_complete: "!true"` | ### Date filters For date filtering, use `inThePast` or `inTheNext` followed by a number and time unit (days, months, or years). These keywords are case sensitive and must be written exactly as shown. ```yaml theme={null} filters: - created_at: 'inThePast 30 days' ``` ### Special characters in filters To use special characters such as `%!_>` in your filter value you can either put the value in quotes, or escape special characters with a backslash `\`. For example, if you wanted to filter for subscription status of `is_subscribed` you can write the metric in one of these ways: ```yaml theme={null} filters: - subscription_status: 'is_subscribed' ``` ```yaml theme={null} filters: - subscription_status: is\_subscribed ``` ### Filtering using a list of values To filter a field using a list of values you can supply them as an array for that field. This generates a SQL `IN` clause, e.g. `WHERE order_status IN ('completed', 'shipped')`. For example, if you wanted to filter for orders with order status `completed` or `shipped` you should write the metric like: ```yaml theme={null} columns: - name: order_id meta: metrics: completed_or_shipped_order_count: type: count_distinct filters: - order_status: - completed - shipped ``` ```yaml theme={null} columns: - name: order_id config: meta: metrics: completed_or_shipped_order_count: type: count_distinct filters: - order_status: - completed - shipped ``` ```yaml theme={null} type: model name: my_model dimensions: - name: order_id metrics: completed_or_shipped_order_count: type: count_distinct sql: ${TABLE}.order_id filters: - order_status: - completed - shipped ``` ### Filters are joined using `AND` For example: ```yaml theme={null} filters: - is_closed_account: false - is_7d_active: true ``` Would give you logic like `is_closed_account = TRUE AND is_7d_active = FALSE`. ### Adding filters from joined models To filter using a field from a joined model, just use the syntax `model_name.field`, like this: ```yaml theme={null} models: - name: sales_stats meta: joins: - join: web_sessions sql_on: ${web_sessions.date} = ${sales_stats.date} columns: - name: user_id description: 'Unique ID for users.' meta: dimension: type: string metrics: count_users: type: count_distinct filters: - is_closed_account: false - web_sessions.is_bot_user: false ``` ```yaml theme={null} models: - name: sales_stats config: meta: joins: - join: web_sessions sql_on: ${web_sessions.date} = ${sales_stats.date} columns: - name: user_id description: 'Unique ID for users.' config: meta: dimension: type: string metrics: count_users: type: count_distinct filters: - is_closed_account: false - web_sessions.is_bot_user: false ``` ```yaml theme={null} type: model name: sales_stats joins: - join: web_sessions sql_on: ${web_sessions.date} = ${sales_stats.date} dimensions: - name: user_id description: 'Unique ID for users.' type: string metrics: count_users: type: count_distinct sql: ${TABLE}.user_id filters: - is_closed_account: false - web_sessions.is_bot_user: false ``` ### Referencing time intervals in filters You can reference specific time intervals of dimensions in metric filters. When a dimension has time intervals defined, you can filter on the specific interval by appending the interval name to the dimension name (e.g., `session_start_day`). ```yaml theme={null} count: type: count filters: - session_start_day: "!null" ``` In this example, the filter checks that `session_start_day` (the `DAY` time interval of the `session_start` dimension) is not null. ### Metric filters cannot be used with non-aggregate metrics You can't use filters with non-aggregate metric types. Instead, if your non-aggregate metrics are referencing aggregate metric types, you need to apply metric filters to the aggregate metrics. Here's an example: imagine you wanted to calculate the average cost per item that had the status `shipped`. You would need to do something like this in your .yml: ```yaml theme={null} models: - name: orders meta: metrics: average_cost_per_item_shipped: type: number sql: ${total_cost_of_shipped} / ${count_unique_items_shipped} columns: - name: item_id description: 'Unique ID for items ordered.' meta: dimension: type: string metrics: count_unique_items: type: count_distinct count_unique_items_shipped: type: count_distinct filters: - status: 'shipped' - name: item_cost description: 'Cost for each item ordered.' meta: dimension: type: number metrics: total_cost: type: sum total_cost_of_shipped: type: sum filters: - status: 'shipped' ``` ```yaml theme={null} models: - name: orders config: meta: metrics: average_cost_per_item_shipped: type: number sql: ${total_cost_of_shipped} / ${count_unique_items_shipped} columns: - name: item_id description: 'Unique ID for items ordered.' config: meta: dimension: type: string metrics: count_unique_items: type: count_distinct count_unique_items_shipped: type: count_distinct filters: - status: 'shipped' - name: item_cost description: 'Cost for each item ordered.' config: meta: dimension: type: number metrics: total_cost: type: sum total_cost_of_shipped: type: sum filters: - status: 'shipped' ``` ```yaml theme={null} type: model name: orders dimensions: - name: item_id description: 'Unique ID for items ordered.' type: string - name: item_cost description: 'Cost for each item ordered.' type: number metrics: count_unique_items: type: count_distinct sql: ${TABLE}.item_id count_unique_items_shipped: type: count_distinct sql: ${TABLE}.item_id filters: - status: 'shipped' total_cost: type: sum sql: ${TABLE}.item_cost total_cost_of_shipped: type: sum sql: ${TABLE}.item_cost filters: - status: 'shipped' average_cost_per_item_shipped: type: number sql: ${total_cost_of_shipped} / ${count_unique_items_shipped} ``` ## Tags You can add tags to individual metrics to categorize them for programmatic use. Tags are string arrays that Lightdash preserves and exposes via the API. Tags are useful for: * **AI agent access control** — restrict which metrics an [AI agent](/guides/ai-agents/data-access) can see * **API filtering** — filter the [data catalog metrics endpoint](/api-reference/v1/recipes#filter-metrics-by-tag-using-the-data-catalog-api) by tag to retrieve only the metrics you need * **Pipeline ingestion** — flag specific metrics for downstream ETL or semantic layer workflows Tags are **not** displayed as Spotlight categories in the Lightdash UI. They function as a backend/programmatic control mechanism only. ```yaml theme={null} models: - name: orders columns: - name: amount meta: metrics: total_order_amount: type: sum tags: ["core", "finance"] average_order_amount: type: average tags: ["core"] ``` ```yaml theme={null} models: - name: orders columns: - name: amount config: meta: metrics: total_order_amount: type: sum tags: ["core", "finance"] average_order_amount: type: average tags: ["core"] ``` ```yaml theme={null} type: model name: orders metrics: total_order_amount: type: sum sql: ${TABLE}.amount tags: ["core", "finance"] average_order_amount: type: average sql: ${TABLE}.amount tags: ["core"] ``` ## Level of detail metrics When you build a query in Lightdash, every metric in the results is grouped by the dimensions you've selected. This is usually what you want, but sometimes you need a metric to be calculated at a different granularity than the rest of the query. For example, you might want a denominator that stays at a coarser grain even when you add more dimensions to the view. This is commonly known as a "level of detail" (LOD) calculation. The idea is that certain metrics should *ignore* specific dimensions during aggregation, so their values remain stable regardless of how the data is sliced. *Coming to the [demo site](https://demo.lightdash.com/projects/d496d901-a76d-4916-9eae-b81bc7337013/home) soon.* ### The problem This comes up most often with percentage or ratio metrics. Consider this scenario: you want to calculate **"what % of accounts in each segment have Won deals?"** and you want to break this down by deal plan. The numerator (accounts with Won deals) should naturally vary by plan. But the denominator (total accounts in the segment) should not. There are 152 Enterprise accounts regardless of which plan you're analyzing. When you join accounts to deals and group by both segment and plan, the denominator gets scoped to only the accounts that have deals in that plan. This is the default behavior in any BI tool that uses a join-then-group approach. **Without level of detail (denominator grouped by plan):** | Segment | Plan | Accounts with Won Deals | Total Accounts | % | | ---------- | ------------ | ----------------------- | -------------- | ----- | | Enterprise | Basic | 36 | 107 | 33.6% | | Enterprise | Professional | 13 | 46 | 28.3% | The total accounts column shows **107** and **46** because only accounts that have deals in that specific plan are included in the count. **With level of detail (denominator independent of plan):** | Segment | Plan | Accounts with Won Deals | Total Accounts | % | | ---------- | ------------ | ----------------------- | -------------- | ----- | | Enterprise | Basic | 36 | 152 | 23.7% | | Enterprise | Professional | 13 | 152 | 8.6% | The total accounts column stays at **152** because the denominator is computed independently of the plan dimension. This is achieved by pre-computing the denominator in a separate CTE in your dbt model. ### The workaround The solution is to pre-compute the coarser-grain metric (total accounts per segment) in your dbt model, so it is always correct regardless of which dimensions are selected in Lightdash. **Step 1: Pre-compute the denominator in your dbt model** ```sql theme={null} with segment_totals as ( select segment, count(distinct account_id) as total_accounts_in_segment from {{ ref('accounts') }} group by segment ), account_deals as ( select a.account_id, a.segment, d.deal_id, d.plan, d.stage from {{ ref('accounts') }} a inner join {{ ref('deals') }} d on a.account_id = d.account_id ) select ad.*, st.total_accounts_in_segment from account_deals ad left join segment_totals st on ad.segment = st.segment ``` **Step 2: Define the metrics in your YAML** ```yaml theme={null} models: - name: account_deal_metrics meta: metrics: pct_accounts_with_won_deals: type: number label: "% Accounts with Won Deals" format: percent sql: ${unique_accounts_with_won_deals} / NULLIF(${segment_total_accounts}, 0) columns: - name: account_id meta: dimension: type: string hidden: true metrics: unique_accounts_with_won_deals: type: count_distinct filters: - stage: 'Won' - name: segment meta: dimension: type: string - name: plan meta: dimension: type: string - name: total_accounts_in_segment meta: dimension: type: number metrics: segment_total_accounts: type: max ``` ```yaml theme={null} models: - name: account_deal_metrics config: meta: metrics: pct_accounts_with_won_deals: type: number label: "% Accounts with Won Deals" format: percent sql: ${unique_accounts_with_won_deals} / NULLIF(${segment_total_accounts}, 0) columns: - name: account_id config: meta: dimension: type: string hidden: true metrics: unique_accounts_with_won_deals: type: count_distinct filters: - stage: 'Won' - name: segment config: meta: dimension: type: string - name: plan config: meta: dimension: type: string - name: total_accounts_in_segment config: meta: dimension: type: number metrics: segment_total_accounts: type: max ``` ```yaml theme={null} type: model name: account_deal_metrics dimensions: - name: account_id type: string hidden: true - name: segment type: string - name: plan type: string - name: total_accounts_in_segment type: number metrics: unique_accounts_with_won_deals: type: count_distinct sql: ${TABLE}.account_id filters: - stage: 'Won' segment_total_accounts: type: max sql: ${TABLE}.total_accounts_in_segment pct_accounts_with_won_deals: type: number label: "% Accounts with Won Deals" format: percent sql: ${unique_accounts_with_won_deals} / NULLIF(${segment_total_accounts}, 0) ``` The key insight is that `total_accounts_in_segment` is pre-computed in the SQL and is the same value for every row in a segment. Using `max` as the aggregation returns the correct segment-level total, regardless of what other dimensions (like `plan`) are in the query. The `pct_accounts_with_won_deals` metric then divides the numerator (which correctly varies by plan) by the denominator (which stays fixed per segment). # Organization credentials Source: https://docs.lightdash.com/references/organization-credentials Organization credentials allow admins to create reusable warehouse credentials at the organization level, making it easier for users to create projects securely. **Organization credentials are only available on Lightdash Enterprise plans.** For more information on our plans, visit our [pricing page](https://www.lightdash.com/pricing). **Currently, organization credentials are only supported for Snowflake SSO connections.** Support for additional warehouse types will be added in the future. Organization credentials provide a secure and convenient way to manage warehouse connections across your Lightdash organization. Instead of requiring each user to input sensitive warehouse credentials when creating a project, organization admins can set up shared credentials that any organization member can use when creating new projects. ## What are organization credentials? Organization credentials are warehouse connection credentials created and managed at the organization level. They allow you to: * **Centralize credential management**: Admins maintain warehouse credentials in one place * **Improve security**: Non-admin users can create projects without accessing sensitive credentials * **Simplify project creation**: Users can select from pre-configured credentials instead of manually entering connection details * **Enable self-service**: Team members can create projects independently without needing admin assistance Organization credentials are compatible with preview projects, allowing the same secure credential workflow for both production and preview environments. ## Who can use organization credentials? ### Creating organization credentials Only **organization admins** can create, edit, or delete organization credentials. Organization admins have exclusive control over managing organization credentials to ensure security and governance standards are maintained. ### Using organization credentials **Organization developers or project admins** can use organization credentials when creating or updating new projects. When creating a project, users can select from available organization credentials without seeing the underlying sensitive connection details such as passwords or access keys. You can also configure the custom roles to limit the access to the project creation feature. ## Setting up organization credentials You must be an organization admin to set up organization credentials. To create organization credentials: 1. Navigate to **Settings** in the Lightdash application 2. Under **Organization settin** Screenshot from 2025-10-20 12-05-34.png 3. Click **Add new credentials** 4. Enter the credential details: * **Name**: A descriptive name for the credential (e.g., "Production Data Warehouse", "Analytics Staging") * **Connection details**: Enter the specific connection information for your warehouse * **Sign in with Snowflake** if you are not authenticated or authentication has expired Screenshot from 2025-10-20 11-45-44.png 5. Click **Save** to create the credential ### Managing existing credentials Organization admins can: * **Edit credentials**: Update connection details or credential names * **Delete credentials**: Remove credentials that are no longer needed. This will not be possible if the credentials are already used by a project * **View usage**: See which projects are using specific credentials * **Reauthenticate with SSO**. If token have expired, you can `relogin` and `save` so the credentials are uptodate with your latest tokens After updating organization credentials, you don't need to recompile the project, not even after updating SSO credentials. You might want however to `refresh dbt` if you changed the database or warehouse, to refresh explores. ## Using organization credentials to create a project When creating a new project in Lightdash: 1. Navigate to **Settings** --> **Project management** --> **Create new project** 2. Enter a project name 3. In the **Warehouse connection** section, now you'll see an option to \*\*Use organization credential, \*\*select the previously created organization credentials. This option will not appear if you don't have any organization credentials. Screenshot from 2025-10-20 12-00-05.png 8. Configure your dbt connection 9. Click **Create project** ## Organization credentials and preview projects Organization credentials work seamlessly with [preview projects](/guides/developer/preview-projects). When you create a preview project from a parent project that uses organization credentials, the preview will automatically inherit those credentials. This means: * Preview projects created from the Lightdash app will use the same organization credential as the parent project * Preview projects created via the CLI or GitHub Actions can also leverage organization credentials ## Organization credentials and user credential requirements If a project is configured to **require user credentials**, end users will need to provide their own individual warehouse credentials when accessing the project, even if the project was created using organization credentials. When "require user credentials" is enabled for a project, users will be prompted to log in with their personal warehouse credentials. These personal credentials will override the organization credentials for that user's queries and data access. This means: * **Project creation**: Organization credentials are used to set up the project's connection * **User queries**: When the project requires user credentials, each user must authenticate with their own warehouse credentials * **Security compliance**: This allows organizations to maintain audit trails and data access controls at the individual user level while still simplifying project setup For more information about personal warehouse connections, see the [Personal warehouse connections documentation](/references/workspace/personal-warehouse-connections). ## Related features * [Creating multiple projects](/references/workspace/how-to-create-multiple-projects): Learn more about project creation in Lightdash * [Preview projects](/guides/developer/preview-projects): Understand how preview projects work with organization credentials * [Roles and permissions](/references/workspace/roles): Learn about organization admin permissions * [Personal warehouse connections](/references/workspace/personal-warehouse-connections): Understand individual user warehouse credentials # Auditing pre-aggregates from the CLI Source: https://docs.lightdash.com/references/pre-aggregates/cli-audit Use lightdash pre-aggregate-audit to inspect coverage, find gaps in your YAML, and gate CI on dashboard hit rates. **Availability:** Pre-aggregates are a [Beta](/references/workspace/feature-maturity-levels) feature available on **Enterprise plans** only. `lightdash pre-aggregate-audit` reports, for one dashboard or every dashboard in a project, which tiles are served from a pre-aggregate, which ones miss (and why), and which ones are ineligible for pre-aggregates entirely. It calls the same audit data as the in-app **Pre-aggregation audit** menu (see [Dashboard pre-aggregate view](/references/pre-aggregates/monitoring#dashboard-pre-aggregate-view)) but exposes it for scripting, automation, and CI. ## When to use it The CLI audit is the right tool when you want to: * Iterate on pre-aggregate YAML and verify that misses you've targeted are now hits, without clicking through dashboards in the UI * Run a project-wide sweep to find dashboards that aren't benefitting from pre-aggregates yet * Get machine-readable JSON for custom reporting (for example, exporting coverage to a BI tool or Slack) * Block merges in CI when a critical dashboard regresses to warehouse queries For a quick spot-check on one dashboard, the in-app audit menu is usually faster. **Pairs well with agentic coding tools.** Cursor, Claude Code, Codex, and similar agents do really well with this command — every miss prints both the failing field and the reason, which is exactly the signal an agent needs to edit the right pre-aggregate in your dbt YAML. A typical loop is "run `lightdash pre-aggregate-audit --dashboard `, then update the model YAML to close the misses, then re-run until it's clean." The output is structured enough that the agent can fix coverage on its own without you having to translate misses into YAML edits manually. ## Prerequisites * Lightdash Enterprise plan * [Install the Lightdash CLI](/guides/cli/how-to-install-the-lightdash-cli) * [Authenticate](/guides/cli/cli-authentication) with `lightdash login` ## Auditing a single dashboard Pass the dashboard's UUID or its URL slug: ```bash theme={null} lightdash pre-aggregate-audit --dashboard sales-overview ``` The output groups tiles by tab and tags each one with its status: ```text theme={null} Dashboard: Sales Overview (sales-overview) 4 hit 2 miss — 1 ineligible Tab: Q1 HIT Total revenue (pre-aggregate: orders_daily_by_status) HIT Average order value (pre-aggregate: orders_daily_by_status) MISS New customers (Metric not in pre-aggregate) MISS Revenue by hour (Granularity too fine) 1 ineligible tile(s) hidden (pass --verbose to show) ``` Each tile is one of: * **Hit** — the chart is served from the named pre-aggregate * **Miss** — the chart is eligible to use pre-aggregates but no pre-aggregate matches. The output prints the miss reason * **Ineligible** — the tile cannot use pre-aggregates at all (markdown tile, SQL chart, orphaned chart, broken explore). Hidden by default; pass `--verbose` to expand ## Auditing every dashboard ```bash theme={null} lightdash pre-aggregate-audit --all ``` The CLI fetches every dashboard in the project and audits each one. This is the workflow for project-wide health checks or CI gates. ## Selecting the project The CLI resolves the project in this order: 1. `--project ` flag 2. `LIGHTDASH_PROJECT_UUID` environment variable 3. The project saved by your last `lightdash login` / `lightdash config set-project` ```bash theme={null} lightdash pre-aggregate-audit --all --project ``` ## JSON output for scripting ```bash theme={null} lightdash pre-aggregate-audit --dashboard sales-overview --json ``` Returns the full audit object per dashboard (`{ "dashboards": [...] }` when combined with `--all`). Pipe into `jq` to extract what you care about — for example, every dashboard with at least one miss: ```bash theme={null} lightdash pre-aggregate-audit --all --json \ | jq '.dashboards[] | select(.summary.missCount > 0) | .dashboardName' ``` ## Using audit results to improve your YAML The miss labels printed by the CLI are the same ones documented in [Why a query misses a pre-aggregate](/references/pre-aggregates/monitoring#why-a-query-misses-a-pre-aggregate) — that table maps each reason to the YAML or configuration change that fixes it. A typical iteration loop: 1. `lightdash pre-aggregate-audit --dashboard ` to see the current misses 2. Edit your dbt model YAML to address each miss (use the [miss-reason table](/references/pre-aggregates/monitoring#why-a-query-misses-a-pre-aggregate) to know which field to change) 3. `lightdash deploy` to push the change 4. Trigger a refresh from **Project Settings > Pre-aggregates** if the pre-aggregate definition changed 5. Re-run the audit to confirm the misses are now hits ## CI integration with `--fail-on-miss` `--fail-on-miss` makes the command exit with code 1 if any tile is a miss, so CI can block changes that regress pre-aggregate coverage: ```yaml theme={null} - name: Audit pre-aggregate coverage run: lightdash pre-aggregate-audit --dashboard executive-summary --fail-on-miss env: LIGHTDASH_API_KEY: ${{ secrets.LIGHTDASH_API_KEY }} LIGHTDASH_URL: ${{ vars.LIGHTDASH_URL }} LIGHTDASH_PROJECT_UUID: ${{ vars.LIGHTDASH_PROJECT_UUID }} ``` Ineligible tiles do not count as misses — only eligible tiles that failed to match contribute to the failure. Gating an entire project with `--all --fail-on-miss` is usually too strict, since most projects have at least one dashboard with unsupported features. Pin the gate to the high-traffic dashboards you care about with `--dashboard --fail-on-miss`, or use `--json` and filter the dashboards you want to enforce. ## Flag reference | Flag | Description | | ---------------------------- | -------------------------------------------------------------------------------------------- | | `--dashboard ` | Audit a specific dashboard. Required unless `--all` is set. | | `--all` | Audit every dashboard in the project. | | `--project ` | Override the active project. Falls back to `LIGHTDASH_PROJECT_UUID`, then to the CLI config. | | `--json` | Emit machine-readable JSON instead of the human-friendly text output. | | `--fail-on-miss` | Exit 1 if any eligible tile misses. Ineligible tiles do not trigger a failure. | | `--verbose` | Include ineligible tiles (and their reason) in the human output. | # Getting started with pre-aggregates Source: https://docs.lightdash.com/references/pre-aggregates/getting-started Define pre-aggregates in your dbt YAML, configure scheduling, and start serving queries from materialized data. ## Defining pre-aggregates Pre-aggregates are defined under the `pre_aggregates` key in your model configuration. If you're using Lightdash YAML instead of dbt model YAML, see the [Lightdash YAML syntax guide](/guides/lightdash-yaml) for the surrounding model structure. ```yaml theme={null} models: - name: orders meta: pre_aggregates: - name: orders_daily_by_status dimensions: - status metrics: - total_order_amount - average_order_size filters: - order_date: inThePast 52 weeks time_dimension: order_date granularity: day ``` ```yaml theme={null} models: - name: orders config: meta: pre_aggregates: - name: orders_daily_by_status dimensions: - status metrics: - total_order_amount - average_order_size filters: - order_date: inThePast 52 weeks time_dimension: order_date granularity: day ``` ```yaml theme={null} type: model name: orders pre_aggregates: - name: orders_daily_by_status dimensions: - status metrics: - total_order_amount - average_order_size filters: - order_date: inThePast 52 weeks time_dimension: order_date granularity: day ``` ## Configuration reference | Property | Required | Description | | ---------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | Yes | Unique identifier for the pre-aggregate. Must contain only letters, numbers, and underscores. | | `dimensions` | Yes | List of dimension names to include. Must contain at least one dimension. | | `metrics` | Yes | List of metric names to include. Must contain at least one metric. | | `filters` | No | Static filters applied when materializing the pre-aggregate. Matching queries must include an equivalent or narrower filter to use this pre-aggregate. | | `time_dimension` | No | A time-based dimension for date grouping. Must be paired with `granularity`. | | `granularity` | No | Time granularity for the `time_dimension`. Valid values: `hour`, `day`, `week`, `month`, `quarter`, `year`. Must be paired with `time_dimension`. | | `max_rows` | No | Maximum number of rows to store in the materialization. If the aggregation exceeds this limit, the result is truncated. Must be a positive integer. | | `refresh` | No | Schedule configuration for automatic re-materialization. See [Scheduling refreshes](#scheduling-refreshes). | | `materialization_role` | No | Fixed access context to use when materializing the pre-aggregate. This is useful when your model or joined tables use [`required_attributes`](/references/tables#required-attributes) or [`any_attributes`](/references/tables#any-attributes). See [Materialization role](#materialization-role). | If you specify `time_dimension`, you **must** also specify `granularity`, and vice versa. ## Filtered pre-aggregates Use `filters` when you want a pre-aggregate to materialize only a subset of the source data. For example, this pre-aggregate only stores data for the last 52 weeks: ```yaml theme={null} models: - name: orders meta: pre_aggregates: - name: recent_orders_daily dimensions: - status metrics: - total_order_amount - order_count filters: - order_date: inThePast 52 weeks time_dimension: order_date granularity: day ``` ```yaml theme={null} models: - name: orders config: meta: pre_aggregates: - name: recent_orders_daily dimensions: - status metrics: - total_order_amount - order_count filters: - order_date: inThePast 52 weeks time_dimension: order_date granularity: day ``` ```yaml theme={null} type: model name: orders pre_aggregates: - name: recent_orders_daily dimensions: - status metrics: - total_order_amount - order_count filters: - order_date: inThePast 52 weeks time_dimension: order_date granularity: day ``` This is useful when a rolling time window is queried frequently and deserves its own smaller materialization. ### How query matching works with filters Filtered pre-aggregates are only used when the query filters are compatible with the pre-aggregate definition: * A query with the same or narrower filter can use the pre-aggregate * A query without the filter, or with a broader or incompatible filter, falls back to another pre-aggregate or the warehouse For the example above: * `order_date inThePast 12 weeks` can use the pre-aggregate * `order_date inThePast 52 weeks` can use the pre-aggregate * `order_date inThePast 104 weeks` cannot use the pre-aggregate * no `order_date` filter: cannot use the pre-aggregate If a field is only used for filtering, you should still include it in the pre-aggregate's `dimensions` list so Lightdash can match and re-aggregate queries correctly. ## Multiple pre-aggregates per model You can define multiple pre-aggregates on the same model, each targeting different query patterns. It is better to have **multiple small, focused pre-aggregates** rather than a single one containing all metrics and dimensions. Including too many dimensions increases the number of unique combinations, which generates large materialization files — this defeats the purpose of pre-aggregates, since they are meant to be smaller and faster than querying the warehouse directly. For example, you might want a fine-grained daily pre-aggregate for detailed dashboards and a coarser monthly one for summary views: ```yaml theme={null} models: - name: orders config: meta: pre_aggregates: - name: orders_daily_by_status dimensions: - status metrics: - total_order_amount - order_count time_dimension: order_date granularity: day - name: orders_monthly_summary dimensions: - status metrics: - total_order_amount time_dimension: order_date granularity: month max_rows: 1000000 ``` When a query matches multiple pre-aggregates, Lightdash picks the smallest one. ## Scheduling refreshes By default, pre-aggregates are materialized when your dbt project compiles. You can also schedule automatic refreshes using cron expressions, using your project's configured timezone (defaults to UTC): ```yaml theme={null} pre_aggregates: - name: orders_daily_by_status dimensions: - status metrics: - total_order_amount time_dimension: order_date granularity: day refresh: cron: "0 6 * * *" # Every day at 6:00 AM UTC ``` ### Materialization triggers Pre-aggregates can be materialized through four different triggers: | Trigger | When it happens | | ----------- | ------------------------------------------------ | | **Compile** | Automatically when your dbt project is compiled | | **Cron** | On the schedule you define in `refresh.cron` | | **Manual** | When you trigger a refresh from the Lightdash UI | ## Row limits You can set `max_rows` to cap the size of a materialization. If the aggregation produces more rows than the limit, the result is truncated. When `max_rows` is applied, some data is excluded from the materialization. Queries that match the pre-aggregate may return incomplete results. Use this setting carefully and monitor for the "max rows applied" warning in the [monitoring UI](/references/pre-aggregates/monitoring). ## Materialization role `materialization_role` is useful when access to the model depends on [`required_attributes`](/references/tables#required-attributes) or [`any_attributes`](/references/tables#any-attributes). For example, if a joined table is only available to users with `region_access: emea`, then materializing a pre-aggregate without a fixed access context could produce different results depending on who triggered the build. Use `materialization_role` to make materialization run with a stable set of [user attributes](/references/workspace/user-attributes). This is intended for access control fields such as: * [`required_attributes`](/references/tables#required-attributes) * [`any_attributes`](/references/tables#any-attributes) ```yaml theme={null} models: - name: orders meta: joins: - join: customers sql_on: ${customers.customer_id} = ${orders.customer_id} pre_aggregates: - name: orders_daily_by_region dimensions: - customers.region metrics: - total_order_amount time_dimension: order_date granularity: day materialization_role: email: materialize@acme.com attributes: region_access: emea ``` ```yaml theme={null} models: - name: orders config: meta: joins: - join: customers sql_on: ${customers.customer_id} = ${orders.customer_id} pre_aggregates: - name: orders_daily_by_region dimensions: - customers.region metrics: - total_order_amount time_dimension: order_date granularity: day materialization_role: email: materialize@acme.com attributes: region_access: emea ``` ## Complete example Here's a full model definition with a pre-aggregate, including joins, scheduling, and row limits: ```yaml theme={null} models: - name: orders meta: joins: - join: customers sql_on: ${customers.customer_id} = ${orders.customer_id} pre_aggregates: - name: orders_daily_by_status dimensions: - status - customers.country metrics: - total_order_amount - average_order_size filters: - status: completed time_dimension: order_date granularity: day max_rows: 5000000 refresh: cron: "0 6 * * *" columns: - name: order_date meta: dimension: type: date - name: status meta: dimension: type: string - name: amount meta: metrics: total_order_amount: type: sum average_order_size: type: average ``` ```yaml theme={null} models: - name: orders config: meta: joins: - join: customers sql_on: ${customers.customer_id} = ${orders.customer_id} pre_aggregates: - name: orders_daily_by_status dimensions: - status - customers.country metrics: - total_order_amount - average_order_size filters: - status: completed time_dimension: order_date granularity: day max_rows: 5000000 refresh: cron: "0 6 * * *" columns: - name: order_date config: meta: dimension: type: date - name: status config: meta: dimension: type: string - name: amount config: meta: metrics: total_order_amount: type: sum average_order_size: type: average ``` ```yaml theme={null} type: model name: orders joins: - join: customers sql_on: ${customers.customer_id} = ${orders.customer_id} pre_aggregates: - name: orders_daily_by_status dimensions: - status - customers.country metrics: - total_order_amount - average_order_size filters: - status: completed time_dimension: order_date granularity: day max_rows: 5000000 refresh: cron: "0 6 * * *" dimensions: - name: order_date type: date - name: status type: string metrics: total_order_amount: type: sum sql: ${TABLE}.amount average_order_size: type: average sql: ${TABLE}.amount ``` With this pre-aggregate, the following queries would be served from materialized data: * Total order amount by status, grouped by day, week, month, or year * Average order size by status, grouped by month * Total order amount filtered to completed orders * Order amount by customer country, grouped by quarter These queries would **not** match and would query the warehouse directly: * Queries including `count_distinct` metrics * Queries grouped by a dimension not in the pre-aggregate (for example, `customer_id`) * Queries with hourly granularity (finer than the pre-aggregate's `day`) * Queries without `status = completed` or with a broader `status` filter * Queries with [Parameters](/references/lightdash-config-yml#parameters-configuration), [user attributes](/references/workspace/user-attributes) inside SQL, or [`sql_filter`](/references/tables#sql-filter-row-level-security) * Queries with raw SQL table calculations # Monitoring and debugging pre-aggregates Source: https://docs.lightdash.com/references/pre-aggregates/monitoring Track materialization status, understand why queries miss pre-aggregates, and manage refreshes. You can monitor pre-aggregates from **Project Settings > Pre-aggregates**. This section has two tabs: **Materializations** for tracking status and **Analytics** for query hit/miss statistics. ## Materialization status The **Materializations** tab shows all your pre-aggregates and their current state. Pre-aggregate materializations list Each pre-aggregate has a materialization lifecycle: | Status | Meaning | | --------------- | -------------------------------------------------------------------------------------------------------------------------------- | | **Active** | The materialization is live and serving matching queries. Only one materialization can be active per pre-aggregate at a time. | | **In progress** | A new materialization is being built. The previous active materialization continues serving queries until the new one completes. | | **Failed** | The materialization encountered an error. Check the error message for details. | You can click on any pre-aggregate to see its full details, including row count, file size, and duration. Pre-aggregate materialization detail ## Hit and miss statistics The **Analytics** tab tracks how often queries hit or miss pre-aggregates on a daily basis. Pre-aggregate analytics You can break down the statistics by: * **Explore name** — which explores are benefiting from pre-aggregates * **Query context** — whether the query came from a chart, dashboard, or the explorer * **Chart or dashboard** — which specific saved content is hitting or missing Use these stats to identify opportunities for new pre-aggregates or to tune existing ones. ## Why a query misses a pre-aggregate When a query doesn't match any pre-aggregate, Lightdash records the specific reason. Understanding these reasons helps you decide whether to adjust your pre-aggregate definition or accept the warehouse query. | Miss reason | What it means | How to fix it | | ----------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **No pre-aggregates defined** | The explore has no pre-aggregates configured. | Add a `pre_aggregates` block to your dbt model. | | **Dimension not in pre-aggregate** | The query includes a dimension not covered by any pre-aggregate. | Add the missing dimension to your pre-aggregate's `dimensions` list. | | **Metric not in pre-aggregate** | The query includes a metric not covered by any pre-aggregate. | Add the missing metric to your pre-aggregate's `metrics` list. | | **Filter dimension not in pre-aggregate** | A filter references a dimension not in the pre-aggregate. | Add the filter dimension to the `dimensions` list — even if it's only used for filtering, not grouping. | | **Pre-aggregate filter not satisfied** | The pre-aggregate definition includes a static filter, but the query is missing it or uses a broader/incompatible filter. | Add the matching filter to the query, narrow the query filter, or create another pre-aggregate for that query pattern. | | **Non-additive metric** | The query includes a metric type that can't be re-aggregated (for example, `count_distinct` or `median`). | This metric type is not supported. See [supported metric types](/references/pre-aggregates/overview#supported-metric-types). | | **Custom SQL metric** | The query includes a non-reaggregatable custom SQL metric, such as a `number` metric. | Use a supported metric type, or let the query run against the warehouse. | | **Granularity too fine** | The query requests a finer time granularity than the pre-aggregate provides (for example, `hour` on a `day` pre-aggregate). | Either lower the pre-aggregate's granularity or accept the warehouse query for this use case. | | **Custom dimension present** | The query uses a custom SQL dimension. | Custom SQL dimensions created in the UI are not supported. [Write them back](/guides/developer/dbt-write-back#write-back-dimensions-automatically-replacing-custom-dimensions) to the semantic layer. | | **Custom metric present** | The query uses a custom metric. | Custom metrics defined in the Explorer are not supported. [Write them back](/guides/developer/dbt-write-back#write-back-dimensions-automatically-replacing-custom-dimensions) to the semantic layer. | | **Table calculation present** | The query includes a raw SQL table calculation. | Use a formula table calculation instead, or let the query run against the warehouse. | | **User bypass** | The user explicitly bypassed the pre-aggregate cache. | No action needed — this is intentional. | ## Dashboard pre-aggregate view You can also monitor and manage pre-aggregates directly from any dashboard. Open the dashboard menu to access pre-aggregate options. Pre-aggregate options in the dashboard menu 1. **Pre-aggregation audit** — Shows which tiles in the dashboard are hitting or missing pre-aggregates, and why. Available to editors, developers, and admins. 2. **Rebuild pre-aggregates** — Triggers a manual re-materialization for the pre-aggregates used by this dashboard. Available to developers and admins only. Pre-aggregate audit view for a dashboard The same audit data is available from the terminal via [`lightdash pre-aggregate-audit`](/references/pre-aggregates/cli-audit), which is useful for scripting, project-wide sweeps, and CI gates. # Pre-aggregates Source: https://docs.lightdash.com/references/pre-aggregates/overview Speed up dashboards and reduce warehouse costs by serving queries from pre-computed, materialized summaries. **Availability:** Pre-aggregates are a [Beta](/references/workspace/feature-maturity-levels) feature available on **Enterprise plans** only. Pre-aggregates let you define materialized summaries of your data directly in your dbt YAML. When a user runs a query in Lightdash, the system checks if the query can be answered from a pre-aggregate instead of querying your warehouse. If it matches, the query is served from the pre-computed results, making it significantly faster and reducing warehouse load. This is especially useful for dashboards with high traffic or expensive aggregations that don't need real-time data. Any query that goes through the Lightdash semantic layer can hit a pre-aggregate — this includes the Lightdash app, the [API](/api-reference/v1/introduction), [MCP](/references/integrations/lightdash-mcp), [AI agents](/guides/ai-agents), the [Embed SDK](/references/embedding), and the [React SDK](/references/react-sdk). Watch this video walkthrough for an overview of how to get started with pre-aggregates: