Quarkus Langfuse

A Quarkus extension for Langfuse, the open-source LLM engineering platform. This extension provides a type-safe REST client (based on the Langfuse Java SDK), DevServices for zero-config local development, and a Dev UI card for quick access to the Langfuse dashboard.

What is Langfuse?

Langfuse is an open-source LLM engineering platform that helps teams collaboratively debug, analyze, and iterate on their LLM applications. It provides:

  • Observability - Capture comprehensive traces covering LLM and non-LLM calls, including retrieval, embedding, API calls, and more. Track multi-turn conversations and multi-step agentic workflows with sessions. Surface quality, cost, and latency metrics at a glance.

  • Prompt management - Manage, version, and optimize prompts throughout development. Deploy prompts to production or other environments without any code changes. Compare latency, cost, and evaluation metrics across different versions.

  • Evaluation - Attach numeric, boolean, or categorical evaluation scores to traces. Create dataset collections for systematic testing. Run LLM-as-a-judge evaluations on production or development traces.

Features

This extension integrates Langfuse into the Quarkus ecosystem with the following features:

  • Type-safe Langfuse API client - Synchronous and asynchronous clients covering the full Langfuse public API (traces, ingestion, prompts, scores, datasets, observations, sessions, and more), built on the Quarkus REST Client Reactive.

  • CDI integration - Inject LangfuseApi directly into your beans. No Quarkus-specific types needed.

  • DevServices - Automatically starts a complete Langfuse stack (Langfuse server, PostgreSQL, ClickHouse, Redis, MinIO, and Worker) in dev and test mode using Testcontainers. No manual setup required.

  • Dev UI - Provides a Dev UI card with a direct link to the Langfuse dashboard running in your local DevServices instance.

  • Native image support - Compatible with GraalVM native image compilation.

  • OpenTelemetry integration - When quarkus-opentelemetry is on the classpath, automatically exports AI-related spans to Langfuse via OTLP. Zero configuration needed with DevServices.

Installation

Add the io.quarkiverse.langfuse:quarkus-langfuse extension to your build file.

Maven

<dependency>
    <groupId>io.quarkiverse.langfuse</groupId>
    <artifactId>quarkus-langfuse</artifactId>
    <version>0.1.1</version>
</dependency>

Gradle

implementation 'io.quarkiverse.langfuse:quarkus-langfuse:0.1.1'

Configuration

Configure your Langfuse connection in application.properties:

quarkus.langfuse.base-url=https://cloud.langfuse.com
quarkus.langfuse.username=pk-lf-...
quarkus.langfuse.password=sk-lf-...
When DevServices is enabled (the default in dev/test mode), base-url, username, and password are automatically configured for you. You only need to set these properties when connecting to an external Langfuse instance or in production.

The username and password properties correspond to the Langfuse project public key and project secret key, respectively. You can find these in the Langfuse dashboard under Settings > API Keys.

For a complete list of configuration properties, see the Extension Configuration Reference.

Usage

Simply inject LangfuseApi into your CDI beans. The extension automatically configures and provides the implementation:

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;

import com.langfuse.api.LangfuseApi;

@ApplicationScoped
public class MyService {

    @Inject
    LangfuseApi langfuseApi;

    public void listTraces() {
        // Synchronous call
        var traces = langfuseApi.trace().traceList(/* parameters */);

        // Asynchronous call
        var asyncTraces = langfuseApi.asyncTrace().traceList(/* parameters */);
    }

    public void listPrompts() {
        var prompts = langfuseApi.prompts().promptsList(/* parameters */);
    }

    public void checkHealth() {
        var health = langfuseApi.health().healthHealth();
    }
}

Available API Groups

The LangfuseApi bean provides access to the full Langfuse public API. Each API group is available as a method, with both synchronous and asynchronous variants (e.g., trace() / asyncTrace()):

API Group Description

health()

Health check endpoints

trace()

Create, list, delete, and manage traces

observations()

Query observations (spans and generations)

ingestion()

Batch ingest traces, spans, generations, scores, and events

prompts()

Manage, version, and retrieve prompts

promptVersion()

Manage individual prompt versions

scores()

Create, query, and delete evaluation scores

scoreConfigs()

Manage score configurations

sessions()

List and query sessions

datasets()

Create and manage datasets

datasetItems()

Manage dataset items

datasetRunItems()

Manage dataset run items

models()

Manage model definitions and pricing

projects()

Query projects

organizations()

Query organizations

comments()

Create and manage comments on traces

media()

Upload and manage media attachments

metrics()

Query usage metrics (cost, token counts, latency)

opentelemetry()

OpenTelemetry trace ingestion

annotationQueues()

Manage annotation queues for human review

llmConnections()

Manage LLM provider connections

Example: Listing Prompts

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;

import com.langfuse.api.LangfuseApi;

@ApplicationScoped
public class PromptService {

    @Inject
    LangfuseApi langfuseApi;

    public void listAllPrompts() {
        var prompts = langfuseApi.prompts().promptsList(APIPromptsListRequest.newBuilder().build());

        prompts.getData().forEach(prompt ->
            System.out.println(prompt.getName() + " (v" + prompt.getVersion() + ")")
        );
    }
}

OpenTelemetry Integration

When the quarkus-opentelemetry extension is present in your project, the Langfuse extension automatically exports OpenTelemetry span data to Langfuse. No additional configuration is needed — the extension uses your existing quarkus.langfuse.username and quarkus.langfuse.password for authentication.

Export Target

The quarkus.langfuse.otel.export-target property (build time) controls how spans are exported:

  • ALL (default) — The extension registers a dedicated Langfuse span processor that runs alongside any other OpenTelemetry exporters you have configured. Spans are exported to both Langfuse and your standard OTLP backend (Jaeger, Zipkin, or any other collector). In this mode, only AI-related spans are sent to Langfuse by default (see AI Span Filtering below), and the gen_ai.prompt / gen_ai.completion attributes are automatically mapped to the Langfuse trace input and output.

  • LANGFUSE_ONLY — The standard OpenTelemetry OTLP exporter is configured to send directly to Langfuse. No separate span processor is registered and no additional OTLP backend receives spans. All spans are exported to Langfuse without filtering. This is equivalent to the manual configuration described in the Quarkus LangChain4j docs, but handled automatically by the extension.

quarkus.langfuse.otel.export-target=LANGFUSE_ONLY

AI Span Filtering

When export-target=ALL (the default), only AI-related spans and their ancestor spans are exported to Langfuse. A span is considered AI-related if it carries any gen_ai.* OpenTelemetry Semantic Convention attributes (such as gen_ai.system, gen_ai.request.model, gen_ai.response.finish_reasons, etc.). Ancestor spans — the parent chain leading up to an AI span — are included to preserve trace structure.

This filtering prevents infrastructure noise (HTTP server spans, database queries, framework internals) from cluttering your Langfuse dashboard while still giving you full context around AI operations.

Additionally, the gen_ai.prompt and gen_ai.completion attributes are automatically mapped to the Langfuse trace input and output fields, so you get immediate visibility into what was sent to and received from the LLM.

To export all spans instead of only AI-related ones:

quarkus.langfuse.otel.span-filter=ALL

Quarkus LangChain4j Integration

When both quarkus-opentelemetry and quarkus-langchain4j are on the classpath, the extension automatically enables LangChain4j prompt tracing by setting the following properties to true:

  • quarkus.langchain4j.tracing.include-prompt

  • quarkus.langchain4j.tracing.include-completion

  • quarkus.langchain4j.tracing.include-tool-arguments

  • quarkus.langchain4j.tracing.include-tool-result

This means prompt content, LLM responses, tool arguments, and tool results are all included in the OpenTelemetry spans emitted by LangChain4j — and therefore visible in Langfuse traces — without any manual configuration.

These defaults are set at a low priority, so you can override any of them in application.properties or via environment variables if needed.

Example

With a simple AI Service

import jakarta.enterprise.context.ApplicationScoped;

import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;

import io.quarkiverse.langchain4j.RegisterAiService;

@RegisterAiService
@ApplicationScoped
public interface ChatService {
    @SystemMessage("You are a helpful assistant.")
    String chat(@UserMessage String prompt);
}

It will automatically send traces to Langfuse:

Trace Dashboard
Trace Details

Zero-Config with DevServices

When DevServices is running, the OpenTelemetry integration works out of the box with no configuration at all. The Langfuse base URL, public key, and secret key are all provided automatically by DevServices, and the span processor uses those values to connect to the local Langfuse instance.

Disabling the Integration

To disable the automatic OpenTelemetry integration (for example, if you want to manage your own OTel exporters or send spans to a different backend):

quarkus.langfuse.otel.enabled=false
When quarkus-opentelemetry is not on the classpath, the integration is automatically skipped regardless of this setting.

For the full list of OpenTelemetry configuration properties, see the Extension Configuration Reference.

DevServices

In dev and test mode, the extension automatically starts a complete Langfuse stack using Testcontainers. This means you can start building and testing against Langfuse immediately with zero configuration - just add the extension and run:

mvn quarkus:dev

The DevServices stack includes:

Service Purpose

Langfuse server

The main Langfuse application with web UI and API

PostgreSQL

Primary database for Langfuse data

ClickHouse

Analytics database for high-performance queries

Redis

Cache and queue management

MinIO

S3-compatible object storage for media and blobs

Worker

Background job processing

The extension automatically configures the quarkus.langfuse.base-url, quarkus.langfuse.username, and quarkus.langfuse.password properties to point to the DevServices instance.

Container Sharing

By default, DevServices containers are shared across multiple Quarkus applications running on the same machine. This is useful when developing microservices that all connect to the same Langfuse instance. Sharing uses label-based container discovery with the quarkus-dev-service-langfuse label.

To disable sharing or use separate containers per application:

quarkus.langfuse.devservices.shared=false

DevServices can be customized under the quarkus.langfuse.devservices prefix. DevServices automatically creates an organization, project, and user for local development. Each infrastructure service (PostgreSQL, ClickHouse, Redis, MinIO, Worker) can also be customized with its own image name, credentials, and container environment variables. For a complete list of DevServices configuration properties, see the Extension Configuration Reference.

Dev UI

When running in dev mode (quarkus dev), the extension adds a Langfuse card to the Quarkus Dev UI (available at http://localhost:8080/q/dev-ui). The card provides a direct link to the Langfuse web dashboard running in your DevServices container.

Langfuse Dev UI card

From the Langfuse dashboard you can:

  • Browse and inspect traces and their nested spans/generations

  • Manage and version prompts

  • View sessions for multi-turn conversation tracking

  • Review scores and evaluation results

  • Create and run datasets for systematic testing

  • Monitor cost, latency, and quality metrics

The default credentials for logging into the DevServices Langfuse UI are:

  • Email: quarkus@quarkus.io

  • Password: quarkuslangfuse

Debugging and Logging

Enable request and response logging for troubleshooting:

quarkus.langfuse.log-requests=true
quarkus.langfuse.log-responses=true
quarkus.langfuse.pretty-print=true

This logs all HTTP requests and responses exchanged with the Langfuse server. Authorization headers are automatically masked in the logs for security.

Extension Configuration Reference

Configuration property fixed at build time - All other configuration properties are overridable at runtime

Configuration property

Type

Default

If DevServices has been explicitly enabled or disabled. DevServices are generally enabled by default, unless there is an existing configuration present.

When DevServices is enabled, Quarkus will attempt to automatically configure and start a Langfuse server when running in Dev or Test mode.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_ENABLED

boolean

true

Indicates if the Langfuse server managed by Quarkus Dev Services is shared. When shared, Quarkus looks for running containers using label-based service discovery. If a matching container is found, it is used, and so a second one is not started. Otherwise, Dev Services for Langfuse starts a new container.

The discovery uses the quarkus-dev-service-langfuse label. The value is configured using the service-name property.

Container sharing is only used in dev mode.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_SHARED

boolean

true

The value of the quarkus-dev-service-langfuse label attached to the started container. This property is used when shared is set to true. In this case, before starting a container, Dev Services for Langfuse looks for a container with the quarkus-dev-service-langfuse label set to the configured value. If found, it will use this container instead of starting a new one. Otherwise, it starts a new container with the quarkus-dev-service-langfuse label set to the specified value.

This property is used when you need multiple shared Langfuse servers.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_SERVICE_NAME

string

langfuse

The container image name to use for the Langfuse web server.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_LANGFUSE_IMAGE_NAME

string

docker.io/langfuse/langfuse:3

The port the Langfuse web server listens on inside the container.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_LANGFUSE_PORT

int

3000

The username used for authentication with the Langfuse API.

This maps to the Langfuse project public key used to initialize the dev instance.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_LANGFUSE_USERNAME

string

quarkus

The password used for authentication with the Langfuse API.

This maps to the Langfuse project secret key used to initialize the dev instance.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_LANGFUSE_PASSWORD

string

quarkuslangfuse

Maximum duration to wait for the Langfuse container to start up.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_LANGFUSE_STARTUP_TIMEOUT

Duration 

${QUARKUS.DEVSERVICES.TIMEOUT:PT3M}

The organization ID to initialize in the Langfuse instance.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_LANGFUSE_INIT_ORG_ID

string

quarkus

The organization name to initialize in the Langfuse instance.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_LANGFUSE_INIT_ORG_NAME

string

Quarkus Dev Org

The project ID to initialize in the Langfuse instance.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_LANGFUSE_INIT_PROJECT_ID

string

quarkus-dev-project

The project name to initialize in the Langfuse instance.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_LANGFUSE_INIT_PROJECT_NAME

string

quarkus-dev

The user email to initialize in the Langfuse instance.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_LANGFUSE_INIT_USER_EMAIL

string

quarkus@quarkus.io

The user name to initialize in the Langfuse instance.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_LANGFUSE_INIT_USER_NAME

string

quarkus

The user password to initialize in the Langfuse instance.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_LANGFUSE_INIT_USER_PASSWORD

string

quarkuslangfuse

Whether to enable experimental features in Langfuse.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_LANGFUSE_ENABLE_EXPERIMENTAL_FEATURES

boolean

false

Whether to enable batch export in Langfuse.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_LANGFUSE_BATCH_EXPORT_ENABLED

boolean

false

The delay between ingestion queue processing cycles.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_LANGFUSE_INGESTION_QUEUE_DELAY

Duration 

The interval between ClickHouse write flushes for ingested events.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_LANGFUSE_INGESTION_CLICKHOUSE_WRITE_INTERVAL

Duration 

The email "from" address for Langfuse email notifications.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_LANGFUSE_EMAIL_FROM_ADDRESS

string

The SMTP connection URL for Langfuse email notifications.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_LANGFUSE_SMTP_CONNECTION_URL

string

Environment variables that are passed to the Langfuse web server container.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_LANGFUSE_CONTAINER_ENV__CONTAINER_ENV_

Map<String,String>

The container image name to use for the PostgreSQL database.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_POSTGRES_IMAGE_NAME

string

postgres:17

The database username.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_POSTGRES_USERNAME

string

quarkus

The database password.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_POSTGRES_PASSWORD

string

quarkuspostgres

The database name.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_POSTGRES_DATABASE_NAME

string

quarkus-langfuse

Environment variables that are passed to the PostgreSQL container.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_POSTGRES_CONTAINER_ENV__CONTAINER_ENV_

Map<String,String>

The container image name to use for the ClickHouse analytics database.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_CLICKHOUSE_IMAGE_NAME

string

clickhouse/clickhouse-server

The database username.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_CLICKHOUSE_USERNAME

string

quarkus

The database password.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_CLICKHOUSE_PASSWORD

string

quarkusclickhouse

The database name.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_CLICKHOUSE_DATABASE_NAME

string

quarkusclickhouse

Environment variables that are passed to the ClickHouse container.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_CLICKHOUSE_CONTAINER_ENV__CONTAINER_ENV_

Map<String,String>

The container image name to use for the Redis cache.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_REDIS_IMAGE_NAME

string

redis:7

The Redis password.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_REDIS_PASSWORD

string

quarkusredis

Whether TLS is enabled for the Redis connection.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_REDIS_TLS_ENABLED

boolean

false

Environment variables that are passed to the Redis container.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_REDIS_CONTAINER_ENV__CONTAINER_ENV_

Map<String,String>

The container image name to use for the MinIO object storage.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_MINIO_IMAGE_NAME

string

cgr.dev/chainguard/minio

The MinIO root user.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_MINIO_ROOT_USER

string

quarkus

The MinIO root password.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_MINIO_ROOT_PASSWORD

string

quarkusminio

The name of the S3 bucket to create.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_MINIO_BUCKET_NAME

string

quarkuslangfuse

Environment variables that are passed to the MinIO container.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_MINIO_CONTAINER_ENV__CONTAINER_ENV_

Map<String,String>

The container image name to use for the Langfuse worker.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_WORKER_IMAGE_NAME

string

docker.io/langfuse/langfuse-worker:3

Environment variables that are passed to the Langfuse worker container.

Environment variable: QUARKUS_LANGFUSE_DEVSERVICES_WORKER_CONTAINER_ENV__CONTAINER_ENV_

Map<String,String>

Whether to automatically configure the OpenTelemetry OTLP exporter to send traces to Langfuse when the quarkus-opentelemetry extension is present.

Defaults to the value of quarkus.otel.enabled, falling back to true if that property is not set.

Environment variable: QUARKUS_LANGFUSE_OTEL_ENABLED

boolean

${quarkus.otel.enabled:true}

Specifies the target destination for exporting telemetry data in the OpenTelemetry integration configuration. The default value is "ALL", which directs telemetry data to both the regular OTLP-configured target and Langfuse.

Environment variable: QUARKUS_LANGFUSE_OTEL_EXPORT_TARGET

all, langfuse-only

all

The base URL of the Langfuse server

Environment variable: QUARKUS_LANGFUSE_BASE_URL

string

required

Langfuse project public key, used for API authentication. Found in the Langfuse dashboard under Settings > API Keys.

Environment variable: QUARKUS_LANGFUSE_USERNAME

string

required

Langfuse project secret key, used for API authentication. Found in the Langfuse dashboard under Settings > API Keys.

Environment variable: QUARKUS_LANGFUSE_PASSWORD

string

required

Timeout for Langfuse calls

Environment variable: QUARKUS_LANGFUSE_TIMEOUT

Duration 

1M

Whether the Langfuse client should log requests

Environment variable: QUARKUS_LANGFUSE_LOG_REQUESTS

boolean

false

Whether the Langfuse client should log responses

Environment variable: QUARKUS_LANGFUSE_LOG_RESPONSES

boolean

false

Controls whether request/response bodies are pretty-printed if log-requests() or log-responses() is set to true

Environment variable: QUARKUS_LANGFUSE_PRETTY_PRINT

boolean

false

Timeout to establish a connection to Langfuse.

Defaults to quarkus.langfuse.timeout

Environment variable: QUARKUS_LANGFUSE_CONNECT_TIMEOUT

Duration 

${QUARKUS.LANGFUSE.TIMEOUT}

Timeout for receiving a response from the Langfuse.

Defaults to quarkus.langfuse.timeout

Environment variable: QUARKUS_LANGFUSE_READ_TIMEOUT

Duration 

${QUARKUS.LANGFUSE.TIMEOUT}

The URL used for ingesting traces in the OpenTelemetry integration for Langfuse. The URL points to the endpoint where trace data is exported.

Environment variable: QUARKUS_LANGFUSE_OTEL_TRACE_INGESTION_URL

string

${quarkus.langfuse.base-url}/api/public/otel/v1/traces

Retrieves the configured span filter type used for OpenTelemetry integration within Langfuse. The span filter determines which spans are included based on their context or relevance to specific operations, such as AI-related activities.

Environment variable: QUARKUS_LANGFUSE_OTEL_SPAN_FILTER

all, ai-only

ai-only

About the Duration format

To write duration values, use the standard java.time.Duration format. See the Duration#parse() Java API documentation for more information.

You can also use a simplified format, starting with a number:

  • If the value is only a number, it represents time in seconds.

  • If the value is a number followed by ms, it represents time in milliseconds.

In other cases, the simplified format is translated to the java.time.Duration format for parsing:

  • If the value is a number followed by h, m, or s, it is prefixed with PT.

  • If the value is a number followed by d, it is prefixed with P.