SfSkills Domains Docs GitHub

Home / apex / sf-cli-and-sfdx-essentials

sf-cli-and-sfdx-essentials

Use this skill when a developer needs to authenticate orgs with sf CLI, set up a Salesforce DX project, create scratch orgs, push or pull source, deploy or retrieve metadata with package.xml manifests, or diagnose common sf CLI errors. Trigger keywords: sf CLI, sfdx, scratch org, source push, source pull, deploy, retrieve, package.xml, org login, sf project. NOT for scripting the CLI in CI with --json, aliases, and non-interactive auth — use devops/salesforce-cli-automation.

Open the skill folder on GitHub


sf CLI and SFDX Essentials

Use this skill to authenticate Salesforce orgs, scaffold projects, manage scratch orgs, and move metadata between local development environments and Salesforce orgs using the Salesforce CLI (sf). Covers the complete local development loop: auth → project → scratch org → push/pull → deploy/retrieve.


Before Starting

Gather this context before working on anything in this domain:


Core Concepts

1. Source Format vs Metadata (mdapi) Format

Salesforce CLI works with two file formats:

Source format is the standard for DX-based development. Metadata format is still required for some deploy/retrieve scenarios, especially when source tracking is not available (sandboxes, production).

Per the Salesforce Metadata API Developer Guide: "The project retrieve start command allows for source tracking. Source tracking includes information about which revision you're working on and when the last changes were made, which makes source commands more developer-friendly."

2. Source Tracking and Scratch Orgs

Scratch orgs use source tracking to know which metadata changed since the last push/pull. This means:

Scratch orgs are ephemeral: lifespan is 1–30 days (specified at creation). They are designed to be disposable. The source of truth is always the version control system, not the org.

3. Dev Hub and Scratch Org Lifecycle

Dev Hub is a production or Developer Edition org with "Dev Hub" enabled in Setup. It is required to create scratch orgs. Each scratch org is linked to the Dev Hub that created it. Scratch org allocation limits vary by Dev Hub edition:

Dev Hub EditionDaily CreatesMax Active Orgs
Developer Edition63
Enterprise Edition4020
Performance Edition10050
Unlimited Edition10050

Exceeding the active org limit causes org create scratch to fail with an allocation error — delete unused scratch orgs before creating new ones.

4. package.xml Manifest Structure

A package.xml manifest tells Metadata API which components to retrieve or deploy. Structure:

<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
    <types>
        <members>*</members>
        <name>CustomObject</name>
    </types>
    <types>
        <members>MyClass</members>
        <name>ApexClass</name>
    </types>
    <version>62.0</version>
</Package>

Key rules:


Common Patterns

Pattern 1 — Authenticate a Developer Org Interactively (Web Flow)

When to use: Developer machine setup. A browser is available.

Commands:

# Authenticate production or sandbox
sf org login web --alias myorg --instance-url https://login.salesforce.com

# Authenticate a sandbox (use test.salesforce.com)
sf org login web --alias mysandbox --instance-url https://test.salesforce.com

# Set as default org for commands
sf config set target-org mysandbox

Flags:

Web flow opens a browser and stores the OAuth refresh token locally. The access token is refreshed automatically on subsequent commands.

Pattern 2 — Authenticate for CI/CD (JWT Bearer)

When to use: Non-interactive pipelines (GitHub Actions, Jenkins, Copado). No browser available.

Prerequisites:

  1. A Connected App in Salesforce with OAuth enabled, using a certificate for JWT.
  2. The private key file (.key) corresponding to the connected app's certificate.
  3. The consumer key (Client ID) of the connected app.

Command:

sf org login jwt \
  --client-id <CONSUMER_KEY> \
  --jwt-key-file server.key \
  --username deployuser@myorg.com \
  --alias prod-ci \
  --instance-url https://login.salesforce.com

Flags:

JWT auth does not store a refresh token. The private key signs a JWT assertion, Salesforce validates it against the Connected App certificate, and returns an access token. For CI pipelines this is the required pattern — web flow cannot run without a browser.

Pattern 3 — Create and Use a Scratch Org

When to use: Feature development, automated testing, package development.

Commands:

# Create project first (if not already done)
sf project generate --name MyProject

# Set Dev Hub as default (first time)
sf config set target-dev-hub devhub@myorg.com

# Create scratch org (Developer edition, 7-day lifespan)
sf org create scratch \
  --edition developer \
  --duration-days 7 \
  --alias myscratch \
  --set-default

# Push local source to scratch org
sf project deploy start

# Pull changes made in scratch org back to local
sf project retrieve start

# Open scratch org in browser
sf org open --target-org myscratch

# Delete scratch org when done
sf org delete scratch --target-org myscratch --no-prompt

Key facts:

Pattern 4 — Deploy and Retrieve with Sandboxes and Production

When to use: Promoting changes to sandboxes or production where source tracking is not available.

Deploy from source directory:

sf project deploy start \
  --source-dir force-app \
  --target-org mysandbox \
  --test-level RunLocalTests

Deploy from package.xml:

sf project deploy start \
  --manifest package.xml \
  --target-org mysandbox \
  --test-level RunLocalTests

Retrieve to local source format:

sf project retrieve start \
  --manifest package.xml \
  --target-org mysandbox

Retrieve to mdapi (metadata) format:

sf project retrieve start \
  --manifest package.xml \
  --target-org mysandbox \
  --target-metadata-dir retrieved/

Preview conflicts before deploying or retrieving:

# See what would be deployed without doing it
sf project deploy preview --target-org mysandbox

# See what would be retrieved without doing it
sf project retrieve preview --target-org mysandbox

Resume a timed-out async deployment:

sf project deploy start --manifest package.xml --target-org prod --async
# Returns a job ID immediately. Resume status check with:
sf project deploy resume --job-id <ID>

Convert between formats explicitly:

# Source format → metadata format (for inspection or legacy tooling)
sf project convert source --output-dir mdapi-out --manifest package.xml

# Metadata format → source format
sf project convert mdapi --root-dir mdapi-out --output-dir force-app

Test level options for deploy:

Platform limits for deploy/retrieve:

Per the Salesforce Metadata API Developer Guide: "A regular deploy call executes automated Apex tests that can take a long time to complete. To skip tests for validated components and deploy components to production quickly, use the deploy recent validation option."

# Validate first (runs tests, no deployment)
sf project deploy validate --manifest package.xml --target-org prod --test-level RunLocalTests

# Then deploy the validated set without re-running tests
sf project deploy quick --job-id <ID from validate output>

Decision Guidance

SituationRecommended ApproachReason
Developer machine, first-time org authsf org login webInteractive, no certificate required
CI/CD pipeline authsf org login jwtNon-interactive; browser not available
Active feature developmentScratch org + push/pullSource tracking minimizes deploy scope
Deploying to sandbox or productionsf project deploy start --manifestExplicit control; source tracking not available
Production deploy with zero downtimeValidate + Quick DeployTests run once; deploy skips re-run
Retrieving org config for version controlsf project retrieve start --manifestGets source-format files ready for git

Step-by-step instructions for an AI agent or practitioner activating this skill:

  1. Gather context — confirm the org edition, relevant objects, and current configuration state
  2. Review official sources — check the references in this skill's well-architected.md before making changes
  3. Implement or advise — apply the patterns from Core Concepts and Common Patterns sections above
  4. Validate — run the skill's checker script and verify against the Review Checklist below
  5. Document — record any deviations from standard patterns and update the template if needed

Review Checklist

Run through these before marking work in this area complete:


Salesforce-Specific Gotchas

  1. Scratch org push/pull does not work with sandboxes — Source tracking is only available on scratch orgs. Running sf project deploy start against a sandbox without --source-dir or --manifest will either fail or behave unexpectedly. Always specify the scope explicitly for non-scratch targets.
  2. package.xml wildcard (*) does not work for all metadata types — Standard objects (Account, Contact, etc.) do not support <members>*</members>. You must list them individually. Attempting wildcard retrieval of standard objects results in a retrieve error or silent omission.
  3. JWT auth fails if the Connected App is not pre-authorized for the user — The Connected App must have its OAuth policies set to allow the specific user profile or permission set, and the user must be pre-authorized. Without pre-authorization, the JWT assertion is rejected even with a correct certificate.
  4. API version mismatch causes silent retrieve failures — If package.xml specifies an API version higher than the org supports, the retrieve may succeed but return empty or partial results. Always match <version> to the org's current API version (sf org display shows the API version).
  5. --target-metadata-dir disables source tracking — Using this flag retrieves metadata in mdapi format and breaks the source-tracking chain. Subsequent sf project deploy start commands (without flags) may not include these retrieved files. Use it only for one-off investigations or when you need the zip-ready directory structure.
  6. .forceignore is not .gitignore — .forceignore controls what the CLI excludes from push/pull/deploy/retrieve operations. It uses .gitignore syntax but has no effect on git. A file ignored in .forceignore is still committed to version control. A file ignored in .gitignore is still synced by the CLI unless also in .forceignore.
  7. Source tracking state is lost between CI pipeline runs — The CLI stores source tracking state in .sf/orgs/<orgId>/ on the local filesystem. If the CI workspace is not persisted (e.g., ephemeral GitHub Actions runners), this directory is lost between runs, causing the next push to treat all local files as new changes or report false conflicts. Either persist .sf/ in CI cache, or always use --source-dir/--manifest flags in CI to avoid dependency on tracking state.
  8. --set-default and --set-default-dev-hub are separate settings — Setting a Dev Hub with sf org login web --set-default-dev-hub does not make it the default org for deploy/retrieve. You must also run sf config set target-org <alias> or pass --set-default separately. Conflating the two causes commands to target the wrong org silently.
  9. Each -meta.xml file carries its own apiVersion — When you retrieve components from an org, each ClassName.cls-meta.xml file contains the API version it was authored at. This is independent of sfdx-project.json's sourceApiVersion. Old retrieved classes may still have API version 40.0 in their metadata even if the project is on 62.0. Update these manually when a newer API version behavior is required.

Output Artifacts

ArtifactDescription
sf CLI commandsExact commands with flags for the developer's scenario
package.xml manifestReady-to-use XML file targeting specific metadata types
sfdx-project.json snippetCorrect packageDirectories and sourceApiVersion for the project

Package files