JS/TS v5 → v6
For most users, v6 is a small upgrade. If you trace with startActiveObservation(), observe(), or an integration, and you create scores and fetch prompts through the managers (langfuse.prompt, langfuse.score, langfuse.dataset), your code keeps working as is. v6 needs Node.js 22+ and Langfuse Cloud or self-hosted Langfuse v4.59.0 or later.
Most removals in v6 were already marked @deprecated in v5. If your editor or a lint rule such as @typescript-eslint/no-deprecated flags no deprecated Langfuse APIs in your v5 code, you're most likely unaffected apart from the minimum versions, requestOptions on argument-less API methods, and direct api.scores calls. v5 didn't log deprecation warnings at runtime, so plain JavaScript code gets no warning.
All @langfuse/* packages are released together. Upgrade them to the same major version:
npm install @langfuse/client@6 @langfuse/tracing@6 @langfuse/otel@6baseUrl, LANGFUSE_BASE_URL, and LANGFUSE_BASEURL keep working as before.
Are you affected?
You only need to change something if one of these applies to you.
New in v6:
- You self-host Langfuse v3, or v4 older than v4.59.0, or run Node.js older than 22, or use
@langchain/coreolder than 1.0 → Minimum versions - You pass
requestOptionsto a generated API method without query parameters or a body, such asapi.datasets.get(name, { timeoutInSeconds })→ Request placeholder beforerequestOptions - You read the response of
api.scores.createor callapi.legacy.scoreV1.*directly →api.scoresresponse and delete - You call
api.scoresV3.getManyV3→ Score reads move toapi.scores.getMany - A proxy between your app and Langfuse rejects gzip-compressed requests → Under the hood
Previously deprecated in v5, now removed:
- You call top-level
LangfuseClientmethods such asgetPrompt(),getDataset(), orfetchTrace()→ DeprecatedLangfuseClientaliases removed - You call deprecated
langfuse.api.*methods, for exampleapi.trace.get,api.sessions,api.legacy.*, orapi.scores.getMany→ Deprecated Public API methods removed - You call
setActiveTraceIO(),span.setTraceIO(), orcreateTraceAttributes()→ Trace input/output setters removed - You call
item.link()on dataset items → Dataset itemlink()removed
If none of these apply, upgrade and you're done.
Breaking changes
These are new in v6. Ordered by how many users they affect.
Minimum versions
Affects: self-hosted Langfuse v3 or older than v4.59.0, Node.js older than 22, and the LangChain integration on LangChain 0.x.
| Requirement | v6 | If not met |
|---|---|---|
| Langfuse | Cloud, or self-hosted v4.59.0 or later | Unsupported. Upgrade Langfuse first, or stay on the previous SDK major |
| Node.js | >=22, packages compiled to ES2022 | Unsupported. Bundles for older runtimes must target ES2022 or transpile the SDK |
| LangChain | @langchain/core@^1.0.0 (was >=0.3.8) | Peer dependency conflict when installing @langfuse/langchain@6 |
If you self-host Langfuse v3, stay on JS/TS SDK v5. See the self-hosted compatibility matrix.
npm install @langfuse/langchain@6 @langchain/core@^1The CallbackHandler API and trace output are unchanged.
Request placeholder before requestOptions
Affects: calls that pass requestOptions to a generated API method that takes no query parameters and no body.
Breaks (new in v6, no prior deprecation): a TypeScript compile error. In plain JavaScript the options are ignored. These methods now take an empty request object before requestOptions, so requestOptions keeps its position if the endpoint gains query parameters later. Calls without requestOptions don't change.
v5:
await langfuse.api.datasets.get("qa-set", { timeoutInSeconds: 10 });
await langfuse.api.health.health({ maxRetries: 0 });v6:
await langfuse.api.datasets.get("qa-set", {}, { timeoutInSeconds: 10 });
await langfuse.api.health.health({}, { maxRetries: 0 });These are all 41 methods whose signature changed. Every other generated method keeps its signature.
| Method | Route |
|---|---|
annotationQueues.getQueue(queueId) | GET /api/public/annotation-queues/{queueId} |
annotationQueues.getQueueItem(queueId, itemId) | GET /api/public/annotation-queues/{queueId}/items/{itemId} |
annotationQueues.deleteQueueItem(queueId, itemId) | DELETE /api/public/annotation-queues/{queueId}/items/{itemId} |
blobStorageIntegrations.getBlobStorageIntegrations() | GET /api/public/integrations/blob-storage |
blobStorageIntegrations.getBlobStorageIntegrationStatus(id) | GET /api/public/integrations/blob-storage/{id} |
blobStorageIntegrations.deleteBlobStorageIntegration(id) | DELETE /api/public/integrations/blob-storage/{id} |
comments.getById(commentId) | GET /api/public/comments/{commentId} |
datasetItems.get(id) | GET /api/public/dataset-items/{id} |
datasetItems.delete(id) | DELETE /api/public/dataset-items/{id} |
datasets.get(datasetName) | GET /api/public/v2/datasets/{datasetName} |
evaluationRules.get(evaluationRuleId) | GET /api/public/v2/evaluation-rules/{evaluationRuleId} |
evaluationRules.delete(evaluationRuleId) | DELETE /api/public/v2/evaluation-rules/{evaluationRuleId} |
evaluators.get(evaluatorId) | GET /api/public/v2/evaluators/{evaluatorId} |
evaluators.delete(evaluatorId) | DELETE /api/public/v2/evaluators/{evaluatorId} |
health.health() | GET /api/public/health |
llmConnections.delete(id) | DELETE /api/public/llm-connections/{id} |
media.get(mediaId) | GET /api/public/media/{mediaId} |
models.get(id) | GET /api/public/models/{id} |
models.delete(id) | DELETE /api/public/models/{id} |
organizations.getOrganizationMemberships() | GET /api/public/organizations/memberships |
organizations.getProjectMemberships(projectId) | GET /api/public/projects/{projectId}/memberships |
organizations.getOrganizationProjects() | GET /api/public/organizations/projects |
organizations.getOrganizationApiKeys() | GET /api/public/organizations/apiKeys |
projects.get() | GET /api/public/projects |
projects.delete(projectId) | DELETE /api/public/projects/{projectId} |
projects.getApiKeys(projectId) | GET /api/public/projects/{projectId}/apiKeys |
projects.deleteApiKey(projectId, apiKeyId) | DELETE /api/public/projects/{projectId}/apiKeys/{apiKeyId} |
scim.getServiceProviderConfig() | GET /api/public/scim/ServiceProviderConfig |
scim.getResourceTypes() | GET /api/public/scim/ResourceTypes |
scim.getSchemas() | GET /api/public/scim/Schemas |
scim.getUser(userId) | GET /api/public/scim/Users/{userId} |
scim.deleteUser(userId) | DELETE /api/public/scim/Users/{userId} |
scoreConfigs.getById(configId) | GET /api/public/score-configs/{configId} |
scores.delete(scoreId) (replaces legacy.scoreV1.delete) | DELETE /api/public/scores/{scoreId} |
trace.delete(traceId) | DELETE /api/public/traces/{traceId} |
unstable.dashboardWidgets.get(widgetId) | GET /api/public/unstable/dashboard-widgets/{widgetId} |
unstable.dashboardWidgets.delete(widgetId) | DELETE /api/public/unstable/dashboard-widgets/{widgetId} |
unstable.dashboards.get(dashboardId) | GET /api/public/unstable/dashboards/{dashboardId} |
unstable.dashboards.delete(dashboardId) | DELETE /api/public/unstable/dashboards/{dashboardId} |
unstable.dashboards.deletePlacement(dashboardId, placementId) | DELETE /api/public/unstable/dashboards/{dashboardId}/placements/{placementId} |
unstable.skills.deleteVersion(skillName, skillVersion) | DELETE /api/public/unstable/skills/{skillName}/versions/{skillVersion} |
api.scores response and delete
Affects: code that reads the response of langfuse.api.scores.create(...) or calls langfuse.api.legacy.scoreV1.* directly. langfuse.score.* is unchanged.
Breaks: TypeScript compile errors, or TypeError / undefined at runtime in JavaScript.
api.scores.create()now accepts a singleCreateScoreRequestor an array, and returnsCreateScoresResponse, a union of the single-score and batch responses. Single-score calls keep working, but TypeScript code that reads fields from the response needs to narrow the type first.api.legacy.scoreV1.delete(scoreId)moves toapi.scores.delete(scoreId).api.legacy.scoreV1.create(...)was already marked@deprecatedin v5 in favor ofapi.scores.create(...). Thelegacy.CreateScoreRequest,legacy.CreateScoreResponse, andlegacy.CreateScoreSourcere-exports are removed; use the score types without thelegacyprefix.
v5:
const { id } = await langfuse.api.scores.create({
name: "accuracy",
value: 0.9,
traceId: "trace-id",
});
await langfuse.api.legacy.scoreV1.delete("score-id");v6:
import { LangfuseClient } from "@langfuse/client";
const langfuse = new LangfuseClient();
const response = await langfuse.api.scores.create({
name: "accuracy",
value: 0.9,
traceId: "trace-id",
});
if ("id" in response) {
console.log(response.id);
}
await langfuse.api.scores.delete("score-id");Score reads move to api.scores.getMany
Affects: code that calls langfuse.api.scoresV3.getManyV3(...).
Breaks: TypeScript compile errors, or TypeError at runtime in JavaScript, because api.scoresV3 no longer exists.
Scores API v3 reads moved into the scores namespace, next to create and delete. The arguments, the GetScoresV3Request and GetScoresV3Response types, and the response are unchanged. The v5 api.scores.getMany({ scoreIds }) read Scores API v2; in v6, the same method name reads Scores API v3 and filters by id instead of scoreIds.
v5:
const scores = await langfuse.api.scoresV3.getManyV3({
traceId: "trace-id",
fields: "subject",
});v6:
import { LangfuseClient } from "@langfuse/client";
const langfuse = new LangfuseClient();
const scores = await langfuse.api.scores.getMany({
traceId: "trace-id",
fields: "subject",
});Previously deprecated, now removed
v5 already marked each of these @deprecated and named the replacement. If you moved to the replacement, nothing changes.
Deprecated LangfuseClient aliases removed
Affects: code that calls the top-level convenience methods on LangfuseClient.
Previously deprecated in v5, now removed. Every alias was marked @deprecated in v5. In v6, TypeScript reports a compile error and JavaScript throws TypeError: ... is not a function. Use the managers or the api client instead. Some v5 notes pointed to api.trace.*, api.sessions.get, or api.datasets.getRun(s), which v6 removes too, so use the replacements below.
| Removed | Replacement |
|---|---|
langfuse.getPrompt(...) | langfuse.prompt.get(...) |
langfuse.createPrompt(...) | langfuse.prompt.create(...) |
langfuse.updatePrompt(...) | langfuse.prompt.update(...) |
langfuse.getDataset(...) | langfuse.dataset.get(...) |
langfuse.createDatasetItem(...) | langfuse.dataset.createItem(...) |
langfuse.resolveMediaReferences(...) | langfuse.media.resolveReferences(...) |
langfuse.createDataset(...) | langfuse.api.datasets.create(...) |
langfuse.getDatasetItem(id) | langfuse.api.datasetItems.get(id) |
langfuse.fetchMedia(id) | langfuse.api.media.get(id) |
langfuse.fetchTrace(id) | langfuse.api.observations.getMany({ traceId: id, ... }) |
langfuse.fetchTraces(...) | langfuse.api.observations.getMany({ ... }) |
langfuse.fetchObservation(id) | langfuse.api.observations.getMany({ filter: ..., ... }) |
langfuse.fetchObservations(...) | langfuse.api.observations.getMany(...) |
langfuse.fetchSessions(...) | langfuse.api.observations.getMany({ sessionId, ... }) |
langfuse.getDatasetRun(...) | langfuse.api.experiments.list(...) and .listItems(...) |
langfuse.getDatasetRuns(...) | langfuse.api.experiments.list({ datasetId, fromStartTime }) |
v5:
const prompt = await langfuse.getPrompt("support-agent");
const trace = await langfuse.fetchTrace("trace-id");v6:
import { LangfuseClient } from "@langfuse/client";
const langfuse = new LangfuseClient();
const prompt = await langfuse.prompt.get("support-agent");
const observations = await langfuse.api.observations.getMany({
traceId: "trace-id",
fields: "core,basic,io",
});Deprecated Public API methods removed
Affects: code that calls the endpoints below through langfuse.api.*.
Previously deprecated in v5, now removed. Each of these methods was marked @deprecated in v5, with a note naming its replacement. In v6 they are gone: TypeScript reports a compile error, and JavaScript gets TypeError or undefined. There is no api.legacy namespace anymore. For full replacement guidance, see the SDK method quick reference.
| Removed | Replacement |
|---|---|
api.trace.get(...), api.trace.list(...) | api.observations.getMany({ traceId, ... }) |
api.sessions.* | api.observations.getMany({ sessionId, ... }) |
api.legacy.observationsV1.* | api.observations.getMany(...) |
api.legacy.metricsV1.metrics(...) | api.metrics.metrics(...) |
api.scores.getMany(...) (v2), api.scores.getById(...) | api.scores.getMany(...) (Scores API v3) |
api.datasetRunItems.* | api.experiments.listItems(...) or the experiment runner |
api.datasets.getRun(...), .getRuns(...) | api.experiments.list(...) and .listItems(...) |
api.datasets.deleteRun(...) | List experiment items, then api.trace.deleteMultiple({ traceIds }) |
api.scores.getMany keeps its name but now reads Scores API v3; see Score reads move to api.scores.getMany.
Removed types include the trace, session, v1 observation, dataset run, and dataset run item response types, the ScoreV1 family, and SdkLogEvent.
To delete an experiment's data, page through its items and delete their traces. This also deletes their observations and scores:
import { LangfuseClient } from "@langfuse/client";
const langfuse = new LangfuseClient();
const dataset = await langfuse.dataset.get("qa-set");
// No experiment item starts before its dataset was created, so this covers every run.
const fromStartTime = dataset.createdAt;
const traceIds = new Set<string>();
let cursor: string | undefined;
do {
const page = await langfuse.api.experiments.listItems({
datasetId: dataset.id,
experimentName: "baseline",
fromStartTime,
cursor,
});
page.data.forEach((item) => traceIds.add(item.traceId));
cursor = page.meta.cursor ?? undefined;
} while (cursor);
const ids = [...traceIds];
for (let i = 0; i < ids.length; i += 1000) {
await langfuse.api.trace.deleteMultiple({ traceIds: ids.slice(i, i + 1000) });
}See Dataset runs → Experiments for details.
Trace input/output setters removed
Affects: code that calls setActiveTraceIO(), span.setTraceIO(), or createTraceAttributes(), or uses the LangfuseTraceAttributes type.
Previously deprecated in v5, now removed. All four were marked @deprecated in v5, pointing to propagateAttributes() for trace attributes. In v6, TypeScript reports a compile error, and JavaScript gets a missing export or TypeError. Trace input and output now come from the root observation.
v5:
import { startActiveObservation, setActiveTraceIO } from "@langfuse/tracing";
await startActiveObservation("request", async () => {
const result = await callLlm(query);
setActiveTraceIO({ input: query, output: result });
});v6:
import {
startActiveObservation,
updateActiveObservation,
} from "@langfuse/tracing";
await startActiveObservation("request", async (span) => {
const result = await callLlm(query);
span.update({ input: query, output: result });
// or, inside the active root observation:
// updateActiveObservation({ input: query, output: result });
});setActiveTraceAsPublic() and span.setTraceAsPublic() are unchanged. If you still use trace-level LLM-as-a-judge evaluators, migrate them to observation-level evaluators.
Dataset item link() removed
Affects: code that calls item.link() or uses the LinkDatasetItemFunction type.
Previously deprecated in v5, now removed. link() and LinkDatasetItemFunction were marked @deprecated in v5 in favor of runExperiment(). In v6, TypeScript reports a compile error and JavaScript throws TypeError: item.link is not a function. dataset.items is now a plain DatasetItem[]. Use the experiment runner to run your application on a dataset.
v5:
const dataset = await langfuse.dataset.get("qa-set");
for (const item of dataset.items) {
await startActiveObservation("qa-task", async (span) => {
const output = await myApp(item.input);
span.update({ input: item.input, output });
await item.link(span, "baseline");
});
}v6:
const dataset = await langfuse.dataset.get("qa-set");
const result = await dataset.runExperiment({
name: "baseline",
task: async (item) => myApp(item.input),
evaluators: [accuracy],
});
console.log(result.experimentUrl);See Experiments via SDK for the full runner API.
New features
These need no code changes.
- Experiment links.
result.experimentUrllinks directly to the experiment comparison view.LangfuseClientalso exposesgetProjectId()andgetExperimentUrl(experimentId). - Typed metadata filters. Numeric and boolean metadata keeps its type, and nested objects can be filtered by dotted path, such as
a.b = 1.propagateAttributes({ metadata })accepts any JSON-serializable value. - Batch score creation.
api.scores.create()accepts an array ofCreateScoreRequestobjects. - Experiment records. Run evaluations are sent for local-data runs too. Dataset versions (
datasetVersion) are recorded on items aslangfuse.experiment.item.version.
Under the hood
None of these need code changes. Each one has a setting if you need different behavior.
- Scores are sent in batches of up to 100 to
POST /api/public/scoresinstead of the legacy ingestion endpoint.langfuse.score.create(),.observation(),.trace(),flush(),shutdown(), and the batching settings work as before. If the server accepts only part of a batch (HTTP 207), the SDK logsLangfuse rejected N of M scores in batch:with the server's errors and doesn't retry the rejected scores. Each score carries the time it was queued as its timestamp.LangfuseBrowserClient.score()also sends each score toPOST /api/public/scores, with public-key authentication. - Score methods never throw. Input is validated on the client. Scores with an empty name or a non-finite or non-string value are logged at error level and dropped.
- Span batches are gzip-compressed on Node.js and Bun. If a proxy rejects compressed requests, pass
new LangfuseSpanProcessor({ compression: "none" })or setLANGFUSE_OTEL_COMPRESSION=none. The setting is read in this order:compression,LANGFUSE_OTEL_COMPRESSION,OTEL_EXPORTER_OTLP_TRACES_COMPRESSION,OTEL_EXPORTER_OTLP_COMPRESSION, then thegzipdefault. Values aregzipornone. Environment variables are case-insensitive, and an invalid value falls through to the next setting. Browser and edge runtimes ignore it. - Spans carry
x-langfuse-ingestion-version: 4, which enables real-time processing on Langfuse v4. To opt out, passadditionalHeaders: { "x-langfuse-ingestion-version": "3" }toLangfuseSpanProcessor.additionalHeadersoverride default headers case-insensitively. - Experiments are recorded through OpenTelemetry. The experiment runner sends experiment and item attributes on its spans instead of calling
POST /api/public/dataset-run-items.
Last updated on