This is the third installment in a five-part series, looking at the changes and opportunities Salesforce DX offers app developers today. Over the course of this series, we’ll talk about:
- What Salesforce DX is (and isn’t)
- Paths to Adoption
- Getting Started with the Salesforce CLI
- Scripting and the CLI
- Continuous Development with Salesforce DX
The content in this series is a collaboration between the Salesforce DX and Salesforce Evangelism teams.
It’s the Salesforce CLI–not the Salesforce DX CLI
Salesforce DX is often referred to as SFDX or sfdx. One reason is because the executable command for the Salesforce CLI is sfdx (another is that we humans like abbreviations). And with that in mind people often think that the Salesforce CLI can only be used with Salesforce DX projects – which isn’t true.
The Salesforce CLI is, as the name says, a command line interface that enables you to run numerous tasks on your Salesforce environments. A major portion of the current functionality is targeted at elements that were introduced with Salesforce DX, like source-driven development using scratch orgs or IDE integration and ALM. However, there’s a lot more going on and available across any type of org.
For example, you can use the CLI to run a SOQL query against a production org.
As you can see, this isn’t dependent on scratch orgs or other new functionalities at all. It’s a standardized— and Salesforce-supported— way of working with any org. Think of it like using Ant with the Force.com Migration Tool, but as a modern tooling.
Wait, what, I can use the CLI with any org?
Yes, you can! By design, not all commands work with every org type. For example, you can’t pull source data from a non-scratch org. But first things first. When you run sfdx force:org:list
you get a list of all your orgs, that you authenticated against using the CLI.
This abbreviated list of my current orgs shows that I have authenticated the CLI against three non-scratch orgs (lines 4-6). This can be, for example, your production org, a Sandbox org or a Developer Edition org. Check out the last column for the scratch org, which shows the expiration date of that org.
The command above demonstrates how to use the CLI to authenticate into a non-scratch org and give it the convenient alias “weather” that can be used to refer to that org later (aliases are great so you don’t have to remember usernames). The CLI opens a new browser tab where you can enter your credentials to authenticate the desired org. Upon successful authentication the CLI automatically stores OAuth credentials on the local machine. Boom! Done.
With that, you can now run CLI commands against that org, like getting the list of all custom objects (snippet 1) or create a new record (snippet 2). The previously set alias “weather” makes it easy to select the org that we want to use.
There are many more commands available that you can run against any org, like running Apex tests, retrieving metadata or assigning permission sets. This is possible because the CLI uses the Tooling API or the Metadata API under the hood.
You can get the full list of available commands using sfdx force:doc:commands:list
. I highly encourage you to check them out and use the CLI as much as possible. It makes you more productive because you don’t have to switch windows and contexts. We’re updating the CLI frequently, so bookmark and keep checking the CLI Release Notes.
Config files, scratch orgs, oh my!
One of the biggest features of Salesforce DX is the introduction of “scratch orgs.” These ephemeral orgs can (and should) be part of your development workflow. But before you can use this type of org you’ll have to set up a Salesforce DX project using the Salesforce CLI. Also, make sure that you have enabled the Dev Hub as explained in the previous post.
The sfdx force:project:create -n MyNewProject
command (line 1) creates within the current folder a new subfolder with the name MyNewProject. It then automatically creates a couple of files and folders within that sub folder as you can see on the output (lines 2-6).
- sfdx-project.json
- config/project-scratch-def.json
- .forceignore
- force-app/main/default/aura (folder)
The sfdx-project.json file controls the main elements of the project and how the CLI behaves for this project (not globally, more on that later). The following snippet showcases the default contents for a new project definition file.
packageDirectories
: This parameter defines where the CLI should look for your source elements. This also means that you can change the location from force-app to something else if it’s more appropriate for your environment. You can add multiple directories here for a modular structure when you want to break up your app into multiple packages.namespace
: If your package uses a dedicated namespace you can (or should) configure it here.sfdcLoginUrl
: This parameter tells the CLI where it should point to for authentication. Why is this configurable? Well, you may want to connect to a sandbox and change the login url to https://test.salesforce.com.sourceApiVersion
: The CLI has the capability of creating new code elements, like Apex classes, Lightning components etc. This parameter is used to automatically set the API version for the new components. The default value will match the API version of your Dev Hub org.
You find the full description of the configuration options here.
More file-based configuration
The second file type controls the “shape” of a newly created scratch org. In a new project an example configuration (project-scratch-def.json in the config folder) is created. You can have multiple configuration files, depending on your needs of developing and testing with different org preferences.
To use it with the CLI, you run the command (from the root folder of the project) sfdx force:org:create -f config/project-scratch-def.json -a MyScratchOrg
.
This kind of configuration file allows for tremendous flexibility for testing your projects against a variety of orgs. For example, you could have a scratch org shape for an Enterprise org with Service Cloud licenses, with Lightning and multi-currency enabled, and another for an Unlimited org with Communities, Einstein Analytics and ETM 2.0 enabled. All of these JSON files can be bundled into the same projects for your team to use while building and testing. You can check out the documentation for scratch org shapes here. One of my personal highlights is the capability to disable the Lightning session cache in a scratch org by disabling the S1EncryptedStoragePref2 preference.
If you’re struggling to create a scratch org shape that perfectly mimics your production org, keep a couple things in mind:
First, your scratch org, even when ‘correctly’ configured, will not perfectly mirror production. You’ll still want a full copy sandbox if you need a mirror of production. Second, the usefulness of a scratch org isn’t tied to how perfectly it mirrors production (and the fact that it can be different can be very useful). Scratch orgs are there to help with the initial stages of development. If you want to test out impacts of turning on new features (like multi-currency or ETM 2.0), you can use a scratch org to do that. Once you’ve got the basics of what you’re building together in a scratch org, you’ll move changes into your regular app development lifecycle. Your sandboxes, which do more closely match production, can help you then perform more robust testing and refactoring before you release to production.
Think global, configure local
The Salesforce CLI relies on a couple of variables when communicating with the Salesforce org of your choice. You can set these variables globally (for all commands) or locally for a specific project. These variables can be the alias or the username (both are interchangeable) for your DevHub, the API version that the CLI should use, or the default username for your project.
Per definition, local variables override global variables. Using the command sfdx force:config:set
you can set project-specific variables. When you append the -g
parameter you’ll set the value globally for all projects. Another example where the CLI is using a local configuration is the -s
parameter in sfdx force:org:create
. When you use this parameter, the command fetches the default username for the created scratch org (or the alias if you set one) and sets it as a local variable for the current project.
Push, change, pull, commit – even when it doesn’t work
One of my favorite features of the Salesforce CLI is to use it with scratch orgs for my daily development flow. These are the most common steps (which you likely already learned in the Trailhead module “App Development with Salesforce DX”).
- Create a new scratch org and push existing code to it (or start with a new project from scratch).
- Develop live in the scratch org and test changes.
- Pull the changes down to the local machine.
- Change some components locally.
- Push the components and validate the work in the org.
- Commit the changes to git (never forget that scratch orgs expire, so make sure your code is in version control).
We have modified the source representation for some of our more cumbersome Metadata API .xml files, such as custom object, static resources, and custom object translations. The force:source:push
and force:source:pull
commands work with a new org metadata tracking feature to help keep your project’s source in sync with the changes that you make in the scratch org. These changes make it easier for you to integrate with source control and manage your source files.
We all have been in the situation when something doesn’t work. Have you ever changed the same file locally and in the scratch org? What about changing a bunch of things in the org the day before and forgetting which files have been touched? That’s where sfdx force:source:status
will be your savior.
Once you run this command it’ll detect which files have changed (from a Salesforce DX perspective) since your last pull or push. This is extremely helpful for detecting remotely changed files, especially when you have changed the same file locally. The pull and push commands provide a —forceoverwrite
flag which you can then use to enforce (as the name says) an overwrite for a changed file.
So what do you do when you have a remote file that you want to “reset” to the status of the local file, but the local file hasn’t changed? The Salesforce CLI uses a fingerprint hash to track local changes, so you have to change the content of the local file. Just change it a bit, like by adding a space somewhere, then run the push command and then undo the change. Done.
Last, but not least, you can exclude files from any of the force:source
commands. The .forceignore
file, which works like gits .gitignore, gives you granular control over that. Read more about how to use it here in the docs. And don’t forget to commit that file to version control, so that it is shared with your team.
The CLI is a powerful tool that simplifies your interaction with any Salesforce org. You can find numerous examples on how to use it with scratch orgs and source controlled code on this site, like in this blog post.
What’s next and what to do now
In the next post of this series we’ll dive into techniques for automating the CLI for an even better development workflow.
Also check out the Salesforce DX Trail on Trailhead to learn more about the standard flows when using the CLI like converting existing code, working with scratch orgs, or how to deploy metadata using the CLI.
You should also be sure to register for the upcoming Ask Me Anything (AMA) with the Salesforce DX Product Management team, coming up on February 27! If you’re looking to get more hands on with Salesforce DX at TrailheaDX, check out the Emerging Tech for Developers Bootcamp.
About the author
René Winkelmeyer works as Principal Developer Evangelist at Salesforce. He focuses on enterprise integrations, mobile, and security with the Salesforce Platform. You can follow him on Twitter @muenzpraeger.