- Docker Compose: Set in your
.envfile - Helm chart: Set via
values.yaml(the chart maps values to env vars automatically) - Raw Kubernetes: Set directly in your Deployment manifests
Core Configuration
Secrets
Authentication
SSO Provider Variables
Each SSO provider requires specific variables. See SSO Configuration for detailed setup guides. Auth0:
Azure AD:
GitHub:
GitLab:
Google:
Okta:
Services
Object Storage (S3)
The dataplane S3 bucket is the general file-storage layer for all externalized byte content. Current consumers:- Stored objects: externalized byte content (audio, image, video, document) extracted from incoming events and dataset uploads. Bytes are content-addressed under
{projectId}/{sha256}and served back viaGET /api/files/:id. - Dataset uploads: persists rows uploaded through the dataset UI. Shares the same
S3_BUCKET_NAMEbucket.
S3_BUCKET_NAME is set, all consumers use that bucket. When it is not set, stored-objects fall back to the local filesystem at LANGWATCH_LOCAL_STORAGE_PATH. That is fine for single-replica installs, not for horizontally-scaled deployments (see warning below).
When running on AWS with IRSA (IAM Roles for Service Accounts), you don’t need to set S3 access keys. The pod’s service account assumes the IAM role automatically.
Object Storage (Azure Blob)
Azure Blob Storage is an alternative to S3 for the same dataplane consumers (stored objects + dataset uploads). It is selected only by the explicitSTORED_OBJECTS_BACKEND=azure toggle. Setting the AZURE_BLOB_* variables below by themselves has no effect. This is deliberate (issue #4133): deployment behavior must not depend on which env vars happen to be set, so a stray AZURE_BLOB_ACCOUNT_KEY left over from a decommissioned integration can never silently redirect writes.
Precedence, evaluated in this order: a per-project BYOC S3 bucket (if configured for that project) beats the azure toggle; the azure toggle beats S3_BUCKET_NAME; S3_BUCKET_NAME beats the local-filesystem fallback. This azure backend covers datasets too: the destination resolver is shared by both write paths.
Migrating an existing installation
Do not switchSTORED_OBJECTS_BACKEND before copying existing data. The migration task uses its own OBJECT_STORAGE_MIGRATION_* credentials, so source reads and destination writes do not depend on the app’s active provider:
plan is read-only. copy is resumable, verifies SHA-256 at the destination, and repairs a mismatched destination object. finalize refuses to run unless both reads and writes are explicitly paused, dataset uploads are idle, and GroupQueue has no pending, delayed, active, blocked, or staged durable references. Reads must remain paused because finalization publishes destination storage addresses before the target-provider deployment is active. It publishes newer ClickHouse stored-object rows only after the final verified copy; it does not rewrite or delete history. No phase deletes source bytes.
After finalize succeeds, update STORED_OBJECTS_BACKEND and the active provider credentials while traffic remains paused, deploy that configuration, run verify, then resume traffic. A global migration excludes projects with private S3 buckets; they remain on their tenant-owned S3 destination.
Keep the source provider’s read credentials configured through the rollback window. Finalization rewrites stored-object addresses to the destination scheme, so a rollback that reverts STORED_OBJECTS_BACKEND and removes the destination provider’s credentials leaves every rewritten address unreadable. The bytes still exist on both providers (no phase deletes them), but the deployment can no longer serve that scheme. Concretely:
- S3 → Azure: after cutover, keep
S3_BUCKET_NAME+ S3 credentials configured (Helm:app.dataplane.legacyS3ReadBucket) so pre-migrations3://history stays readable. If you roll back to S3, keep theAZURE_BLOB_*settings configured (Helm:app.dataplane.legacyAzureRead: true) so the finalizedazure-blob://addresses stay readable. - Azure → S3: the mirror image. Keep
AZURE_BLOB_*(Helm:legacyAzureRead) after cutover, and keep the S3 settings if you roll back.
file:// from a local-storage era). Those rows are out of the migration’s scope, stay on their current addresses, and remain readable as long as that scheme’s backend stays configured.
Authenticating without an account key
AZURE_BLOB_AUTH_MODE selects how the app proves who it is. It defaults to sharedKey, so existing installs are unaffected.
Many organisations set allowSharedKeyAccess=false on the storage account, frequently enforced through Azure Policy. On such an account the shared-key mode does not degrade: every request is refused. Use one of the identity modes instead:
Whichever identity you use, grant it Storage Blob Data Contributor on the storage account or the specific container. The control-plane Contributor role does not grant data access. This is the single most common setup mistake, and it surfaces as a permission error rather than a sign-in error.
Three rules before you configure it:
- There is no fallback. If an identity mode is selected and the identity is missing or unauthorised, storage fails loudly and stays down until it is fixed. It never quietly reverts to an account key, because that would reverse your security decision at the moment you are least likely to notice.
- An account key alongside an identity mode is rejected. A key that would be silently ignored is worse than no key, since you would believe it was in use.
- Bearer tokens require HTTPS. A plaintext
AZURE_BLOB_ENDPOINTis refused before any token is sent.
app.dataplane.providers.azureBlob.authMode and enable global.serviceAccount (create: true plus the azure.workload.identity/client-id annotation). The chart refuses to render workloadIdentity without a ServiceAccount, since the identity would have nothing to bind to. Federated Kubernetes identity is supported on AKS only, because the token injection depends on the Azure workload-identity webhook. On clusters without it, use managedIdentity or sharedKey.
On AKS, three things must line up or the token exchange fails with AADSTS70021 before any storage call is made. The app surfaces that code and this remedy in the error, but they are easier to get right up front:
- The federated identity credential’s issuer must match the cluster’s OIDC issuer exactly, including the trailing slash. Read it with
az aks show --query oidcIssuerProfile.issuerUrl. If the cluster is ever recreated the issuer changes and every federated credential silently stops working. - Its subject must be
system:serviceaccount:<namespace>:<service-account-name>, matched case-exactly against the ServiceAccount the chart creates. - Its audience must be
api://AzureADTokenExchange.
EMAIL_PROVIDER.
See Email for choosing a gateway and setting one up.
When
EMAIL_PROVIDER is not set, the gateway is inferred from whichever credentials are present (USE_AWS_SES first, then SENDGRID_API_KEY), so existing installs keep working untouched. smtp and resend must always be named explicitly.
SendGrid
AWS SES
Credentials come from the standard AWS chain (instance role, IRSA, or
AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY).
SMTP
Use this for an internal relay, Azure Communication Services, Office 365, Google Workspace, Postmark, Mailgun, Brevo, or any other gateway that speaks SMTP.Resend
Sending through an outbound proxy
Deployments whose only egress is a corporate HTTP proxy can set the standardHTTPS_PROXY (or HTTP_PROXY) and NO_PROXY variables. The ses, resend and sendgrid gateways all route their API calls through it; NO_PROXY entries are honoured, including leading-dot domain suffixes and *.
The smtp gateway ignores these variables on purpose, because an SMTP relay is normally an internal host that must be reached directly. Point it at your relay’s real address, or use a vendor’s SMTP endpoint if that is what the proxy allows out.
Neither the AWS SDK nor Node’s HTTP client reads
HTTPS_PROXY on its own, so LangWatch attaches the proxy to the SES and Resend clients itself. SendGrid’s client is axios-based and reads the variables directly. Without this wiring, a proxied deployment fails with a read ETIMEDOUT reaching the provider.Evaluator Providers
Feature Flags
Telemetry
Langy (optional)
Langy, the automated AI engineer, runs as a separate agent pod that is off by default. Enabling it adds alangyagent.chartManaged toggle and a shared LANGY_INTERNAL_SECRET (plus optional GITHUB_LANGY_* and mirror-lane vars). Those are documented on their own page.
See Langy environment variables for the full
LANGY_* and GITHUB_LANGY_* reference, and Setup for the langyagent.chartManaged toggle and the LANGY_INTERNAL_SECRET secret.Helm Chart Mapping
When using the Helm chart, configuration is set invalues.yaml rather than environment variables directly. Here’s how key values map: