---
title: Architecture
description: "How the Langfuse architecture evolved from Next.js on Vercel and Postgres to a distributed setup with ClickHouse, Redis, and blob storage."
---

# Langfuse Platform Architecture - High-Level Overview

Langfuse's infrastructure continuously evolves to support increasing scale and new product features. We started on Vercel and Supabase with Next.js and Postgres, and have evolved to the distributed architecture described below. As our product and scale requirements grow, we'll continue to mature our infrastructure to meet those needs.

Langfuse only depends on open source components and can be deployed locally, on cloud infrastructure, or on-premises.

```mermaid
flowchart TB
    User["UI, API, SDKs"]
    subgraph vpc["VPC"]
        Web["Web Server<br/>(langfuse/langfuse)"]
        Worker["Async Worker<br/>(langfuse/worker)"]
        Postgres@{ img: "/images/logos/postgres_icon.svg", label: "Postgres - OLTP\n(Transactional Data)", pos: "b", w: 60, h: 60, constraint: "on" }
        Cache@{ img: "/images/logos/redis_icon.png", label: "Redis\n(Cache, Queue)", pos: "b", w: 60, h: 60, constraint: "on" }
        Clickhouse@{ img: "/images/logos/clickhouse_icon.svg", label: "Clickhouse - OLAP\n(Observability Data)", pos: "b", w: 60, h: 60, constraint: "on" }
        S3@{ img: "/images/logos/s3_icon.svg", label: "S3 / Blob Storage\n(Raw events, multi-modal attachments)", pos: "b", w: 60, h: 60, constraint: "on" }
    end
    LLM["LLM API/Gateway<br/>(optional; BYO; can be same VPC or VPC-peered)"]

    User --> Web
    Web --> S3
    Web --> Postgres
    Web --> Cache
    Web --> Clickhouse
    Web -..->|"optional for playground"| LLM

    Cache --> Worker
    Worker --> Clickhouse
    Worker --> Postgres
    Worker --> S3
    Worker -..->|"optional for evals"| LLM
```

Langfuse consists of two application containers, storage components, and an optional LLM API/Gateway.

- [**Application Containers**](/self-hosting/deployment/infrastructure/containers)
  - Langfuse Web: The main web application serving the Langfuse UI and APIs.
  - Langfuse Worker: A worker that asynchronously processes events.
- **Storage Components**:
  - [Postgres](/self-hosting/deployment/infrastructure/postgres): The main database for transactional workloads.
  - [Clickhouse](/self-hosting/deployment/infrastructure/clickhouse): High-performance OLAP database which stores traces, observations, and scores.
  - [Redis/Valkey cache](/self-hosting/deployment/infrastructure/cache): A fast in-memory data structure store. Used for queue and cache operations.
  - [S3/Blob Store](/self-hosting/deployment/infrastructure/blobstorage): Object storage to persist all incoming events, multi-modal inputs, and large exports.
- [**LLM API / Gateway**](/self-hosting/deployment/infrastructure/llm-api): Some features depend on an external LLM API or gateway.

Langfuse can be deployed within a VPC or on-premises in high-security environments.
Internet access is optional.
See [networking](/self-hosting/security/networking) documentation for more details.

## Infrastructure Components

### Application Layer

```mermaid
graph LR
    Web["Langfuse Web<br/>(Next.js UI + API Layer)"]
    Worker["Langfuse Worker<br/>(Async Event Processing)"]

    Web -->|Queue| Worker
```

- **Web container (NextJs)**: Serves the UI application and all APIs.
- **Worker container (Express)**: Processes ingestion events in the background and executes async tasks (e.g. exports, eval execution).

### Evaluation Layer

```mermaid
graph LR
    Worker["Langfuse Worker<br/>(Evaluation Orchestration)"]
    LLM["External LLM Providers<br/>(LLM-as-a-Judge)"]
    CodeEval["AWS Lambda<br/>(Code Evaluator Runners)"]

    Worker -->|LLM API Calls| LLM
    Worker -->|CodeEvalDispatcher| CodeEval
```

- **LLM-as-a-Judge**: The worker calls external LLM providers to execute model-based evaluators.
- **Code evaluator Lambda runners**: Execute [code evaluators](/docs/evaluation/evaluation-methods/code-evaluators) outside the worker through the `CodeEvalDispatcher` abstraction. Production deployments use tenant-isolated AWS Lambda runners with [AWS Lambda tenant isolation](https://docs.aws.amazon.com/lambda/latest/dg/tenant-isolation.html).

### Storage Layer

```mermaid
flowchart LR
    Postgres["PostgreSQL<br/>(OLTP)<br/><br/>Transactional Data"]
    ClickHouse["ClickHouse<br/>(OLAP)<br/><br/>Observability Analytics"]
    Redis["Redis<br/>(Queue)<br/><br/>Event Queue"]
    S3["S3/Blob Storage<br/><br/>Raw Events +<br/>Media Files"]

    Postgres ~~~ ClickHouse ~~~ Redis ~~~ S3
```

- **PostgreSQL**: Stores transactional data (users, organizations, projects, API keys, prompts, datasets, LLM as a Judge settings).
- **ClickHouse**: Stores tracing data (traces, observations, scores). We use it to run dashboards, metrics, and render tables in the UI.
- **Redis**: Stores event queue (BullMQ) and caching layer (API keys, prompts).
- **S3**: Stores raw ingestion events and multi-modal attachments (images, audio).

### Why do we need an OLAP database (Clickhouse) for observability data?

- We built Langfuse initially on Postgres and eventually migrated to Clickhouse. We always knew that Postgres won't be the best fit for our observability data.
- OLAP databases have a columnar layout. With that the database only scans data required to produce results for analytical queries (e.g. LLM cost over time).
- We needed a multi-node database to scale our data insert.
- As we are an open source product, we required a database which runs on an open source license.

---

## Production environments

Our production infrastructure is deployed across multiple AWS regions with a fully automated CI/CD pipeline. All infrastructure is managed using Terraform. Cloudflare WAF (Web Application Firewall) serves as a central proxy in front of AWS.

```mermaid
---
config:
  flowchart:
    subGraphTitleMargin:
      bottom: 30
---
graph TB


    MR["Turborepo Monorepository (web/worker/shared code)"]
    Python["Python SDK"]
    JS["JS/TS SDK"]

    NPM["NPM Registry"]
    PYPI["PyPI Registry"]


    JS --> NPM
    Python --> PYPI


    GHA["GitHub Actions"]

    MR --> GHA

    TF["Terraform <br/>(private repository)"]
    TF --> ECR
    TF --> VPN
    TF --> Observability


    subgraph CD["CI/CD Pipeline"]
        GHA -->|Build & Push| ECR[AWS ECR]
        GHA -->|Build & Push| DockerHub["Docker Hub<br/>(OSS releases)"]
    end
    ECR -->|Deploy| VPN

    subgraph CF["Cloudflare"]
        WAF["WAF<br/>(Web Application Firewall)"]
        Proxy["Central Proxy"]
    end

    CF -->|Traffic| VPN

    subgraph VPN["<span style='display:block; width:100%; text-align:left; white-space: nowrap;'><i>Langfuse Cloud (US, EU, HIPAA)</i></span>"]
        ECS["AWS ECS Fargate (Web + Worker)"]

        subgraph StorageInfra["Storage"]
            ElastiCache["ElastiCache Redis (Clustered)"]
            S3[S3 Buckets]
            Aurora[Aurora PostgreSQL]
            CH[ClickHouse Cloud]
        end

        subgraph EvaluationInfra["Evaluation Execution"]
            Lambda["AWS Lambda<br/>(Tenant-Isolated Code Evaluator Runners)"]
        end

        ECS --> ElastiCache
        ECS --> S3
        ECS --> Aurora
        ECS --> CH
        ECS -->|CodeEvalDispatcher| Lambda
    end

    subgraph OSS["Managed OSS Deployment Templates"]
        direction LR
        DockerCompose["Docker Compose"]
        AWSCustomer["AWS"]
        AzureCustomer["Azure"]
        GCPCustomer["GCP"]
        HelmCharts["Helm Charts"]
    end

    DockerHub -->|Deploy| OSS



    subgraph "Observability"
        DataDog
        Sentry
        Pagerduty

        DataDog --> Pagerduty
        Sentry --> Pagerduty
    end

    VPN --> Observability
```

## Data Ingestion from SDKs

  ![Architecture](/images/handbook/product-engineering/architecture.png)

- **SDKs**: SDKs instrument the applications of our users. We built our own Python/JS SDKs which use OpenTelemetry under the hood.
- **API**: SDKs send data to our API, which uploads the data to S3 and queues it for processing by the worker.
- **Redis queue**: Decouples ingestion from processing. We only pass S3 references through Redis.
- **Worker processing**: Asynchronously processes ingestion events, enriches events, flushes to ClickHouse.
- **Dual database**: ClickHouse for analytical queries, Postgres for transactional data

<!-- agent-instructions -->

---

## Agent Instructions

This page is part of the [Langfuse](https://langfuse.com) documentation, published as plain Markdown for AI agents. Every page is available as Markdown by appending `.md` to its URL, or by sending an `Accept: text/markdown` header. This page: `https://langfuse.com/handbook/product-engineering/architecture.md`.

### Querying these docs

If the answer is not on this page, query the documentation instead of guessing:

- **Semantic search** across all Langfuse docs, returning an answer with the relevant pages and excerpts. Ask a specific, self-contained question:

  ```bash
  curl -sG "https://langfuse.com/api/search-docs" --data-urlencode "query=How do I trace a LangGraph agent?"
  ```

- **Index of every page**: <https://langfuse.com/llms.txt>, with per-section indexes [llms-docs.txt](https://langfuse.com/llms-docs.txt), [llms-integrations.txt](https://langfuse.com/llms-integrations.txt), and [llms-self-hosting.txt](https://langfuse.com/llms-self-hosting.txt).

### Before writing Langfuse code

- **Install the [Langfuse Agent Skill](https://langfuse.com/docs/api-and-data-platform/features/agent-skill).** It encodes Langfuse's own best practices for instrumentation, prompt management, and evaluation, and materially improves results.
- **Read [What does a good trace look like?](https://langfuse.com/docs/observability/best-practices.md)** before instrumenting an application.
- **Verify endpoints, parameters, and response fields** against the [API reference](https://api.reference.langfuse.com) instead of inferring them from code examples.
- **Use the [Langfuse CLI](https://langfuse.com/docs/api-and-data-platform/features/cli)** (`npx langfuse-cli api <resource> <action>`) to read or write traces, prompts, datasets, and scores from the terminal.

Found an error in these docs? Please open an issue at <https://github.com/langfuse/langfuse-docs/issues>.
