Query and manage Salesforce CRM data via the Salesforce CLI (`sf`). Run SOQL/SOSL queries, inspect object schemas, create/update/delete records, bulk import/export, execute Apex, deploy metadata, and make raw REST API calls.
---
name: salesforce
description: "Query and manage Salesforce CRM data via the Salesforce CLI (`sf`). Run SOQL/SOSL queries, inspect object schemas, create/update/delete records, bulk import/export, execute Apex, deploy metadata, and make raw REST API calls."
homepage: https://developer.salesforce.com/tools/salesforcecli
metadata: {"clawdbot":{"emoji":"☁️","requires":{"bins":["sf"]},"install":[{"id":"npm","kind":"node","package":"@salesforce/cli","bins":["sf"],"label":"Install Salesforce CLI (npm)"}]}}
---
# Salesforce Skill
Use the Salesforce CLI (`sf`) to interact with Salesforce orgs. The CLI must be authenticated before use. Always add `--json` for structured output.
If the `sf` binary is not available, install it via npm (`npm install -g @salesforce/cli`) or download it from https://developer.salesforce.com/tools/salesforcecli. After installing, authenticate immediately with `sf org login web` to connect to a Salesforce org.
## Authentication and Org Management
### Log in (opens browser)
```bash
sf org login web --alias my-org
```
Other login methods:
```bash
# JWT-based login (CI/automation)
sf org login jwt --client-id <consumer-key> --jwt-key-file server.key --username user@example.com --alias my-org
# Login with an existing access token
sf org login access-token --instance-url https://mycompany.my.salesforce.com
# Login via SFDX auth URL (from a file)
sf org login sfdx-url --sfdx-url-file authUrl.txt --alias my-org
```
### Manage orgs
```bash
# List all authenticated orgs
sf org list --json
# Display info about the default org (access token, instance URL, username)
sf org display --json
# Display info about a specific org
sf org display --target-org my-org --json
# Display with SFDX auth URL (sensitive - contains refresh token)
sf org display --target-org my-org --verbose --json
# Open org in browser
sf org open
sf org open --target-org my-org
# Log out
sf org logout --target-org my-org
```
### Configuration and aliases
```bash
# Set default target org
sf config set target-org my-org
# List all config variables
sf config list
# Get a specific config value
sf config get target-org
# Set an alias
sf alias set prod=user@example.com
# List aliases
sf alias list
```
## Querying Data (SOQL)
Standard SOQL queries via the default API:
```bash
# Basic query
sf data query --query "SELECT Id, Name, Email FROM Contact LIMIT 10" --json
# WHERE clause
sf data query --query "SELECT Id, Name, Amount, StageName FROM Opportunity WHERE StageName = 'Closed Won'" --json
# Relationship queries (parent-to-child)
sf data query --query "SELECT Id, Name, (SELECT LastName, Email FROM Contacts) FROM Account LIMIT 5" --json
# Relationship queries (child-to-parent)
sf data query --query "SELECT Id, Name, Account.Name FROM Contact" --json
# LIKE for text search
sf data query --query "SELECT Id, Name FROM Account WHERE Name LIKE '%Acme%'" --json
# Date filtering
sf data query --query "SELECT Id, Name, CreatedDate FROM Lead WHERE CreatedDate = TODAY" --json
# ORDER BY + LIMIT
sf data query --query "SELECT Id, Name, Amount FROM Opportunity ORDER BY Amount DESC LIMIT 20" --json
# Include deleted/archived records
sf data query --query "SELECT Id, Name FROM Account" --all-rows --json
# Query from a file
sf data query --file query.soql --json
# Tooling API queries (metadata objects like ApexClass, ApexTrigger)
sf data query --query "SELECT Id, Name, Status FROM ApexClass" --use-tooling-api --json
# Output to CSV file
sf data query --query "SELECT Id, Name, Email FROM Contact" --result-format csv --output-file contacts.csv
# Target a specific org
sf data query --query "SELECT Id, Name FROM Account" --target-org my-org --json
```
For queries returning more than 10,000 records, use Bulk API instead:
```bash
sf data export bulk --query "SELECT Id, Name, Email FROM Contact" --output-file contacts.csv --result-format csv --wait 10
sf data export bulk --query "SELECT Id, Name FROM Account" --output-file accounts.json --result-format json --wait 10
```
## Text Search (SOSL)
SOSL searches across multiple objects at once:
```bash
# Search for text across objects
sf data search --query "FIND {John Smith} IN ALL FIELDS RETURNING Contact(Name, Email), Lead(Name, Email)" --json
# Search in name fields only
sf data search --query "FIND {Acme} IN NAME FIELDS RETURNING Account(Name, Industry), Contact(Name)" --json
# Search from a file
sf data search --file search.sosl --json
# Output to CSV
sf data search --query "FIND {test} RETURNING Contact(Name)" --result-format csv
```
## Single Record Operations
### Get a record
```bash
# By record ID
sf data get record --sobject Contact --record-id 003XXXXXXXXXXXX --json
# By field match (WHERE-like)
sf data get record --sobject Account --where "Name=Acme" --json
# By multiple fields (values with spaces need single quotes)
sf data get record --sobject Account --where "Name='Universal Containers' Phone='(123) 456-7890'" --json
```
### Create a record (confirm with user first)
```bash
sf data create record --sobject Contact --values "FirstName='Jane' LastName='Doe' Email='jane@example.com'" --json
sf data create record --sobject Account --values "Name='New Company' Website=www.example.com Industry='Technology'" --json
# Tooling API object
sf data create record --sobject TraceFlag --use-tooling-api --values "DebugLevelId=7dl... LogType=CLASS_TRACING" --json
```
### Update a record (confirm with user first)
```bash
# By ID
sf data update record --sobject Contact --record-id 003XXXXXXXXXXXX --values "Email='updated@example.com'" --json
# By field match
sf data update record --sobject Account --where "Name='Old Acme'" --values "Name='New Acme'" --json
# Multiple fields
sf data update record --sobject Account --record-id 001XXXXXXXXXXXX --values "Name='Acme III' Website=www.example.com" --json
```
### Delete a record (require explicit user confirmation)
```bash
# By ID
sf data delete record --sobject Account --record-id 001XXXXXXXXXXXX --json
# By field match
sf data delete record --sobject Account --where "Name=Acme" --json
```
## Bulk Data Operations (Bulk API 2.0)
For large datasets (thousands to millions of records):
### Bulk export
```bash
# Export to CSV
sf data export bulk --query "SELECT Id, Name, Email FROM Contact" --output-file contacts.csv --result-format csv --wait 10
# Export to JSON
sf data export bulk --query "SELECT Id, Name FROM Account" --output-file accounts.json --result-format json --wait 10
# Include soft-deleted records
sf data export bulk --query "SELECT Id, Name FROM Account" --output-file accounts.csv --result-format csv --all-rows --wait 10
# Resume a timed-out export
sf data export resume --job-id 750XXXXXXXXXXXX --json
```
### Bulk import
```bash
# Import from CSV
sf data import bulk --file accounts.csv --sobject Account --wait 10
# Resume a timed-out import
sf data import resume --job-id 750XXXXXXXXXXXX --json
```
### Bulk upsert
```bash
sf data upsert bulk --file contacts.csv --sobject Contact --external-id Email --wait 10
```
### Bulk delete
```bash
# Delete records listed in CSV (CSV must have an Id column)
sf data delete bulk --file records-to-delete.csv --sobject Contact --wait 10
```
### Tree export/import (for related records)
```bash
# Export with relationships into JSON tree format
sf data export tree --query "SELECT Id, Name, (SELECT Name, Email FROM Contacts) FROM Account" --json
# Export with a plan file (for multiple objects)
sf data export tree --query "SELECT Id, Name FROM Account" --plan --output-dir export-data
# Import from tree JSON files
sf data import tree --files Account.json,Contact.json
# Import using a plan definition file
sf data import tree --plan Account-Contact-plan.json
```
## Schema Inspection
```bash
# Describe an object (fields, relationships, picklist values)
sf sobject describe --sobject Account --json
# Describe a custom object
sf sobject describe --sobject MyCustomObject__c --json
# Describe a Tooling API object
sf sobject describe --sobject ApexClass --use-tooling-api --json
# List all objects
sf sobject list --json
# List only custom objects
sf sobject list --sobject custom --json
# List only standard objects
sf sobject list --sobject standard --json
```
## Execute Apex Code
```bash
# Execute Apex from a file
sf apex run --file script.apex --json
# Run interactively (type code, press Ctrl+D to execute)
sf apex run
# Run Apex tests
sf apex run test --test-names MyTestClass --json
# Get test results
sf apex get test --test-run-id 707XXXXXXXXXXXX --json
# View Apex logs
sf apex list log --json
sf apex get log --log-id 07LXXXXXXXXXXXX
```
## REST API (Advanced)
Make arbitrary authenticated REST API calls:
```bash
# GET request
sf api request rest 'services/data/v62.0/limits' --json
# List API versions
sf api request rest '/services/data/' --json
# Create a record via REST
sf api request rest '/services/data/v62.0/sobjects/Account' --method POST --body '{"Name":"REST Account","Industry":"Technology"}' --json
# Update a record via REST (PATCH)
sf api request rest '/services/data/v62.0/sobjects/Account/001XXXXXXXXXXXX' --method PATCH --body '{"BillingCity":"San Francisco"}' --json
# GraphQL query
sf api request graphql --body '{"query":"{ uiapi { query { Account { edges { node { Name { value } } } } } } }"}' --json
# Custom headers
sf api request rest '/services/data/v62.0/limits' --header 'Accept: application/xml'
# Save response to file
sf api request rest '/services/data/v62.0/limits' --stream-to-file limits.json
```
## Metadata Deployment and Retrieval
```bash
# Deploy metadata to an org
sf project deploy start --source-dir force-app --json
# Deploy specific metadata components
sf project deploy start --metadata ApexClass:MyClass --json
# Retrieve metadata from an org
sf project retrieve start --metadata ApexClass --json
# Check deploy status
sf project deploy report --job-id 0AfXXXXXXXXXXXX --json
# Generate a new Salesforce DX project
sf project generate --name my-project
# List metadata components in the org
sf project list ignored --json
```
## Diagnostics
```bash
# Run CLI diagnostics
sf doctor
# Check CLI version
sf version
# See what is new
sf whatsnew
```
## Common SOQL Patterns
```sql
-- Count records
SELECT COUNT() FROM Contact WHERE AccountId = '001XXXXXXXXXXXX'
-- Aggregate query
SELECT StageName, COUNT(Id), SUM(Amount) FROM Opportunity GROUP BY StageName
-- Date literals
SELECT Id, Name FROM Lead WHERE CreatedDate = LAST_N_DAYS:30
-- Subquery (semi-join)
SELECT Id, Name FROM Account WHERE Id IN (SELECT AccountId FROM Contact WHERE Email LIKE '%@acme.com')
-- Polymorphic lookup
SELECT Id, Who.Name, Who.Type FROM Task WHERE Who.Type = 'Contact'
-- Multiple WHERE conditions
SELECT Id, Name, Amount FROM Opportunity WHERE Amount > 10000 AND StageName != 'Closed Lost' AND CloseDate = THIS_QUARTER
```
## Guardrails
- **Always use `--json`** for structured, parseable output.
- **Never create, update, or delete records** without explicit user confirmation. Describe the operation and ask before executing.
- **Never delete records** unless the user explicitly requests it and confirms the specific record(s).
- **Never bulk delete or bulk import** without user reviewing the file/query and confirming.
- Use `LIMIT` on queries to avoid excessive data. Start with `LIMIT 10` and increase if the user needs more.
- For queries over 10,000 records, use `sf data export bulk` instead of `sf data query`.
- When the user asks to "find" or "search" a single object, use SOQL `WHERE ... LIKE '%term%'`. When searching across multiple objects, use SOSL via `sf data search`.
- Use `--target-org <alias>` when the user has multiple orgs; ask which org if ambiguous.
- If authentication fails or a session expires, guide the user through `sf org login web`.
- Bulk API 2.0 has SOQL limitations (no aggregate functions like `COUNT()`). Use standard `sf data query` for those.
- When describing objects (`sf sobject describe`), the JSON output can be very large. Summarize the key fields, required fields, and relationships for the user rather than dumping the raw output.
don't have the plugin yet? install it then click "run inline in claude" again.
by @clawhub
restructured original content into implexa's six-component framework, added explicit decision logic for multi-org scenarios, rate limits, auth expiry, bulk timeouts, and empty result sets, documented all external connections and setup requirements, clarified confirmation requirements for write/delete operations, and provided detailed input/output contracts for each operation.
interact with salesforce orgs via the CLI (sf) to query data, manage records, inspect schemas, execute apex, deploy metadata, and make authenticated REST calls. use this when you need to read, write, or modify salesforce data or configuration, or when you need to search across multiple objects. the CLI must be authenticated before any operation and always use --json for structured output.
npm install -g @salesforce/cli) or direct download from https://developer.salesforce.com/tools/salesforceclisf org login web --alias <alias-name>. subsequent operations target this org unless --target-org <alias> is specified--query or in files (.soql, .sosl).apex files for sf apex runforce-app/ directory structure or specific metadata componentsinput: system with npm or direct internet access to download sf
steps:
npm install -g @salesforce/clisf versionsf org login web --alias my-org (opens browser; follow prompts and allow access)sf org list --json to confirmoutput: authenticated org alias stored locally, CLI ready for data operations
input: SOQL SELECT statement, optional target org, optional output format (json, csv)
steps:
sf data query --query "SELECT Id, Name FROM Contact LIMIT 10" --jsonsf data export bulk --query "SELECT Id, Name, Email FROM Contact" --output-file contacts.csv --result-format csv --wait 10sf data query --file query.soql --json--target-org my-org--all-rows--use-tooling-api--result-format csv --output-file contacts.csvoutput: JSON object with records array, or CSV file at specified path
input: SOSL FIND query, optional target org, optional output format
steps:
FIND {search term} IN <FIELDS> RETURNING <Objects>sf data search --query "FIND {John Smith} IN ALL FIELDS RETURNING Contact(Name, Email), Lead(Name)" --jsonsf data search --file search.sosl --json--result-format csvoutput: JSON object grouped by sobject type, or CSV file
input: object name (e.g. Account, Contact, or custom object)
steps:
sf sobject describe --sobject Account --jsonsf sobject list --jsonsf sobject list --sobject custom --jsonsf sobject describe --sobject ApexClass --use-tooling-api --jsonoutput: JSON schema including fields, required status, relationships, picklist values, record type info
input: sobject type, record ID or WHERE clause with field values
steps:
sf data get record --sobject Contact --record-id 003XXXXXXXXXXXX --jsonsf data get record --sobject Account --where "Name=Acme" --jsonsf data get record --sobject Account --where "Name='Universal Containers' Phone='(123) 456-7890'" --json (values with spaces use single quotes)output: JSON object representing the record
input: sobject type, field values as key=value pairs, explicit user confirmation
steps:
FirstName='Jane' LastName='Doe' Email='jane@example.com'sf data create record --sobject Contact --values "FirstName='Jane' LastName='Doe' Email='jane@example.com'" --json--use-tooling-apioutput: JSON object with newly created record ID and fields
input: sobject type, record ID or WHERE clause, field values to update, explicit user confirmation
steps:
sf data update record --sobject Contact --record-id 003XXXXXXXXXXXX --values "Email='updated@example.com'" --jsonsf data update record --sobject Account --where "Name='Old Acme'" --values "Name='New Acme'" --jsonoutput: JSON object with updated record
input: sobject type, record ID or WHERE clause, explicit user confirmation with record details
steps:
sf data delete record --sobject Account --record-id 001XXXXXXXXXXXX --jsonsf data delete record --sobject Account --where "Name=Acme" --jsonoutput: confirmation message; record is removed from salesforce
input: SOQL query, output file path, output format (csv or json), optional --all-rows for soft-deleted records
steps:
SELECT Id, Name, Email FROM Contactsf data export bulk --query "SELECT Id, Name, Email FROM Contact" --output-file contacts.csv --result-format csv --wait 10--wait 10 means wait up to 10 minutes for completionsf data export resume --job-id 750XXXXXXXXXXXX --json--all-rowsoutput: CSV or JSON file at specified path with exported records
input: CSV or JSON file with records matching sobject schema, sobject type, explicit user review and confirmation
steps:
sf data import bulk --file accounts.csv --sobject Account --wait 10sf data import resume --job-id 750XXXXXXXXXXXX --jsonoutput: job completion report with success/error counts
input: CSV file with records + ID field, sobject type, external ID field name, explicit user confirmation
steps:
sf data upsert bulk --file contacts.csv --sobject Contact --external-id Email --wait 10output: job report with insert/update/error counts
input: CSV file with Id column, sobject type, explicit user confirmation
steps:
sf data delete bulk --file records-to-delete.csv --sobject Contact --wait 10output: job report with delete count and errors
input: SOQL query with child relationships, output directory
steps:
SELECT Id, Name, (SELECT Name, Email FROM Contacts) FROM Accountsf data export tree --query "SELECT Id, Name, (SELECT Name, Email FROM Contacts) FROM Account" --json or with plan: sf data export tree --query "SELECT Id, Name FROM Account" --plan --output-dir export-dataoutput: JSON files (one per parent sobject) with nested child records
input: JSON tree files (output from tree export), optional plan file
steps:
sf data import tree --files Account.json,Contact.jsonsf data import tree --plan Account-Contact-plan.jsonoutput: records created in salesforce with relationships intact
input: org alias, optional instance URL or SFDX URL file
steps:
sf org login web --alias my-orgsf org login jwt --client-id <key> --jwt-key-file server.key --username user@example.com --alias my-orgsf org login access-token --instance-url https://mycompany.my.salesforce.comsf org login sfdx-url --sfdx-url-file authUrl.txt --alias my-orgsf org list --jsonsf org display --target-org my-org --jsonsf org open --target-org my-orgsf org logout --target-org my-orgsf config set target-org my-orgoutput: authenticated org alias or list of authenticated orgs
input: apex script file or code text
steps:
sf apex run --file script.apex --jsonsf apex runsf apex run test --test-names MyTestClass --jsonsf apex get test --test-run-id 707XXXXXXXXXXXX --jsonsf apex list log --jsonsf apex get log --log-id 07LXXXXXXXXXXXXoutput: apex execution result or test report JSON
input: source directory (force-app) or metadata component list
steps:
sf project deploy start --source-dir force-app --jsonsf project deploy start --metadata ApexClass:MyClass --jsonsf project retrieve start --metadata ApexClass --jsonsf project deploy report --job-id 0AfXXXXXXXXXXXX --jsonsf project generate --name my-projectoutput: deployment/retrieval report JSON with status and component list
input: REST endpoint path (relative to /services/data), optional method (GET, POST, PATCH, DELETE), optional request body
steps:
sf api request rest 'services/data/v62.0/limits' --jsonsf api request rest '/services/data/v62.0/sobjects/Account' --method POST --body '{"Name":"REST Account","Industry":"Technology"}' --jsonsf api request rest '/services/data/v62.0/sobjects/Account/001XXXXXXXXXXXX' --method PATCH --body '{"BillingCity":"San Francisco"}' --jsonsf api request graphql --body '{"query":"{ uiapi { query { Account { edges { node { Name { value } } } } } } }"}' --jsonsf api request rest '/services/data/v62.0/limits' --header 'Accept: application/xml'sf api request rest '/services/data/v62.0/limits' --stream-to-file limits.jsonoutput: JSON response body
if the user has multiple authenticated orgs, ask which org to target. if ambiguous, use the default org (set via sf config set target-org). always specify --target-org <alias> in commands to avoid mistakes.
if authentication fails or session expires, guide the user through sf org login web --alias <alias> to refresh. JWT and SFDX URL auth do not expire but require correct credentials at script start.
if the query returns no results, return empty records array in JSON or empty CSV. do not invent data.
if a query would return more than 10,000 records, automatically recommend bulk API: sf data export bulk instead of sf data query. bulk API 2.0 does not support aggregate functions like COUNT(), so for those use standard sf data query.
if the user wants to search a single object by text, use SOQL with LIKE '%term%'. if searching across multiple objects, use SOSL via sf data search.
if bulk import/export/upsert/delete times out, provide the job ID and show the user how to resume: sf data <operation> resume --job-id <id> --json.
if the user asks to create, update, or delete any record, do not execute until you describe the operation and get explicit confirmation. for delete, show the record details (ID, name, key fields) before asking.
if the user provides a CSV for bulk operations, always show a preview of the first 5-10 rows and confirm the record count before proceeding.
if describing an object via sf sobject describe, the JSON output can be large (100+ fields). summarize key fields, required fields, and relationships for the user rather than dumping raw JSON.
if the CLI encounters a rate-limit error (usually HTTP 429), wait and retry. check your org's API usage via the setup UI. bulk API 2.0 counts as one call regardless of record volume, so prefer bulk for large imports.
if the user targets a tooling API object (ApexClass, ApexTrigger, TraceFlag), add --use-tooling-api to sobject describe and record operations. tooling API is read-only for most metadata.
records array (each record is object) + totalSize (count). alternatively CSV file with headers + rows if --result-format csv --output-file <file> specifiedsearchRecords array--json used)--output-filenumberRecordsFailed, numberRecordsProcessed, numberRecordsCompletedfields array (each field has name, type, required, picklist values, relationships), recordTypeInfos, childRelationshipsrecords arrayid, status, numberComponentsDeployed, numberTestsCompleted, component detailsusername, orgId, isDefaultDevHubUsername, isDefaultUsername, alias, connectedStatus, defaultMarkerusername, orgId, instanceUrl, accessToken (if authenticated), alias inforecords array with matching results, or CSV file appears at specified path with data rowsnumberRecordsProcessed > 0 and numberRecordsFailed == 0 (or low failure count if partial success expected). output file exists and contains recordsstatus: Succeeded, component counts match expectationsf org list --json shows new alias with connectedStatus: Connectedsf org open or sf org display succeeds and returns correct org details