Skip to main content
Cluster runs Latitude on Kubernetes through a cloud-agnostic Helm chart: a Deployment per application service, a one-shot migrations job, ingress, and bundled infrastructure (Postgres, ClickHouse, Redis, Temporal, SeaweedFS) — every piece replaceable by a managed equivalent. It deploys the published Docker images.
For a simpler start on one machine, use the Single-host deployment — same images, same configuration contract, no cluster required.

Quick start

1

Get the chart

The chart lives in the Latitude repository under charts/latitude — a sparse checkout downloads just that folder:
git clone --depth 1 --filter=blob:none --sparse https://github.com/latitude-dev/latitude-llm.git
cd latitude-llm
git sparse-checkout set charts/latitude
cd charts/latitude
2

Create your values file

Don’t name it values.yaml — that file already holds the chart’s defaults.
my-values.yaml
config:
  webUrl: https://latitude.example.com
  apiUrl: https://api.latitude.example.com
  ingestUrl: https://ingest.latitude.example.com
  extraEnv:
    # Email transport — required for magic-link sign-in (choose one provider)
    - name: LAT_SMTP_HOST
      value: smtp.example.com
    - name: LAT_SMTP_PORT
      value: "587"
    - name: LAT_SMTP_USER
      value: apikey
    - name: LAT_SMTP_FROM
      value: noreply@example.com

secrets:
  masterEncryptionKey: # openssl rand -hex 32
  betterAuthSecret: # openssl rand -hex 32
  # Optional secret env vars (email passwords, AI provider keys, OAuth
  # client secrets) — delivered through the chart-managed Secret.
  extra:
    LAT_SMTP_PASS: your-smtp-password

postgres:
  auth:
    password: # openssl rand -hex 16
    runtimePassword: # openssl rand -hex 16

clickhouse:
  auth:
    password: # openssl rand -hex 16

ingress:
  className: nginx
  # tls: [...]
The secrets are permanent for the installation — keep this file (or move the keys into a pre-created Secret and set secrets.existingSecret). Every future helm upgrade must receive the same values.
3

Install the chart in your cluster

The install brings up the bundled infrastructure, runs database migrations and the Temporal schema setup as one-shot jobs, and starts the five application services.
helm install latitude . \
  --namespace latitude --create-namespace \
  --values my-values.yaml --timeout 15m
4

Verify the Latitude services are running

All pods should reach Running/Ready and the latitude-migrations, latitude-temporal-schema, and latitude-temporal-namespace jobs should show Complete.
kubectl get pods -n latitude
kubectl get jobs -n latitude
5

Create the first account

Open the web UI (at your config.webUrl) and register. Latitude sends a magic link through the email transport you configured; click it to finish signing in and create your organization.

What gets deployed

WorkloadKindPurpose
web, api, ingestDeployment + ServiceUI, public API & MCP server, OTLP trace ingestion — exposed via the ingress
workers, workflowsDeploymentBullMQ background jobs and Temporal workers — internal only
migrationsJob (post-install, pre-upgrade)One-shot Postgres + ClickHouse migrations
postgresStatefulSet + PVCPrimary store + pgvector
clickhouseStatefulSet + PVCSpan/telemetry OLAP store
redis, redis-bullmqDeployment / StatefulSet + PVCCache + durable queues
temporalDeployment + schema JobsWorkflow engine, Postgres-backed (no Elasticsearch/Cassandra)
seaweedfsStatefulSet + PVCS3-compatible object store (single container, same recipe as Single-host)

Secrets

Optional non-secret settings (email transport, LAT_AI_* model selection, integrations) go in config.extraEnv as standard EnvVar entries; optional secret values (AI provider keys, email passwords, OAuth client secrets) go in secrets.extra, which merges them into the chart-managed Secret — never as extraEnv literals, which would sit readable in the pod spec. To manage secrets yourself (e.g. with an external secrets operator), create a Secret carrying the chart’s expected keys and set secrets.existingSecret — the chart then renders no Secret of its own. The key list is in the chart README. See the secrets reference for what each application secret does.

AI features

The stack boots and core observability (ingest + trace viewing) works without API keys. AI-dependent features stay disabled until you add credentials for the providers you configure — keys in secrets.extra, LAT_AI_* provider/model selection in config.extraEnv:
CapabilityProvidersFeature
GenerationAmazon Bedrock (default), Anthropic, OpenAI, Google, or any OpenAI-compatible endpointFlaggers, evaluations, issue summarization, taxonomy naming, AI generation
EmbeddingsVoyage AI (default), OpenAI, Google, or any OpenAI-compatible endpointSemantic trace/issue search, search highlights, issue clustering
RerankingVoyage AI (default) or Amazon BedrockIssue-discovery candidate matching
Every provider and model is selectable per feature through environment variables — see the AI configuration reference.

Scaling

The five application services are stateless and scale horizontally:
helm upgrade latitude . --values my-values.yaml --set api.replicas=3
# or imperatively:
kubectl scale deploy/latitude-api -n latitude --replicas=3
Every service ships with resource requests (HPA-ready); add limits and HorizontalPodAutoscalers to taste. The bundled stateful services stay single-instance by design — for HA move them to managed equivalents (Bring your own infrastructure).

Backups

Persistent state lives in the PVCs of postgres, clickhouse, redis-bullmq, and seaweedfs. Use your storage provider’s volume snapshots, plus:
  • Postgreskubectl exec -n latitude latitude-postgres-0 -- pg_dump -U latitude latitude (the source of truth for projects, users, and metadata).
  • ClickHouse — volume snapshots or ClickHouse BACKUP (span/telemetry data).
  • Object store — volume snapshots (or rely on your managed S3’s durability).

Upgrading

The chart version tracks the Latitude release, and the images default to the chart’s appVersion — so the chart always deploys the release it shipped with. To upgrade, pull the new chart and run:
helm upgrade latitude . --values my-values.yaml
To deviate from the chart’s pinned release, set image.tag (X.Y.Z with no leading v, or latest). Migrations run as a pre-upgrade hook — the schema is upgraded before the new pods roll. Latitude migrations are backward-compatible, so the previous release keeps working during the rollout.

Health and observability

Every service exposes an HTTP health endpoint, wired as readiness and liveness probes (/health; the web app uses /api/health; workers/workflows listen on internal ports 9090/9091). OpenTelemetry export is available through the LAT_OBSERVABILITY_* variables via config.extraEnv.

TLS and reverse proxy

The chart’s Ingress routes the three public hosts (taken from config.{web,api,ingest}Url) to the web, api, and ingest Services over plain HTTP inside the cluster — terminate TLS at your ingress controller. Reference your certificate Secrets in ingress.tls, or have cert-manager issue them via ingress.annotations:
ingress:
  className: nginx
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt
  tls:
    - secretName: latitude-tls
      hosts:
        - latitude.example.com
        - api.latitude.example.com
        - ingest.latitude.example.com
Keep the config.*Url values on https:// — they feed the LAT_*_URL and CORS/trusted-origin settings.

Bring your own infrastructure

Every bundled dependency is an independent toggle: set <dep>.enabled: false and fill its external: block, and the chart wires the right LAT_* configuration at your existing or managed instance instead of deploying the bundle.
postgres:
  enabled: false
  external:
    databaseUrl: postgres://latitude_app:...@my-rds:5432/latitude
    adminDatabaseUrl: postgres://latitude:...@my-rds:5432/latitude

temporal:
  enabled: false
  external:
    address: my-namespace.a1b2c.tmprl.cloud:7233
    namespace: my-namespace.a1b2c
    apiKey: ...
DependencyToggleNotes
Postgrespostgres.enabledNeeds the vector (pgvector) extension and a schema-create admin role
ClickHouseclickhouse.enabledDedicated database; external.migrationUrl is host:port only (clickhouse://host:9000)
Redis (cache)redis.enabledLatitude namespaces all keys under latitude:, so a shared Redis is safe
Redis (queue)redisBullmq.enabledSame namespacing; needs noeviction
Temporaltemporal.enabledTemporal Cloud or the official temporalio/helm-charts (SQL persistence, no Cassandra/Elasticsearch) for an HA cluster
Object storageseaweedfs.enabledAny S3-compatible store; omit endpoint/forcePathStyle for AWS S3

Next steps

Configuration reference

The full Latitude configurable environment-variable reference for self-hosting.