If you already installed Salesforce CLI but your pipeline still breaks, this playbook is your next step. It focuses on post-install workflows that fail most often: authentication, deploy strategy, test levels, and CI troubleshooting.
If you still need installation help, start with How to Install Salesforce CLI with NPM and keep How to Fix Salesforce CLI NPM Installation Errors open for common setup failures.
What should I configure right after installing Salesforce CLI?
Set a known CLI version, confirm plugin health, and verify you can run core commands in the same shell your scripts use. This removes “works on my machine” drift before you touch authentication or deploys.
Use this quick baseline:
# 1) Verify version and executable location
sf --version
which sf
# 2) Check plugin state
sf plugins --core
# 3) Optional: pin a known CLI version for reproducible CI
npm install @salesforce/[email protected] --global
Then store the chosen version in your CI config so local and pipeline behavior stay aligned.
How do I set up Salesforce CLI auth for local development and CI/CD?
Use interactive browser auth for local work, then use JWT-based headless auth in CI. Mixing both in pipelines is a common source of unstable deploy jobs.
For local development, browser auth is simplest:
sf org login web --alias devhub --set-default-dev-hub
For CI, JWT auth requires three things set up in Salesforce before the CLI command will work:
Generate a self-signed certificate and private key (the private key must not have a passphrase):
openssl req -x509 -sha256 -nodes \ -days 365 -newkey rsa:2048 \ -keyout server.key -out server.crtCreate a Connected App in the target org:
- Enable OAuth settings with the
apiandrefresh_tokenscopes. - Upload
server.crtas the digital certificate. - Pre-authorize the CI user’s profile under “Manage” > “Policies.”
- Enable OAuth settings with the
Store secrets in your CI platform —
SF_CLIENT_ID(the Connected App consumer key),SF_USERNAME, and the private key file content as encrypted secrets.
Then the CI auth command is:
sf org login jwt \
--client-id "$SF_CLIENT_ID" \
--jwt-key-file "$SF_JWT_KEY_PATH" \
--username "$SF_USERNAME" \
--instance-url https://login.salesforce.com
If JWT auth fails silently, check these first: private key has no passphrase, the Connected App scopes include api, the CI user profile is pre-authorized, and IP restrictions are not blocking your CI runner’s address range.
In CI, always fail fast if auth does not succeed before deploy steps run.
How should I structure metadata deploy commands to reduce failures?
Deploy specific metadata paths intentionally, validate before pushing to production, and separate destructive steps from routine deploys. Smaller, explicit deploy scopes fail less and are easier to debug.
Use the validate-then-quick-deploy pattern for production releases. Validation runs your tests against the target org without committing changes. If validation passes, quick deploy pushes the same component set without re-running tests, cutting production deployment time significantly.
# Step 1: Validate against production (runs tests, commits nothing)
sf project deploy validate \
--source-dir force-app \
--target-org "$SF_USERNAME" \
--test-level RunLocalTests \
--wait 30
# Step 2: Quick deploy the validated set (skips tests)
sf project deploy quick \
--use-most-recent \
--target-org "$SF_USERNAME"
Validations expire after 10 days. If you run sf project deploy quick after that window, you will get an undefinedComponentSet error and must re-validate.
For non-production environments where you want a faster feedback loop, a direct deploy is fine:
sf project deploy start \
--source-dir force-app \
--target-org "$SF_USERNAME" \
--test-level RunSpecifiedTests \
--tests MyFeatureTest \
--wait 30
When you must run destructive changes, isolate them in their own pipeline job with explicit approval gates.
Which Apex test level should I use in each environment?
Use faster levels for lower-risk environments and stricter levels for production-bound changes. Over-testing every deploy slows teams; under-testing production deploys creates rollback pain.
Practical default matrix:
NoTestRun: scratch org setup tasks and metadata-only experiments.RunSpecifiedTests: feature branch validation with targeted, relevant test classes.RunLocalTests: integration, UAT, and production deployment paths.RunAllTestsInOrg: only when policy or release criteria explicitly require it.
Keep your test strategy written in-repo so engineers do not guess per pipeline.
How do I speed up Salesforce CLI deploys without risky shortcuts?
Reduce deployment scope and avoid retesting unaffected metadata instead of lowering quality bars. The safest speed gains come from precision, not from disabling tests.
Focus on these levers:
- Deploy only changed package directories when your repo structure supports it.
- Use
sf project deploy previewto review what will be deployed before committing to a full run. - Prefer
RunSpecifiedTestsfor fast feedback in non-production stages. - Keep test data factories efficient so targeted tests finish quickly.
- Cache dependencies in CI to cut setup time before CLI commands run.
- Use
.forceignoreto exclude metadata that should never leave your repo. A practical starting point:
# .forceignore
package.xml
# Admin-managed metadata
**/profiles/**
**/settings/**
# IDE and OS files
.eslintrc.json
.prettierrc
.gitignore
How do I prevent CLI and plugin version drift across the team?
Pin versions where stability matters and document upgrade cadence. Unmanaged updates can break commands, output parsing, and automation scripts without warning.
Team guardrails that work:
- Pin the CLI version in CI and publish it in
READMEor pipeline docs. - Avoid unreviewed plugin installs on shared runners.
- Schedule regular dependency updates and validate pipeline behavior in a branch first.
- Track command changes in release notes before bumping major versions.
- If your scripts still use
sfdxcommands, migrate them to thesfequivalents. Salesforce removed deprecatedsfdx-style commands in November 2024, and old scripts that referencesfdx force:source:deployor similar will fail on current CLI versions. Salesforce publishes a command migration mapping that covers every renamed command.
How do I troubleshoot failed Salesforce CLI deploys quickly?
Capture the deploy ID, fetch detailed status, and classify errors into auth, metadata validation, test failure, or platform limits. Fast classification prevents wasted retries.
Use this debug flow:
# Start deploy and capture output
sf project deploy start --source-dir force-app --target-org "$SF_USERNAME" --wait 30
# If the CLI exits without printing component errors, pull the full report
sf project deploy report --use-most-recent --target-org "$SF_USERNAME"
sf project deploy start sometimes exits without printing component-level errors. Always run sf project deploy report when you see a failure with no detail.
What if the deploy succeeded but the CLI timed out?
A common CI/CD frustration: the CLI prints The client has timed out but the deployment actually completed in Salesforce. The CLI has a client-side timeout that is separate from the server-side deploy.
When this happens:
- Check the deployment status in Setup > Deployment Status, or run
sf project deploy report --use-most-recentonce the CLI is responsive again. - If the deployment succeeded, your pipeline failed for nothing. Increase the
--waitvalue or restructure the job to poll separately. - If this keeps happening, delete the
.sfdirectory in your project root. A corrupted local state cache can cause the CLI to hang after otherwise successful operations.
If your failures are install- or environment-related, use the fixes in How to Fix Salesforce CLI NPM Installation Errors.
How do I set up a GitHub Actions pipeline for Salesforce CLI?
Define a workflow that installs the CLI, authenticates with JWT, validates against the target org, and then quick-deploys on success. This example covers the full path from push to production deploy.
Store your Connected App consumer key, username, and private key as encrypted repository secrets (SF_CLIENT_ID, SF_USERNAME, SF_JWT_KEY).
name: Salesforce Deploy
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
validate:
name: Validate Metadata
runs-on: ubuntu-latest
steps:
- name: Checkout source
uses: actions/checkout@v4
- name: Install Salesforce CLI
run: npm install @salesforce/[email protected] --global
- name: Write JWT key file
run: echo "${{ secrets.SF_JWT_KEY }}" > server.key
- name: Authenticate target org
run: |
sf org login jwt \
--client-id "${{ secrets.SF_CLIENT_ID }}" \
--jwt-key-file server.key \
--username "${{ secrets.SF_USERNAME }}" \
--instance-url https://login.salesforce.com
- name: Validate deployment
run: |
sf project deploy validate \
--source-dir force-app \
--target-org "${{ secrets.SF_USERNAME }}" \
--test-level RunLocalTests \
--wait 30
- name: Clean up key file
if: always()
run: rm -f server.key
deploy:
name: Quick Deploy to Production
needs: validate
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
runs-on: ubuntu-latest
environment: production
steps:
- name: Checkout source
uses: actions/checkout@v4
- name: Install Salesforce CLI
run: npm install @salesforce/[email protected] --global
- name: Write JWT key file
run: echo "${{ secrets.SF_JWT_KEY }}" > server.key
- name: Authenticate target org
run: |
sf org login jwt \
--client-id "${{ secrets.SF_CLIENT_ID }}" \
--jwt-key-file server.key \
--username "${{ secrets.SF_USERNAME }}" \
--instance-url https://login.salesforce.com
- name: Quick deploy validated set
run: |
sf project deploy quick \
--use-most-recent \
--target-org "${{ secrets.SF_USERNAME }}"
- name: Clean up key file
if: always()
run: rm -f server.key
Pull requests run validation only. Pushes to main validate and then quick-deploy to production, using a GitHub environment with manual approval gates if you need them.
Adapt this pattern for other CI platforms (GitLab CI, Bitbucket Pipelines, Azure DevOps) by translating the YAML structure and secret references to each platform’s format.
Should I use Salesforce CLI or DevOps Center for this pipeline?
Use Salesforce CLI when you need scriptable, repeatable automation in Git-based workflows. Use DevOps Center (now Generally Available) when your team prefers guided releases with less terminal-heavy operations.
A simple decision rule:
- Choose Salesforce CLI for high automation, custom checks, and advanced CI control.
- Choose DevOps Center for admin-heavy teams and guided change promotion with a built-in UI.
- Use both when needed: DevOps Center for release orchestration, CLI for custom validations and edge-case deploy logic.
Related guides you can use now
If you need help before or during these CI/CD workflows, start with these: