Langfuse — Setup & Architecture¶
Cloud vs Self-Hosted¶
| Aspect | Langfuse Cloud | Self-hosted (OSS / Enterprise Edition) |
|---|---|---|
| Start time | Minutes: sign up, create project, copy keys | Docker Compose in minutes, production (Helm/Terraform) in days |
| Regions | EU (cloud.langfuse.com), US (us.cloud.langfuse.com), JP, HIPAA |
Wherever you run it |
| Data residency | Vendor-managed | Full control — often required for prompts with customer data |
| Upgrades, backups, scaling | Vendor | You: Postgres, ClickHouse, Redis, S3 |
| Data access window | Plan-based (Hobby 30 days, Core 90 days, Pro/Enterprise 3 years) | Unlimited by default |
| Paid features | Plan tiers (Hobby, Core, Pro, Enterprise) | Some features (project-level RBAC, data retention, SSO enforcement, audit logs) need an Enterprise license key |
For a QA team
Use a separate project (or a separate self-hosted instance) for test and CI traffic. Test traces then never pollute production dashboards, and retention can be short.
Self-Hosting Architecture¶
flowchart LR
SDK["Python SDK / OTLP exporters"] -- "HTTPS /api/public/*" --> WEB["langfuse-web<br/>UI + public API :3000"]
UI["Browser"] --> WEB
WEB -- "raw events" --> S3[("S3 / MinIO<br/>events, media, exports")]
WEB -- "enqueue" --> REDIS[("Redis / Valkey<br/>queues + cache")]
REDIS --> WORKER["langfuse-worker<br/>async processing :3030"]
WORKER --> S3
WORKER --> CH[("ClickHouse<br/>traces, observations, scores")]
WEB --> PG[("Postgres<br/>users, projects, prompts, datasets")]
WORKER --> PG
WEB --> CH
WORKER -. "LLM-as-a-judge, playground" .-> LLM["LLM API / gateway"]
| Component | Role | Notes |
|---|---|---|
| langfuse-web | Next.js app: UI and public REST/OTLP API | Stateless, scale horizontally |
| langfuse-worker | Consumes queues, writes events to ClickHouse, runs evals and exports | Stateless, scale by queue depth |
| Postgres | Transactional data: orgs, projects, API keys, prompts, datasets, score configs | Back up like any OLTP DB |
| ClickHouse | OLAP store for traces, observations, scores | Largest storage consumer |
| Redis / Valkey | Ingestion queue and cache | Must be persistent enough not to lose the queue on restart |
| S3 / MinIO / Blob | Raw event payloads, multi-modal media, batch exports | Any S3-compatible storage |
Ingestion is asynchronous: the API accepts the batch, stores the raw event in S3, enqueues it, and the worker writes it to ClickHouse. Expect a delay of a few seconds before a trace is queryable — important when tests read traces back.
Docker Compose Quick Start¶
git clone https://github.com/langfuse/langfuse.git
cd langfuse
# edit every line marked "# CHANGEME" in docker-compose.yml (or override via .env)
docker compose up -d
docker compose ps # web, worker, postgres, clickhouse, redis, minio
open http://localhost:3000 # sign up → create org → create project → API keys
| Service | Image (current major) | Port on host |
|---|---|---|
langfuse-web |
docker.langfuse.com/langfuse/langfuse:4 |
3000 |
langfuse-worker |
docker.langfuse.com/langfuse/langfuse-worker:4 |
127.0.0.1:3030 |
postgres |
postgres:17 |
127.0.0.1:5432 |
clickhouse |
clickhouse/clickhouse-server |
127.0.0.1:8123, 127.0.0.1:9000 |
redis |
redis:7 |
127.0.0.1:6379 |
minio |
MinIO | 9090 (S3 API for media uploads) |
- Compose is for local and test use: single VM, no HA. For production use the Helm chart or the cloud Terraform modules.
- VM sizing for Compose: at least 4 cores, 16 GiB RAM, ~100 GiB disk.
- Secrets to replace:
SALT,ENCRYPTION_KEY(openssl rand -hex 32),NEXTAUTH_SECRET, DB/ClickHouse/Redis/MinIO passwords. NEXTAUTH_URLmust match the URL users type in the browser.
Headless initialization (ephemeral CI instance)¶
The web container can create an org, project, user and API keys on first start — useful for a throwaway Langfuse in a CI job:
# .env next to docker-compose.yml
LANGFUSE_INIT_ORG_ID=qa-org
LANGFUSE_INIT_ORG_NAME=QA
LANGFUSE_INIT_PROJECT_ID=llm-tests
LANGFUSE_INIT_PROJECT_NAME=llm-tests
LANGFUSE_INIT_PROJECT_PUBLIC_KEY=pk-lf-ci-local
LANGFUSE_INIT_PROJECT_SECRET_KEY=sk-lf-ci-local
LANGFUSE_INIT_USER_EMAIL=qa@example.com
LANGFUSE_INIT_USER_NAME=qa
LANGFUSE_INIT_USER_PASSWORD=change-me-please
docker compose up -d
until curl -fsS http://localhost:3000/api/public/health; do sleep 2; done
export LANGFUSE_BASE_URL=http://localhost:3000
export LANGFUSE_PUBLIC_KEY=pk-lf-ci-local LANGFUSE_SECRET_KEY=sk-lf-ci-local
SDK Environment Variables¶
| Variable | Default | Purpose |
|---|---|---|
LANGFUSE_PUBLIC_KEY |
— | Project public key (pk-lf-...) |
LANGFUSE_SECRET_KEY |
— | Project secret key (sk-lf-...), server-side only |
LANGFUSE_BASE_URL |
https://cloud.langfuse.com |
API URL; LANGFUSE_HOST is the deprecated alias |
LANGFUSE_TRACING_ENVIRONMENT |
default |
Environment label: production, staging, ci |
LANGFUSE_RELEASE |
— | Release / git SHA attached to traces |
LANGFUSE_TRACING_ENABLED |
true |
Kill switch — false disables export |
LANGFUSE_SAMPLE_RATE |
1.0 |
Fraction of traces to send |
LANGFUSE_FLUSH_AT / LANGFUSE_FLUSH_INTERVAL |
SDK defaults | Batch size / interval (seconds) |
LANGFUSE_TIMEOUT |
SDK default | HTTP timeout in seconds |
LANGFUSE_DEBUG |
false |
Verbose SDK logs |
LANGFUSE_PROMPT_CACHE_DEFAULT_TTL_SECONDS |
60 |
Prompt cache TTL |
The same settings are constructor arguments when you need them in code:
from langfuse import Langfuse
langfuse = Langfuse(
public_key="pk-lf-...",
secret_key="sk-lf-...",
base_url="http://localhost:3000",
environment="ci",
release="a1b2c3d",
sample_rate=1.0,
)
assert langfuse.auth_check(), "Langfuse keys or base URL are wrong"
Environment names
Environments are free-form strings but must be lowercase letters, digits, - or _, and cannot start with langfuse. Pick a fixed set (production, staging, ci, local) and filter dashboards by it.
Organizations, Projects, API Keys¶
Organization (billing, members, SSO)
└── Project (traces, prompts, datasets, scores, API keys, retention)
├── Public key pk-lf-… identifies the project (safe in browser for feedback scores)
└── Secret key sk-lf-… full API access — backend and CI secrets only
- API keys are per project; data never crosses projects.
- Create a dedicated key pair per consumer (app, CI, notebook) so you can rotate one without breaking the others.
- Public API authentication is HTTP Basic:
public_key:secret_key.
curl -s -u "$LANGFUSE_PUBLIC_KEY:$LANGFUSE_SECRET_KEY" \
"$LANGFUSE_BASE_URL/api/public/traces?limit=5&tags=ci" | jq '.data[].id'
RBAC¶
| Role | Can do |
|---|---|
| Owner | Everything, including deleting the org/project and billing |
| Admin | Edit project settings, manage members and API keys |
| Member | View all data, create scores and annotations, work with prompts and datasets; no project configuration |
| Viewer | Read-only; most configuration hidden |
| None | No org-wide access — combine with a project-level role to grant a single project |
- Roles are assigned at organization level and inherited by projects.
- Project-level roles (override per project) require Pro + Teams add-on, Enterprise, or self-hosted Enterprise Edition.
- Typical QA setup: QA engineers are
Memberon the test project (create datasets, annotate) andVieweron production.
See also¶
- Langfuse — LLM Tracing, Prompts & Evals
- Langfuse — Tracing with the Python SDK
- Docker & Docker Compose — Compose
- OpenTelemetry — Python Observability
- Arize Phoenix