A Python CLI for migrating users and roles, datasets, experiments, annotation queues, project rules, prompts, and charts between LangSmith instances, plus CSV-driven access sync for a single LangSmith deployment.
# Install (requires uv: https://docs.astral.sh/uv/)
uv tool install "langsmith-data-migration-tool @ https://github.com/langchain-ai/langsmith-data-migration-tool/releases/latest/download/langsmith_data_migration_tool-0.0.65-py3-none-any.whl"
# Set up environment variables
export LANGSMITH_OLD_API_KEY="your_source_api_key"
export LANGSMITH_NEW_API_KEY="your_destination_api_key"
# Test connections
langsmith-migrator test
# Start migrating
langsmith-migrator datasets- All-in-One Wizard: Interactive migration of all resources (
migrate-all) - Users & Roles: Migrate custom roles, org members, and workspace memberships between instances
- Single-Instance Access Sync: Apply CSV-driven add/update or authoritative access sync to one LangSmith instance (
users --csv ... [--sync]) - Datasets: Migrate datasets with examples and file attachments
- Experiments: Include experiments, runs, and feedback during dataset migration (
datasets --include-experiments) or throughmigrate-all - Annotation Queues: Transfer queue configurations
- Project Rules: Copy automation rules with project mapping and optional project creation in interactive flows
- Prompts: Migrate prompts (latest by default, full history with
--include-all-commits) - Charts: Migrate monitoring charts with filter preservation
- Workspace Scoping: Run resource migrations per workspace pair with explicit IDs or interactive workspace mapping
- Remediation & Resume: Persist migration state, write remediation bundles, print grouped actionable next steps, and retry pending/failed work with
resume - Interactive CLI: TUI-based selection with search/filter, plus
--non-interactivemode for automation
This tool does not support migrating trace data. It migrates:
- Datasets and examples (including file attachments)
- Experiments, runs, and feedback
- Annotation queues
- Project rules
- Prompts
- Charts
For trace data, use LangSmith's Bulk Export functionality: LangSmith Bulk Export Documentation
Prerequisites: Python 3.12+, uv
uv tool install "langsmith-data-migration-tool @ https://github.com/langchain-ai/langsmith-data-migration-tool/releases/latest/download/langsmith_data_migration_tool-0.0.65-py3-none-any.whl"
# To update an existing installation, use --force:
uv tool install --force "langsmith-data-migration-tool @ https://github.com/langchain-ai/langsmith-data-migration-tool/releases/latest/download/langsmith_data_migration_tool-0.0.65-py3-none-any.whl"uvx --from "langsmith-data-migration-tool @ https://github.com/langchain-ai/langsmith-data-migration-tool/releases/latest/download/langsmith_data_migration_tool-0.0.65-py3-none-any.whl" langsmith-migrator testpip install "langsmith-data-migration-tool @ https://github.com/langchain-ai/langsmith-data-migration-tool/releases/latest/download/langsmith_data_migration_tool-0.0.65-py3-none-any.whl"git clone https://github.com/langchain-ai/langsmith-data-migration-tool.git
cd langsmith-data-migration-tool
uv sync
# Run with: uv run langsmith-migrator <command>export LANGSMITH_OLD_API_KEY="your_source_api_key"
export LANGSMITH_NEW_API_KEY="your_destination_api_key"
# Optional: Custom base URLs (default: https://api.smith.langchain.com)
export LANGSMITH_OLD_BASE_URL="https://your-source-instance.com"
export LANGSMITH_NEW_BASE_URL="https://your-destination-instance.com"Or use a .env file (auto-loaded on startup):
LANGSMITH_OLD_API_KEY=your_source_api_key
LANGSMITH_NEW_API_KEY=your_destination_api_key
LANGSMITH_OLD_BASE_URL=https://your-source-instance.com
LANGSMITH_NEW_BASE_URL=https://your-destination-instance.com
LANGSMITH_VERIFY_SSL=true# Test connections
langsmith-migrator test
# Interactive wizard for all resources
langsmith-migrator migrate-all
langsmith-migrator migrate-all --rules-create-enabled # Create migrated rules as enabled
# Datasets
langsmith-migrator datasets # Interactive selection
langsmith-migrator datasets --all # All datasets
langsmith-migrator datasets --include-experiments # With experiments, runs, and feedback
# Note: When running `datasets` without `--include-experiments`, you'll be prompted
# interactively whether to include experiments. Experiments include all runs and feedback.
# Annotation queues
langsmith-migrator queues
# Prompts
langsmith-migrator prompts
langsmith-migrator prompts --all --include-all-commits
# Project rules
langsmith-migrator rules
langsmith-migrator rules --strip-projects # As global rules
langsmith-migrator rules --project-mapping '{"old-project-id": "new-project-id"}'
langsmith-migrator rules --project-mapping mapping.json # From file
langsmith-migrator rules --map-projects # Interactive TUI project mapping
langsmith-migrator rules --create-enabled # Create rules enabled (default: disabled)
# Charts
langsmith-migrator charts
langsmith-migrator charts --session "project-name"
langsmith-migrator charts --map-projects # Interactive TUI project mapping
langsmith-migrator charts --same-instance # Reuse source project/session IDs on destination
# Utilities
langsmith-migrator list-projects --source
langsmith-migrator list_workspaces --source --dest
langsmith-migrator resume # Resume pending/failed items from a prior migration session
langsmith-migrator cleantest: verify source and destination connectivity before running a migrationmigrate-all: guided end-to-end wizard for users, datasets, prompts, queues, rules, and chartsdatasets: migrate datasets; optionally include experiments, runs, and feedbackqueues: migrate annotation queuesprompts: migrate prompts, optionally with full commit historyrules: migrate automation rules with project mapping controlscharts: migrate monitoring charts, either all sessions or one named session/projectusers: migrate users/roles between instances, or run single-instance CSV access syncresume: retry resumable items from a prior session and show grouped manual blockerslist-projects/list_workspaces: inspect project and workspace IDs for mappingclean: remove saved migration sessions
When running users, you can provide member details from CSV instead of source member list APIs:
langsmith-migrator users --members-csv examples/users_members_example.csv --map-workspacesFor a single deployed LangSmith instance, users can also run as an access-sync command instead of a source→destination migration.
Safe default: add or update access from the CSV without removing anyone:
langsmith-migrator users \
--api-key "$LANGSMITH_API_KEY" \
--url "https://your-langsmith-instance.example.com" \
--csv examples/users_members_example.csvPreview the same run without making changes:
langsmith-migrator users \
--dry-run \
--api-key "$LANGSMITH_API_KEY" \
--url "https://your-langsmith-instance.example.com" \
--csv examples/users_members_example.csvAuthoritative mode: make the CSV the source of truth for access and remove anything not present:
langsmith-migrator users \
--api-key "$LANGSMITH_API_KEY" \
--url "https://your-langsmith-instance.example.com" \
--csv examples/users_members_example.csv \
--syncEquivalent explicit form:
langsmith-migrator \
--dest-key "$LANGSMITH_API_KEY" \
--dest-url "https://your-langsmith-instance.example.com" \
users \
--single-instance \
--members-csv examples/users_members_example.csv \
--csv-source-of-truthIn --single-instance mode, the command mirrors the provided instance configuration onto both internal clients, so you only need one working LangSmith connection. Workspace rows use the target workspace IDs directly; there is no workspace mapping step. All CSV rows are applied automatically after a single confirmation summary; there is no row-selection step in this mode. --api-key/--url imply --single-instance, --csv is a short alias for --members-csv, and --sync is a short alias for --csv-source-of-truth.
users --dry-run is also supported as a command-local preview flag if you prefer to put dry-run after the subcommand instead of before it.
For cron jobs and other headless runs, users --non-interactive is also supported as a command-local alias for the global langsmith-migrator --non-interactive users ... form. In headless mode, missing credentials fail fast instead of prompting.
CSV schema:
email,langsmith_role,workspace_id,workspace_name
alice@example.com,Organization Admin,,
alice@example.com,Workspace Admin,ws_src_prod_us,Production USNotes:
emailandlangsmith_roleare required.workspace_idis optional. Leave it empty for org-level role assignments.workspace_nameis optional and informational only.langsmith_roleshould be a built-in LangSmith role name (for exampleOrganization Admin,Organization Operator,Organization User,Organization Viewer,Workspace Admin,Workspace User, orWorkspace Viewer) or a custom roledisplay_name.- Users who only appear in workspace rows are invited to the org with the source
ORGANIZATION_USERrole before workspace membership is applied. Organization Adminon a workspace row is treated as org-level admin access only. No explicit workspace membership is created because org admins already have workspace access.- Other org-scoped roles cannot be used on workspace rows. If you want org-level access, leave
workspace_idempty. - Workspace-scoped roles such as
Workspace Admincannot be used on org-level rows. --sync/--csv-source-of-truthis the only mode that removes access. Without it, single-instance CSV mode only adds or updates access.--csv-source-of-truthis available with--single-instanceand makes the CSV authoritative for access:- users missing from the CSV are removed from the org
- pending org invites missing from the CSV are cancelled
- workspace memberships missing from the CSV are removed
- workspaces omitted from the CSV are treated as having no desired memberships
Guardrails:
--api-keyand--urlmust be provided together when either is used.--single-instancerequires--csv/--members-csv.--syncrequires--csvand cannot be combined with--skip-existingor--skip-workspace-members.--single-instancecannot be combined with workspace mapping flags.--roles-onlycannot be combined with--single-instanceor--members-csv.- If the CSV contains workspace rows and
--skip-workspace-membersis set, the command fails instead of silently ignoring those rows. - If the CSV contains workspace-only users, the target instance must have an
ORGANIZATION_USERrole available or the command fails before applying member changes. - If the CSV references unknown
workspace_idvalues, the command fails before any membership changes are applied.
--source-key TEXT Source API key
--dest-key TEXT Destination API key
--source-url TEXT Source base URL
--dest-url TEXT Destination base URL
--no-ssl Disable SSL verification
--batch-size INTEGER Batch size for operations (1-1000, default: 100)
--workers INTEGER Number of concurrent workers (1-10, default: 4)
--dry-run Run without making changes
--skip-existing Skip existing resources instead of updating them
--non-interactive Disable prompts and exit with code 2 when remediation is required
--verbose, -v Verbose output--include-experiments Include experiments with datasets
--all Migrate all datasets--all Migrate all prompts
--include-all-commits Include all commit history--strip-projects Strip project associations and create as global rules
--project-mapping TEXT JSON string or file path with project ID mapping (e.g., '{"old-id": "new-id"}')
--map-projects Launch interactive TUI to map source projects to destination projects
--create-enabled Create rules as enabled (default: disabled to bypass secrets validation)
--all Migrate all rules without interactive selection--rules-create-enabled Create migrated rules as enabled (default: disabled)If --rules-create-enabled is omitted, migrate-all asks interactively whether to create rules enabled.
The prompt default is No (rules are created disabled).
--skip-users Skip user and role migration
--skip-datasets Skip dataset migration
--skip-experiments Skip experiment migration
--skip-prompts Skip prompt migration
--skip-queues Skip annotation queue migration
--skip-rules Skip rules migration
--skip-charts Skip chart migration
--include-all-commits Include all prompt commit history
--strip-projects Strip project associations from rules
--map-projects Launch interactive TUI to map source projects to destination projects
--rules-create-enabled Create migrated rules as enabled instead of asking interactively--session TEXT Migrate charts for a specific session/project (by name or ID)
--map-projects Launch interactive TUI to map source projects to destination projects
--same-instance Source and destination are the same instance (use same session IDs)--dry-run Preview this users sync without making POST/PATCH/DELETE changes
--non-interactive Disable prompts for this users run. Same as the global --non-interactive.
--roles-only Only migrate custom roles (skip member migration)
--skip-workspace-members Skip workspace member migration
--single-instance, --instance
Use one target LangSmith instance for CSV-driven access sync instead of source→destination migration
--csv-source-of-truth, --sync
Make the CSV authoritative for single-instance sync: any active org user or pending invite not
present in the CSV will be removed, and workspace memberships not present in the CSV will also
be removed. Without this flag, CSV mode only adds or updates access.
--members-csv, --csv PATH CSV file with member details (email, langsmith_role, workspace_id, workspace_name)
Replaces source member API lookups. In --single-instance mode, all CSV rows are applied
automatically.
--api-key TEXT API key for the single-instance CSV sync target. Must be provided together with --url.
--url TEXT Base URL for the single-instance CSV sync target. Must be provided together with --api-key.
--source-workspace TEXT Source workspace ID (skip auto-detection)
--dest-workspace TEXT Destination workspace ID (skip auto-detection)
--map-workspaces Force workspace mapping TUI even for single-workspace instancesThese flags are available on datasets, queues, prompts, rules, charts, migrate-all, and users:
--source-workspace TEXT Source workspace ID (skip auto-detection)
--dest-workspace TEXT Destination workspace ID (skip auto-detection)
--map-workspaces Force workspace mapping TUI even for single-workspace instancesMigration proceeds in three phases:
- Role sync (org-scoped): match built-in roles by name, create/update custom roles
- Org members (org-scoped): invite missing members, update roles for existing ones
- Workspace members (per workspace pair): add members to workspaces with correct roles
Rules are created disabled by default. Use --create-enabled on the rules command to override.
--skip-users Skip user and role migration in migrate-all wizardWhen --skip-users is omitted, migrate-all runs user/role migration as Step 0 before all other resources. Phases 1-2 (roles + org members) run once; phase 3 (workspace members) runs per workspace pair.
Rules and charts reference projects by ID. When migrating between instances, project IDs differ.
- Interactive TUI (
--map-projects): Launch a visual TUI to map source projects to destination projects. Available onrules,charts, andmigrate-allcommands. Select a source project and type a destination name directly — existing projects appear as filterable suggestions below the input. Supports auto-match by name, skip, and custom name entry. - Rules (
--project-mapping): Supply an explicit source→destination project ID mapping as JSON or a file path. Uselist-projects --sourceandlist-projects --destto get IDs. Mutually exclusive with--map-projects. - Charts: Without
--map-projects, project mapping is built automatically by matching project names between source and destination. migrate-all: Supports--strip-projects,--map-projects, and--rules-create-enabledfor rules. Use the standalonerulescommand for--project-mappingJSON mappings.
Keyboard shortcuts in resource selection TUI:
↑↓Navigate |SpaceToggle |aSelect all |nClear/Search |EnterConfirm |EscCancel
Keyboard shortcuts in project mapper TUI (--map-projects):
Enter/SpaceEdit destination |sSkip |mSame name |uUnmapaAuto-match all |/Search |Ctrl+SSave |EscCancel
Keyboard shortcuts in workspace mapper TUI (--map-workspaces):
EnterPick destination |nCreate new |cCreate all unmappedpMap projects |sSkip |aAuto-match all |uUnmapCtrl+SSave |EscCancel
For multi-workspace organizations, all resource commands support workspace-scoped migration:
# Interactive workspace mapping TUI (available on all commands)
langsmith-migrator datasets --map-workspaces
langsmith-migrator queues --map-workspaces
langsmith-migrator prompts --map-workspaces
langsmith-migrator rules --map-workspaces --map-projects
langsmith-migrator charts --map-workspaces --map-projects
langsmith-migrator migrate-all --map-workspaces
# Explicit workspace pair
langsmith-migrator datasets --source-workspace WS_ID --dest-workspace WS_IDWhen using --map-workspaces, each command iterates all mapped workspace pairs, running the full fetch/select/migrate flow per pair. For rules and charts with --map-projects, the project mapping TUI is shown per workspace pair so projects are correctly scoped.
Every migration session persists state and writes a remediation bundle when there are blocked or manual-follow-up items.
- Session state is stored under
~/.langsmith-migrator/state. - Remediation bundles are written under
./.langsmith-migrator/remediation/<session_id>by default. - The CLI prints a Resolution Summary with grouped Actionable Next Steps instead of one repeated line per failed item.
--non-interactivedisables prompts and exits with status code2if manual remediation is still required.
langsmith-migrator resume retries pending or failed items from a previous session. Today that includes:
- datasets
- experiments
- prompts
- annotation queues
- rules
- charts
- org members
- workspace members
Use langsmith-migrator clean to remove saved sessions once you no longer need their state or remediation bundles.
For self-hosted instances with SSL errors:
# Use --no-ssl flag
langsmith-migrator --no-ssl datasets
# Or set environment variable
export LANGSMITH_VERIFY_SSL=falseMIT License - see LICENSE for details.
Contributions welcome! Fork, create a feature branch, and submit a Pull Request.
For release changes, update all of:
pyproject.tomlversionCHANGELOG.mdrelease notesREADME.mdrelease-facing docs/examples
CI enforces this on pull requests: if pyproject.toml or CHANGELOG.md changes, README.md must also be updated (including dependency-only bumps).
For issues or questions: GitHub repository