How to Self-Host Langfuse

Open-source LLM observability on your own infrastructure — tracing, evaluation, and dashboards with zero per-trace cost. This guide walks through a Docker Compose deployment suitable for testing and moderate-scale production, with clear guidance on when to graduate to Kubernetes for high volume.

By the LLM Academy team · Reviewed June 2026 · Based on official Langfuse self-hosting docs and community production guides

Why self-host Langfuse?

Langfuse is MIT-licensed and free to self-host with no trace limits and feature parity with the managed cloud tier. For teams that want full observability without per-trace bills, data residency control, or freedom from vendor lock-in, self-hosting is the answer. The trade-off is operational: you run the Langfuse backend, a PostgreSQL database (12+), and optionally Redis for caching. For most teams this is one Docker Compose stack on a single VM.

When to self-host vs. use Langfuse Cloud

If you want zero operations, Langfuse Cloud is managed. If you want cost control at scale, data residency, or no per-trace limits, self-host. See our observability platform comparison for the full tradeoff across vendors.

Prerequisites

You need a host with Docker and Docker Compose — any cloud VM or on-prem server with 2+ GB RAM works for testing and low-volume production. Langfuse requires PostgreSQL 12 or newer to store traces, evaluations, and project metadata. The Docker Compose file below bundles Postgres so you can start in minutes; for production-scale deployments, use a managed Postgres instance rather than the bundled one.

Step 1 — Run Langfuse with Docker Compose

The official Langfuse Docker Compose deployment bundles the Langfuse web app, a PostgreSQL database, and the required configuration. Save this as docker-compose.yml, set the environment variables, and bring it up. The NEXTAUTH_SECRET and SALT must be random strings you generate (use openssl rand -hex 32).

# docker-compose.yml (Langfuse v3)
services:
  langfuse:
    image: langfuse/langfuse:latest
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgresql://langfuse:langfuse@postgres:5432/langfuse
      - NEXTAUTH_URL=http://localhost:3000
      - NEXTAUTH_SECRET=${NEXTAUTH_SECRET}      # openssl rand -hex 32
      - SALT=${SALT}                            # openssl rand -hex 32
      - CLICKHOUSE_URL=http://clickhouse:8123
      - REDIS_URL=redis://redis:6379
    depends_on:
      - postgres
      - clickhouse
      - redis

  postgres:
    image: postgres:16
    environment:
      - POSTGRES_USER=langfuse
      - POSTGRES_PASSWORD=langfuse
      - POSTGRES_DB=langfuse
    volumes:
      - langfuse_pg:/var/lib/postgresql/data

  clickhouse:
    image: clickhouse/clickhouse-server:latest
    volumes:
      - langfuse_ch:/var/lib/clickhouse

  redis:
    image: redis:7

volumes:
  langfuse_pg:
  langfuse_ch:

Bring it up with docker-compose up -d. Langfuse v3 uses ClickHouse for high-volume trace event storage alongside Postgres for metadata — this separation lets it scale to millions of spans without slowing the UI. Open http://localhost:3000, create an account, and create your first project.

[IMAGE: Langfuse stack topology — app → Langfuse SDK → Langfuse API → Postgres (metadata) + ClickHouse (events)]

Step 2 — Create a project and API keys

Inside the Langfuse UI, create a project (e.g., "production") and generate a pair of API keys: a public key and a secret key. These keys authenticate your application when it sends traces. The secret key must be kept server-side — never expose it in client code.

# In the Langfuse UI:
# Settings → Projects → New Project → "production"
# API Keys → Create new keys
# Copy: pk-lf-xxxxxxxx  (public)  and  sk-lf-xxxxxxxx  (secret)

The project also gets a unique project_id that scopes all traces, evaluations, and dashboards. For multi-tenant setups, create one project per environment (production, staging) or per application.

Step 3 — Instrument your app

Install the Langfuse SDK and initialize it with your keys. For Python, the langfuse package wraps your LLM calls; for JavaScript/TypeScript, use langfuse. The SDK captures prompts, responses, token counts, latency, and costs automatically when you use its decorators or the OpenTelemetry integration.

# Python example
from langfuse import Langfuse
from langfuse.openai import openai   # drop-in OpenAI wrapper

langfuse = Langfuse(
    public_key="pk-lf-xxxxxxxx",
    secret_key="sk-lf-xxxxxxxx",
    host="http://localhost:3000",
)

# Use the wrapped openai client — every call is traced
response = openai.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "Hello"}],
)

For applications not using OpenAI directly, the OpenTelemetry integration works with any framework — LangChain, LlamaIndex, Haystack, or raw HTTP calls. Traces appear in the Langfuse UI within seconds, grouped by trace with nested spans for each step.

Production considerations

The official Langfuse docs are explicit: Docker Compose is suitable for testing and low-scale deployments. For production-scale workloads, the v3 architecture discussion recommends Kubernetes (via Helm) or a managed Postgres + ClickHouse rather than the bundled containers. Specifically:

Pair Langfuse tracing with a gateway like LiteLLM for correlated cost and quality data across every request.

Common pitfalls

Traces not appearing usually means the SDK host is wrong (must point at your Langfuse instance, not langfuse.com) or the API keys are mismatched to the project. Slow UI at scale means ClickHouse is undersized — Langfuse v3 separates hot event storage (ClickHouse) from metadata (Postgres) precisely so the UI stays fast under load. High memory use on the bundled Postgres under heavy trace volume is the signal to move to managed databases.

Related deep dives

Sources

Langfuse ships frequent releases (v2 → v3 changed the storage architecture). Always verify against langfuse.com/self-hosting for your target version before deploying.