Skip to main content

Context

In May 2026, we released SmithDB, a new observability database built for modern AI agents. SmithDB delivers industry-leading performance across every key observability workload, making core LangSmith experiences dramatically faster. SmithDB-powered methods are now available to SDK users in eligible regions.

Deployment support

DeploymentStatus
US SaaSAvailable. Methods are fully SmithDB-backed.
EU and other SaaS regionsMethods are available but not yet backed by SmithDB.
Self-hostedSupported starting with self-hosted version 0.16.0.

Minimum SDK version

The SmithDB-backed methods require a minimum SDK version:
LanguagePackageMinimum version
Pythonlangsmith>=0.9.8
TypeScriptlangsmith>=0.7.15
Javalangsmith-java0.1.0-beta.11
Golangsmith-gov0.17.0

Migrate with an AI agent

This guide is written to be fetched and applied directly by an AI coding agent. Copy the following prompt into your agent to migrate your codebase to the SmithDB-backed methods.
Migrate this codebase's LangSmith SDK usage to the new SmithDB-backed methods.

Fetch https://docs.langchain.com/langsmith/smithdb-sdk-migration.md and treat it
as the source of truth for what changed, including which methods and
parameters are affected, what replaces them, and deployment support.

1. Check the installed LangSmith SDK version against the minimum version
   required for the SmithDB-backed methods per the guide, and upgrade the
   dependency if it does not meet that minimum.
2. Identify every call site in this codebase that uses a method the guide
   marks as migrated, in whichever language(s) this codebase uses.
3. For each call site, apply the corresponding before/after change from the
   guide, including any added, removed, or renamed parameters.

If a call site or parameter is not covered by the guide, stop and ask rather
than guessing.

Runs: query

Query runs from a project with optional filtering and field projection. Returns a paginated result set.

Main changes

Method name

BeforeAfter
client.list_runs()client.runs.query()

Query parameters

project_name is not supported in runs.query. Pass project_ids with the project UUID instead. To look up a UUID by name, use client.read_project(project_name="my-project"), or await client.aread_project(project_name="my-project") in async code.
min_start_time defaults to 1 day ago when omitted. list_runs with no start_time returned all historical runs; runs.query without min_start_time silently scopes the query to the last 24 hours. Pass an explicit min_start_time if you need a wider window.
Before (list_runs)After (runs.query)Notes
project_name(removed)Use project_ids with UUID(s)—see warning above
project_idproject_idsNow takes a list; mutually exclusive with reference_dataset_id
run_typerun_typeValues must now be uppercase: "LLM", "CHAIN", "TOOL", "RETRIEVER", "EMBEDDING", "PROMPT", "PARSER"
trace_idtrace_idUnchanged
reference_example_idreference_examplesNow takes a list of UUIDs
query(removed)No equivalent
filterfilterSyntax unchanged
trace_filtertrace_filterUnchanged
tree_filtertree_filterUnchanged
is_rootis_rootUnchanged
parent_run_id(removed)No equivalent
start_timemin_start_timeRenamed; defaults to 1 day ago—see warning above
errorhas_errorRenamed
run_idsidsRenamed
selectselectsField names are now uppercase ("NAME", "STATUS", etc.)
limit(removed)Use page_size for per-request batch size
(not available)max_start_timeUpper bound for start_time; defaults to now
(not available)page_sizePer-request result count (default 100, max 1000)
(not available)reference_dataset_idAlternative to project_ids; mutually exclusive
(not available)cursorPass next_cursor from previous response to fetch next page

Response fields

Pass SCREAMING_SNAKE_CASE strings to selects (eg. "ID", "NAME", "STATUS") to control which fields are populated on each Run; only selected fields are non-None. Default selects contains only "ID".
Before (v1 Run attribute)After (v2 Run attribute)Notes
run.idrun.idUnchanged; returned by default when selects is omitted
run.namerun.nameUnchanged
run.run_typerun.run_typeValues are now uppercase Literals: "LLM", "CHAIN", etc.
run.statusrun.statusValues: "SUCCESS", "ERROR", "PENDING"
run.start_timerun.start_timeUnchanged
run.end_timerun.end_timeUnchanged
run.errorrun.errorUnchanged
run.inputsrun.inputsUnchanged
run.outputsrun.outputsUnchanged
run.tagsrun.tagsUnchanged
run.extrarun.extraUnchanged
run.metadatarun.metadataUnchanged
run.eventsrun.eventsUnchanged
run.reference_example_idrun.reference_example_idUnchanged
run.trace_idrun.trace_idUnchanged
run.dotted_orderrun.dotted_orderUnchanged
run.parent_run_id(removed)Use run.parent_run_ids (list of all ancestor UUIDs, root first)
run.parent_run_idsrun.parent_run_idsUnchanged
run.session_idrun.project_idRenamed; session_id was the project UUID
run.feedback_statsrun.feedback_statsUnchanged
run.app_pathrun.app_pathUnchanged
run.attachmentsrun.attachmentsv2 returns pre-signed download URLs instead of raw bytes
run.total_tokensrun.total_tokensUnchanged
run.prompt_tokensrun.prompt_tokensUnchanged
run.completion_tokensrun.completion_tokensUnchanged
run.total_costrun.total_costUnchanged
run.prompt_costrun.prompt_costUnchanged
run.completion_costrun.completion_costUnchanged
run.first_token_timerun.first_token_timeUnchanged
run.latency (property)run.latency_secondsRenamed; was a computed timedelta property, now a native float field
run.in_datasetrun.is_in_datasetRenamed
run.child_run_ids(removed)No equivalent
run.child_runs(removed)No equivalent
run.serialized(removed)Use run.manifest
run.manifest_id(removed)Use run.manifest
(not available)run.is_rootNew
(not available)run.manifestNew: full manifest object (replaces serialized and manifest_id)
(not available)run.error_previewNew: truncated error snippet
(not available)run.inputs_previewNew: truncated inputs preview
(not available)run.outputs_previewNew: truncated outputs preview
(not available)run.thread_idNew: conversation thread UUID
(not available)run.reference_dataset_idNew: dataset UUID for the reference example
(not available)run.share_urlNew: public share URL (only set when the run has been shared)
run.prompt_token_detailsrun.prompt_token_details.rawField now wraps the dict; access .raw to get dict[str, int] (element type unchanged)
run.completion_token_detailsrun.completion_token_details.rawField now wraps the dict; access .raw to get dict[str, int] (element type unchanged)
run.prompt_cost_detailsrun.prompt_cost_details.rawField now wraps the dict; access .raw to get dict[str, float] (was dict[str, Decimal])
run.completion_cost_detailsrun.completion_cost_details.rawField now wraps the dict; access .raw to get dict[str, float] (was dict[str, Decimal])

Examples

List all runs in a project

runs.query does not accept a project name directly. Resolve the project UUID with client.aread_project() first, then pass it as a string in project_ids.
Before
from langsmith import Client

client = Client()
runs = client.list_runs(project_name="default")

Selecting fields

list_runs returns a default set of fields with no selection needed. runs.query returns only id by default—pass selects=[...] to request more. Field names are now uppercase ("name""NAME").
Before
from langsmith import Client

client = Client()
# returns a default set of fields; no explicit selection needed
runs = client.list_runs(project_name="default")
for run in runs:
    print(run.id, run.name, run.run_type, run.status, run.start_time, run.inputs, run.error)

Filter by run type and time range

start_time is renamed to min_start_time, and run_type values are now uppercase ("llm""LLM").
Before
from datetime import datetime, timedelta

from langsmith import Client

client = Client()
runs = client.list_runs(
    project_name="default",
    start_time=datetime.now() - timedelta(days=1),
    run_type="llm",
)

Filter root runs only

is_root is unchanged.
Before
from langsmith import Client

client = Client()
runs = client.list_runs(project_name="default", is_root=True)

Fetch runs by ID list

id=[...] is renamed to ids=[...]. project_ids is now required even when filtering by run IDs—v1 allowed omitting the project context.
Before
from langsmith import Client

client = Client()
runs = client.list_runs(id=["<run-id-1>", "<run-id-2>"])

Iterate through runs

list_runs auto-paginates transparently, fetching up to 100 runs per API call and stopping once limit results are returned. runs.query does not accept a total limit; iterate with async for and break once you have enough, or use the returned page’s has_next_page()/get_next_page() for manual page-by-page control.
Before
from langsmith import Client

client = Client()
runs = client.list_runs(project_name="default", limit=150)

Filter runs with errors

error=True/False is renamed to has_error=True/False.
Before
from langsmith import Client

client = Client()
runs = client.list_runs(project_name="default", error=True)

Filter by metadata

The filter string syntax is unchanged: eq(metadata_key, ...) checks for key presence, combined with eq(metadata_value, ...) to match a specific value.
Before
from langsmith import Client

client = Client()
filter_str = 'and(eq(metadata_key, "user_id"), eq(metadata_value, "u_123"))'
runs = client.list_runs(project_name="default", filter=filter_str)

Complex boolean filters

Nested and() / or() filter expressions are unchanged.
Before
from langsmith import Client

client = Client()
filter_str = (
    'and(gt(start_time, "2023-07-15T12:34:56Z"),'
    ' or(neq(status, "error"),'
    '    and(eq(feedback_key, "Correctness"), eq(feedback_score, 0.0))))'
)
runs = client.list_runs(project_name="default", filter=filter_str)

Scoped filters: filter, trace_filter, tree_filter

filter, trace_filter, and tree_filter are unchanged. filter applies to the matched run, trace_filter to the root of its trace, and tree_filter to other runs in the trace tree (siblings and children).
Before
from langsmith import Client

client = Client()
runs = client.list_runs(
    project_name="default",
    filter='eq(name, "RetrieveDocs")',
    trace_filter='and(eq(feedback_key, "user_score"), eq(feedback_score, 1))',
    tree_filter='eq(name, "ExpandQuery")',
)

Runs: retrieve

Fetch a single run by ID. Returns only the run ID by default—specify a field selection list to retrieve additional data.

Main changes

Method name

BeforeAfter
client.read_run()client.runs.retrieve()

Query parameters

runs.retrieve requires two new fields—project_id and start_time—that read_run did not need. Both are required to locate the run in SmithDB.
Before (read_run)After (runs.retrieve)Notes
run_idrun_idUnchanged
load_child_runs(removed)No equivalent
(not available)project_idRequired—UUID of the project that owns the run
(not available)start_timeRequired—run’s start time (RFC3339), used with project_id to locate the run
(all fields returned by default)selectsField projection; defaults to ["ID"] only; field names are uppercase

Response fields

Pass SCREAMING_SNAKE_CASE strings to selects (eg. "ID", "NAME", "STATUS") to control which fields are populated on the returned Run; only selected fields are non-None. Default selects contains only "ID".
Before (v1 Run attribute)After (v2 Run attribute)Notes
run.idrun.idUnchanged; returned by default when selects is omitted
run.namerun.nameUnchanged
run.run_typerun.run_typeValues are now uppercase Literals: "LLM", "CHAIN", etc.
run.statusrun.statusValues: "SUCCESS", "ERROR", "PENDING"
run.start_timerun.start_timeUnchanged
run.end_timerun.end_timeUnchanged
run.errorrun.errorUnchanged
run.inputsrun.inputsUnchanged
run.outputsrun.outputsUnchanged
run.tagsrun.tagsUnchanged
run.extrarun.extraUnchanged
run.metadatarun.metadataUnchanged
run.eventsrun.eventsUnchanged
run.reference_example_idrun.reference_example_idUnchanged
run.trace_idrun.trace_idUnchanged
run.dotted_orderrun.dotted_orderUnchanged
run.parent_run_id(removed)Use run.parent_run_ids (list of all ancestor UUIDs, root first)
run.parent_run_idsrun.parent_run_idsUnchanged
run.session_idrun.project_idRenamed; session_id was the project UUID
run.feedback_statsrun.feedback_statsUnchanged
run.app_pathrun.app_pathUnchanged
run.attachmentsrun.attachmentsv2 returns pre-signed download URLs instead of raw bytes
run.total_tokensrun.total_tokensUnchanged
run.prompt_tokensrun.prompt_tokensUnchanged
run.completion_tokensrun.completion_tokensUnchanged
run.total_costrun.total_costUnchanged
run.prompt_costrun.prompt_costUnchanged
run.completion_costrun.completion_costUnchanged
run.first_token_timerun.first_token_timeUnchanged
run.latency (property)run.latency_secondsRenamed; was a computed timedelta property, now a native float field
run.in_datasetrun.is_in_datasetRenamed
run.child_run_ids(removed)No equivalent
run.child_runs(removed)No equivalent
run.serialized(removed)Use run.manifest
run.manifest_id(removed)Use run.manifest
(not available)run.is_rootNew
(not available)run.manifestNew: full manifest object (replaces serialized and manifest_id)
(not available)run.error_previewNew: truncated error snippet
(not available)run.inputs_previewNew: truncated inputs preview
(not available)run.outputs_previewNew: truncated outputs preview
(not available)run.thread_idNew: conversation thread UUID
(not available)run.reference_dataset_idNew: dataset UUID for the reference example
(not available)run.share_urlNew: public share URL (only set when the run has been shared)
run.prompt_token_detailsrun.prompt_token_details.rawField now wraps the dict; access .raw to get dict[str, int] (element type unchanged)
run.completion_token_detailsrun.completion_token_details.rawField now wraps the dict; access .raw to get dict[str, int] (element type unchanged)
run.prompt_cost_detailsrun.prompt_cost_details.rawField now wraps the dict; access .raw to get dict[str, float] (was dict[str, Decimal])
run.completion_cost_detailsrun.completion_cost_details.rawField now wraps the dict; access .raw to get dict[str, float] (was dict[str, Decimal])

Examples

Fetch a single run by ID

runs.retrieve requires two additional parameters that read_run did not need: project_id (UUID) and start_time. Both are required by the SmithDB storage model to locate a run efficiently. Resolve the project UUID via client.aread_project() first.
Before
from langsmith import Client

client = Client()
run_id = "<run-id>"
run = client.read_run(run_id)

Selecting fields

read_run returns a full run object with no selection needed. runs.retrieve returns only id by default—pass selects=[...] to request more.
Before
from langsmith import Client

client = Client()
run_id = "<run-id>"
run = client.read_run(run_id=run_id)
print(run.name, run.status, run.total_tokens)