Set up the required S3-compatible bucket on GCP, AWS, Azure, or MinIO
On Lightdash, we generate some files like:
Images for Slack unfurl and scheduled deliveries
Results on JSONL/CSV/Excel format
These files need to be stored in a S3 Compatible Cloud storage. Some options are GCP Buckets, S3 Storage and MinIO.
S3-compatible storage is required. Lightdash will fail to start if S3_ENDPOINT, S3_BUCKET, and S3_REGION are not set. All warehouses (including Snowflake) fetch async query results from S3.
In the Google Cloud console, go to Cloud Storage and create a bucket with these details:
Give it a unique Bucket name, such as lightdash-cloud-file-storage-eu
Select a region, such as multi-region US, multi-region EU, or a single region like europe-west1
Select the default Standard storage class
Enable Enforce public access prevention on this bucket
Select Uniform access control
Set Protection to none
Set S3_ENDPOINT to https://storage.googleapis.com and S3_REGION to auto.Then choose how Lightdash authenticates to the bucket. Google Cloud Storage accepts two
methods, and they are not interchangeable.
Use this option anywhere outside Google Kubernetes Engine (GKE), or when you want the
simplest setup.
Go to Settings > Interoperability and create an Access key for service account.
Copy the access key and the secret.
Set S3_ACCESS_KEY and S3_SECRET_KEY.
These keys are long-lived static secrets. Rotate them on a schedule. Google Cloud Storage
supports several active keys per service account, so you can rotate without downtime.
Use this option when Lightdash runs on GKE and you do not want static secrets in the
cluster. Lightdash sends a short-lived Google OAuth token instead of signing requests with
a key.Set S3_AUTH_MODE=gcp_oauth and leave S3_ACCESS_KEY and S3_SECRET_KEY unset.
S3_USE_CREDENTIALS_FROM does not enable this option, even though its ecs and ec2
values look like they should. Every source that setting accepts is an AWS credential
provider, and Google Cloud Storage cannot verify AWS credentials. On GKE, use
S3_AUTH_MODE=gcp_oauth.
Grant these permissions to the Google service account that the pod runs as:
Grant the roles/storage.objectUser role on the bucket. Do not grant a project-wide
role such as Editor.
Grant the roles/iam.serviceAccountTokenCreator role on the service account itself.
The member and the resource are the same service account. Lightdash needs this role to
sign download URLs.
Enable the iamcredentials.googleapis.com API in the project.
If you skip step 3, the deployment looks healthy. Uploads, downloads, and result caching
all work. Only signed download links fail, and only when a user asks for one. The error is
Permission 'iam.serviceAccounts.signBlob' denied on resource.
Both URL styles work with Google Cloud Storage. Path style also works for bucket names that
contain dots, which break TLS certificate matching in the other style.Signed URLs in this mode last at most 7 days, which is a Google Cloud Storage limit.
Lightdash fails to start if S3_EXPIRATION_TIME exceeds 604800 seconds.To develop locally against a bucket that uses this mode, run:
Your own user credentials cannot sign URLs, and the error is
Cannot sign data without 'client_email'. Impersonating the service account fixes it. Do
not download a service account key file.
Azure Blob Storage is not natively compatible with the S3 API. While Lightdash supports external object storage by allowing integration with S3-compatible APIs, Azure’s storage service does not provide this compatibility out of the box. This means that you cannot use Azure Blob Storage as a drop-in replacement for S3 in Lightdash deployments.Instead, you can use one of the following S3-compatible solutions within your Azure setup:
To enable Lightdash to use your S3 bucket for cloud storage, you’ll need to set the following environment variables:
S3_ENDPOINT # requiredS3_REGION # requiredS3_BUCKET # requiredS3_ACCESS_KEY # optional if using IAM roleS3_SECRET_KEY # optional if using IAM roleS3_EXPIRATION_TIME # optional, defaults to 259200 seconds (3 days)
For a comprehensive list of all possible S3-related environment variables and other configurations, please visit the Environment Variables documentation.
Query results use the main S3 configuration by default. To store them with a different S3-compatible provider, set the RESULTS_S3_* variables that differ from it — credentials and path-style addressing have RESULTS_S3_* equivalents too:
Any omitted result storage setting inherits its corresponding S3_* value.
Raw JSONL result downloads use a presigned URL that browsers fetch directly from RESULTS_S3_ENDPOINT. This endpoint must be reachable from users’ browsers; S3_PUBLIC_ENDPOINT does not apply to the query results bucket. The bucket can remain private, but an IP policy that limits GetObject to Lightdash’s backend egress addresses will block these downloads.
AI agent avatars and homepage announcement images are served through permanent links, so they must not be deleted by a lifecycle rule. If your main bucket has one, point these uploads at a bucket without one:
UPLOADS_S3_BUCKET=my-lightdash-uploads
The uploads bucket shares the endpoint, region, credentials and auth mode of the main S3 configuration. Leave it unset if your main bucket keeps objects indefinitely. Once set, keep it: uploads made while it was set are only looked up in that bucket. Available from Lightdash 3.56.0.
How you do this depends on the cloud provider, because the two mechanisms are unrelated.On AWS. Omit S3_ACCESS_KEY and S3_SECRET_KEY, and the AWS SDK looks for an IAM role
automatically. To control which credential sources it tries and in what order, set
S3_USE_CREDENTIALS_FROM. For more detail, read the
AWS SDK for JavaScript documentation on setting credentials in Node.js.On Google Cloud. Set S3_AUTH_MODE=gcp_oauth. See
Option B: workload identity, with no keys.
S3_USE_CREDENTIALS_FROM does not work here, because every source it accepts is an AWS
credential provider.Signed URLs last at most 7 days in both cases, whatever you set S3_EXPIRATION_TIME to.
The limit comes from the signing algorithm, not from Lightdash.
For an enterprise deployment, use a dedicated bucket per purpose, each with a scoped credential that can only touch its own bucket. This is how Lightdash Cloud sets up storage:
Results / cache bucket — add a lifecycle rule deleting objects after 1 day. Results are ephemeral, so this keeps the bucket small and cheap.
Pre-aggregations bucket (if using pre-aggregates) — lifecycle delete after ~30 days.
Data-apps bucket (if using data apps) — persistent, with no delete lifecycle.
Uploads bucket (UPLOADS_S3_BUCKET) — persistent, with no delete lifecycle. Holds AI agent avatars and homepage announcement images, which are served through permanent links. Required if the main bucket has a delete lifecycle rule.
Block all public access on every bucket, and prefer short-lived credentials over static
keys. On EKS, use IAM roles for service accounts (IRSA). On GKE, set
S3_AUTH_MODE=gcp_oauth to use workload identity. In both cases, signed URLs last at most
7 days.If users share download links that must outlive the signed-URL TTL (S3_EXPIRATION_TIME, default 3 days), enable PERSISTENT_DOWNLOAD_URLS_ENABLED: "true" — see persistent download URLs.
{"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":""},"chroma":{"liveDeploymentHistoryId":"6ae529ad62aee27005e8b6b7","collectionId":"625fe8df-b0d6-42f7-9977-14276fecd726","schemaVersion":"v3","latestBuiltDeploymentHistoryId":"6ae529ad62aee27005e8b6b7"},"feedback":{"issues":true,"thumbs":true},"entitlements":{"AI_CHAT":{"status":"ENABLED"},"WEB_MCP":{"status":"ENABLED"},"NARRATION":{"status":"ENABLED"}},"buildId":"6ae529ad62aee27005e8b6b7","clientVersion":"0.0.4044","searchFilterCounts":[{"language":"default","tag":"API","count":875},{"language":"default","tag":"Reference","count":871},{"language":"default","tag":"Docs","count":206},{"language":"default","tag":"API Reference","count":193},{"language":"default","tag":"Projects","count":138},{"language":"default","tag":"v2","count":127},{"language":"default","tag":"Organizations","count":76},{"language":"default","tag":"Integrations","count":40},{"language":"default","tag":"Explore","count":34},{"language":"default","tag":"Self-host","count":31}],"searchSettings":{"maxResults":10}},"assistantConfig":{"enableAskAiButton":true,"enableAskAiSearchBar":true,"deflection":{"enabled":true,"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":"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":"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":"byok-sep-25","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":"vite-origin","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-updated-9-15","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":"sso-setup-deadline-banner","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:.375rem;margin:1rem 0;font-size:.8125rem}#content>.callout:first-child,.feature-badges: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 td:first-child,.sticky-first-col table th:first-child{position:sticky;left:0;z-index:1;min-width:260px;max-width:320px;white-space:normal;background-color:#fff;box-shadow:inset -1px 0 0 0 rgba(0,0,0,.08)}.sticky-first-col table thead th:first-child{z-index:2}html.dark .sticky-first-col table td:first-child,html.dark .sticky-first-col table th:first-child{background-color:#0b0b0f;box-shadow:inset -1px 0 0 0 rgba(255,255,255,.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:.75rem;padding:.75rem 1.375rem;border:0;border-radius:9999px;background-color:#8072ff;color:#fff;font-size:.875rem;font-weight:500;line-height:1.25rem;cursor:pointer;box-shadow:0 1px 2px rgba(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:.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:.625rem 0 0 .25rem;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.8125rem;color:#9ca3af;opacity:0;transform:translateY(4px);transition:opacity 200ms ease,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-preview.is-copied,.copy-prompt:has(.copy-prompt-btn:focus-visible) .copy-prompt-preview,.copy-prompt:hover .copy-prompt-preview{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:.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:0 0;border:2px dashed var(--setup-path-line);color:var(--setup-path-faint)}.setup-path-node{display:grid;gap:.75rem;min-width:0}.setup-path-answer,.setup-path-question{display:flex;align-items:center;min-height:2.375rem}.setup-path-question{font-size:1.125rem;font-weight:600;line-height:1.3}.setup-path-answer{justify-content:space-between;gap:1rem}.setup-path-answer p{display:grid;min-width:0;line-height:1.3}.setup-path-answer p span{font-size:.8125rem;color:var(--setup-path-muted)}.setup-path-answer p strong{font-weight:600}.setup-path-change{flex:none;padding:.25rem .625rem;border:1px solid transparent;border-radius:.5rem;background:0 0;font-size:.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:.375rem;margin-top:-.25rem}.setup-path-leaves a{display:inline-flex;align-items:center;gap:.375rem;padding:.1875rem .625rem;border-radius:.5rem;background:var(--setup-path-surface);font-size:.8125rem;color:inherit;text-decoration:none}.setup-path-leaves a:hover{text-decoration:underline}.setup-path-chevron,.setup-path-leaves svg{color:var(--setup-path-faint)}.setup-path-note,.setup-path-pending{font-size:.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:.9375rem;line-height:1.4}.setup-path-options{display:grid;grid-template-columns:repeat(var(--setup-path-columns),minmax(0,1fr));gap:.625rem}.setup-path-option{display:flex;align-items:center;gap:.75rem;min-width:0;padding:.75rem .875rem;border:1px solid var(--setup-path-line);border-radius:.75rem;background:var(--setup-path-ground);text-align:left;transition:border-color 150ms ease,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-change:focus-visible,.setup-path-ghost:focus-visible,.setup-path-option: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:.1875rem .5rem;font-size:.9375rem;font-weight:600;line-height:1.3}.setup-path-option-hint{font-size:.8125rem;line-height:1.4;color:var(--setup-path-muted)}.setup-path-tag{padding:1px .4375rem;border:1px solid var(--setup-path-line);border-radius:99px;font-size:.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,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:.5625rem .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,.setup-path-phase li>button{align-items:center;border-radius:.5rem;background:0 0}.setup-path-ghost{display:inline-flex;gap:.375rem;padding:.375rem .75rem;border:1px solid var(--setup-path-line);font-size:.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:.5rem 1rem;min-height:2.375rem}.setup-path-result-title{font-size:1.125rem;font-weight:600}.setup-path-result-title span{margin-left:.5rem;font-size:.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:.75rem 0;border-bottom:1px solid var(--setup-path-line)}.setup-path-phase-name{display:flex;align-items:center;align-self:start;gap:.5rem;padding:.4375rem 0;font-size:.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;gap:.75rem;width:100%;min-width:0;padding:.4375rem .5rem;border:0;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:.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:.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:.375rem;justify-items:start;padding:0 .5rem .625rem 2.5rem;font-size:.875rem;color:var(--setup-path-muted)}.setup-path-step-body a{display:inline-flex;align-items:center;gap:.3125rem}.setup-path-step-body>span{font-size:.8125rem;color:var(--setup-path-faint)}@media (max-width:640px){.setup-path-options,.setup-path-phase{grid-template-columns:1fr}.setup-path-options.is-compact{grid-template-columns:repeat(2,minmax(0,1fr))}.setup-path-phase{gap:.25rem}}@media (prefers-reduced-motion:reduce){.setup-path-chevron,.setup-path-option,.setup-path-radio,.setup-path-tile{transition:none}}"}],"page":{"pagePath":"self-host/customize-deployment/configure-lightdash-to-use-external-object-storage","slug":"/self-host/customize-deployment/configure-lightdash-to-use-external-object-storage","pageMetadata":{"title":"Configure Lightdash to use external storage","sidebarTitle":"External storage","description":"Set up the required S3-compatible bucket on GCP, AWS, Azure, or MinIO","boost":0.001,"doc-type":"tutorial","href":"/self-host/customize-deployment/configure-lightdash-to-use-external-object-storage"},"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: \"Set up the required S3-compatible bucket on GCP, AWS, Azure, or MinIO\"\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];function _createMdxContent(props){const _components={a:`a`,code:`code`,li:`li`,ol:`ol`,p:`p`,pre:`pre`,span:`span`,strong:`strong`,ul:`ul`,..._provideComponents(),...props.components},{CodeBlock,Heading,Warning}=_components;if(!CodeBlock)_missingMdxReference(`CodeBlock`,true);if(!Heading)_missingMdxReference(`Heading`,true);if(!Warning)_missingMdxReference(`Warning`,true);return _jsxs(_Fragment,{children:[_jsx(_components.p,{children:`On Lightdash, we generate some files like:`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsx(_components.li,{children:`Images for Slack unfurl and scheduled deliveries`}),`\n`,_jsx(_components.li,{children:`Results on JSONL/CSV/Excel format`}),`\n`]}),`\n`,_jsx(_components.p,{children:`These files need to be stored in a S3 Compatible Cloud storage. Some options are GCP Buckets, S3 Storage and MinIO.`}),`\n`,_jsx(Warning,{children:_jsxs(_components.p,{children:[`S3-compatible storage is `,_jsx(_components.strong,{children:`required`}),`. Lightdash will fail to start if `,_jsx(_components.code,{children:`S3_ENDPOINT`}),`, `,_jsx(_components.code,{children:`S3_BUCKET`}),`, and `,_jsx(_components.code,{children:`S3_REGION`}),` are not set. All warehouses (including Snowflake) fetch async query results from S3.`]})}),`\n`,_jsx(Heading,{level:`2`,id:`configure-cloud-storage-on-google-cloud-platform`,children:`Configure cloud storage on Google Cloud Platform`}),`\n`,_jsx(_components.p,{children:`In the Google Cloud console, go to Cloud Storage and create a bucket with these details:`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[`Give it a unique `,_jsx(_components.code,{children:`Bucket name`}),`, such as `,_jsx(_components.code,{children:`lightdash-cloud-file-storage-eu`})]}),`\n`,_jsxs(_components.li,{children:[`Select a region, such as multi-region US, multi-region EU, or a single region like `,_jsx(_components.code,{children:`europe-west1`})]}),`\n`,_jsxs(_components.li,{children:[`Select the default `,_jsx(_components.code,{children:`Standard`}),` storage class`]}),`\n`,_jsxs(_components.li,{children:[`Enable `,_jsx(_components.code,{children:`Enforce public access prevention on this bucket`})]}),`\n`,_jsxs(_components.li,{children:[`Select `,_jsx(_components.code,{children:`Uniform`}),` access control`]}),`\n`,_jsxs(_components.li,{children:[`Set Protection to `,_jsx(_components.code,{children:`none`})]}),`\n`]}),`\n`,_jsxs(_components.p,{children:[`Set `,_jsx(_components.code,{children:`S3_ENDPOINT`}),` to `,_jsx(_components.code,{children:`https://storage.googleapis.com`}),` and `,_jsx(_components.code,{children:`S3_REGION`}),` to `,_jsx(_components.code,{children:`auto`}),`.`]}),`\n`,_jsx(_components.p,{children:`Then choose how Lightdash authenticates to the bucket. Google Cloud Storage accepts two\nmethods, and they are not interchangeable.`}),`\n`,_jsx(Heading,{level:`3`,id:`option-a-hmac-keys`,children:`Option A: HMAC keys`}),`\n`,_jsx(_components.p,{children:`Use this option anywhere outside Google Kubernetes Engine (GKE), or when you want the\nsimplest setup.`}),`\n`,_jsxs(_components.ol,{children:[`\n`,_jsxs(_components.li,{children:[`Go to `,_jsx(_components.strong,{children:`Settings > Interoperability`}),` and create an `,_jsx(_components.strong,{children:`Access key for service account`}),`.`]}),`\n`,_jsx(_components.li,{children:`Copy the access key and the secret.`}),`\n`,_jsxs(_components.li,{children:[`Set `,_jsx(_components.code,{children:`S3_ACCESS_KEY`}),` and `,_jsx(_components.code,{children:`S3_SECRET_KEY`}),`.`]}),`\n`]}),`\n`,_jsx(_components.p,{children:`These keys are long-lived static secrets. Rotate them on a schedule. Google Cloud Storage\nsupports several active keys per service account, so you can rotate without downtime.`}),`\n`,_jsx(Heading,{level:`3`,id:`option-b-workload-identity-with-no-keys`,children:`Option B: Workload identity, with no keys`}),`\n`,_jsx(_components.p,{children:`Use this option when Lightdash runs on GKE and you do not want static secrets in the\ncluster. Lightdash sends a short-lived Google OAuth token instead of signing requests with\na key.`}),`\n`,_jsxs(_components.p,{children:[`Set `,_jsx(_components.code,{children:`S3_AUTH_MODE=gcp_oauth`}),` and leave `,_jsx(_components.code,{children:`S3_ACCESS_KEY`}),` and `,_jsx(_components.code,{children:`S3_SECRET_KEY`}),` unset.`]}),`\n`,_jsx(Warning,{children:_jsxs(_components.p,{children:[_jsx(_components.code,{children:`S3_USE_CREDENTIALS_FROM`}),` does not enable this option, even though its `,_jsx(_components.code,{children:`ecs`}),` and `,_jsx(_components.code,{children:`ec2`}),`\nvalues look like they should. Every source that setting accepts is an `,_jsx(_components.strong,{children:`AWS`}),` credential\nprovider, and Google Cloud Storage cannot verify AWS credentials. On GKE, use\n`,_jsx(_components.code,{children:`S3_AUTH_MODE=gcp_oauth`}),`.`]})}),`\n`,_jsx(_components.p,{children:`Grant these permissions to the Google service account that the pod runs as:`}),`\n`,_jsxs(_components.ol,{children:[`\n`,_jsxs(_components.li,{children:[`Bind the Kubernetes service account to the Google service account, as described in the\n`,_jsx(_components.a,{href:`https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity`,children:`GKE workload identity documentation`}),`.`]}),`\n`,_jsxs(_components.li,{children:[`Grant the `,_jsx(_components.code,{children:`roles/storage.objectUser`}),` role `,_jsx(_components.strong,{children:`on the bucket`}),`. Do not grant a project-wide\nrole such as Editor.`]}),`\n`,_jsxs(_components.li,{children:[`Grant the `,_jsx(_components.code,{children:`roles/iam.serviceAccountTokenCreator`}),` role `,_jsx(_components.strong,{children:`on the service account itself`}),`.\nThe member and the resource are the same service account. Lightdash needs this role to\nsign download URLs.`]}),`\n`,_jsxs(_components.li,{children:[`Enable the `,_jsx(_components.code,{children:`iamcredentials.googleapis.com`}),` API in the project.`]}),`\n`]}),`\n`,_jsx(Warning,{children:_jsxs(_components.p,{children:[`If you skip step 3, the deployment looks healthy. Uploads, downloads, and result caching\nall work. Only signed download links fail, and only when a user asks for one. The error is\n`,_jsx(_components.code,{children:`Permission 'iam.serviceAccounts.signBlob' denied on resource`}),`.`]})}),`\n`,_jsx(_components.p,{children:`Set these environment variables:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`5`,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:`5`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`S3_ENDPOINT`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`https://storage.googleapis.com`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`S3_REGION`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`auto`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`S3_BUCKET`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`your-bucket-name`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`S3_AUTH_MODE`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`gcp_oauth`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`S3_FORCE_PATH_STYLE`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`true`})]}),`\n`]})})}),`\n`,_jsx(_components.p,{children:`Both URL styles work with Google Cloud Storage. Path style also works for bucket names that\ncontain dots, which break TLS certificate matching in the other style.`}),`\n`,_jsxs(_components.p,{children:[`Signed URLs in this mode last at most 7 days, which is a Google Cloud Storage limit.\nLightdash fails to start if `,_jsx(_components.code,{children:`S3_EXPIRATION_TIME`}),` exceeds 604800 seconds.`]}),`\n`,_jsx(_components.p,{children:`To develop locally against a bucket that uses this mode, run:`}),`\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:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`gcloud`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` auth`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` application-default`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` login`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` --impersonate-service-account=SERVICE_ACCOUNT_EMAIL`})]}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`Your own user credentials cannot sign URLs, and the error is\n`,_jsx(_components.code,{children:`Cannot sign data without 'client_email'`}),`. Impersonating the service account fixes it. Do\nnot download a service account key file.`]}),`\n`,_jsx(Heading,{level:`2`,id:`configure-cloud-storage-on-aws`,children:`Configure cloud storage on AWS`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsx(_components.li,{children:`Navigate to the S3 section of the AWS Management Console and click on the Create Bucket button.`}),`\n`,_jsx(_components.li,{children:`Give your bucket a name and select the region where you want to store your data.`}),`\n`,_jsx(_components.li,{children:`Next, you need to set the permissions for your bucket. Make it private.`}),`\n`]}),`\n`,_jsx(_components.p,{children:`To export your S3 credentials, you need to follow these steps:`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsx(_components.li,{children:`Navigate to the IAM section and click on the Users tab.`}),`\n`,_jsx(_components.li,{children:`Click on the user whose credentials you want to export.`}),`\n`,_jsx(_components.li,{children:`Click on the Security Credentials tab and locate the Access Keys section.`}),`\n`,_jsx(_components.li,{children:`Click on the Create Access Key button.`}),`\n`,_jsx(_components.li,{children:`Download the CSV file that contains your Access Key ID and Secret Access Key.`}),`\n`]}),`\n`,_jsxs(_components.p,{children:[`Check `,_jsx(_components.a,{href:`https://docs.aws.amazon.com/general/latest/gr/s3.html`,children:`this guide`}),` to see what’s the right `,_jsx(_components.code,{children:`S3_ENDPOINT`}),` for your bucket`]}),`\n`,_jsx(Heading,{level:`2`,id:`configure-cloud-storage-using-minio`,children:`Configure cloud storage using MinIO`}),`\n`,_jsx(_components.p,{children:`Creating a bucket in MinIO`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsx(_components.li,{children:`Login to the MinIO console and click on “Buckets” in the side bar`}),`\n`,_jsx(_components.li,{children:`Click on “Create Bucket”`}),`\n`,_jsx(_components.li,{children:`Give your bucket a name and click “Create Bucket”`}),`\n`]}),`\n`,_jsx(_components.p,{children:`Creating access credentials in MinIO`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsx(_components.li,{children:`Click on “Access Keys” in the side bar`}),`\n`,_jsx(_components.li,{children:`Click “Create access key”`}),`\n`,_jsx(_components.li,{children:`Give a name to your new access key and click “Create”`}),`\n`,_jsx(_components.li,{children:`Download the JSON file containing both your Access Key ID and Secret Access Key`}),`\n`]}),`\n`,_jsxs(_components.p,{children:[`MinIO needs path style bucket URLs, for this you will need to set `,_jsx(_components.code,{children:`S3_FORCE_PATH_STYLE: true`}),` in your environment variables.`]}),`\n`,_jsx(Heading,{level:`2`,id:`azure-storage`,children:`Azure Storage`}),`\n`,_jsxs(_components.p,{children:[`Azure Blob Storage is not natively compatible with the S3 API. While Lightdash supports external object storage by allowing integration with S3-compatible APIs, Azure’s storage service does not provide this compatibility out of the box. This means that you `,_jsx(_components.strong,{children:`cannot use Azure Blob Storage as a drop-in replacement for S3`}),` in Lightdash deployments.`]}),`\n`,_jsx(_components.p,{children:`Instead, you can use one of the following S3-compatible solutions within your Azure setup:`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.a,{href:`https://min.io`,children:_jsx(_components.strong,{children:`MinIO`})}),_jsx(_components.strong,{children:`:`}),` S3-compatible object storage`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.a,{href:`https://github.com/gaul/s3proxy`,children:_jsx(_components.strong,{children:`s3proxy`})}),_jsx(_components.strong,{children:`:`}),` A lightweight proxy that adds an S3-compatible API layer on top of Azure Blob Storage.`]}),`\n`]}),`\n`,_jsx(Heading,{level:`2`,id:`configure-lightdash-to-use-s3-credentials`,children:`Configure Lightdash to use S3 credentials`}),`\n`,_jsx(_components.p,{children:`To enable Lightdash to use your S3 bucket for cloud storage, you’ll need to set the following environment variables:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`6`,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:`6`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`S3_ENDPOINT`}),_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:` # required`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`S3_REGION`}),_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:` # required`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`S3_BUCKET`}),_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:` # required`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`S3_ACCESS_KEY`}),_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:` # optional if using IAM role`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`S3_SECRET_KEY`}),_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:` # optional if using IAM role`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`S3_EXPIRATION_TIME`}),_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:` # optional, defaults to 259200 seconds (3 days)`})]}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`For a comprehensive list of all possible S3-related environment variables and other configurations, please visit the `,_jsx(_components.a,{href:`/self-host/customize-deployment/environment-variables#s3`,children:`Environment Variables documentation`}),`.`]}),`\n`,_jsx(Heading,{level:`3`,id:`use-separate-storage-for-query-results`,children:`Use separate storage for query results`}),`\n`,_jsxs(_components.p,{children:[`Query results use the main S3 configuration by default. To store them with a different S3-compatible provider, set the `,_jsx(_components.code,{children:`RESULTS_S3_*`}),` variables that differ from it — credentials and path-style addressing have `,_jsx(_components.code,{children:`RESULTS_S3_*`}),` equivalents too:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`3`,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:`3`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`RESULTS_S3_ENDPOINT`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`https://s3.eu-west-1.amazonaws.com`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`RESULTS_S3_REGION`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`eu-west-1`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`RESULTS_S3_BUCKET`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`my-lightdash-query-results`})]}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`Any omitted result storage setting inherits its corresponding `,_jsx(_components.code,{children:`S3_*`}),` value.`]}),`\n`,_jsx(Warning,{children:_jsxs(_components.p,{children:[`Raw JSONL result downloads use a presigned URL that browsers fetch directly from `,_jsx(_components.code,{children:`RESULTS_S3_ENDPOINT`}),`. This endpoint must be reachable from users’ browsers; `,_jsx(_components.code,{children:`S3_PUBLIC_ENDPOINT`}),` does not apply to the query results bucket. The bucket can remain private, but an IP policy that limits `,_jsx(_components.code,{children:`GetObject`}),` to Lightdash’s backend egress addresses will block these downloads.`]})}),`\n`,_jsx(Heading,{level:`3`,id:`use-separate-storage-for-uploads`,children:`Use separate storage for uploads`}),`\n`,_jsx(_components.p,{children:`AI agent avatars and homepage announcement images are served through permanent links, so they must not be deleted by a lifecycle rule. If your main bucket has one, point these uploads at a bucket without one:`}),`\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:`UPLOADS_S3_BUCKET`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`my-lightdash-uploads`})]}),`\n`]})})}),`\n`,_jsx(_components.p,{children:`The uploads bucket shares the endpoint, region, credentials and auth mode of the main S3 configuration. Leave it unset if your main bucket keeps objects indefinitely. Once set, keep it: uploads made while it was set are only looked up in that bucket. Available from Lightdash 3.56.0.`}),`\n`,_jsx(Heading,{level:`3`,id:`authenticate-without-static-keys`,children:`Authenticate without static keys`}),`\n`,_jsx(_components.p,{children:`How you do this depends on the cloud provider, because the two mechanisms are unrelated.`}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`On AWS.`}),` Omit `,_jsx(_components.code,{children:`S3_ACCESS_KEY`}),` and `,_jsx(_components.code,{children:`S3_SECRET_KEY`}),`, and the AWS SDK looks for an IAM role\nautomatically. To control which credential sources it tries and in what order, set\n`,_jsx(_components.code,{children:`S3_USE_CREDENTIALS_FROM`}),`. For more detail, read the\n`,_jsx(_components.a,{href:`https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/setting-credentials-node.html`,children:`AWS SDK for JavaScript documentation on setting credentials in Node.js`}),`.`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`On Google Cloud.`}),` Set `,_jsx(_components.code,{children:`S3_AUTH_MODE=gcp_oauth`}),`. See\n`,_jsx(_components.a,{href:`#option-b-workload-identity-with-no-keys`,children:`Option B: workload identity, with no keys`}),`.\n`,_jsx(_components.code,{children:`S3_USE_CREDENTIALS_FROM`}),` does not work here, because every source it accepts is an AWS\ncredential provider.`]}),`\n`,_jsxs(_components.p,{children:[`Signed URLs last at most 7 days in both cases, whatever you set `,_jsx(_components.code,{children:`S3_EXPIRATION_TIME`}),` to.\nThe limit comes from the signing algorithm, not from Lightdash.`]}),`\n`,_jsx(Heading,{level:`2`,id:`production-bucket-strategy`,children:`Production bucket strategy`}),`\n`,_jsxs(_components.p,{children:[`For an enterprise deployment, use a `,_jsx(_components.strong,{children:`dedicated bucket per purpose`}),`, each with a scoped credential that can only touch its own bucket. This is how Lightdash Cloud sets up storage:`]}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Results / cache bucket`}),` — add a lifecycle rule deleting objects after `,_jsx(_components.strong,{children:`1 day`}),`. Results are ephemeral, so this keeps the bucket small and cheap.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Pre-aggregations bucket`}),` (if using `,_jsx(_components.a,{href:`/self-host/nats-workers/pre-aggregate-workers`,children:`pre-aggregates`}),`) — lifecycle delete after `,_jsx(_components.strong,{children:`~30 days`}),`.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Data-apps bucket`}),` (if using `,_jsx(_components.a,{href:`/self-host/enterprise-features/data-apps`,children:`data apps`}),`) — persistent, with `,_jsx(_components.strong,{children:`no`}),` delete lifecycle.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Uploads bucket`}),` (`,_jsx(_components.code,{children:`UPLOADS_S3_BUCKET`}),`) — persistent, with `,_jsx(_components.strong,{children:`no`}),` delete lifecycle. Holds AI agent avatars and homepage announcement images, which are served through permanent links. Required if the main bucket has a delete lifecycle rule.`]}),`\n`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Block all public access`}),` on every bucket, and prefer short-lived credentials over static\nkeys. On EKS, use IAM roles for service accounts (IRSA). On GKE, set\n`,_jsx(_components.code,{children:`S3_AUTH_MODE=gcp_oauth`}),` to use workload identity. In both cases, signed URLs last at most\n7 days.`]}),`\n`,_jsxs(_components.p,{children:[`If users share download links that must outlive the signed-URL TTL (`,_jsx(_components.code,{children:`S3_EXPIRATION_TIME`}),`, default 3 days), enable `,_jsx(_components.code,{children:`PERSISTENT_DOWNLOAD_URLS_ENABLED: \"true\"`}),` — see `,_jsx(_components.a,{href:`/self-host/customize-deployment/environment-variables#persistent-download-urls`,children:`persistent download URLs`}),`.`]})]})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{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":"Configure Lightdash to use external storage","sidebarTitle":"External storage","description":"Set up the required S3-compatible bucket on GCP, AWS, Azure, or MinIO","boost":0.001,"doc-type":"tutorial","href":"/self-host/customize-deployment/configure-lightdash-to-use-external-object-storage"}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[{"title":"Configure cloud storage on Google Cloud Platform","slug":"configure-cloud-storage-on-google-cloud-platform","depth":2,"children":[{"title":"Option A: HMAC keys","slug":"option-a-hmac-keys","depth":3,"children":[]},{"title":"Option B: Workload identity, with no keys","slug":"option-b-workload-identity-with-no-keys","depth":3,"children":[]}]},{"title":"Configure cloud storage on AWS","slug":"configure-cloud-storage-on-aws","depth":2,"children":[]},{"title":"Configure cloud storage using MinIO","slug":"configure-cloud-storage-using-minio","depth":2,"children":[]},{"title":"Azure Storage","slug":"azure-storage","depth":2,"children":[]},{"title":"Configure Lightdash to use S3 credentials","slug":"configure-lightdash-to-use-s3-credentials","depth":2,"children":[{"title":"Use separate storage for query results","slug":"use-separate-storage-for-query-results","depth":3,"children":[]},{"title":"Use separate storage for uploads","slug":"use-separate-storage-for-uploads","depth":3,"children":[]},{"title":"Authenticate without static keys","slug":"authenticate-without-static-keys","depth":3,"children":[]}]},{"title":"Production bucket strategy","slug":"production-bucket-strategy","depth":2,"children":[]}],"codeExamples":{}},"jsLinks":["/_mintlify/custom/lightdash/d0a9cf4e6619eae5/analytics.js"],"subdomain":"lightdash","siteName":"Lightdash","title":"Configure Lightdash to use external storage - Lightdash","navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-10-26T15:22:40.836Z","originalFileLocation":"self-host/customize-deployment/configure-lightdash-to-use-external-object-storage.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=\"Set up the required S3-compatible bucket on GCP, AWS, Azure, or MinIO\">\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=\"Configure Lightdash to use external storage - Lightdash\">\u003cmeta data-mint-head property=\"og:description\" content=\"Set up the required S3-compatible bucket on GCP, AWS, Azure, or MinIO\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"Lightdash\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://docs.lightdash.com/self-host/customize-deployment/configure-lightdash-to-use-external-object-storage\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://lightdash.mintlify.app/_mintlify/api/og/v2?division=Infrastructure\u0026amp;title=Configure+Lightdash+to+use+external+storage\u0026amp;description=Set+up+the+required+S3-compatible+bucket+on+GCP%2C+AWS%2C+Azure%2C+or+MinIO\u0026amp;theme=ec550573033c2195fadd36ad\u0026amp;signature=1f7e77f2e861de28e44805ad2d65ed71f34b7b2a34aac8ba7f65d769c821596c\">\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=\"Configure Lightdash to use external storage - Lightdash\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"Set up the required S3-compatible bucket on GCP, AWS, Azure, or MinIO\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://lightdash.mintlify.app/_mintlify/api/og/v2?division=Infrastructure\u0026amp;title=Configure+Lightdash+to+use+external+storage\u0026amp;description=Set+up+the+required+S3-compatible+bucket+on+GCP%2C+AWS%2C+Azure%2C+or+MinIO\u0026amp;theme=ec550573033c2195fadd36ad\u0026amp;signature=1f7e77f2e861de28e44805ad2d65ed71f34b7b2a34aac8ba7f65d769c821596c\">\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/customize-deployment/configure-lightdash-to-use-external-object-storage\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/self-host/customize-deployment/configure-lightdash-to-use-external-object-storage.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/customize-deployment/configure-lightdash-to-use-external-object-storage#webpage\",\"url\":\"https://docs.lightdash.com/self-host/customize-deployment/configure-lightdash-to-use-external-object-storage\",\"name\":\"Configure Lightdash to use external storage\",\"description\":\"Set up the required S3-compatible bucket on GCP, AWS, Azure, or MinIO\",\"dateModified\":\"2026-10-26T15:22:40.836Z\",\"isPartOf\":{\"@id\":\"https://docs.lightdash.com#website\"},\"breadcrumb\":{\"@id\":\"https://docs.lightdash.com/self-host/customize-deployment/configure-lightdash-to-use-external-object-storage#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://docs.lightdash.com/self-host/customize-deployment/configure-lightdash-to-use-external-object-storage#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Self-host\",\"item\":\"https://docs.lightdash.com/self-host\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Infrastructure\",\"item\":\"https://docs.lightdash.com/self-host/customize-deployment/configure-lightdash-to-use-an-external-database\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Configure Lightdash to use external storage\",\"item\":\"https://docs.lightdash.com/self-host/customize-deployment/configure-lightdash-to-use-external-object-storage\"}]},{\"@type\":[\"Article\",\"TechArticle\"],\"@id\":\"https://docs.lightdash.com/self-host/customize-deployment/configure-lightdash-to-use-external-object-storage#article\",\"headline\":\"Configure Lightdash to use external storage\",\"name\":\"Configure Lightdash to use external storage\",\"description\":\"Set up the required S3-compatible bucket on GCP, AWS, Azure, or MinIO\",\"url\":\"https://docs.lightdash.com/self-host/customize-deployment/configure-lightdash-to-use-external-object-storage\",\"mainEntityOfPage\":{\"@id\":\"https://docs.lightdash.com/self-host/customize-deployment/configure-lightdash-to-use-external-object-storage#webpage\"},\"dateModified\":\"2026-10-26T15:22:40.836Z\",\"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\",\"creator\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","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":"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":"Lightdash CLI","href":"/workflow/cli/reference"}]},{"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":"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":"Agent visibility","sidebarTitle":"Visibility","href":"/agents/visibility"},{"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"},{"title":"Creating and editing content","sidebarTitle":"Content editing","tag":"Beta","href":"/agents/enable-content-tools"},{"title":"AI Router","sidebarTitle":"AI Router","href":"/agents/enable-ai-router"},{"title":"Lightdash MCP server","href":"/agents/lightdash-mcp"},{"title":"Connect external MCP servers","sidebarTitle":"External MCP servers","href":"/agents/connect-external-mcp-servers"},{"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"}]},{"group":"Work with agents","pages":[{"title":"Using AI agents","href":"/agents/use-ai-agents"},{"title":"Lightdash Desktop","sidebarTitle":"Desktop","tag":"Experimental","href":"/agents/lightdash-desktop"},{"title":"Deep research","sidebarTitle":"Deep research","href":"/agents/deep-research"},{"title":"Autopilot","sidebarTitle":"Autopilot","tag":"Beta","href":"/agents/autopilot"}]},{"group":"Improve answers","pages":[{"title":"Effective analytics with agents","sidebarTitle":"Effective analytics","href":"/agents/effective-analytics-with-agents"},{"title":"Custom agent skills","href":"/agents/custom-agent-skills"},{"title":"Agent context","sidebarTitle":"Agent context","href":"/agents/agent-context"},{"title":"Verified Answers","href":"/agents/verified-answers"},{"title":"Create evaluation suites","href":"/agents/create-evaluation-suites"},{"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":"Data apps","icon":"cube-spark","root":{"title":"Data apps","tag":"Beta","href":"/data-apps"},"tag":"Beta","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":"Download data apps as code","sidebarTitle":"Download as code","href":"/data-apps/download-data-apps-as-code"},{"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"}]},{"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":"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":"Organization credentials","href":"/workspace-admin/organization-credentials"},{"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","tag":"Beta","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","description":"Point Lightdash at a managed PostgreSQL database with the settings it needs","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","description":"Run scheduled deliveries on a dedicated worker so heavy exports can't starve the API","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":"Enterprise features","href":"/self-host/enterprise-features"},"pages":[{"title":"AI agents","href":"/self-host/enterprise-features/ai-agents"},{"title":"Data apps","href":"/self-host/enterprise-features/data-apps"},{"title":"Chart library","href":"/self-host/enterprise-features/chart-library"},{"title":"AI writeback","href":"/self-host/enterprise-features/ai-writeback"},{"title":"MCP","href":"/self-host/enterprise-features/mcp"},{"title":"Pre-aggregates","href":"/self-host/enterprise-features/pre-aggregates"},{"title":"Usage analytics","tag":"Beta","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":"Configure Lightdash to use external storage - Lightdash","buildId":"dpl_DeHjVRGfFnhYQwHnfC2pjeXXv8h9","deploymentId":"dpl_DeHjVRGfFnhYQwHnfC2pjeXXv8h9","dynamics":[],"chunks":[]}