smt-studio
v2.0.2
Published
Salesforce Data Migration Studio - A tool to simplify Salesforce data migration tasks.
Maintainers
Readme
Salesforce Migration Studio
A modern web-based interface for Salesforce data migration — with real-time monitoring, AI-assisted analysis, data comparison, deletion candidate detection, and export capabilities.
Screenshots
Edit Load Plan

Compare Org Data
)
)
CSV Generation

Data Deletion in Target Org

AI SideKick

🌟 Features
🎨 Modern Web Interface
- Dark Theme: Professional dark mode UI built with Tailwind CSS
- Tab-Based Navigation: Organized workflow across 6 main sections
- Split Pane Layout: Resizable Monaco editor on left, real-time terminal on right
- Custom Dialogs: All confirmation and pause prompts are in-app modals (no browser
alert/confirm)
🔐 Authentication
- Authenticate source and target Salesforce orgs via Salesforce CLI (
sf) - Org dropdown populated from
sf org list— grouped by type (Production/Sandbox/Scratch) - Visual connection status card with alias, URL, and connected status
- Supports both username and alias
📦 Object Selection
- Search Functionality: Quickly find objects in large load plans
- Bulk Selection: Select All / Deselect All respects the active search filter
- Visual Indicators: Shows single-step vs multi-step objects
- Keyboard Shortcuts:
Ctrl+K/Cmd+Kto focus search,Escapeto clear
📋 Load Plan Management
- Monaco Editor: Full VS Code editing experience with JSON syntax highlighting
- File Upload: Load existing migration plans (
.json) - Sample Plans: Quick-start with pre-built configurations
- Auto-formatting: JSON validation and formatting on paste/type
- Tracked Filename: Server remembers your uploaded filename for CLI command generation
⚙️ Generate Load Plan
- Auto-describe any Salesforce object from an authenticated org
- Generates Type 1 (relationship composite keys) and Type 2 (Global_Key__c) plans
- Smart lookup key detection — checks if referenced objects have a
Codefield vsName - Field summary table showing which fields are in the query and mappings
- Copy / Download / Load directly into the Edit Plan editor
🔍 Data Comparison
- SOQL Editor: Monaco-powered query editor with field autocomplete (via
sf sobject describe) - Visual Tables: Compare records between source and target orgs
- Advanced Features: Column sorting, search, pagination (10/25/50/100 rows), nested field support
- Three Categories: Only in Source · Only in Target · In Both
- Export: Download any category as CSV
- CLI Helper: Personalized
sf-data-utilcommand with your actual credentials
🚀 Migration Operations
- Validate Configuration: Check object/field accessibility before touching data
- Generate CSV Files: Write insert/update CSVs without loading to target
- Start Migration: Full migration with real-time progress; confirms via in-app dialog
- Export to ZIP: Download source + target data as a compressed archive
- Deletion Candidates: Find target records absent from source — one object at a time, paginated table with direct target-org record links, CSV download
- CSV Output Folder: Optional path for all generated CSVs and
all.zip(UI field +--csv-output-folderCLI flag; folder auto-created) - Per-Object Pause: After each object a modal popup lets you Continue or Stop
📟 Real-time Terminal
- Live logs with color coding: info / success / warning / error
- Per-Object Tabs: A tab is created for each object as it's processed; auto-switches during runs; "All" tab always available
- Search: Live highlight as you type, navigate matches with ▲▼ or Enter / Shift+Enter, Escape to clear
- Timestamps on every entry
- Download logs as
.txt - Clear terminal (resets tabs too)
✦ AI Sidekick (opt-in)
- Slide-in panel with CHAT and SETTINGS tabs
- Supports Ollama (local), Claude by Anthropic, OpenAI, xAI (Grok), Google Gemini
- Ollama model list fetched live from
/api/tags— full dropdown with all installed models - Context-aware system prompt: source org, target org, selected objects, full load plan with composite keys injected automatically
- Multi-turn conversation history
- Enable with
--enable-aiserver flag
🚀 Quick Start
Prerequisites
- Node.js v14 or higher
- Salesforce CLI (
sf) - Authenticated Salesforce orgs
Installation
npm install -g smt-studio📖 Usage Guide
Step 1 — Authenticate Orgs
- Open the 🔐 Authentication tab
- Click Refresh Org List — orgs are loaded from
sf org list - Select source org → Connect
- Select target org → Connect
- Status badges in the top nav turn green ✅
Step 2 — Select Objects
- Open the 📦 Select Objects tab
- Use the search box to filter (
Ctrl+K/Cmd+K), then Select All or pick individually - Click Next: Edit Plan →
Step 3 — Configure Load Plan
- Open the 📋 Edit Plan tab
- Load a Sample, Upload a JSON file, or use ⚙️ Generate Load Plan to auto-build one
- Edit in the Monaco editor, then 💾 Save Plan
Step 4 — Compare Data (recommended)
- Open the 🔍 Compare Data tab
- Select an object, optionally edit the SOQL query, click Compare
- Review the three category tables and download CSVs as needed
Step 5 — Execute Migration
- Open the 🚀 Migration tab
- (Optional) Enter a CSV Output Folder — leave blank to use the current working directory
- Choose an operation:
| Button | What it does |
|---|---|
| ✅ Validate Configuration | Checks object/field accessibility — no data touched |
| 📄 Generate CSV Files | Writes insert/update CSVs, nothing loaded to target |
| 🚀 Start Migration | Full migration with confirmation dialog |
| 📦 Export to ZIP | Downloads source + target data as all.zip |
| 🗑️ Deletion Candidates | Finds target records absent from source — object by object |
- After each object a Processing Paused popup appears — click ▶ Continue or ⛔ Stop
- Monitor progress in the terminal; switch per-object tabs or search logs
Deletion Candidates Workflow
- Click 🗑️ Deletion Candidates on the Migration tab
- Select one object from the dropdown
- Click 🔍 Find Candidates
- Review the table —
Idvalues link directly to the target org record - Click 📥 Download CSV to export the list for bulk deletion via Data Loader or the CLI
AI Sidekick (requires --enable-ai)
- Start the server with
smt-studio --enable-ai - Click ✦ AI Sidekick in the top nav
- Open SETTINGS, pick a provider, enter credentials / select model
- Switch to CHAT and ask anything about your migration
💻 Command Line Options
smt-studio --help
# Custom port
smt-studio --port 8080
# Bind to all interfaces
smt-studio --host 0.0.0.0
# Default CSV output folder for all operations
smt-studio --csv-output-folder /tmp/migration-csvs
# Enable AI Sidekick
smt-studio --enable-ai
# Don't auto-open browser
smt-studio --no-open
# Verbose logging
smt-studio --verbose
# Combine
smt-studio -p 8080 --host 0.0.0.0 --csv-output-folder ./output --enable-ai -v
smt-studio -p 3333 --csv-output-folder ~/my-smt-csv-output --enable-ai🎯 Sample Load Plan Format
[
{
"object": "Manufacturer__c",
"compositeKeys": [
"Global_Key__c"
],
"compositeKeys_v1": [
"Name"
],
"query": "SELECT Global_Key__c, Name, Country__c FROM Manufacturer__c",
"query_v1": "SELECT Name, Country__c FROM Manufacturer__c",
"fieldMappings": {
"Global_Key__c": "Global_Key__c",
"Name": "Name",
"Country__c": "Country__c"
}
},
{
"object": "VehicleCustomer__c",
"compositeKeys": [
"Global_Key__c"
],
"compositeKeys_v1": [
"Name"
],
"query": "SELECT Global_Key__c, Name, Email__c FROM VehicleCustomer__c",
"query_v1": "SELECT Name, Email__c FROM VehicleCustomer__c",
"fieldMappings": {
"Global_Key__c": "Global_Key__c",
"Name": "Name",
"Email__c": "Email__c"
}
},
{
"object": "Vehicle__c",
"compositeKeys": [
"Global_Key__c"
],
"compositeKeys_v1": [
"Name"
],
"query": "SELECT Global_Key__c, Name, Model__c, Manufacturer__r.Global_Key__c, VehicleCustomer__r.Global_Key__c FROM Vehicle__c",
"query_v1": "SELECT Name, Model__c, Manufacturer__r.Name, VehicleCustomer__r.Name FROM Vehicle__c",
"fieldMappings": {
"Global_Key__c": "Global_Key__c",
"Name": "Name",
"Model__c": "Model__c",
"Manufacturer__c": {
"lookup": {
"object": "Manufacturer__c",
"key": "Global_Key__c",
"field": "Manufacturer__r.Global_Key__c"
}
},
"VehicleCustomer__c": {
"lookup": {
"object": "VehicleCustomer__c",
"key": "Global_Key__c",
"field": "VehicleCustomer__r.Global_Key__c"
}
}
}
}
]🔌 REST API Reference
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/config | Get current configuration |
| PUT | /api/selected-objects | Update selected objects |
| POST | /api/auth | Authenticate source or target org |
| POST | /api/load-plan | Save load plan JSON |
| POST | /api/load-plan/file | Upload plan file (multipart) |
| POST | /api/validate | Validate configuration |
| POST | /api/migrate | Start migration (csvOutputFolder in body) |
| POST | /api/generate-csv | Generate CSV files (csvOutputFolder in body) |
| POST | /api/export | Export data to ZIP (csvOutputFolder in body) |
| POST | /api/compare | Compare object data between orgs |
| POST | /api/compare/custom | Compare with a custom SOQL query |
| POST | /api/deletion-candidates | Records in target not in source for one object |
| GET | /api/orgs | List authenticated orgs via sf org list |
| GET | /api/sobjects | List SObject API names for an org |
| GET | /api/describe/:sobject | Describe a Salesforce object's fields |
| GET | /api/download/:filename | Download a generated file |
| GET | /api/ai/status | Whether AI Sidekick is enabled |
| GET | /api/ai/ollama/tags | Proxy Ollama /api/tags for model list |
| POST | /api/ai/chat | Unified AI chat proxy (all providers) |
🔄 WebSocket Events (Socket.IO)
Server → Client
| Event | Payload | When |
|---|---|---|
| terminal | { timestamp, message } | Any console.log in server process |
| object-start | { objectName } | Processing begins for an object (creates terminal tab) |
| pause-prompt | { objectName, message, context } | After each object is processed |
| migration-complete | { success, error? } | Migration finishes or fails |
| csv-generation-complete | { success, error? } | CSV generation finishes or fails |
| export-complete | { success, error? } | Export finishes or fails |
Client → Server
| Event | Payload | When |
|---|---|---|
| pause-response | { action: 'continue' \| 'stop' } | User clicks Continue or Stop in the popup |
🛠️ Configuration Storage
Persisted to ~/.migrationrc:
{
"sourceConnection": { "instanceUrl": "...", "accessToken": "...", "username": "..." },
"targetConnection": { "instanceUrl": "...", "accessToken": "...", "username": "..." },
"loadPlan": [ ... ],
"selectedObjects": [ "Account", "Contact" ],
"loadPlanFilename": "my-migration.json"
}⚠️ Never commit
.migrationrcto version control — it contains access tokens.
⌨️ Keyboard Shortcuts
| Shortcut | Where | Action |
|---|---|---|
| Ctrl+K / Cmd+K | Select Objects tab | Focus object search |
| Escape | Object search | Clear search |
| Enter | Terminal search | Next match |
| Shift+Enter | Terminal search | Previous match |
| Escape | Terminal search | Clear search |
| Enter | AI Sidekick chat | Send message |
| Shift+Enter | AI Sidekick chat | New line |
| Ctrl+Space | Monaco editor | Autocomplete |
| Ctrl+F | Monaco editor | Find |
| Alt+Shift+F | Monaco editor | Format JSON |
🔒 Security Notes
- Local use only by default (
localhostbinding) - Use
--host 0.0.0.0only on trusted networks - Access tokens are stored in
~/.migrationrc— protect this file - Add
.migrationrcto.gitignore - AI provider API keys are held in browser memory only — never sent to or stored by the server beyond the proxied request
- For public-facing deployments, put a reverse proxy with HTTPS in front
🐛 Troubleshooting
Port already in use
smt-studio -p 3001
# or kill the occupying process
lsof -ti:3000 | xargs kill -9Salesforce CLI not found
npm install -g @salesforce/cli
sf versionRe-authenticate an org
sf org login web --alias my-org
sf org listOllama models not loading in AI Sidekick
# Confirm Ollama is running
curl http://localhost:11434/api/tags
# Then refresh the Base URL field in AI Sidekick SettingsAI Sidekick button not visible
# Server must be started with --enable-ai
smt-studio --enable-ai📝 Version
Version: 2.0.0
Author: Mohan Chinnappan
📄 License
MIT
