Configure a self-hosted Lightdash instance to run data apps
Enable data apps on your self-hosted Lightdash instance by configuring a sandbox provider, a coding-agent provider, and object storage. For creating apps, sharing them, and permissions, see Data apps.Sandbox providers are configured separately and cover several runtimes — E2B, AWS Lambda MicroVMs, Azure Container Apps, and Google Cloud Run. See sandboxes for the full provider setup; this page covers everything else data apps need.For custom chart types, see Chart Studio to configure authoring or Chart library to install published chart types without a sandbox.
Enterprise license - LIGHTDASH_LICENSE_KEY must be set on your instance.
S3-compatible storage - a bucket Lightdash can write to for app source and built artifacts. If your instance isn’t already using S3, set that up first.
A coding-agent provider - Anthropic, OpenAI, or an AWS Bedrock account with access to the model used by your selected agent. It serves every user’s builds, so it can’t be tied to one person’s subscription — see building with your own subscription.
A headless browser (optional) - needed for the app image in Slack build notifications and link previews. See enabling the headless browser.
Data apps use your instance’s S3 configuration. Set APPS_S3_BUCKET if you want a dedicated bucket for app source and built artifacts. See the data apps runtime variables for storage overrides and the full configuration reference.Choose one of the coding-agent and provider combinations below.
This uses Anthropic directly when AI_DEFAULT_PROVIDER is not bedrock. For gateway routing, set ANTHROPIC_BASE_URL to the base before /v1.With ANTHROPIC_BASE_URL, Lightdash uses ANTHROPIC_API_KEY as a bearer token and allows the gateway hostname through the sandbox firewall. The gateway must implement Anthropic Messages. See Corporate LLM gateways for authentication and API-path requirements, including separate gateway routes for Data apps.
Codex uses OpenAI directly when AI_DEFAULT_PROVIDER is not bedrock; app generation does not require an Anthropic key in this mode. For gateway routing, set OPENAI_BASE_URL to a gateway that supports the Responses API and the configured Codex model IDs.
Set AI_DEFAULT_PROVIDER=bedrock and choose APPS_CODING_AGENT=claude or APPS_CODING_AGENT=codex. Configure the region, credentials, and model access for that agent using the AWS Bedrock variables. The sandbox firewall allows the provider endpoints required for the selected agent and region.When BEDROCK_BASE_URL is set, the gateway must support the protocol used by each selected consumer. Claude uses Bedrock’s streaming Invoke API, while Codex uses the OpenAI Responses API through a custom gateway provider. Codex requires BEDROCK_API_KEY in gateway mode and sends model IDs with the openai. prefix; the gateway must register or translate those names. See the required gateway APIs matrix.AI_DEFAULT_PROVIDER is an instance-wide setting. Setting it to bedrock also routes AI agents through Bedrock. APPS_CODING_AGENT changes only the coding agent used by data apps and Chart Studio.
The coding-agent credential you configure here builds apps for every user on the instance, so it has to be a credential that can serve all of them: a direct ANTHROPIC_API_KEY or OPENAI_API_KEY, an Anthropic- or OpenAI-compatible gateway, or Bedrock credentials. A credential tied to one person’s individual subscription, such as a Claude Code CLAUDE_CODE_OAUTH_TOKEN, isn’t supported here.To build with your own AI coding agent and your own subscription instead, use local data app development: you edit the app with your own agent and credentials, and the server only runs a deterministic Vite build (no AI) when you upload.
The Lightdash backend and the Data app sandbox make separate connections to the gateway. E2B and Azure Sandboxes receive the configured gateway hostname in their dynamic egress allowlist. AWS Lambda MicroVMs use a pre-provisioned egress connector instead, so LAMBDA_MICROVM_EGRESS_CONNECTOR_ARN must permit the gateway hostname. Docker and Cloud Run follow their existing runtime network policy. See LLM gateway egress.Restart the backend after configuring the runtime and provider. Follow Creating a new app to verify generation.
External connections block private and internal network addresses by default. To let a data app call a trusted internal HTTPS API, set APP_RUNTIME_EXTERNAL_CONNECTION_ALLOWED_PRIVATE_HOST_CIDRS in the Lightdash backend’s deployment environment:
This example allows private addresses in 10.20.0.0/16 for api.internal.example and only 10.30.1.5 for auth.internal.example. Use the hostnames and narrowest address ranges needed by your services. Restart the backend after changing the variable; malformed entries cause a configuration error at startup.
Each entry pairs an exact hostname with an IPv4 or IPv6 CIDR. Do not include a URL scheme, port, path, or wildcard. Hostnames are case-insensitive and a trailing DNS dot is ignored.
Repeat a hostname to approve multiple ranges, for example api.internal.example@10.20.0.0/16,api.internal.example@fd12:3456::/48.
A private destination must match both the hostname and one of its CIDRs. Lightdash checks every DNS answer and rejects the request if any private address is outside the approved ranges. Public addresses keep their existing behavior.
For OAuth 2.0 client credentials, approve the token endpoint’s hostname and private address range separately if it differs from the API host.
The backend must already have network access and DNS resolution for both services. HTTPS remains required, including a valid certificate trusted by the backend. This setting does not create network routes or disable certificate verification.
After restarting, create the connection under Project Settings → Data app connections with the API’s HTTPS base URL, authentication, and allowed methods and paths. Use the wizard’s test request to verify it before linking an app. See testing a connection.
This is an instance-wide trust policy for external connections across all projects. A hostname entry covers every HTTPS port, and explicitly approved ranges can include sensitive internal services, loopback, or cloud metadata addresses. Only approve destinations you trust with data from linked apps, and keep connection methods and paths appropriately restricted.
Leaving the variable unset or empty preserves the existing private-network block. The exception applies only to requests through external connections, including connection tests and OAuth client-credentials token requests. Connection permissions, credential handling, DNS pinning, redirect blocking, request limits, and rate limits remain in place. Direct browser image loading, sandbox networking, and other backend requests are unaffected.If a test returns blocked_ip, check the exact hostname and every address it resolves to from the backend against the configured CIDRs. For Failed to obtain OAuth access token, also check the token endpoint’s entry, network access, certificate, and client credentials.
Chart Studio builds custom chart types on the same runtime, with its own switch. It turns on for every organization once the instance has an Enterprise license and a configured sandbox provider. It doesn’t need APPS_RUNTIME_ENABLED, so you can offer Chart Studio while leaving data apps off. Builds use the same coding-agent provider and bucket as data apps.
Enable the chart library on your self-hosted Lightdash instance, or configure a private mirror for a restricted network. For browsing, installing, and using chart types, see Chart library.Lightdash reads the library from a static website. The public library lives at https://lightdash.github.io/lightdash-library. Instances that cannot reach it can read a mirror of the same files from inside their own network instead.
Enterprise license - LIGHTDASH_LICENSE_KEY must be set on your instance.
Outbound access to the library - the backend fetches the library over https. The browser never talks to the library directly; images and other assets are proxied through the backend.
The library does not need data apps or Chart Studio configured. To also let people edit chart types, configure the Chart Studio runtime.
If LIGHTDASH_ENABLE_FEATURE_FLAGS already contains flags, append chart-type-registry to the comma-separated list. See feature flags.Open the chart library to verify that the backend can fetch the index. If the library cannot be reached, the tab is hidden and already-installed chart types keep working.
Base URL of the chart library the instance reads. Unset uses Lightdash’s public library at https://lightdash.github.io/lightdash-library. Set it to the URL of a private mirror. An empty value turns the library off and hides the Chart library tab.
LIGHTDASH_CHART_REGISTRY_CHANNEL
Which index the instance reads: stable (default) or next, which also lists beta chart types.
LIGHTDASH_CHART_REGISTRY_ALLOW_PRIVATE_HOSTS
Set to true when the library URL resolves to a private or internal address, such as a mirror inside your network. Lightdash otherwise refuses private addresses. Requests still have to use https, redirects are still refused, and the connection stays pinned to the address Lightdash resolved. (default=false)
LIGHTDASH_CHART_REGISTRY_AUTHORIZATION_HEADER
Full Authorization header value sent with every library request, for example Basic <base64> or Bearer <token>. Use it for a mirror that requires authentication. Credentials in the URL (user:pass@host) are not supported. Unset sends no credentials.
LIGHTDASH_CHART_REGISTRY_ALLOW_INSECURE
Allows a plain http library URL and turns off address pinning. For local development fixtures only. Logs a security warning at startup. Do not use it for a mirror; use LIGHTDASH_CHART_REGISTRY_ALLOW_PRIVATE_HOSTS instead. (default=false)
A deployment with no route to the public internet can serve the library from inside its network. The library is a static tree of files, so any artifact proxy or object store that can mirror a website works, for example a remote repository in your artifact manager that caches https://lightdash.github.io/lightdash-library, or a bucket you sync the tree into.Mirror the tree as published. Lightdash reads index.json at the base URL and the chart files beneath it (charts/<slug>/<version>/...), and it verifies every downloaded artifact against the checksums in the index, so a mirror cannot alter chart code without the install failing.Then point the instance at the mirror:
LIGHTDASH_CHART_REGISTRY_URL=https://artifacts.internal.example/lightdash-libraryLIGHTDASH_CHART_REGISTRY_ALLOW_PRIVATE_HOSTS=true# Only if the mirror requires authenticationLIGHTDASH_CHART_REGISTRY_AUTHORIZATION_HEADER="Bearer <token>"
LIGHTDASH_CHART_REGISTRY_ALLOW_PRIVATE_HOSTS is needed whenever the mirror’s hostname resolves to a private address. It lifts only that check. The mirror must still be served over https with a certificate the backend trusts, redirects are refused, and the connection stays pinned to the resolved address. Do not use LIGHTDASH_CHART_REGISTRY_ALLOW_INSECURE for a mirror.
LIGHTDASH_CHART_REGISTRY_AUTHORIZATION_HEADER holds the complete header value. Treat it as a secret: deliver it from your secret store rather than writing it into plain configuration. On Kubernetes, add the key to the Secret your deployment already injects, or use an extraEnv entry with a secretKeyRef.
If the mirror uses a certificate from an internal certificate authority, give the backend the CA bundle with NODE_EXTRA_CA_CERTS. Lightdash does not offer a way to skip certificate validation for the library.
Artifact proxies often rewrite the content type of binary files to application/octet-stream. Lightdash detects PNG, JPEG, WebP and GIF screenshots from their contents, so the library still renders previews behind such a proxy.
Restart the backend after changing any of these variables.
Set LIGHTDASH_CHART_REGISTRY_URL to an empty string. The Chart library tab disappears and no library requests are made. Chart types already installed keep working, and Chart Studio is unaffected.
The Chart library tab doesn’t appear.
Check that LIGHTDASH_LICENSE_KEY is set, chart-type-registry is in LIGHTDASH_ENABLE_FEATURE_FLAGS, and the signed-in user can install chart types in the project. If all of that is in place, the backend could not fetch the library index: check the backend logs for the request to LIGHTDASH_CHART_REGISTRY_URL.The logs say the library host resolves to a private address.
The mirror is on an internal address and LIGHTDASH_CHART_REGISTRY_ALLOW_PRIVATE_HOSTS is not set.The logs show a certificate error against the mirror.
The backend does not trust the mirror’s certificate. Add the issuing CA bundle with NODE_EXTRA_CA_CERTS.Installs fail with a checksum mismatch.
The mirror served a file that differs from the published one. Check that the mirror serves the tree unchanged and is not injecting or rewriting content.
The “Data apps” entry doesn’t appear in the New menu.
Check that APPS_RUNTIME_ENABLED=true, LIGHTDASH_LICENSE_KEY is set, and the signed-in user has the create:DataApp scope.Chart Studio doesn’t appear in the Browse menu.
Check that LIGHTDASH_LICENSE_KEY is set and your sandbox provider has all its required variables, for example E2B_API_KEY with E2B. APPS_RUNTIME_ENABLED isn’t needed.Builds fail immediately with a sandbox creation error.
Check your sandbox provider’s credentials and template configuration — see sandboxes.Builds fail mid-generation with an Anthropic error.
For direct Anthropic, check account usage limits and confirm ANTHROPIC_API_KEY is valid. With ANTHROPIC_BASE_URL, confirm the sandbox can reach the gateway and that it accepts bearer authentication at /v1/messages.Codex builds fail with an OpenAI authentication or model error.
Confirm APPS_CODING_AGENT=codex. For OpenAI, verify OPENAI_API_KEY; if OPENAI_BASE_URL is set, the gateway must support the Responses API and the model IDs shown in the Data app model picker. For a Bedrock gateway, verify BEDROCK_API_KEY, /responses support, and the openai.-prefixed model ID.App queries fail with a warehouse network-policy or IP allowlist error.
A data app’s queries run through the Lightdash backend like any chart query, not from the sandbox or the viewer’s browser. The blocked IP is the outbound address of your Lightdash backend, or of your warehouse worker pods if you run them. Allowlist that address, or the NAT gateway the traffic leaves through, in the warehouse’s network policy.Builds fail mid-generation with a Bedrock error.
Confirm BEDROCK_REGION is set to a region where the selected agent’s model is available, and that either BEDROCK_API_KEY or the BEDROCK_ACCESS_KEY_ID / BEDROCK_SECRET_ACCESS_KEY pair is valid. If you use IAM credentials, the principal must have permission to invoke the selected model. With BEDROCK_BASE_URL, confirm the gateway supports the selected agent’s API and is allowed by the sandbox network policy. Codex requires an exact OpenAI Bedrock model ID with the openai. prefix.
{"docsConfig":{"theme":"mint","$schema":"https://mintlify.com/docs.json","name":"Lightdash","colors":{"primary":"#8072ff","light":"#8072ff","dark":"#8072ff"},"logo":{"light":"https://mintcdn.com/lightdash/NAoHiyWrKI0dLTGZ/logo/light.svg?fit=max\u0026auto=format\u0026n=NAoHiyWrKI0dLTGZ\u0026q=85\u0026s=4b91c8292b732e3daca7558549cf018c","dark":"https://mintcdn.com/lightdash/NAoHiyWrKI0dLTGZ/logo/dark.svg?fit=max\u0026auto=format\u0026n=NAoHiyWrKI0dLTGZ\u0026q=85\u0026s=c15813eedf4ff7a28709d8c163765fd1","href":"https://lightdash.com/"},"favicon":"https://mintcdn.com/lightdash/fPTXVBgl8dEzSm3L/favicon.png?fit=max\u0026auto=format\u0026n=fPTXVBgl8dEzSm3L\u0026q=85\u0026s=ab889bc3b46d3db2eb20c3ff381c098a","api":{"playground":{"display":"simple"}},"appearance":{"default":"light"},"background":{"decoration":"gradient"},"navbar":{"links":[{"href":"https://www.lightdash.com/#","label":"Book a demo"},{"href":"https://app.lightdash.cloud/login","label":"Login"}],"primary":{"type":"button","label":"Start for free","href":"https://www.lightdash.com/start?utm_source=docs\u0026utm_medium=internal_cta\u0026utm_campaign=get_started"}},"footer":{"socials":{"github":"https://github.com/lightdash/lightdash","slack":"https://join.slack.com/t/lightdash-community/shared_invite/zt-3pbwqmq5e-vhTc7HHcS787w618ngoPHA","linkedin":"https://www.linkedin.com/company/lightdash","x":"https://x.com/lightdash_devs"},"links":[{"header":"Lightdash","items":[{"label":"About us","href":"https://www.lightdash.com/about"},{"label":"Community","href":"https://join.slack.com/t/lightdash-community/shared_invite/zt-3pbwqmq5e-vhTc7HHcS787w618ngoPHA"},{"label":"Blog","href":"https://www.lightdash.com/blog"}]}]},"seo":{"indexing":"all"},"fonts":{"heading":{"family":"Space Grotesk","weight":600,"source":"https://fonts.gstatic.com/s/spacegrotesk/v16/V8mDoQDjQSkFtoMM3T6r8E7mPbF4Cw.woff2","format":"woff2"}},"icons":{"library":"tabler"},"styling":{"latex":false},"navigation":{"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"lightdash","hasAudioNarration":false,"actualSubdomain":"lightdash","customDomains":["docs.lightdash.com"],"gitSource":{"type":"github","owner":"lightdash","repo":"mintlify-docs","deployBranch":"main","contentDirectory":"","isPrivate":false,"mountPath":"","label":""},"feedback":{"issues":true,"thumbs":true},"entitlements":{"AI_CHAT":{"status":"ENABLED"},"WEB_MCP":{"status":"ENABLED"},"NARRATION":{"status":"ENABLED"}},"buildId":"6af39488aea70e7e4342682c","clientVersion":"0.0.4102","searchFilterCounts":[{"language":"default","tag":"API","count":896},{"language":"default","tag":"Reference","count":892},{"language":"default","tag":"Docs","count":218},{"language":"default","tag":"API Reference","count":190},{"language":"default","tag":"Projects","count":146},{"language":"default","tag":"v2","count":128},{"language":"default","tag":"Organizations","count":76},{"language":"default","tag":"Integrations","count":52},{"language":"default","tag":"My Account","count":38},{"language":"default","tag":"Explore","count":35}],"searchSettings":{"maxResults":10}},"assistantConfig":{"enableAskAiButton":true,"enableAskAiSearchBar":true,"deflection":{"enabled":true,"type":"email","email":"support@lightdash.com","showHelpButton":false}},"basePath":"","hasChatPermissions":true,"hasWebMcpPermissions":true,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-rbac-roles","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"rbac-expansion","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"full-page-search","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-sso-scim","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-signup","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-dual-write","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-enabled","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"approve-review-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-metadata","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"sso-setup-deadline-banner","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-serve","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"live-agents","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"googleFontsInlined":false},"customCss":[{"filePath":"styles.css","content":"#navigation-items>ul.sidebar-group{margin-top:12px}.feature-badges{display:flex;flex-wrap:wrap;align-items:center;gap:0.375rem;margin:1rem 0;font-size:0.8125rem}.feature-badges:first-child{margin-top:0}#content>.callout:first-child{margin-top:0}.feature-badge-link{display:inline-flex;align-items:center;vertical-align:middle;border:0;border-radius:9999px;text-decoration:none!important;background-image:none!important}.feature-badge-link:hover [data-badge]{background-color:color-mix(in srgb, var(--color-text) 20%, transparent);box-shadow:0 0 0 1px var(--color-text)}.feature-badge-link:active [data-badge]{background-color:color-mix(in srgb, var(--color-text) 35%, transparent);box-shadow:inset 0 0 0 2px var(--color-text);transform:translateY(1px)}.feature-badge-link:focus-visible{outline:2px solid currentColor;outline-offset:3px}.sticky-first-col{overflow-x:auto;position:relative;max-width:100%}.sticky-first-col table{width:max-content;min-width:100%;border-collapse:separate;border-spacing:0}.sticky-first-col table th:first-child,.sticky-first-col table td:first-child{position:sticky;left:0;z-index:1;min-width:260px;max-width:320px;white-space:normal;background-color:#ffffff;box-shadow:inset -1px 0 0 0 rgba(0, 0, 0, 0.08)}.sticky-first-col table thead th:first-child{z-index:2}html.dark .sticky-first-col table th:first-child,html.dark .sticky-first-col table td:first-child{background-color:#0b0b0f;box-shadow:inset -1px 0 0 0 rgba(255, 255, 255, 0.1)}svg.matrix-no{background-color:#d9d5f0}html.dark svg.matrix-no{background-color:#2e2947}.copy-prompt{margin:1.5rem 0}.copy-prompt-btn{display:inline-flex;align-items:center;gap:0.75rem;padding:0.75rem 1.375rem;border:none;border-radius:9999px;background-color:#8072ff;color:#ffffff;font-size:0.875rem;font-weight:500;line-height:1.25rem;cursor:pointer;box-shadow:0 1px 2px rgba(0, 0, 0, 0.08);transition:background-color 150ms ease}.copy-prompt-btn:hover{background-color:#6c5df2}.copy-prompt-btn:focus-visible{outline:2px solid #8072ff;outline-offset:2px}.copy-prompt-label{font-family:ui-monospace, SFMono-Regular, Menlo, Consolas, monospace}.copy-prompt-icons{display:inline-flex;align-items:center;gap:0.3125rem}.copy-prompt-icons svg{width:1.25rem;height:1.25rem;flex:none;transition:transform 300ms ease-out}.copy-prompt-icons svg:nth-child(1){transform:rotate(-6deg)}.copy-prompt-icons svg:nth-child(4){transform:rotate(6deg)}.copy-prompt-btn:hover .copy-prompt-icons svg:nth-child(1){transform:translateX(-4px) rotate(-12deg)}.copy-prompt-btn:hover .copy-prompt-icons svg:nth-child(2){transform:translate(-1px, -1px) rotate(6deg) scale(1.1)}.copy-prompt-btn:hover .copy-prompt-icons svg:nth-child(3){transform:translate(1px, 2px) rotate(-6deg) scale(1.1)}.copy-prompt-btn:hover .copy-prompt-icons svg:nth-child(4){transform:translateX(4px) rotate(12deg)}.copy-prompt-preview{margin:0.625rem 0 0 0.25rem;font-family:ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;font-size:0.8125rem;color:#9ca3af;opacity:0;transform:translateY(4px);transition:opacity 200ms ease,\n transform 200ms ease}html.dark .copy-prompt-preview{color:#6b7280}.copy-prompt-preview.is-copied{color:#5747cf}html.dark .copy-prompt-preview.is-copied{color:#cfc9ff}.copy-prompt:hover .copy-prompt-preview,.copy-prompt:has(.copy-prompt-btn:focus-visible) .copy-prompt-preview,.copy-prompt-preview.is-copied{opacity:1;transform:none}.copy-prompt-sr-status{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0}@media (prefers-reduced-motion: reduce){.copy-prompt-icons svg,.copy-prompt-preview{transition:none}.copy-prompt-preview{transform:none}}.setup-path{--setup-path-line: #e2e2e8;--setup-path-surface: #f5f5f7;--setup-path-ground: #ffffff;--setup-path-ink: #16151d;--setup-path-muted: #5d5c69;--setup-path-faint: #8b8a97;--setup-path-accent: #8072ff;display:grid;gap:1rem;justify-items:start;margin:1.5rem 0;color:var(--setup-path-ink);font-size:1rem;line-height:1.55}html.dark .setup-path{--setup-path-line: #2d2d38;--setup-path-surface: #1b1b22;--setup-path-ground: #0f0f14;--setup-path-ink: #efeff3;--setup-path-muted: #a5a5b2;--setup-path-faint: #777784}.setup-path p{margin:0}.setup-path ol{list-style:none;margin:0;padding:0}.setup-path svg{display:block;flex:none}.setup-path button{font-family:inherit;color:inherit;cursor:pointer}.setup-path-trunk{display:grid;width:100%}.setup-path-trunk>li{position:relative;display:grid;grid-template-columns:2.375rem minmax(0, 1fr);gap:1rem;padding:0 0 1.5rem;margin:0}.setup-path-trunk>li::before{content:\"\";position:absolute;left:calc(1.1875rem - 1px);top:2.375rem;bottom:0;width:2px;background:var(--setup-path-line)}.setup-path-trunk>li.is-done::before{background:var(--setup-path-accent)}.setup-path-trunk>li.is-last{padding-bottom:0}.setup-path-trunk>li.is-last::before{display:none}.setup-path-tile{position:relative;z-index:1;display:grid;place-items:center;width:2.375rem;height:2.375rem;flex:none;border-radius:0.625rem;background:var(--setup-path-surface);transition:transform 180ms ease}.setup-path-tile.is-dark{background:#16151d}.setup-path-trunk>li.is-current>.setup-path-tile{background:var(--setup-path-ink);color:var(--setup-path-ground)}.setup-path-trunk>li.is-pending>.setup-path-tile{background:transparent;border:2px dashed var(--setup-path-line);color:var(--setup-path-faint)}.setup-path-node{display:grid;gap:0.75rem;min-width:0}.setup-path-question{display:flex;align-items:center;min-height:2.375rem;font-size:1.125rem;font-weight:600;line-height:1.3}.setup-path-answer{display:flex;align-items:center;justify-content:space-between;gap:1rem;min-height:2.375rem}.setup-path-answer p{display:grid;min-width:0;line-height:1.3}.setup-path-answer p span{font-size:0.8125rem;color:var(--setup-path-muted)}.setup-path-answer p strong{font-weight:600}.setup-path-change{flex:none;padding:0.25rem 0.625rem;border:1px solid transparent;border-radius:0.5rem;background:none;font-size:0.875rem;font-weight:500;color:var(--setup-path-muted)!important}.setup-path-change:hover{border-color:var(--setup-path-line);color:var(--setup-path-ink)!important}.setup-path-leaves{display:flex;flex-wrap:wrap;gap:0.375rem;margin-top:-0.25rem}.setup-path-leaves a{display:inline-flex;align-items:center;gap:0.375rem;padding:0.1875rem 0.625rem;border-radius:0.5rem;background:var(--setup-path-surface);font-size:0.8125rem;color:inherit;text-decoration:none}.setup-path-leaves a:hover{text-decoration:underline}.setup-path-leaves svg,.setup-path-chevron{color:var(--setup-path-faint)}.setup-path-note{font-size:0.8125rem;color:var(--setup-path-muted)}.setup-path-note a,.setup-path-step-body a{color:var(--setup-path-ink);font-weight:600;text-decoration:underline;text-underline-offset:3px}.setup-path-pending{display:flex;align-items:center;min-height:2.375rem;font-size:0.9375rem;line-height:1.4;color:var(--setup-path-muted)}.setup-path-options{display:grid;grid-template-columns:repeat(var(--setup-path-columns), minmax(0, 1fr));gap:0.625rem}.setup-path-option{display:flex;align-items:center;gap:0.75rem;min-width:0;padding:0.75rem 0.875rem;border:1px solid var(--setup-path-line);border-radius:0.75rem;background:var(--setup-path-ground);text-align:left;transition:border-color 150ms ease,\n background 150ms ease}.setup-path-option:hover{border-color:var(--setup-path-faint)}.setup-path-option:hover .setup-path-tile{transform:scale(1.06)}.setup-path-option:focus-visible,.setup-path-change:focus-visible,.setup-path-ghost:focus-visible,.setup-path-phase li>button:focus-visible{outline:2px solid var(--setup-path-accent);outline-offset:2px}.setup-path-option[aria-checked=\"true\"]{border-color:var(--setup-path-ink);background:var(--setup-path-surface)}.setup-path-option[aria-checked=\"true\"] .setup-path-tile:not(.is-dark){background:var(--setup-path-ground)}.setup-path-option-text{display:grid;flex:1;gap:1px;min-width:0}.setup-path-option-title{display:flex;flex-wrap:wrap;align-items:center;gap:0.1875rem 0.5rem;font-size:0.9375rem;font-weight:600;line-height:1.3}.setup-path-option-hint{font-size:0.8125rem;line-height:1.4;color:var(--setup-path-muted)}.setup-path-tag{padding:1px 0.4375rem;border:1px solid var(--setup-path-line);border-radius:99px;font-size:0.6875rem;font-weight:600;color:var(--setup-path-muted);white-space:nowrap}.setup-path-radio{display:grid;place-items:center;width:1.125rem;height:1.125rem;flex:none;border:1.5px solid var(--setup-path-line);border-radius:50%;color:transparent;transition:background 150ms ease,\n border-color 150ms ease}.setup-path-option[aria-checked=\"true\"] .setup-path-radio{border-color:var(--setup-path-ink);background:var(--setup-path-ink);color:var(--setup-path-ground)}.setup-path-options.is-compact .setup-path-option{padding:0.5625rem 0.75rem}.setup-path-options.is-compact .setup-path-radio{display:none}.setup-path-options.is-compact .setup-path-option-title{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.setup-path-ghost{display:inline-flex;align-items:center;gap:0.375rem;padding:0.375rem 0.75rem;border:1px solid var(--setup-path-line);border-radius:0.5rem;background:none;font-size:0.875rem;font-weight:500}.setup-path-ghost:hover{border-color:var(--setup-path-ink)}.setup-path-result{display:grid;gap:1rem;min-width:0}.setup-path-result-head{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:0.5rem 1rem;min-height:2.375rem}.setup-path-result-title{font-size:1.125rem;font-weight:600}.setup-path-result-title span{margin-left:0.5rem;font-size:0.875rem;font-weight:500;color:var(--setup-path-muted)}.setup-path-phases{display:grid;border-top:1px solid var(--setup-path-line)}.setup-path-phase{display:grid;grid-template-columns:8rem minmax(0, 1fr);gap:0 1rem;padding:0.75rem 0;border-bottom:1px solid var(--setup-path-line)}.setup-path-phase-name{display:flex;align-items:center;align-self:start;gap:0.5rem;padding:0.4375rem 0;font-size:0.9375rem;font-weight:600}.setup-path-phase-name svg{color:var(--setup-path-muted)}.setup-path-phase li{margin:0;padding:0}.setup-path-phase li>button{display:flex;align-items:center;gap:0.75rem;width:100%;min-width:0;padding:0.4375rem 0.5rem;border:0;border-radius:0.5rem;background:none;text-align:left}.setup-path-phase li>button:hover{background:var(--setup-path-surface)}.setup-path-step-number{width:1.25rem;flex:none;font-size:0.8125rem;font-weight:600;font-variant-numeric:tabular-nums;color:var(--setup-path-faint)}.setup-path-step-title{flex:1;min-width:0;font-size:0.9375rem;font-weight:500}.setup-path-chevron{transition:transform 150ms ease}.setup-path-phase li.is-open .setup-path-chevron{transform:rotate(90deg)}.setup-path-step-body{display:grid;gap:0.375rem;justify-items:start;padding:0 0.5rem 0.625rem 2.5rem;font-size:0.875rem;color:var(--setup-path-muted)}.setup-path-step-body a{display:inline-flex;align-items:center;gap:0.3125rem}.setup-path-step-body>span{font-size:0.8125rem;color:var(--setup-path-faint)}@media (max-width: 640px){.setup-path-options{grid-template-columns:1fr}.setup-path-options.is-compact{grid-template-columns:repeat(2, minmax(0, 1fr))}.setup-path-phase{grid-template-columns:1fr;gap:0.25rem}}@media (prefers-reduced-motion: reduce){.setup-path-tile,.setup-path-option,.setup-path-radio,.setup-path-chevron{transition:none}}"},{"filePath":"sidebar-filter.css","content":".nav-filter{--filter-ink: rgb(var(--gray-700));--filter-muted: rgb(var(--gray-500));--filter-breadcrumb: rgb(var(--gray-600) / 0.8);--filter-border: rgb(var(--gray-200));--filter-surface: rgb(var(--background-light));--filter-hover: rgb(var(--gray-600) / 0.05);color:var(--filter-ink);margin-bottom:1rem;font-size:0.875rem;line-height:1.5}html.dark .nav-filter{--filter-ink: rgb(var(--gray-300));--filter-muted: rgb(var(--gray-400));--filter-breadcrumb: rgb(var(--gray-400) / 0.8);--filter-border: rgb(var(--gray-800));--filter-surface: rgb(var(--background-dark));--filter-hover: rgb(var(--gray-200) / 0.05)}.nav-filter-field{display:flex;align-items:center;gap:0.5rem;min-height:2.25rem;padding:0 0.625rem;border:1px solid var(--filter-border);border-radius:0.75rem;background:var(--filter-surface);transition:border-color 150ms ease, box-shadow 150ms ease}.nav-filter-field:focus-within{border-color:rgb(var(--primary));box-shadow:0 0 0 3px rgb(var(--primary) / 0.12)}.nav-filter svg{width:1rem;height:1rem;flex:none;color:var(--filter-muted)}.nav-filter input{width:100%;min-width:0;padding:0.5rem 0;font:inherit;color:inherit;background:transparent;border:0;outline:none}.nav-filter input::placeholder{color:var(--filter-muted)}.nav-filter button{display:grid;place-items:center;width:1.75rem;height:1.75rem;flex:none;border-radius:0.5rem;cursor:pointer}.nav-filter button:hover,.nav-filter-results a:hover{background:var(--filter-hover)}.nav-filter button:focus-visible,.nav-filter-results a:focus-visible{outline:2px solid rgb(var(--primary));outline-offset:2px}.nav-filter-status{padding:0.625rem 0.75rem 0;color:var(--filter-muted);font-size:0.75rem}.nav-filter-status:empty{display:none}.nav-filter-results{margin-top:0.5rem}.nav-filter-results ul{list-style:none;padding:0;margin:0}.nav-filter-results a{display:grid;gap:0.125rem;padding:0.5rem 0.75rem;border-radius:0.75rem;color:inherit;text-decoration:none}.nav-filter-results small{color:var(--filter-breadcrumb);font-size:0.75rem}.nav-filter-results small svg{display:inline;width:0.625rem;height:0.625rem;margin:0 0.125rem;vertical-align:-0.0625rem;color:inherit}.nav-filter-results a[aria-current=\"page\"]{background:rgb(var(--primary) / 0.1);color:rgb(var(--primary))}.nav-filter-empty{padding:0.75rem;color:var(--filter-muted)}.nav-filter [hidden],#navigation-items[hidden]{display:none}#mobile-nav #navigation-items[data-nav-filter-active]>:not(.nav-filter):not([data-nav-filter-controls]){display:none}@media (max-width: 1023px){.nav-filter input{font-size:1rem}.nav-filter-field{min-height:2.75rem}}@media (prefers-reduced-motion: reduce){.nav-filter-field{transition:none}}"}],"page":{"pagePath":"self-host/enterprise-features/data-apps","slug":"/self-host/enterprise-features/data-apps","pageMetadata":{"title":"Self-host data apps","sidebarTitle":"Data apps","description":"Configure a self-hosted Lightdash instance to run data apps","href":"/self-host/enterprise-features/data-apps"},"description":{"compiledSource":"\"use strict\";\nconst {jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n p: \"p\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsx(_components.p, {\n children: \"Configure a self-hosted Lightdash instance to run data apps\"\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx,jsxs:_jsxs}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];const FeatureBadge=({label})=>{const _components={a:`a`,..._provideComponents()},{Badge}=_components;if(!Badge)_missingMdxReference(`Badge`,true);const badges={Experimental:{color:`orange`,icon:`test-pipe-2`,href:`/support/feature-badges#experimental`},Beta:{color:`purple`,icon:`flask`,href:`/support/feature-badges#beta`},Deprecated:{color:`gray`,icon:`haze-moon`,href:`/support/feature-badges#deprecated`},Pro:{color:`blue`,icon:`bolt`,href:`/support/feature-badges#pro`},Enterprise:{color:`blue`,icon:`building-plus`,href:`/support/feature-badges#enterprise`},\"Add-on\":{color:`blue`,icon:`puzzle`,href:`/support/feature-badges#add-ons`},\"Cloud-only\":{color:`blue`,icon:`cloud-bolt`,href:`/support/feature-badges#cloud-only`},\"Self-hosted\":{color:`blue`,icon:`server`,href:`/support/feature-badges#self-hosted`}};const badge=badges[label];if(!badge)throw new Error(`Unknown feature badge: ${label}`);return _jsx(_components.a,{className:`feature-badge-link`,href:badge.href,\"aria-label\":`${label}: read the definition`,children:_jsx(Badge,{icon:badge.icon,color:badge.color,size:`sm`,shape:`pill`,children:label})})};function _createMdxContent(props){const _components={a:`a`,code:`code`,li:`li`,p:`p`,pre:`pre`,span:`span`,strong:`strong`,tbody:`tbody`,td:`td`,th:`th`,thead:`thead`,tr:`tr`,ul:`ul`,..._provideComponents(),...props.components},{CodeBlock,Heading,Table,Warning,_MdxComponentBoundary}=_components;if(!CodeBlock)_missingMdxReference(`CodeBlock`,true);if(!Heading)_missingMdxReference(`Heading`,true);if(!Table)_missingMdxReference(`Table`,true);if(!Warning)_missingMdxReference(`Warning`,true);if(!_MdxComponentBoundary)_missingMdxReference(`_MdxComponentBoundary`,true);return _jsxs(_Fragment,{children:[_jsxs(`div`,{className:`feature-badges`,children:[_jsx(_MdxComponentBoundary,{name:`FeatureBadge`,children:_jsx(FeatureBadge,{label:`Self-hosted`})}),_jsx(_MdxComponentBoundary,{name:`FeatureBadge`,children:_jsx(FeatureBadge,{label:`Enterprise`})})]}),`\n`,_jsxs(_components.p,{children:[`Enable data apps on your self-hosted Lightdash instance by configuring a sandbox provider, a coding-agent provider, and object storage. For creating apps, sharing them, and permissions, see `,_jsx(_components.a,{href:`/data-apps`,children:`Data apps`}),`.`]}),`\n`,_jsxs(_components.p,{children:[`Sandbox providers are configured separately and cover several runtimes — E2B, AWS Lambda MicroVMs, Azure Container Apps, and Google Cloud Run. See `,_jsx(_components.a,{href:`/self-host/customize-deployment/sandboxes`,children:`sandboxes`}),` for the full provider setup; this page covers everything else data apps need.`]}),`\n`,_jsxs(_components.p,{children:[`For custom chart types, see `,_jsx(_components.a,{href:`#chart-studio`,children:`Chart Studio`}),` to configure authoring or `,_jsx(_components.a,{href:`#chart-library`,children:`Chart library`}),` to install published chart types without a sandbox.`]}),`\n`,_jsx(Heading,{level:`2`,id:`prerequisites`,children:`Prerequisites`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Enterprise license`}),` - `,_jsx(_components.code,{children:`LIGHTDASH_LICENSE_KEY`}),` must be set on your instance.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`S3-compatible storage`}),` - a bucket Lightdash can write to for app source and built artifacts. If your instance isn’t already using S3, `,_jsx(_components.a,{href:`/self-host/customize-deployment/configure-lightdash-to-use-external-object-storage`,children:`set that up first`}),`.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`A configured sandbox provider`}),` - see `,_jsx(_components.a,{href:`/self-host/customize-deployment/sandboxes`,children:`sandboxes`}),`.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`A coding-agent provider`}),` - Anthropic, OpenAI, or an `,_jsx(_components.a,{href:`https://aws.amazon.com/bedrock/`,children:`AWS Bedrock`}),` account with access to the model used by your selected agent. It serves every user’s builds, so it can’t be tied to one person’s subscription — see `,_jsx(_components.a,{href:`#building-with-your-own-subscription`,children:`building with your own subscription`}),`.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`A headless browser`}),` (optional) - needed for the app image in Slack build notifications and link previews. See `,_jsx(_components.a,{href:`/self-host/customize-deployment/enable-headless-browser-for-lightdash`,children:`enabling the headless browser`}),`.`]}),`\n`]}),`\n`,_jsx(Heading,{level:`2`,id:`configuration`,children:`Configuration`}),`\n`,_jsx(_components.p,{children:`Enable the runtime in your deployment:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`APPS_RUNTIME_ENABLED`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`true`})]}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`Data apps use your instance’s S3 configuration. Set `,_jsx(_components.code,{children:`APPS_S3_BUCKET`}),` if you want a dedicated bucket for app source and built artifacts. See the `,_jsx(_components.a,{href:`/self-host/customize-deployment/environment-variables#data-apps-runtime`,children:`data apps runtime variables`}),` for storage overrides and the full configuration reference.`]}),`\n`,_jsx(_components.p,{children:`Choose one of the coding-agent and provider combinations below.`}),`\n`,_jsx(Heading,{level:`3`,id:`claude-through-anthropic-default`,children:`Claude through Anthropic (default)`}),`\n`,_jsx(_components.p,{children:`Configure Claude with an Anthropic API key:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`2`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`2`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`APPS_CODING_AGENT`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`claude`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`ANTHROPIC_API_KEY`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=\u003c`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`your-anthropic-api-key`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`>`})]}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`This uses Anthropic directly when `,_jsx(_components.code,{children:`AI_DEFAULT_PROVIDER`}),` is not `,_jsx(_components.code,{children:`bedrock`}),`. For gateway routing, set `,_jsx(_components.code,{children:`ANTHROPIC_BASE_URL`}),` to the base before `,_jsx(_components.code,{children:`/v1`}),`.`]}),`\n`,_jsxs(_components.p,{children:[`With `,_jsx(_components.code,{children:`ANTHROPIC_BASE_URL`}),`, Lightdash uses `,_jsx(_components.code,{children:`ANTHROPIC_API_KEY`}),` as a bearer token and allows the gateway hostname through the sandbox firewall. The gateway must implement Anthropic Messages. See `,_jsx(_components.a,{href:`/self-host/enterprise-features/ai-agents#corporate-llm-gateways`,children:`Corporate LLM gateways`}),` for authentication and API-path requirements, including `,_jsx(_components.a,{href:`/self-host/enterprise-features/ai-agents#separate-gateway-routes-for-data-apps`,children:`separate gateway routes for Data apps`}),`.`]}),`\n`,_jsx(Heading,{level:`3`,id:`codex-through-openai`,children:`Codex through OpenAI`}),`\n`,_jsx(_components.p,{children:`Configure Codex with an OpenAI API key:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`2`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`2`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`APPS_CODING_AGENT`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`codex`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`OPENAI_API_KEY`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=\u003c`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`your-openai-api-key`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`>`})]}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`Codex uses OpenAI directly when `,_jsx(_components.code,{children:`AI_DEFAULT_PROVIDER`}),` is not `,_jsx(_components.code,{children:`bedrock`}),`; app generation does not require an Anthropic key in this mode. For gateway routing, set `,_jsx(_components.code,{children:`OPENAI_BASE_URL`}),` to a gateway that supports the Responses API and the configured Codex model IDs.`]}),`\n`,_jsx(Heading,{level:`3`,id:`claude-or-codex-through-bedrock`,children:`Claude or Codex through Bedrock`}),`\n`,_jsxs(_components.p,{children:[`Set `,_jsx(_components.code,{children:`AI_DEFAULT_PROVIDER=bedrock`}),` and choose `,_jsx(_components.code,{children:`APPS_CODING_AGENT=claude`}),` or `,_jsx(_components.code,{children:`APPS_CODING_AGENT=codex`}),`. Configure the region, credentials, and model access for that agent using the `,_jsx(_components.a,{href:`/self-host/customize-deployment/environment-variables#aws-bedrock-configuration`,children:`AWS Bedrock variables`}),`. The sandbox firewall allows the provider endpoints required for the selected agent and region.`]}),`\n`,_jsxs(_components.p,{children:[`When `,_jsx(_components.code,{children:`BEDROCK_BASE_URL`}),` is set, the gateway must support the protocol used by each selected consumer. Claude uses Bedrock’s streaming Invoke API, while Codex uses the OpenAI Responses API through a custom gateway provider. Codex requires `,_jsx(_components.code,{children:`BEDROCK_API_KEY`}),` in gateway mode and sends model IDs with the `,_jsx(_components.code,{children:`openai.`}),` prefix; the gateway must register or translate those names. See the `,_jsx(_components.a,{href:`/self-host/enterprise-features/ai-agents#required-gateway-apis`,children:`required gateway APIs`}),` matrix.`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.code,{children:`AI_DEFAULT_PROVIDER`}),` is an instance-wide setting. Setting it to `,_jsx(_components.code,{children:`bedrock`}),` also routes AI agents through Bedrock. `,_jsx(_components.code,{children:`APPS_CODING_AGENT`}),` changes only the coding agent used by data apps and Chart Studio.`]}),`\n`,_jsx(Heading,{level:`3`,id:`building-with-your-own-subscription`,children:`Building with your own subscription`}),`\n`,_jsxs(_components.p,{children:[`The coding-agent credential you configure here builds apps for every user on the instance, so it has to be a credential that can serve all of them: a direct `,_jsx(_components.code,{children:`ANTHROPIC_API_KEY`}),` or `,_jsx(_components.code,{children:`OPENAI_API_KEY`}),`, an Anthropic- or OpenAI-compatible gateway, or Bedrock credentials. A credential tied to one person’s individual subscription, such as a Claude Code `,_jsx(_components.code,{children:`CLAUDE_CODE_OAUTH_TOKEN`}),`, isn’t supported here.`]}),`\n`,_jsxs(_components.p,{children:[`To build with your own AI coding agent and your own subscription instead, use `,_jsx(_components.a,{href:`/workflow/local-data-app-development#creating-a-new-app-locally`,children:`local data app development`}),`: you edit the app with your own agent and credentials, and the server only runs a deterministic Vite build (no AI) when you upload.`]}),`\n`,_jsx(Heading,{level:`3`,id:`gateway-networking`,children:`Gateway networking`}),`\n`,_jsxs(_components.p,{children:[`The Lightdash backend and the Data app sandbox make separate connections to the gateway. E2B and Azure Sandboxes receive the configured gateway hostname in their dynamic egress allowlist. AWS Lambda MicroVMs use a pre-provisioned egress connector instead, so `,_jsx(_components.code,{children:`LAMBDA_MICROVM_EGRESS_CONNECTOR_ARN`}),` must permit the gateway hostname. Docker and Cloud Run follow their existing runtime network policy. See `,_jsx(_components.a,{href:`/self-host/customize-deployment/sandboxes#llm-gateway-egress`,children:`LLM gateway egress`}),`.`]}),`\n`,_jsxs(_components.p,{children:[`Restart the backend after configuring the runtime and provider. Follow `,_jsx(_components.a,{href:`/data-apps#creating-a-new-app`,children:`Creating a new app`}),` to verify generation.`]}),`\n`,_jsx(Heading,{level:`3`,id:`private-network-external-connections`,children:`Private-network external connections`}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.a,{href:`/data-apps/external-connections`,children:`External connections`}),` block private and internal network addresses by default. To let a data app call a trusted internal HTTPS API, set `,_jsx(_components.code,{children:`APP_RUNTIME_EXTERNAL_CONNECTION_ALLOWED_PRIVATE_HOST_CIDRS`}),` in the Lightdash backend’s deployment environment:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`APP_RUNTIME_EXTERNAL_CONNECTION_ALLOWED_PRIVATE_HOST_CIDRS`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"api.internal.example@10.20.0.0/16,auth.internal.example@10.30.1.5/32\"`})]}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`This example allows private addresses in `,_jsx(_components.code,{children:`10.20.0.0/16`}),` for `,_jsx(_components.code,{children:`api.internal.example`}),` and only `,_jsx(_components.code,{children:`10.30.1.5`}),` for `,_jsx(_components.code,{children:`auth.internal.example`}),`. Use the hostnames and narrowest address ranges needed by your services. Restart the backend after changing the variable; malformed entries cause a configuration error at startup.`]}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsx(_components.li,{children:`Each entry pairs an exact hostname with an IPv4 or IPv6 CIDR. Do not include a URL scheme, port, path, or wildcard. Hostnames are case-insensitive and a trailing DNS dot is ignored.`}),`\n`,_jsxs(_components.li,{children:[`Repeat a hostname to approve multiple ranges, for example `,_jsx(_components.code,{children:`api.internal.example@10.20.0.0/16,api.internal.example@fd12:3456::/48`}),`.`]}),`\n`,_jsx(_components.li,{children:`A private destination must match both the hostname and one of its CIDRs. Lightdash checks every DNS answer and rejects the request if any private address is outside the approved ranges. Public addresses keep their existing behavior.`}),`\n`,_jsx(_components.li,{children:`For OAuth 2.0 client credentials, approve the token endpoint’s hostname and private address range separately if it differs from the API host.`}),`\n`,_jsx(_components.li,{children:`The backend must already have network access and DNS resolution for both services. HTTPS remains required, including a valid certificate trusted by the backend. This setting does not create network routes or disable certificate verification.`}),`\n`]}),`\n`,_jsxs(_components.p,{children:[`After restarting, create the connection under `,_jsx(_components.strong,{children:`Project Settings → Data app connections`}),` with the API’s HTTPS base URL, authentication, and allowed methods and paths. Use the wizard’s test request to verify it before linking an app. See `,_jsx(_components.a,{href:`/data-apps/external-connections#testing-a-connection`,children:`testing a connection`}),`.`]}),`\n`,_jsx(Warning,{children:_jsx(_components.p,{children:`This is an instance-wide trust policy for external connections across all projects. A hostname entry covers every HTTPS port, and explicitly approved ranges can include sensitive internal services, loopback, or cloud metadata addresses. Only approve destinations you trust with data from linked apps, and keep connection methods and paths appropriately restricted.`})}),`\n`,_jsx(_components.p,{children:`Leaving the variable unset or empty preserves the existing private-network block. The exception applies only to requests through external connections, including connection tests and OAuth client-credentials token requests. Connection permissions, credential handling, DNS pinning, redirect blocking, request limits, and rate limits remain in place. Direct browser image loading, sandbox networking, and other backend requests are unaffected.`}),`\n`,_jsxs(_components.p,{children:[`If a test returns `,_jsx(_components.code,{children:`blocked_ip`}),`, check the exact hostname and every address it resolves to from the backend against the configured CIDRs. For `,_jsx(_components.code,{children:`Failed to obtain OAuth access token`}),`, also check the token endpoint’s entry, network access, certificate, and client credentials.`]}),`\n`,_jsx(Heading,{level:`2`,id:`chart-studio`,children:`Chart Studio`}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.a,{href:`/visualizations/chart-studio`,children:`Chart Studio`}),` builds custom chart types on the same runtime, with its own switch. It turns on for every organization once the instance has an Enterprise license and a `,_jsx(_components.a,{href:`/self-host/customize-deployment/sandboxes`,children:`configured sandbox provider`}),`. It doesn’t need `,_jsx(_components.code,{children:`APPS_RUNTIME_ENABLED`}),`, so you can offer Chart Studio while leaving data apps off. Builds use the same coding-agent provider and bucket as data apps.`]}),`\n`,_jsx(Heading,{level:`2`,id:`chart-library`,children:`Chart library`}),`\n`,_jsxs(_components.p,{children:[`Enable the chart library on your self-hosted Lightdash instance, or configure a private mirror for a restricted network. For browsing, installing, and using chart types, see `,_jsx(_components.a,{href:`/visualizations/chart-library`,children:`Chart library`}),`.`]}),`\n`,_jsxs(_components.p,{children:[`Lightdash reads the library from a static website. The public library lives at `,_jsx(_components.code,{children:`https://lightdash.github.io/lightdash-library`}),`. Instances that cannot reach it can read a mirror of the same files from inside their own network instead.`]}),`\n`,_jsx(Heading,{level:`3`,id:`chart-library-prerequisites`,children:`Chart library prerequisites`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Enterprise license`}),` - `,_jsx(_components.code,{children:`LIGHTDASH_LICENSE_KEY`}),` must be set on your instance.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Outbound access to the library`}),` - the backend fetches the library over `,_jsx(_components.code,{children:`https`}),`. The browser never talks to the library directly; images and other assets are proxied through the backend.`]}),`\n`]}),`\n`,_jsxs(_components.p,{children:[`The library does not need data apps or Chart Studio configured. To also let people edit chart types, configure the `,_jsx(_components.a,{href:`#chart-studio`,children:`Chart Studio runtime`}),`.`]}),`\n`,_jsx(Heading,{level:`3`,id:`enable-the-chart-library`,children:`Enable the chart library`}),`\n`,_jsx(_components.p,{children:`Add the flag to your deployment and restart the backend:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`LIGHTDASH_ENABLE_FEATURE_FLAGS`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`chart-type-registry`})]}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`If `,_jsx(_components.code,{children:`LIGHTDASH_ENABLE_FEATURE_FLAGS`}),` already contains flags, append `,_jsx(_components.code,{children:`chart-type-registry`}),` to the comma-separated list. See `,_jsx(_components.a,{href:`/self-host/customize-deployment/environment-variables#feature-flags`,children:`feature flags`}),`.`]}),`\n`,_jsxs(_components.p,{children:[`Open the `,_jsx(_components.a,{href:`/visualizations/chart-library#finding-the-library`,children:`chart library`}),` to verify that the backend can fetch the index. If the library cannot be reached, the tab is hidden and already-installed chart types keep working.`]}),`\n`,_jsx(Heading,{level:`3`,id:`chart-library-configuration`,children:`Chart library configuration`}),`\n`,_jsxs(Table,{children:[_jsx(_components.thead,{children:_jsxs(_components.tr,{children:[_jsx(_components.th,{style:{textAlign:`left`},children:`Variable`}),_jsx(_components.th,{style:{textAlign:`left`},children:`Description`})]})}),_jsxs(_components.tbody,{children:[_jsxs(_components.tr,{children:[_jsx(_components.td,{style:{textAlign:`left`},children:_jsx(_components.code,{children:`LIGHTDASH_CHART_REGISTRY_URL`})}),_jsxs(_components.td,{style:{textAlign:`left`},children:[`Base URL of the chart library the instance reads. Unset uses Lightdash’s public library at `,_jsx(_components.code,{children:`https://lightdash.github.io/lightdash-library`}),`. Set it to the URL of a `,_jsx(_components.a,{href:`/self-host/enterprise-features/data-apps#mirror-the-chart-library`,children:`private mirror`}),`. An empty value turns the library off and hides the `,_jsx(_components.strong,{children:`Chart library`}),` tab.`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{style:{textAlign:`left`},children:_jsx(_components.code,{children:`LIGHTDASH_CHART_REGISTRY_CHANNEL`})}),_jsxs(_components.td,{style:{textAlign:`left`},children:[`Which index the instance reads: `,_jsx(_components.code,{children:`stable`}),` (default) or `,_jsx(_components.code,{children:`next`}),`, which also lists beta chart types.`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{style:{textAlign:`left`},children:_jsx(_components.code,{children:`LIGHTDASH_CHART_REGISTRY_ALLOW_PRIVATE_HOSTS`})}),_jsxs(_components.td,{style:{textAlign:`left`},children:[`Set to `,_jsx(_components.code,{children:`true`}),` when the library URL resolves to a private or internal address, such as a mirror inside your network. Lightdash otherwise refuses private addresses. Requests still have to use `,_jsx(_components.code,{children:`https`}),`, redirects are still refused, and the connection stays pinned to the address Lightdash resolved. (default=false)`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{style:{textAlign:`left`},children:_jsx(_components.code,{children:`LIGHTDASH_CHART_REGISTRY_AUTHORIZATION_HEADER`})}),_jsxs(_components.td,{style:{textAlign:`left`},children:[`Full `,_jsx(_components.code,{children:`Authorization`}),` header value sent with every library request, for example `,_jsx(_components.code,{children:`Basic \u003cbase64>`}),` or `,_jsx(_components.code,{children:`Bearer \u003ctoken>`}),`. Use it for a mirror that requires authentication. Credentials in the URL (`,_jsx(_components.code,{children:`user:pass@host`}),`) are not supported. Unset sends no credentials.`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{style:{textAlign:`left`},children:_jsx(_components.code,{children:`LIGHTDASH_CHART_REGISTRY_ALLOW_INSECURE`})}),_jsxs(_components.td,{style:{textAlign:`left`},children:[`Allows a plain `,_jsx(_components.code,{children:`http`}),` library URL and turns off address pinning. For local development fixtures only. Logs a security warning at startup. Do not use it for a mirror; use `,_jsx(_components.code,{children:`LIGHTDASH_CHART_REGISTRY_ALLOW_PRIVATE_HOSTS`}),` instead. (default=false)`]})]})]})]}),`\n`,_jsx(Heading,{level:`3`,id:`mirror-the-chart-library`,children:`Mirror the chart library`}),`\n`,_jsxs(_components.p,{children:[`A deployment with no route to the public internet can serve the library from inside its network. The library is a static tree of files, so any artifact proxy or object store that can mirror a website works, for example a remote repository in your artifact manager that caches `,_jsx(_components.code,{children:`https://lightdash.github.io/lightdash-library`}),`, or a bucket you sync the tree into.`]}),`\n`,_jsxs(_components.p,{children:[`Mirror the tree as published. Lightdash reads `,_jsx(_components.code,{children:`index.json`}),` at the base URL and the chart files beneath it (`,_jsx(_components.code,{children:`charts/\u003cslug>/\u003cversion>/...`}),`), and it verifies every downloaded artifact against the checksums in the index, so a mirror cannot alter chart code without the install failing.`]}),`\n`,_jsx(_components.p,{children:`Then point the instance at the mirror:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`4`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`4`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`LIGHTDASH_CHART_REGISTRY_URL`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`https://artifacts.internal.example/lightdash-library`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`LIGHTDASH_CHART_REGISTRY_ALLOW_PRIVATE_HOSTS`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`true`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:`# Only if the mirror requires authentication`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`LIGHTDASH_CHART_REGISTRY_AUTHORIZATION_HEADER`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"Bearer \u003ctoken>\"`})]}),`\n`]})})}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.code,{children:`LIGHTDASH_CHART_REGISTRY_ALLOW_PRIVATE_HOSTS`}),` is needed whenever the mirror’s hostname resolves to a private address. It lifts only that check. The mirror must still be served over `,_jsx(_components.code,{children:`https`}),` with a certificate the backend trusts, redirects are refused, and the connection stays pinned to the resolved address. Do not use `,_jsx(_components.code,{children:`LIGHTDASH_CHART_REGISTRY_ALLOW_INSECURE`}),` for a mirror.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.code,{children:`LIGHTDASH_CHART_REGISTRY_AUTHORIZATION_HEADER`}),` holds the complete header value. Treat it as a secret: deliver it from your secret store rather than writing it into plain configuration. On Kubernetes, add the key to the Secret your deployment already injects, or use an `,_jsx(_components.code,{children:`extraEnv`}),` entry with a `,_jsx(_components.code,{children:`secretKeyRef`}),`.`]}),`\n`,_jsxs(_components.li,{children:[`If the mirror uses a certificate from an internal certificate authority, give the backend the CA bundle with `,_jsx(_components.code,{children:`NODE_EXTRA_CA_CERTS`}),`. Lightdash does not offer a way to skip certificate validation for the library.`]}),`\n`,_jsxs(_components.li,{children:[`Artifact proxies often rewrite the content type of binary files to `,_jsx(_components.code,{children:`application/octet-stream`}),`. Lightdash detects PNG, JPEG, WebP and GIF screenshots from their contents, so the library still renders previews behind such a proxy.`]}),`\n`]}),`\n`,_jsx(_components.p,{children:`Restart the backend after changing any of these variables.`}),`\n`,_jsx(Heading,{level:`3`,id:`turn-off-the-chart-library`,children:`Turn off the chart library`}),`\n`,_jsxs(_components.p,{children:[`Set `,_jsx(_components.code,{children:`LIGHTDASH_CHART_REGISTRY_URL`}),` to an empty string. The `,_jsx(_components.strong,{children:`Chart library`}),` tab disappears and no library requests are made. Chart types already installed keep working, and Chart Studio is unaffected.`]}),`\n`,_jsx(Heading,{level:`3`,id:`troubleshoot-the-chart-library`,children:`Troubleshoot the chart library`}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`The Chart library tab doesn’t appear.`}),`\nCheck that `,_jsx(_components.code,{children:`LIGHTDASH_LICENSE_KEY`}),` is set, `,_jsx(_components.code,{children:`chart-type-registry`}),` is in `,_jsx(_components.code,{children:`LIGHTDASH_ENABLE_FEATURE_FLAGS`}),`, and the signed-in user can install chart types in the project. If all of that is in place, the backend could not fetch the library index: check the backend logs for the request to `,_jsx(_components.code,{children:`LIGHTDASH_CHART_REGISTRY_URL`}),`.`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`The logs say the library host resolves to a private address.`}),`\nThe mirror is on an internal address and `,_jsx(_components.code,{children:`LIGHTDASH_CHART_REGISTRY_ALLOW_PRIVATE_HOSTS`}),` is not set.`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`The logs show a certificate error against the mirror.`}),`\nThe backend does not trust the mirror’s certificate. Add the issuing CA bundle with `,_jsx(_components.code,{children:`NODE_EXTRA_CA_CERTS`}),`.`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Installs fail with a checksum mismatch.`}),`\nThe mirror served a file that differs from the published one. Check that the mirror serves the tree unchanged and is not injecting or rewriting content.`]}),`\n`,_jsx(Heading,{level:`2`,id:`provider-usage`,children:`Provider usage`}),`\n`,_jsx(_components.p,{children:`Your sandbox and model providers bill your accounts directly. Monitor usage and configure limits with those providers before rolling out data apps.`}),`\n`,_jsx(Heading,{level:`2`,id:`troubleshooting`,children:`Troubleshooting`}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`The “Data apps” entry doesn’t appear in the New menu.`}),`\nCheck that `,_jsx(_components.code,{children:`APPS_RUNTIME_ENABLED=true`}),`, `,_jsx(_components.code,{children:`LIGHTDASH_LICENSE_KEY`}),` is set, and the signed-in user has the `,_jsx(_components.code,{children:`create:DataApp`}),` scope.`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Chart Studio doesn’t appear in the Browse menu.`}),`\nCheck that `,_jsx(_components.code,{children:`LIGHTDASH_LICENSE_KEY`}),` is set and your `,_jsx(_components.a,{href:`/self-host/customize-deployment/sandboxes`,children:`sandbox provider`}),` has all its required variables, for example `,_jsx(_components.code,{children:`E2B_API_KEY`}),` with E2B. `,_jsx(_components.code,{children:`APPS_RUNTIME_ENABLED`}),` isn’t needed.`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Builds fail immediately with a sandbox creation error.`}),`\nCheck your sandbox provider’s credentials and template configuration — see `,_jsx(_components.a,{href:`/self-host/customize-deployment/sandboxes`,children:`sandboxes`}),`.`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Builds fail mid-generation with an Anthropic error.`}),`\nFor direct Anthropic, check account usage limits and confirm `,_jsx(_components.code,{children:`ANTHROPIC_API_KEY`}),` is valid. With `,_jsx(_components.code,{children:`ANTHROPIC_BASE_URL`}),`, confirm the sandbox can reach the gateway and that it accepts bearer authentication at `,_jsx(_components.code,{children:`/v1/messages`}),`.`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Codex builds fail with an OpenAI authentication or model error.`}),`\nConfirm `,_jsx(_components.code,{children:`APPS_CODING_AGENT=codex`}),`. For OpenAI, verify `,_jsx(_components.code,{children:`OPENAI_API_KEY`}),`; if `,_jsx(_components.code,{children:`OPENAI_BASE_URL`}),` is set, the gateway must support the Responses API and the model IDs shown in the Data app model picker. For a Bedrock gateway, verify `,_jsx(_components.code,{children:`BEDROCK_API_KEY`}),`, `,_jsx(_components.code,{children:`/responses`}),` support, and the `,_jsx(_components.code,{children:`openai.`}),`-prefixed model ID.`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`App queries fail with a warehouse network-policy or IP allowlist error.`}),`\nA data app’s queries run through the Lightdash backend like any chart query, not from the sandbox or the viewer’s browser. The blocked IP is the outbound address of your Lightdash backend, or of your `,_jsx(_components.a,{href:`/self-host/nats-workers/warehouse-workers`,children:`warehouse worker`}),` pods if you run them. Allowlist that address, or the NAT gateway the traffic leaves through, in the warehouse’s network policy.`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Builds fail mid-generation with a Bedrock error.`}),`\nConfirm `,_jsx(_components.code,{children:`BEDROCK_REGION`}),` is set to a region where the selected agent’s model is available, and that either `,_jsx(_components.code,{children:`BEDROCK_API_KEY`}),` or the `,_jsx(_components.code,{children:`BEDROCK_ACCESS_KEY_ID`}),` / `,_jsx(_components.code,{children:`BEDROCK_SECRET_ACCESS_KEY`}),` pair is valid. If you use IAM credentials, the principal must have permission to invoke the selected model. With `,_jsx(_components.code,{children:`BEDROCK_BASE_URL`}),`, confirm the gateway supports the selected agent’s API and is allowed by the sandbox network policy. Codex requires an exact OpenAI Bedrock model ID with the `,_jsx(_components.code,{children:`openai.`}),` prefix.`]})]})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{FeatureBadge,default:MDXContent};function _missingMdxReference(id,component){throw new Error(`Expected `+(component?`component`:`object`)+\" `\"+id+\"` to be defined: you likely forgot to import, pass, or provide it.\")}","frontmatter":{},"scope":{"config":{},"pageMetadata":{"title":"Self-host data apps","sidebarTitle":"Data apps","description":"Configure a self-hosted Lightdash instance to run data apps","href":"/self-host/enterprise-features/data-apps"}}},"mdxSourceWithNoJs":null,"noJsSplices":[[148,1260,")=>null;function _cr"]]},"mdxExtracts":{"tableOfContents":[{"title":"Prerequisites","slug":"prerequisites","depth":2,"children":[]},{"title":"Configuration","slug":"configuration","depth":2,"children":[{"title":"Claude through Anthropic (default)","slug":"claude-through-anthropic-default","depth":3,"children":[]},{"title":"Codex through OpenAI","slug":"codex-through-openai","depth":3,"children":[]},{"title":"Claude or Codex through Bedrock","slug":"claude-or-codex-through-bedrock","depth":3,"children":[]},{"title":"Building with your own subscription","slug":"building-with-your-own-subscription","depth":3,"children":[]},{"title":"Gateway networking","slug":"gateway-networking","depth":3,"children":[]},{"title":"Private-network external connections","slug":"private-network-external-connections","depth":3,"children":[]}]},{"title":"Chart Studio","slug":"chart-studio","depth":2,"children":[]},{"title":"Chart library","slug":"chart-library","depth":2,"children":[{"title":"Chart library prerequisites","slug":"chart-library-prerequisites","depth":3,"children":[]},{"title":"Enable the chart library","slug":"enable-the-chart-library","depth":3,"children":[]},{"title":"Chart library configuration","slug":"chart-library-configuration","depth":3,"children":[]},{"title":"Mirror the chart library","slug":"mirror-the-chart-library","depth":3,"children":[]},{"title":"Turn off the chart library","slug":"turn-off-the-chart-library","depth":3,"children":[]},{"title":"Troubleshoot the chart library","slug":"troubleshoot-the-chart-library","depth":3,"children":[]}]},{"title":"Provider usage","slug":"provider-usage","depth":2,"children":[]},{"title":"Troubleshooting","slug":"troubleshooting","depth":2,"children":[]}],"codeExamples":{}},"jsLinks":["/_mintlify/custom/lightdash/d0a9cf4e6619eae5/analytics.js","/_mintlify/custom/lightdash/09fccb112e45cce5/sidebar-filter.js","/_mintlify/custom/lightdash/64eb1617514bf8f9/sidebar-navigation.js"],"subdomain":"lightdash","siteName":"Lightdash","title":"Self-host data apps - Lightdash","navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-11-10T16:01:59.030Z","originalFileLocation":"self-host/enterprise-features/data-apps.mdx"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"light\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"Configure a self-hosted Lightdash instance to run data apps\">\u003cmeta data-mint-head name=\"application-name\" content=\"Lightdash\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/lightdash/x1yO_UZNDKcOd4RY/_generated/favicon/android-chrome-192x192.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"/mintlify-assets/_mintlify/favicons/lightdash/x1yO_UZNDKcOd4RY/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/lightdash/x1yO_UZNDKcOd4RY/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/lightdash/x1yO_UZNDKcOd4RY/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/lightdash/x1yO_UZNDKcOd4RY/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/lightdash/x1yO_UZNDKcOd4RY/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/lightdash/x1yO_UZNDKcOd4RY/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/lightdash/x1yO_UZNDKcOd4RY/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/lightdash/x1yO_UZNDKcOd4RY/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"Self-host data apps - Lightdash\">\u003cmeta data-mint-head property=\"og:description\" content=\"Configure a self-hosted Lightdash instance to run data apps\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"Lightdash\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://docs.lightdash.com/self-host/enterprise-features/data-apps\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://lightdash.mintlify.site/_mintlify/api/og/v2?division=Enterprise+features\u0026amp;title=Self-host+data+apps\u0026amp;description=Configure+a+self-hosted+Lightdash+instance+to+run+data+apps\u0026amp;theme=2e2830855f4456878570ebd9\u0026amp;signature=755d2afe07bc21b28741ca2d6c8da0a992c24a74b3905d1189073d17a35716e9\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"Self-host data apps - Lightdash\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"Configure a self-hosted Lightdash instance to run data apps\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://lightdash.mintlify.site/_mintlify/api/og/v2?division=Enterprise+features\u0026amp;title=Self-host+data+apps\u0026amp;description=Configure+a+self-hosted+Lightdash+instance+to+run+data+apps\u0026amp;theme=2e2830855f4456878570ebd9\u0026amp;signature=755d2afe07bc21b28741ca2d6c8da0a992c24a74b3905d1189073d17a35716e9\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"/mintlify-assets/_mintlify/favicons/lightdash/x1yO_UZNDKcOd4RY/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"Lightdash\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#8072ff\">\u003clink data-mint-head rel=\"canonical\" href=\"https://docs.lightdash.com/self-host/enterprise-features/data-apps\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/self-host/enterprise-features/data-apps.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://docs.lightdash.com/#organization\",\"name\":\"Lightdash\",\"url\":\"https://docs.lightdash.com\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://mintcdn.com/lightdash/NAoHiyWrKI0dLTGZ/logo/light.svg?fit=max\u0026auto=format\u0026n=NAoHiyWrKI0dLTGZ\u0026q=85\u0026s=4b91c8292b732e3daca7558549cf018c\"}},{\"@type\":\"WebSite\",\"@id\":\"https://docs.lightdash.com#website\",\"name\":\"Lightdash\",\"url\":\"https://docs.lightdash.com\",\"publisher\":{\"@id\":\"https://docs.lightdash.com/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://docs.lightdash.com/self-host/enterprise-features/data-apps#webpage\",\"url\":\"https://docs.lightdash.com/self-host/enterprise-features/data-apps\",\"name\":\"Self-host data apps\",\"description\":\"Configure a self-hosted Lightdash instance to run data apps\",\"dateModified\":\"2026-11-10T16:01:59.030Z\",\"isPartOf\":{\"@id\":\"https://docs.lightdash.com#website\"},\"breadcrumb\":{\"@id\":\"https://docs.lightdash.com/self-host/enterprise-features/data-apps#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://docs.lightdash.com/self-host/enterprise-features/data-apps#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Self-host\",\"item\":\"https://docs.lightdash.com/self-host\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Enterprise features\",\"item\":\"https://docs.lightdash.com/self-host/enterprise-features\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Self-host data apps\",\"item\":\"https://docs.lightdash.com/self-host/enterprise-features/data-apps\"}]},{\"@type\":[\"Article\",\"TechArticle\"],\"@id\":\"https://docs.lightdash.com/self-host/enterprise-features/data-apps#article\",\"headline\":\"Self-host data apps\",\"name\":\"Self-host data apps\",\"description\":\"Configure a self-hosted Lightdash instance to run data apps\",\"url\":\"https://docs.lightdash.com/self-host/enterprise-features/data-apps\",\"mainEntityOfPage\":{\"@id\":\"https://docs.lightdash.com/self-host/enterprise-features/data-apps#webpage\"},\"dateModified\":\"2026-11-10T16:01:59.030Z\",\"publisher\":{\"@id\":\"https://docs.lightdash.com/#organization\"},\"isPartOf\":{\"@id\":\"https://docs.lightdash.com#website\"}}]}\u003c/script>\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"name\":\"Lightdash\",\"publisher\":{\"@type\":\"Organization\",\"name\":\"Lightdash\"},\"provider\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","agentPointerHref":"/self-host/enterprise-features/data-apps.md","siteName":"Lightdash","nav":{"global":null,"tabs":[{"tab":"Docs","pages":[{"title":"Welcome to Lightdash","mode":"wide","href":"/introduction"},{"group":"Get started","icon":"rocket","root":{"title":"Getting started","href":"/get-started"},"directory":"card","pages":[{"title":"Quickstart","href":"/get-started/quickstart"},{"title":"Agentic onboarding with Aurora","sidebarTitle":"Agentic onboarding","tag":"Beta","href":"/get-started/agentic-onboarding"},{"title":"Explore your data","href":"/get-started/explore-your-data"},{"title":"Build your semantic layer","href":"/get-started/build-your-semantic-layer"},{"title":"Migrating from another BI tool","sidebarTitle":"Migrate from another BI tool","href":"/get-started/migrate-from-another-bi-tool"},{"title":"The Lightdash Way","href":"/get-started/lightdash-way"}]},{"group":"Explore","icon":"telescope","root":{"title":"Explore your data","href":"/explore"},"directory":"card","pages":[{"group":"Build charts","pages":[{"title":"Configure your charts","href":"/explore/configure-charts"},{"title":"Custom tooltips","href":"/explore/configure-custom-tooltip"},{"title":"Using custom fields","sidebarTitle":"Custom fields","href":"/explore/create-custom-fields"},{"title":"Formatting your fields","sidebarTitle":"Formatting fields","href":"/explore/formatting-your-fields"},{"title":"Period-over-period comparisons","sidebarTitle":"Period-over-period","href":"/explore/period-over-period"},{"title":"SQL runner","sidebarTitle":"SQL runner","href":"/explore/sql-runner"},{"title":"Merge queries","sidebarTitle":"Merge queries","href":"/explore/merge-queries"},{"title":"External sources","sidebarTitle":"External sources","tag":"Experimental","href":"/explore/external-sources"}]},{"group":"Table calculations","root":{"title":"Table calculations","href":"/explore/table-calculations"},"directory":"card","pages":[{"title":"Formula table calculations","sidebarTitle":"Formula","href":"/explore/table-calculations/formulas"},{"title":"Row functions","href":"/explore/table-calculations/functions/row-functions"},{"title":"Pivot functions","href":"/explore/table-calculations/functions/pivot-functions"},{"title":"Aggregate functions","href":"/explore/table-calculations/functions/aggregate-functions"},{"title":"SQL templates","href":"/explore/table-calculations/sql-templates"}]},{"group":"Dashboards","root":{"title":"Dashboards","href":"/explore/dashboards"},"pages":[{"title":"Interacting with dashboards","href":"/explore/dashboards/interact"},{"title":"Dashboard filters","href":"/explore/dashboards/filter"},{"title":"Dashboard parameter controls","sidebarTitle":"Parameter controls","tag":"Experimental","href":"/explore/dashboards/parameter-controls"},{"title":"Date zoom","href":"/explore/dashboards/date-zoom"}]},{"title":"Documents","href":"/explore/documents"},{"group":"Explore view","root":{"title":"The Explore view","href":"/explore/explore-view"},"pages":[{"title":"Filtering in the Explore view","href":"/explore/explore-view/filter"}]},{"title":"Filters reference","href":"/explore/filters-reference"},{"group":"Metrics catalog","root":{"title":"Metrics catalog","href":"/explore/metrics-catalog"},"directory":"card","pages":[{"title":"Catalog","href":"/explore/metrics-catalog/curate-the-catalog"},{"title":"Saved Trees","href":"/explore/metrics-catalog/build-saved-trees"},{"title":"Drivers","href":"/explore/metrics-catalog/drivers"}]},{"title":"Search","href":"/explore/search"},{"title":"Learn","tag":"Beta","href":"/explore/learn"},{"group":"Organize and share","pages":[{"title":"Spaces","href":"/explore/spaces"},{"title":"Default user spaces","href":"/explore/default-user-spaces"},{"title":"Review requests","sidebarTitle":"Review requests","href":"/explore/review-requests"},{"title":"Homepage","href":"/explore/homepage"},{"title":"How to promote content","sidebarTitle":"Promoting content","href":"/explore/promote-content"},{"title":"Verified charts and dashboards","sidebarTitle":"Verified content","href":"/explore/verified-content"},{"title":"Version history","sidebarTitle":"Version history","href":"/explore/version-history"},{"title":"Sharing charts","href":"/explore/share-charts"},{"title":"Scheduled deliveries","href":"/explore/create-scheduled-deliveries"},{"title":"Alerts","href":"/explore/create-alerts"}]}]},{"group":"Visualizations","icon":"chart-histogram","root":{"title":"Visualizations","href":"/visualizations"},"directory":"card","pages":[{"group":"Built-in charts","pages":[{"title":"Bar chart","icon":"chart-bar","href":"/visualizations/bar-chart"},{"title":"Line chart","icon":"chart-line","href":"/visualizations/line-chart"},{"title":"Area chart","icon":"chart-area","href":"/visualizations/area-chart"},{"title":"Mixed chart","icon":"chart-area-line","href":"/visualizations/mixed-chart"},{"title":"Scatter chart","icon":"chart-scatter","href":"/visualizations/scatter-chart"},{"title":"Pie chart","icon":"chart-pie","href":"/visualizations/pie-chart"},{"title":"Funnel chart","icon":"chart-funnel","href":"/visualizations/funnel-chart"},{"title":"Treemap chart","icon":"chart-treemap","href":"/visualizations/treemap-chart"},{"title":"Sankey chart","icon":"chart-sankey","tag":"Beta","href":"/visualizations/sankey"},{"title":"Table","icon":"table","href":"/visualizations/table"},{"title":"Big value","icon":"number-123","href":"/visualizations/big-value"},{"title":"Gauge","icon":"gauge","href":"/visualizations/gauge"},{"title":"Map","icon":"world","href":"/visualizations/map"}]},{"group":"Custom charts","root":{"title":"Custom charts","sidebarTitle":"Custom charts","href":"/visualizations/custom-charts"},"pages":[{"title":"Create reusable chart types with Chart Studio","sidebarTitle":"Chart Studio","href":"/visualizations/chart-studio"},{"title":"Install chart types from the chart library","sidebarTitle":"Chart library","href":"/visualizations/chart-library"}]}]},{"group":"Semantic layer","icon":"stack-2","root":{"title":"Lightdash semantic layer","href":"/semantic-layer"},"directory":"card","pages":[{"title":"Tables reference","sidebarTitle":"Tables","href":"/semantic-layer/tables"},{"title":"Dimensions reference","sidebarTitle":"Dimensions","href":"/semantic-layer/dimensions"},{"title":"Metrics reference","sidebarTitle":"Metrics","href":"/semantic-layer/metrics"},{"title":"Joins reference","sidebarTitle":"Joins","href":"/semantic-layer/joins"},{"title":"Nested and repeated columns","href":"/semantic-layer/nested-and-repeated-columns"},{"title":"Explores","sidebarTitle":"Explores","href":"/semantic-layer/explores"},{"title":"How to use parameters","sidebarTitle":"Parameters","href":"/semantic-layer/parameters"},{"title":"SQL variables","href":"/semantic-layer/sql-variables"},{"title":"Virtual views","href":"/semantic-layer/virtual-views"},{"title":"Lightdash YAML","sidebarTitle":"Lightdash YAML","href":"/semantic-layer/yaml"},{"title":"Caching","href":"/semantic-layer/caching"},{"group":"Pre-aggregates","root":{"title":"Pre-aggregates","href":"/semantic-layer/pre-aggregates"},"directory":"card","pages":[{"title":"External pre-aggregates","sidebarTitle":"External","href":"/semantic-layer/pre-aggregates/external"},{"title":"Monitoring and debugging pre-aggregates","sidebarTitle":"Monitoring and debugging","href":"/semantic-layer/pre-aggregates/monitoring"},{"title":"Auditing pre-aggregates from the CLI","sidebarTitle":"CLI audit","href":"/semantic-layer/pre-aggregates/audit-with-cli"}]},{"title":"lightdash.config.yml reference","sidebarTitle":"lightdash.config.yml","href":"/semantic-layer/lightdash-config-yml"},{"title":"Writing useful descriptions in your semantic layer","sidebarTitle":"Writing descriptions","href":"/semantic-layer/writing-descriptions"},{"title":"dbt modeling strategies for Lightdash","sidebarTitle":"Modeling strategies","href":"/semantic-layer/modeling-strategies"}]},{"group":"Workflow","icon":"git-branch","root":{"title":"Workflow","href":"/workflow"},"directory":"card","pages":[{"group":"CLI","root":{"title":"Lightdash CLI","sidebarTitle":"CLI","href":"/workflow/cli"},"directory":"card","pages":[{"title":"How to install the Lightdash CLI","sidebarTitle":"Install the CLI","href":"/workflow/cli/install"},{"title":"Authenticate the CLI","sidebarTitle":"Authenticate","href":"/workflow/cli/authenticate"},{"title":"Generate semantic layer YAML","sidebarTitle":"Generate YAML","href":"/workflow/cli/generate"},{"title":"Deploy changes to production","sidebarTitle":"Deploy changes","href":"/workflow/cli/deploy"},{"title":"Validate content","sidebarTitle":"Validate","href":"/workflow/cli/validate"},{"title":"Lint your code","sidebarTitle":"Lint","href":"/workflow/cli/lint"},{"title":"Compilation","sidebarTitle":"Compilation","href":"/workflow/cli/compile"},{"title":"Lightdash CLI reference","sidebarTitle":"Reference","href":"/workflow/cli/reference"}]},{"title":"Lightdash Desktop","sidebarTitle":"Desktop","tag":"Experimental","href":"/workflow/lightdash-desktop"},{"title":"Lightdash Mobile","sidebarTitle":"Mobile","href":"/workflow/lightdash-mobile"},{"title":"Preview projects","href":"/workflow/preview-projects"},{"title":"Pull requests","href":"/workflow/pull-requests"},{"title":"Automate with CI/CD","href":"/workflow/set-up-ci-cd"},{"title":"Validating your content","href":"/workflow/validating-your-content"},{"title":"Content as code","href":"/workflow/content-as-code"},{"title":"Local data app development","href":"/workflow/local-data-app-development"},{"title":"Migrate dashboards between projects","sidebarTitle":"Migrate dashboards","href":"/workflow/migrate-dashboards-between-projects"},{"title":"Editing dashboards with agents","href":"/workflow/edit-dashboards-with-agents"},{"title":"Agent skills","href":"/workflow/install-agent-skills"},{"title":"Set up VS Code for Lightdash","sidebarTitle":"Set up VS Code","href":"/workflow/set-up-vs-code"},{"title":"Renaming models, metrics, and dimensions","sidebarTitle":"Rename models and fields","href":"/workflow/rename-models-and-fields"},{"title":"Keyboard shortcuts","href":"/workflow/keyboard-shortcuts"}]},{"group":"Agents","icon":"robot","root":{"title":"AI agents","href":"/agents"},"directory":"card","pages":[{"group":"Set up agents","pages":[{"title":"Set up AI agents","sidebarTitle":"Set up agents","href":"/agents/set-up-agents"},{"title":"AI Router","sidebarTitle":"AI Router","href":"/agents/enable-ai-router"},{"title":"Data access control","href":"/agents/data-access"},{"title":"Agent identity","sidebarTitle":"Agent identity","tag":"Beta","href":"/agents/agent-identity"},{"title":"Agent permissions","sidebarTitle":"Agent permissions","tag":"Beta","href":"/agents/agent-permissions"},{"title":"Agent access to restricted data","sidebarTitle":"Restricted data","href":"/agents/agent-access-to-restricted-data"},{"title":"Thread retention","href":"/agents/thread-retention"}]},{"group":"Work with agents","pages":[{"title":"Using AI agents","href":"/agents/use-ai-agents"},{"title":"Deep research","sidebarTitle":"Deep research","href":"/agents/deep-research"},{"title":"Creating and editing content","sidebarTitle":"Content editing","tag":"Beta","href":"/agents/enable-content-tools"}]},{"group":"Improve answers","pages":[{"title":"Effective analytics with agents","sidebarTitle":"Effective analytics","href":"/agents/effective-analytics-with-agents"},{"title":"Agent context","sidebarTitle":"Agent context","href":"/agents/agent-context"},{"title":"Knowledge documents","href":"/agents/knowledge-documents"},{"title":"Custom agent skills","href":"/agents/custom-agent-skills"},{"title":"Verified answers","href":"/agents/verified-answers"},{"title":"Create evaluation suites","href":"/agents/create-evaluation-suites"},{"title":"Agent visibility","sidebarTitle":"Visibility","href":"/agents/visibility"},{"title":"AI agent issues","sidebarTitle":"Issues","tag":"Beta","href":"/agents/issues"},{"title":"Send issues to Linear and Jira","sidebarTitle":"Linear and Jira","tag":"Beta","href":"/agents/issues-linear-jira"}]},{"group":"Build agent workflows","pages":[{"title":"AI agents as code","sidebarTitle":"Agents as code","href":"/agents/agents-as-code"},{"title":"AI writeback","href":"/agents/ai-writeback"},{"title":"AI coding agent","tag":"Beta","href":"/agents/ai-coding-agent"},{"title":"Autopilot","sidebarTitle":"Autopilot","tag":"Beta","href":"/agents/autopilot"}]},{"group":"Integrations","pages":[{"title":"Set up agents in Slack","href":"/agents/set-up-slack-agents"},{"title":"Lightdash MCP server","href":"/agents/lightdash-mcp"},{"title":"Lightdash Docs MCP","href":"/agents/lightdash-docs-mcp"},{"title":"Connect external MCP servers","sidebarTitle":"External MCP servers","href":"/agents/connect-external-mcp-servers"}]}]},{"group":"Data apps","icon":"cube-spark","root":{"title":"Data apps","href":"/data-apps"},"directory":"card","pages":[{"title":"Customize themes","sidebarTitle":"Themes","href":"/data-apps/customize-themes"},{"title":"External connections","sidebarTitle":"External connections","href":"/data-apps/external-connections"},{"title":"Custom dependencies","tag":"Experimental","href":"/data-apps/custom-dependencies"},{"title":"Scheduled deliveries and syncs","sidebarTitle":"Deliveries and syncs","href":"/data-apps/deliveries-and-syncs"},{"title":"Build maps and globes in a data app","sidebarTitle":"Build maps and globes","href":"/data-apps/build-maps-and-globes"},{"title":"AI analysis","sidebarTitle":"AI analysis","tag":"Experimental","href":"/data-apps/ai-analysis"},{"title":"Saved app state","sidebarTitle":"Saved app state","tag":"Experimental","href":"/data-apps/saved-app-state"}]},{"group":"Embed","icon":"image-in-picture","root":{"title":"Embedding","href":"/embed"},"directory":"card","pages":[{"title":"Set up embedding","sidebarTitle":"Set up embedding","href":"/embed/set-up-embedding"},{"title":"How to Embed Dashboards","sidebarTitle":"Dashboards","href":"/embed/embed-dashboards"},{"title":"How to Embed Charts","sidebarTitle":"Charts","href":"/embed/embed-charts"},{"title":"How to embed AI agents","sidebarTitle":"AI agents","href":"/embed/embed-ai-agents"},{"title":"How to embed the metrics catalog","sidebarTitle":"Metrics catalog","href":"/embed/embed-metrics-catalog"},{"title":"How to embed data apps","sidebarTitle":"Data apps","href":"/embed/embed-data-apps"},{"title":"Embedding reference","href":"/embed/reference"},{"title":"Embedding with iframe","sidebarTitle":"iframe","href":"/embed/iframe"},{"title":"Embedding with React SDK","sidebarTitle":"React SDK","href":"/embed/react-sdk"},{"title":"How to translate embedded dashboards","sidebarTitle":"Translating dashboards","href":"/embed/translate-embedded-dashboards"}]},{"group":"Integrations","icon":"plug","root":{"title":"Integrations","href":"/integrations"},"directory":"card","pages":[{"title":"Connect your warehouse and project","sidebarTitle":"Connect your project","href":"/integrations/connect-project"},{"title":"Connect through an SSH tunnel","href":"/integrations/connect-through-ssh-tunnel"},{"title":"Connect Athena with web identity","sidebarTitle":"Athena web identity","tag":"Beta","href":"/integrations/connect-athena-with-web-identity"},{"group":"dbt","root":{"title":"dbt","href":"/integrations/dbt"},"directory":"card","pages":[{"title":"Syncing dbt projects","sidebarTitle":"Syncing dbt projects","href":"/integrations/dbt/projects"},{"title":"dbt write-back","href":"/integrations/dbt/write-back"},{"title":"dbt MetricFlow metrics","sidebarTitle":"dbt MetricFlow","href":"/integrations/dbt/metricflow"},{"title":"Upgrading dbt","href":"/integrations/dbt/upgrading"}]},{"title":"Slack integration","sidebarTitle":"Slack","href":"/integrations/slack"},{"group":"Google Sheets","root":{"title":"Google Sheets","href":"/integrations/google-sheets"},"directory":"card","pages":[{"title":"Lightdash for Google Sheets","sidebarTitle":"Google Sheets add-on","href":"/integrations/google-sheets/add-on"}]},{"group":"Live data sources","root":{"title":"Live data sources","tag":"Beta","href":"/integrations/live-data-sources"},"tag":"Beta","pages":[{"title":"Set up and manage live data sources","sidebarTitle":"Set up and manage","href":"/integrations/live-data-sources/set-up-and-manage"},{"title":"PostHog","href":"/integrations/live-data-sources/posthog"},{"title":"Google Analytics 4","sidebarTitle":"Google Analytics 4","href":"/integrations/live-data-sources/google-analytics"},{"title":"Google Search Console","href":"/integrations/live-data-sources/google-search-console"},{"title":"Meta Ads","href":"/integrations/live-data-sources/meta-ads"},{"title":"Google Ads","href":"/integrations/live-data-sources/google-ads"},{"title":"YouTube Analytics","href":"/integrations/live-data-sources/youtube-analytics"},{"title":"LinkedIn Ads","href":"/integrations/live-data-sources/linkedin-ads"}]},{"title":"Metrics SQL API","tag":"Beta","href":"/integrations/metrics-sql-api"},{"title":"Snowflake Cortex","href":"/integrations/snowflake-cortex"},{"title":"Apache Ossie","tag":"Experimental","href":"/integrations/apache-ossie"}]},{"group":"Workspace admin","icon":"shield-cog","root":{"title":"Workspace admin","href":"/workspace-admin"},"directory":"card","pages":[{"group":"Access and permissions","pages":[{"title":"Invite your team","sidebarTitle":"Invite your team","href":"/workspace-admin/invite-new-users"},{"title":"Roles and permissions","href":"/workspace-admin/roles"},{"title":"Direct access","href":"/workspace-admin/direct-access"},{"title":"Custom Roles","href":"/workspace-admin/custom-roles"},{"title":"Groups","href":"/workspace-admin/manage-groups"},{"title":"User attributes","href":"/workspace-admin/user-attributes"},{"title":"Service accounts","href":"/workspace-admin/service-accounts"}]},{"group":"SSO","root":{"title":"SSO providers","href":"/workspace-admin/sso"},"directory":"card","pages":[{"title":"SSO setup","href":"/workspace-admin/sso/setup"},{"title":"Verified domains","href":"/workspace-admin/sso/verified-domains"},{"title":"SCIM Integration","href":"/workspace-admin/sso/scim"}]},{"group":"Organization settings","pages":[{"title":"Managing your organization","href":"/workspace-admin/manage-your-organization"},{"title":"Creating multiple projects","href":"/workspace-admin/manage-projects"},{"title":"AI settings","href":"/workspace-admin/ai-settings"},{"title":"Customizing the appearance of your project","sidebarTitle":"Color palettes","href":"/workspace-admin/appearance"},{"title":"Custom email domain","href":"/workspace-admin/set-up-custom-email-domain"},{"title":"Multiple warehouse connections","sidebarTitle":"Warehouse connections","tag":"Experimental","href":"/workspace-admin/multiple-warehouse-connections"},{"title":"Set up timezones","sidebarTitle":"Timezones","href":"/workspace-admin/set-project-timezone"}]},{"group":"Monitoring and limits","pages":[{"title":"Usage analytics","href":"/workspace-admin/usage-analytics"},{"title":"Usage analytics project","href":"/workspace-admin/usage-analytics-project"},{"title":"Project compilation history","href":"/workspace-admin/project-compilation-history"},{"title":"Export limits","href":"/workspace-admin/export-limits"},{"title":"Instance health","href":"/workspace-admin/instance-health"}]}]},{"group":"Personal settings","icon":"user-cog","root":{"title":"Personal settings","href":"/personal-settings"},"directory":"card","pages":[{"title":"Personal access tokens","sidebarTitle":"Access tokens","href":"/personal-settings/create-personal-tokens"},{"title":"Personal warehouse connections","sidebarTitle":"Warehouse connections","href":"/personal-settings/personal-warehouse-connections"},{"title":"Timezones","href":"/personal-settings/timezone"}]},{"group":"Self-host","icon":"server-bolt","root":{"title":"Self-hosting","href":"/self-host"},"directory":"card","pages":[{"title":"Lightdash Cloud vs. Self-Hosted","href":"/self-host/lightdash-cloud-vs-self-hosted"},{"title":"Enterprise on-prem setup","sidebarTitle":"On-prem setup","href":"/self-host/enterprise-on-prem"},{"title":"Production deployment checklist","href":"/self-host/production-deployment-checklist"},{"title":"Data flows and telemetry in self-hosted Lightdash","sidebarTitle":"Data flows and telemetry","href":"/self-host/data-flows-and-telemetry"},{"title":"Environment variables","mode":"wide","href":"/self-host/customize-deployment/environment-variables"},{"group":"Install","pages":[{"title":"Self-Host Lightdash","href":"/self-host/self-host-lightdash"},{"title":"Self-host Lightdash using docker compose","sidebarTitle":"Docker compose","href":"/self-host/self-host-lightdash-docker-compose"}]},{"group":"Upgrading","pages":[{"title":"Upgrade your instance","href":"/self-host/upgrading"},{"title":"Upgrade notes","href":"/self-host/upgrade-notes"}]},{"group":"Connect services","pages":[{"title":"Configure a Github integration for self-hosted Lightdash","sidebarTitle":"Github Integration","href":"/self-host/customize-deployment/configure-github-for-lightdash"},{"title":"Configure a Slack integration for self-hosted Lightdash","sidebarTitle":"Slack Integration","href":"/self-host/customize-deployment/configure-a-slack-app-for-lightdash"},{"title":"Configure a Google Sheets integration for self-hosted Lightdash","sidebarTitle":"Google sheets","href":"/self-host/customize-deployment/configure-google-sheets-integration"}]},{"group":"Infrastructure","pages":[{"title":"Configure Lightdash to use an external database","sidebarTitle":"Use External Database","href":"/self-host/customize-deployment/configure-lightdash-to-use-an-external-database"},{"title":"Configure Lightdash to use external storage","sidebarTitle":"External storage","href":"/self-host/customize-deployment/configure-lightdash-to-use-external-object-storage"},{"title":"Run a dedicated scheduler worker","sidebarTitle":"Scheduler worker","href":"/self-host/customize-deployment/scheduler"},{"title":"Add headless browser on self-hosting","sidebarTitle":"Headless browser","href":"/self-host/customize-deployment/enable-headless-browser-for-lightdash"},{"title":"Sandboxes","sidebarTitle":"Sandboxes","href":"/self-host/customize-deployment/sandboxes"},{"title":"Secure Lightdash with HTTPS","sidebarTitle":"Secure with HTTPS","href":"/self-host/customize-deployment/secure-lightdash-with-https"},{"title":"Configure Prometheus metrics for self-hosted Lightdash","sidebarTitle":"Prometheus metrics","href":"/self-host/customize-deployment/configure-prometheus-metrics-for-self-hosted-lightdash"},{"title":"Configure OpenTelemetry tracing for self-hosted Lightdash","sidebarTitle":"OpenTelemetry tracing","href":"/self-host/customize-deployment/configure-opentelemetry-tracing-for-self-hosted-lightdash"}]},{"group":"Access and licensing","pages":[{"title":"Configure Lightdash to use passwords or SSO for authentication","sidebarTitle":"SSO and auth","href":"/self-host/customize-deployment/use-sso-login-for-self-hosted-lightdash"},{"title":"Organization roadmap","href":"/self-host/customize-deployment/organization-roadmap"}]},{"group":"Enterprise features","root":{"title":"Self-hosting Enterprise Edition","sidebarTitle":"Enterprise features","href":"/self-host/enterprise-features"},"pages":[{"title":"Self-host agents","sidebarTitle":"Agents","href":"/self-host/enterprise-features/ai-agents"},{"title":"Self-host the MCP server","sidebarTitle":"MCP","description":"Enable the Model Context Protocol server on a self-hosted Lightdash instance","href":"/self-host/enterprise-features/mcp"},{"title":"Self-host data apps","sidebarTitle":"Data apps","href":"/self-host/enterprise-features/data-apps"},{"title":"Self-host pre-aggregates","sidebarTitle":"Pre-aggregates","description":"Enable pre-aggregate query routing on a self-hosted Lightdash instance","href":"/self-host/enterprise-features/pre-aggregates"},{"title":"Self-hosted usage analytics","sidebarTitle":"Usage analytics","href":"/self-host/enterprise-features/usage-analytics"}]},{"group":"NATS workers","root":{"title":"NATS workers","href":"/self-host/nats-workers"},"directory":"card","pages":[{"title":"Warehouse workers","sidebarTitle":"Warehouse workers","href":"/self-host/nats-workers/warehouse-workers"},{"title":"Pre-aggregate workers","sidebarTitle":"Pre-aggregate workers","href":"/self-host/nats-workers/pre-aggregate-workers"}]}]},{"group":"Support","icon":"lifebuoy","root":{"title":"Support","href":"/support"},"directory":"card","pages":[{"title":"Generating a HAR file","href":"/support/generate-har-file"},{"title":"AI thread debug dump","href":"/support/ai-thread-debug-dump"},{"title":"Feature badges reference","href":"/support/feature-badges"},{"title":"Support access","href":"/support/support-access"}]}]},{"tab":"API","pages":[{"title":"API","href":"/api-reference/v1/introduction"}]}]},"basePath":"","title":"Self-host data apps - Lightdash","buildId":"dpl_596ePT575z4qnAFksq1biRW97aLY","deploymentId":"dpl_596ePT575z4qnAFksq1biRW97aLY","dynamics":[],"chunks":[]}