Infrastructure for managing charts and dashboards as code with slug-based access, versioning, and promotion workflows. Enables GitOps-style workflows for deploying content across environments with internationalization support and synchronization tracking.
Versioned chart definitions with slug-based access, decoupled from UUID references for portability across environments.
type ChartAsCode = Pick<
SavedChart,
| 'name'
| 'description'
| 'tableName'
| 'metricQuery'
| 'chartConfig'
| 'tableConfig'
| 'pivotConfig'
| 'slug'
| 'updatedAt'
> & {
dashboardSlug: string | undefined;
version: number;
spaceSlug: string;
downloadedAt?: Date;
}
type ApiChartAsCodeListResponse = {
status: 'ok';
results: {
charts: ChartAsCode[];
languageMap?: Array<PartialDeep<ChartAsCodeLanguageMap, { recurseIntoArrays: true }> | undefined>;
missingIds: string[];
total: number;
offset: number;
};
};
type ApiChartAsCodeUpsertResponse = {
status: 'ok';
results: PromotionChanges;
};Key Properties:
Versioned dashboard definitions with slug-based tile references and filter configuration.
type DashboardAsCode = Pick<
Dashboard,
'name' | 'description' | 'updatedAt' | 'tabs' | 'slug'
> & {
tiles: DashboardTileAsCode[];
version: number;
spaceSlug: string;
downloadedAt?: Date;
filters: Omit<DashboardFilters, 'dimensions'> & {
dimensions: Omit<DashboardFilterRule, 'id'>[];
};
}
type ApiDashboardAsCodeListResponse = {
status: 'ok';
results: {
dashboards: DashboardAsCode[];
languageMap?: Array<PartialDeep<DashboardAsCodeLanguageMap, { recurseIntoArrays: true }> | undefined>;
missingIds: string[];
total: number;
offset: number;
};
};
type ApiDashboardAsCodeUpsertResponse = {
status: 'ok';
results: PromotionChanges;
};Dashboard tiles with slug-based chart references and optional UUID removal for portability.
type DashboardTileAsCode = Omit<DashboardTile, 'properties' | 'uuid'> & {
uuid: string | undefined; // Optional for new tiles
tileSlug: string | undefined;
properties:
| Pick<DashboardChartTileProperties['properties'], 'title' | 'hideTitle' | 'chartSlug' | 'chartName'>
| DashboardMarkdownTileProperties['properties']
| DashboardLoomTileProperties['properties'];
};
type DashboardTileWithSlug = DashboardTile & {
tileSlug: string | undefined;
};Chart Tile Properties:
const currentVersion = 1; // Current schema version for charts/dashboards-as-codeimport type { ChartAsCode, ApiChartAsCodeListResponse } from '@lightdash/common';
// Download charts from a space for version control
async function downloadChartsAsCode(spaceSlug: string): Promise<ChartAsCode[]> {
const response: ApiChartAsCodeListResponse = await api.get(
`/api/v1/spaces/${spaceSlug}/charts-as-code`
);
return response.results.charts.map(chart => ({
...chart,
downloadedAt: new Date() // Track download time for sync
}));
}import type { ChartAsCode, ApiChartAsCodeUpsertResponse } from '@lightdash/common';
// Upload chart definition to target environment
async function upsertChartAsCode(
projectUuid: string,
chart: ChartAsCode
): Promise<ApiChartAsCodeUpsertResponse> {
// Returns PromotionChanges detailing what was created/updated
return await api.post(`/api/v1/projects/${projectUuid}/charts-as-code`, {
chart,
version: chart.version
});
}import type { DashboardAsCode, DashboardTileAsCode } from '@lightdash/common';
// Define dashboard with slug-based references
const dashboard: DashboardAsCode = {
name: 'Sales Dashboard',
description: 'Key sales metrics and trends',
slug: 'sales-dashboard',
version: 1,
spaceSlug: 'sales-team',
updatedAt: new Date(),
tiles: [
{
uuid: undefined, // New tile, no UUID yet
tileSlug: 'revenue-chart-tile',
type: 'saved_chart',
x: 0,
y: 0,
h: 10,
w: 12,
properties: {
chartSlug: 'monthly-revenue', // References chart by slug
chartName: 'Monthly Revenue',
title: 'Revenue Trends',
hideTitle: false
}
},
{
uuid: undefined,
tileSlug: 'markdown-note',
type: 'markdown',
x: 0,
y: 10,
h: 5,
w: 12,
properties: {
content: '## Sales Dashboard\n\nUpdated monthly with latest data.',
title: 'Dashboard Notes'
}
}
],
filters: {
dimensions: [
{
target: { fieldId: 'orders.created_date' },
operator: 'inThePast',
values: [30],
settings: { unitOfTime: 'days' }
}
]
}
};import type { ChartAsCodeLanguageMap, DashboardAsCodeLanguageMap } from '@lightdash/common';
import { type PartialDeep } from 'type-fest';
// Language maps provide translations for chart/dashboard text
// Note: Uses PartialDeep from type-fest to allow partial nested objects
const chartLanguageMap: PartialDeep<ChartAsCodeLanguageMap, { recurseIntoArrays: true }> = {
'en-US': {
name: 'Monthly Revenue',
description: 'Revenue trends over time',
// ... field labels and other translatable text
},
'es-ES': {
name: 'Ingresos Mensuales',
description: 'Tendencias de ingresos a lo largo del tiempo',
}
};JSON Schema objects for validating chart and dashboard definitions in CI/CD pipelines or development tools.
import chartAsCodeSchema from '@lightdash/common/schemas/json/chart-as-code-1.0.json';
import dashboardAsCodeSchema from '@lightdash/common/schemas/json/dashboard-as-code-1.0.json';
import modelAsCodeSchema from '@lightdash/common/schemas/json/model-as-code-1.0.json';
import lightdashDbtYamlSchema from '@lightdash/common/schemas/json/lightdash-dbt-2.0.json';
import lightdashProjectConfigSchema from '@lightdash/common/schemas/json/lightdash-project-config-1.0.json';
// These are standard JSON Schema objects that can be used with:
// - ajv (JSON Schema validator)
// - VS Code YAML/JSON schema associations
// - CI/CD validation pipelines
// - Development tooling for autocomplete and validationAvailable Schemas:
Usage Example with AJV:
// External dependency - Install separately: npm install ajv
import Ajv from 'ajv';
import chartAsCodeSchema from '@lightdash/common/schemas/json/chart-as-code-1.0.json';
const ajv = new Ajv();
const validate = ajv.compile(chartAsCodeSchema);
// Validate a chart definition
const chartData = {
name: 'My Chart',
version: 1,
spaceSlug: 'analytics',
// ... rest of chart definition
};
if (validate(chartData)) {
console.log('Valid chart definition');
} else {
console.error('Validation errors:', validate.errors);
}VS Code Schema Association Example:
// In .vscode/settings.json
{
"yaml.schemas": {
"./node_modules/@lightdash/common/dist/schemas/json/chart-as-code-1.0.json": "charts/*.chart.yml",
"./node_modules/@lightdash/common/dist/schemas/json/dashboard-as-code-1.0.json": "dashboards/*.dashboard.yml"
}
}downloadedAt and updatedAt timestamps detect out-of-sync contentPromotionChanges detailing what was created/updated/skipped