Implementation:Langfuse Langfuse Traces Repository
| Knowledge Sources | |
|---|---|
| Domains | Tracing, ClickHouse, Data Access |
| Last Updated | 2026-02-14 00:00 GMT |
Overview
The Traces Repository is the data-access layer for all trace-related ClickHouse operations, providing functions to check trace existence, upsert, query, filter, stream, and aggregate trace records.
Description
This repository module serves as the primary interface between the Langfuse application and the ClickHouse analytics database for trace data. Traces are the top-level entities in Langfuse's observability model, representing a single end-to-end request or workflow through an LLM application.
The module exports over 25 functions covering:
- Existence and validation -
checkTraceExistsAndGetTimestampvalidates trace references before evaluation job creation, using a +/- 2 day time window with optional observation-level filtering. - CRUD operations -
upsertTraceinserts or updates trace records;deleteTracesanddeleteTracesByIdshandle soft-deletion. - Batch retrieval -
getTracesByIds,getTracesBySessionId,getTraceByIdfor fetching individual or groups of traces. - Table listing with dynamic filters -
getTracesTable,getTracesTableCount,getTracesTableMetricsfor the paginated traces UI table with full filter and sort support. - Streaming -
getTracesStreamfor large-scale data export. - Analytics -
getTraceCountsByProjectAndDayfor usage aggregation per project per day, intentionally skipping FINAL for performance. - LangGraph support -
getObservationsForLanggraphVisualizationretrieves observation data with LangGraph-specific metadata fields (node, step) for graph visualization. - Session-related queries -
getTracesBySessionIdfor fetching all traces belonging to a session.
The module uses the shared ClickHouse query infrastructure including measureAndReturn for performance instrumentation, FilterList and createFilterFromFilterState for dynamic filtering, and deduplication via LIMIT 1 BY id, project_id with ORDER BY event_ts DESC.
Trace data is converted from ClickHouse row format to domain objects via convertClickhouseToDomain, which also applies rendering properties for controlling output format.
Usage
Use this module when you need to:
- Validate that a trace exists before scheduling an evaluation job.
- Upsert traces received from the ingestion API or SDK.
- Query filtered, paginated trace data for the web UI traces table.
- Fetch traces by ID for detail views or session views.
- Stream trace records for bulk CSV/JSON export.
- Retrieve per-project trace counts for usage analytics and billing.
Code Reference
Source Location
- Repository: Langfuse
- File: packages/shared/src/server/repositories/traces.ts
- Lines: 1-1619
Signature
export const checkTraceExistsAndGetTimestamp = async (params: {
projectId: string;
traceId: string;
timestamp: Date;
filter: FilterState;
maxTimeStamp: Date | undefined;
exactTimestamp?: Date;
}) => Promise<{ exists: boolean; timestamp?: Date }>;
export const upsertTrace = async (trace: Partial<TraceRecordReadType>) => Promise<void>;
export const getTracesByIds = async (
traceIds: string[],
projectId: string,
timestamp?: Date,
clickhouseConfigs?: ClickHouseClientConfigOptions,
) => TraceDomain[];
export const getTracesBySessionId = async (
projectId: string,
sessionIds: string[],
timestamp?: Date,
) => TraceDomain[];
export const getTraceCountsByProjectAndDay = async (params: {
startDate: Date;
endDate: Date;
}) => Array<{ count: number; projectId: string; date: string }>;
export function getObservationsForLanggraphVisualization(params: {
projectId: string;
traceId: string;
chMinStartTime: string;
chMaxStartTime: string;
}): Promise<Array<{
id: string;
parent_observation_id: string;
type: string;
name: string;
start_time: string;
end_time: string;
node: string;
step: string;
}>>;
Import
import {
checkTraceExistsAndGetTimestamp,
upsertTrace,
getTracesByIds,
getTracesBySessionId,
getTraceCountsByProjectAndDay,
} from "@langfuse/shared/src/server/repositories/traces";
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| projectId | string | Yes | The project ID scoping all queries |
| traceId | string | Yes (for single ops) | The unique identifier of the trace |
| traceIds | string[] | Yes (for batch ops) | Array of trace IDs for batch retrieval |
| timestamp | Date | Varies | Timestamp for time-windowed filtering; uses event payload or job timestamp |
| filter | FilterState | No | Dynamic filter conditions from the UI filter bar |
| orderBy | OrderByState | No | Column and direction for sorting results |
| limit / page | number | No | Pagination parameters |
| maxTimeStamp | Date | No | Upper bound timestamp for existence checks |
| exactTimestamp | Date | No | Exact date match for trace lookups |
| startDate / endDate | Date | Yes (for analytics) | Date range for aggregation queries (half-open interval) |
Outputs
| Name | Type | Description |
|---|---|---|
| TraceDomain | object | Domain model with id, name, timestamp, userId, sessionId, tags, metadata, input, output, etc. |
| exists | boolean | Whether a trace matching the criteria was found |
| count | number | Row count for paginated queries |
| stream | ReadableStream | Streaming interface for large data exports |
| analytics | Array<{count, projectId, date}> | Per-project per-day trace counts |
Usage Examples
// Check if a trace exists before scheduling an eval job
const result = await checkTraceExistsAndGetTimestamp({
projectId: "proj-123",
traceId: "trace-abc",
timestamp: new Date(),
filter: [],
maxTimeStamp: undefined,
});
if (result.exists) {
// Schedule evaluation job
}
// Upsert a trace from the ingestion pipeline
await upsertTrace({
id: "trace-abc",
project_id: "proj-123",
timestamp: new Date().toISOString(),
name: "chat-completion",
user_id: "user-1",
});
// Batch fetch traces by IDs
const traces = await getTracesByIds(
["trace-1", "trace-2", "trace-3"],
"proj-123",
);
// Get trace counts per project per day for usage analytics
const counts = await getTraceCountsByProjectAndDay({
startDate: new Date("2024-03-01"),
endDate: new Date("2024-03-03"),
});