Level: BeginnerSalesforce

Salesforce CLI Deploy and Retrieve: Move Metadata Step by Step

8 min read
Salesforce CLI Deploy featured image: title card showing files moving to the cloud

Salesforce CLI Deploy and retrieve commands are how developers move metadata between their computer and their orgs. Deploy sends your files up to an org. Retrieve pulls changes down from an org into your files. Together, they replace most of the clicking you did with change sets.

You already ran a first deploy in our Salesforce CLI setup post. You also learned the project folder layout and the different org types. Now we will learn every common way to deploy and retrieve, including tests and safe production releases.

What is Salesforce CLI Deploy?

A Salesforce CLI Deploy takes metadata files from your project and sends them to a target org. The org checks the files, compiles any code and saves the changes. If one item fails, the whole deploy rolls back by default, so the org never ends up half-changed.

Retrieve does the opposite. It reads metadata from an org and writes it into your project as files.

Think of your project folder as a shared notebook and the org as a whiteboard in a meeting room. Deploy copies your notes onto the whiteboard. Retrieve copies the whiteboard into your notebook, so you do not lose what someone else wrote.

Why Salesforce CLI Deploy Matters

Change sets work only between connected orgs, and you build them by clicking. The CLI is faster and far more flexible.

  • Any org. Deploy to scratch orgs, sandboxes, Developer Edition orgs or production.
  • Repeatable. The same command gives the same result every time.
  • Scriptable. Pipelines can run the exact commands you type.
  • Testable. You choose which Apex tests run during the deploy.
  • Fast feedback. Errors show up right in your terminal with file names and line numbers.

How Salesforce CLI Deploy and Retrieve Work

Every command needs two answers: what to move, and which org to use. You choose “what” with one of three flags. You choose “which org” with --target-org, or the CLI uses your default org.

Salesforce CLI Deploy diagram showing deploy and retrieve between a project and an org
Deploy sends files to an org, and retrieve pulls them back.

The table below shows the three ways to choose what to move.

FlagWhat it selectsGood for
–source-dirA file or folder in your projectQuick deploys while building
–metadataNamed items, like ApexClass:CourseServiceOne or two exact items
–manifestEverything listed in package.xmlPlanned releases

Deploy by Folder or File

This is the most common option during daily work. You point at a file or a folder, and the CLI deploys everything inside.

sf project deploy start --source-dir force-app/main/default/classes/CourseService.cls
sf project deploy start --source-dir force-app

The first command deploys one Apex class and its meta file. The second command deploys the whole project. Both use your default org.

Deploy by Metadata Name

You can also name the items directly with the type and API name. Separate several items with spaces.

sf project deploy start --metadata ApexClass:CourseService ApexTrigger:CourseTrigger

This deploys one class and one trigger, as long as their files exist in your project.

Deploy with a Manifest

A manifest is a file named package.xml. It lists every item for a release. Here is one for the Bright Path Tutors course feature.

<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
    <types>
        <members>CourseService</members>
        <members>CourseWelcome</members>
        <name>ApexClass</name>
    </types>
    <types>
        <members>CourseTrigger</members>
        <name>ApexTrigger</name>
    </types>
    <types>
        <members>Course__c</members>
        <name>CustomObject</name>
    </types>
    <version>65.0</version>
</Package>

Each types block holds one metadata type. The members tags list the API names, and name gives the type. You can let the CLI build this file for you with sf project generate manifest --source-dir force-app.

Then deploy it with this command.

sf project deploy start --manifest manifest/package.xml --target-org brightpath-uat

Salesforce CLI Deploy with Apex Tests

Production needs tested code, so every Salesforce CLI Deploy to production runs Apex tests. Salesforce requires at least 75% code coverage across your Apex before a production deploy can pass. You control which tests run with --test-level.

Test levelWhat runsTypical use
NoTestRunNo testsSandboxes and scratch orgs only
RunSpecifiedTestsOnly the tests you listFast, focused production deploys
RunLocalTestsAll tests except managed package testsMost production deploys
RunAllTestsInOrgEvery test, including packagesRare, full checks

For example, this deploy runs only the CourseService tests.

sf project deploy start --source-dir force-app --test-level RunSpecifiedTests --tests CourseServiceTest

With RunSpecifiedTests, each class and trigger you deploy needs at least 75% coverage from the tests you list. So choose your test classes carefully.

Validate First, Then Quick Deploy

Big teams rarely deploy straight to production. Instead, they validate first. A validation runs the full deploy and the tests but saves nothing. If it passes, you can release it later with a quick deploy.

sf project deploy validate --manifest manifest/package.xml --test-level RunLocalTests --target-org production
sf project deploy quick --job-id 0Af5g00000AbCdEFGH --target-org production

The first command checks everything and prints a job ID. The second command uses that ID to release the same changes in seconds, without running the tests again. A successful validation stays ready for a quick deploy for up to 10 days.

This is perfect for release nights. You validate in the afternoon, and you quick deploy in a short evening window. Users see almost no downtime, and the team avoids last-minute surprises. If the validation fails, you still have hours to fix the problem before the window opens.

Retrieving Metadata

Retrieve uses the same three flags as deploy. Here are the most common examples.

sf project retrieve start --metadata ApexClass:CourseService
sf project retrieve start --metadata CustomObject:Course__c
sf project retrieve start --manifest manifest/package.xml

The first line pulls one class. Next, line two pulls the Course object with its fields, list views and rules. Finally, line three pulls everything in the manifest. In each case, the CLI writes the files into force-app in source format.

Deleting Metadata with Salesforce CLI Deploy

Sometimes a release must remove things, such as an old class nobody uses. Change sets cannot do this. The CLI, however, can delete metadata safely.

For one or two items, use the delete command. It removes the item from the org and from your local files.

sf project delete source --metadata ApexClass:OldCourseHelper --target-org brightpath-uat

For planned releases, use a destructive manifest instead. You create a file named destructiveChanges.xml with the same layout as package.xml. Then you add it to a Salesforce CLI Deploy with the --post-destructive-changes flag. As a result, the deploy adds the new items first and removes the old ones after.

Be careful with deletes in production. Always validate first, and keep a backup of the files in Git.

Source Tracking in Scratch Orgs

Scratch orgs and Developer sandboxes can track changes for you. Salesforce calls this feature source tracking. The CLI remembers what you deployed and spots what changed in the org since then.

So in a tracked org, you can run a Salesforce CLI Deploy with no flags at all. The CLI sends only the files you changed. In the same way, a plain sf project retrieve start pulls only what changed in Setup.

Before you move anything, you can see the list of changes with a preview.

sf project deploy preview
sf project retrieve preview

Each command prints a table of items that would move, with no changes made. This is a safe habit before every deploy or retrieve in a tracked org.

Salesforce CLI Deploy vs Change Sets

Admins often ask how the CLI compares to change sets. The table below shows the main differences.

FeatureChange setsSalesforce CLI Deploy
Works betweenConnected orgs onlyAny org you can log in to
How you build itClicks in SetupFiles and commands
Version historyNoneFull history with Git
Delete metadataNoYes, with destructive changes
AutomationNoYes, in CI/CD pipelines
Learning effortLowMedium

When to use which depends on your team. Change sets are fine for small admin changes. However, for code and team projects, the CLI is the better choice.

Salesforce CLI Deploy diagram comparing change sets and the CLI
Change sets vs Salesforce CLI deploy.

A Real Salesforce CLI Deploy Example

Let’s run a full Salesforce CLI Deploy for the Bright Path Tutors course feature, from a sandbox to production.

  1. Retrieve the latest Course object from the sandbox, so your files include any admin changes.
  2. Run sf project generate manifest --source-dir force-app --output-dir manifest to build package.xml.
  3. Validate the release against production with RunLocalTests.
  4. Read the result and fix any failed tests or errors.
  5. Quick deploy with the job ID during your release window.
  6. Retrieve once more from production to confirm the files match.

If a Salesforce CLI Deploy fails, the terminal shows a table of errors. Each row names the item and the problem. Here is a typical example.

Component Failures [1]
Type       Name           Problem
ApexClass  CourseService  Variable does not exist: Fee (12:20)

This tells you the file, the line and the column of the problem. In this case, the code used Fee instead of Fee__c on line 12. So you fix the name and deploy again.

Common Mistakes with Salesforce CLI Deploy

  • Deploying to the wrong org. Always check the target alias before you press Enter.
  • Not retrieving first. You may overwrite a change an admin made in Setup.
  • Forgetting tests in production. Plan your test classes before the release day.
  • Leaving out dependencies. A field must exist before a class that uses it can compile.
  • Using NoTestRun in production. Salesforce does not allow it when your deploy has Apex.

Best Practices for Salesforce CLI Deploy

  • Validate production releases early, then quick deploy during a short window.
  • Keep package.xml in Git, so every release has a clear list.
  • Use RunSpecifiedTests for small releases to save time, but keep good coverage.
  • Retrieve before you deploy, so your files match the latest org state.
  • Add --wait 30 on long deploys, so the command waits up to 30 minutes for the result.

Practice Task

Create a package.xml with your CourseService class and Course object. Validate it against a scratch org or sandbox, then run a quick deploy with the job ID. Hint: use sf project deploy report if you lose the job ID.

Official Resources

Quick Recap

  • Deploy sends metadata files to an org, and retrieve pulls them back.
  • Choose what to move with --source-dir, --metadata or --manifest.
  • A Salesforce CLI Deploy to production needs tests and 75% coverage.
  • Validate first, then quick deploy within 10 days.
  • Retrieve before you deploy, so you never overwrite admin changes.

What’s Next?

Next, we look at a handy browser tool for quick tests and logs. Read our Salesforce Developer Console guide to learn its logs, query editor and anonymous Apex window.