Organize datasets with tags and stars, pin versions with snapshots, validate with schemas, and edit records programmatically.
After creating a dataset, you’ll typically organize, version, and modify it over time. Use the UI to tag, snapshot, and validate datasets at the dataset level, and use the SDK or the bt CLI to filter and edit individual records.
You can tag and star datasets to organize and find them in the datasets list. Tagging a dataset adds metadata that can be used to filter and group records, while starring a dataset causes it to sort first in the datasets table and dataset picker dropdowns.To tag datasets:
Tags are configured at the project level and shared across all objects — logs, experiments, dataset records, and entire datasets. See project tag settings.
To star a dataset, click the star icon next to the dataset’s name in the datasets list.
Snapshots are named checkpoints of a dataset at a specific point in time. Save a snapshot to preserve the current state before making changes, or to pin a specific version for experiments and environments.
Click Snapshots > + Save snapshot in the toolbar.This option is available only when the dataset is non-empty and has changed since the last snapshot was saved.
From the Snapshots dropdown, you can also:
Rename: Give the snapshot a descriptive name.
View: Open the snapshot in a read-only viewer.
Evaluate in experiment or Evaluate in playground: Run an eval using the snapshot’s data.
Restore: Roll the dataset back to the snapshot’s state.
Delete: Permanently remove the snapshot.
To create a snapshot, fetch a row from the dataset to get the current xact_id, then call POST /v1/dataset_snapshot. The dataset must be non-empty — an empty dataset has no xact_id to snapshot.
const datasetId = "<your-dataset-id>";// Fetch a row to get the current xact_idconst fetchResp = await fetch( `https://api.braintrust.dev/v1/dataset/${datasetId}/fetch?limit=1`, { headers: { Authorization: `Bearer ${process.env.BRAINTRUST_API_KEY}` } },);const { events } = await fetchResp.json();if (events.length === 0) { throw new Error("Cannot create a snapshot of an empty dataset.");}const xactId = events[0]._xact_id;// Create the snapshotawait fetch("https://api.braintrust.dev/v1/dataset_snapshot", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRAINTRUST_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ dataset_id: datasetId, name: "my-snapshot", xact_id: xactId }),});
import osimport httpxdataset_id = "<your-dataset-id>"# Fetch a row to get the current xact_idresp = httpx.get( f"https://api.braintrust.dev/v1/dataset/{dataset_id}/fetch", params={"limit": 1}, headers={"Authorization": f"Bearer {os.environ['BRAINTRUST_API_KEY']}"},)events = resp.json()["events"]if not events: raise ValueError("Cannot create a snapshot of an empty dataset.")xact_id = events[0]["_xact_id"]# Create the snapshothttpx.post( "https://api.braintrust.dev/v1/dataset_snapshot", json={"dataset_id": dataset_id, "name": "my-snapshot", "xact_id": xact_id}, headers={"Authorization": f"Bearer {os.environ['BRAINTRUST_API_KEY']}"},)
Use bt datasets snapshots to create, list, restore, and delete snapshots from the CLI:
# Snapshot the dataset's current statebt datasets snapshots create my-dataset baseline# List saved snapshotsbt datasets snapshots list my-dataset# Restore the dataset to a snapshotbt datasets snapshots restore my-dataset --name baseline# Delete a snapshotbt datasets snapshots delete my-dataset baseline
If you want to ensure all records have the same structure or make editing easier, define JSON schemas for your dataset fields. Schemas are particularly useful when multiple team members are manually adding records or when you need strict data validation.Dataset schemas enable:
Validation: Catch structural errors when adding or editing records.
Form-based editing: Edit records with intuitive forms instead of raw JSON.
Documentation: Make field expectations explicit for your team.
Filter dataset records using the Filter button in the dataset table. You can filter by any field — input, expected, metadata, tags, or scores — using SQL expressions.
import { initDataset } from "braintrust";const dataset = initDataset("My App", { dataset: "Customer Support" });// Insert a recordconst id = dataset.insert({ input: { question: "How do I reset my password?" }, expected: { answer: "Click 'Forgot Password' on the login page." },});// Update the recorddataset.update({ id, metadata: { reviewed: true, difficulty: "easy" },});await dataset.flush();
import braintrustdataset = braintrust.init_dataset(project="My App", name="Customer Support")# Insert a recordid = dataset.insert( input={"question": "How do I reset my password?"}, expected={"answer": "Click 'Forgot Password' on the login page."},)# Update the recorddataset.update( id=id, metadata={"reviewed": True, "difficulty": "easy"},)dataset.flush()
The update() method applies a merge strategy: only the fields you provide will be updated, and all other existing fields in the record will remain unchanged.
Use the bt datasets update CLI command (also available as add and refresh) to upsert records by stable ID:
Dot-separated path to use as the record ID instead of the id field
Each row must have a stable ID via the id field or --id-field. Rows without IDs are rejected.These commands upsert rows directly — rows not in the input are not deleted. refresh fails if the dataset does not exist.Use --id-field to extract an ID from a nested field (e.g., metadata.case_id). Escape literal dots as \. and literal backslashes as \\.
The Braintrust SDK flushes records asynchronously and installs exit handlers, but these hooks are not always respected (e.g., by certain runtimes or when exiting a process abruptly). Call flush() to ensure records are written:
import { initDataset } from "braintrust";const dataset = initDataset("My App", { dataset: "Customer Support" });// Insert recordsdataset.insert({ input: { question: "How do I reset my password?" }, expected: { answer: "Click 'Forgot Password' on the login page." },});// Flush to ensure all records are savedawait dataset.flush();
import braintrustdataset = braintrust.init_dataset(project="My App", name="Customer Support")# Insert recordsdataset.insert( input={"question": "How do I reset my password?"}, expected={"answer": "Click 'Forgot Password' on the login page."},)# Flush to ensure all records are saveddataset.flush()
Assign dataset rows to team members for review, analysis, or follow-up action. Assignments are particularly useful for distributing review work across multiple team members.See Assign rows for review for details.
Custom dataset views let you build tailored interfaces for reviewing individual dataset rows. Open a dataset row, select Views, and describe the interface you want in natural language. Loop generates a customizable React component your team can use directly in Braintrust.See Custom dataset views for guidance on creating, editing, and sharing views.
Organization default: Visible to all members when they open the page. This applies per page. For example, you can set separate organization defaults for Logs, Experiments, and Review. To set an organization default, you need the Manage settings organization permission (included by default in the Owner role). See Access control for details.
Project default: Overrides the organization default for everyone viewing this project. To set a project default, you need the project-level Update permission. Project admins can set project defaults even without organization-level permissions. See Access control for details.
Personal default: Overrides the project and organization defaults for you only. Personal defaults are stored in your browser, so they do not carry over across devices or browsers.
To set a default view:
Switch to the view you want by selecting it from the menu.
Open the menu again and hover over the currently selected view to reveal its submenu.
Choose Set as personal default view, Set as project default view, or Set as organization default view.
To clear a default view:
Open the menu and hover over the currently selected view to reveal its submenu.
Choose Clear personal default view, Clear project default view, or Clear organization default view.
Default view settings are mutually exclusive on a given view. Setting one type of default on a view automatically clears any other default that was previously set on the same view.When a user opens a page, Braintrust loads the first match in this order: personal default, project default, organization default, then the standard “All …” view (for example, “All logs view”).
If you’ve built a useful custom table view in one project, you can duplicate it to another project via the API rather than recreating it from scratch. Datasets have two customizable views:
Datasets list: The project’s Datasets tab, where each row is a dataset.
Single dataset table: The rows of data inside one dataset.
The following steps work for either. Choose the corresponding view_type in the API call.
Use the list views API endpoint to fetch the dataset views in your source project. Pass the following query parameters:
object_type=project
object_id=<source-project-id>
view_type=dataset for a single dataset table view, or view_type=datasets for the datasets list