Start tracking your progress
Trailhead Home
Trailhead Home

Build Your First Unlocked Package

Learning Objectives

After completing this unit, you’ll be able to:
  • Become familiar with CLI commands for packaging.
  • Describe the basic packaging use cases.
  • Package the DreamHouse sample app and install it in a Trailhead Playground.

Why We Love Package Development

We think packaging is one of the most exciting new features for Salesforce Platform developers. It’s on par with some well-known disruptive innovations, such as sliced bread, the mobile phone, and home-video service. But just in case you need more convincing, let’s sum up the key benefits that we’ve learned so far. Package development:

  • Follows best practices regarding the software development life cycle. It’s compatible with the new features of Salesforce DX: projects, source-driven development commands, and scratch orgs were built specifically with packaging in mind.
  • Encapsulates all the changes you are tracking between lifecycle stages in a versioned artifact.
  • Makes it easier for you to accommodate new feature requests. Simply add, update, and remove components in your package.
  • Provides an improved audit history, so you can more easily track and understand the changes made to your production org.
  • Organizes source. It’s much easier to know which components belong to which applications and features.
  • Promotes iterative and modular development.
  • Supports interdependencies among unlocked packages. A single unlocked package can depend on multiple unlocked packages and classic packages.
  • Supports continuous integration and continuous delivery because the packaging CLI commands enable each step in the deployment pipeline to be fully automated.

Now that you’re clued in to the benefits of package development, we’re going to show you how to create an unlocked package.

Simple Packaging Use Cases

Unlocked packages are superbly suited for internal business applications. Let’s say:

  • Your Finance business group wants your IT team to build an app that employees can use to submit expenses. Your team decides to develop and deliver it using unlocked packages.
  • Your HR team wants your IT team to build an app that employees can use to refer potential hires. Employees will use the Referral app to post job postings, refer their buddies, and get referral bonuses. Your team decides to develop and deliver it using unlocked packages.

For each of these cases, you start a completely new project, and all your source is contained in Salesforce DX project format (and committed to your version control system). When you’re ready to deliver one of these apps, you create an unlocked package that you can test in a scratch org or sandbox, and then install in your production org. And when the team needs a new feature, you can add it and create a new package version. Easy. Peasy.

Configure Your Environment

Before you can get to the good stuff, let’s make sure you have everything set up that you need to ace the challenge ahead.

  • Have you already set up a Dev Hub and installed the Salesforce CLI? Head over to this unit in the App Development with Salesforce DX module for details.
  • Do you have a GitHub account?
  • Have you turned on packaging in your Dev Hub org? From Setup, enter Dev Hub in the Quick Find box and select Dev Hub. Click Enable Unlocked Packages and Second-Generation Managed Packages.

“Git” the DreamHouse Source Code

For demonstration purposes, let’s pretend that you’re building and delivering the DreamHouse app to one of your business teams.

If you’re currently using Salesforce DX features and tooling, you may already be familiar with the DreamHouse sample repo. DreamHouse is a stand-alone application that incorporates many features available in Salesforce Platform. It uses Lightning components, Apex, Notifications, Einstein, Process Builder, and more. It allows users to browse for properties and contact real estate brokers online.

So you can focus on packaging, you’re going to pull down the DreamHouse source code and Salesforce DX project files that have already been created. Although this example uses one package, a Salesforce DX project can have multiple packages. You can isolate different packages based on the directory structure, yet share components where it makes sense.

By creating a package for this app, you can easily install it in scratch orgs, UAT sandboxes, and production orgs as you iterate through the development life cycle.

We’ll walk you through the whole process using the tools specifically designed for package development.

Let’s get the source code for the DreamHouse app.

  1. Download the source from the DreamHouse GitHub repository.
  2. Click Clone or download.
  3. Copy the HTTPS link to the repository.
  4. In a command window, change to the directory where you want to put the source code, then run this command.
    git clone

Notice that the source is in Salesforce DX project structure, and contains a DX project file and a scratch org definition. Because the DreamHouse repo is continually updated, don’t be alarmed if your version of the project looks a little different.

Shows the complete dreamhouse-sfdx directory structure if you were to open it something like Finder or Windows Explorer.

Create a Package and Package Version

If you’ve been trekking on this trail for a while, chances are you’re already logged in to your Dev Hub org.

  1. In the command window, let’s make sure that the Dev Hub org is connected.
    sfdx force:org:list
    The output of this command lists any org that you’re connected to, including Dev Hub, Trailhead Playgrounds, and scratch orgs. The (D) indicates your default Dev Hub org. If you see a (U), all CLI commands run against that username by default.
    === Orgs
         ALIAS       USERNAME                         ORG ID              CONNECTED STATUS
    ───  ──────────  ───────────────────────────────  ──────────────────  ────────────────
    (D)  DevHub             00DB0000000Ige5MAC  Connected
         MyTP   00D6A000000fH8CUAU  Connected
         TestingOrg                 00DB0000000Im58MAC  Connected
    ────────  ────────────────  ───────────────────  ──────────────────  ────────────────
    Scratch1  myAcme       00DZ000000N8ItoMAF  2018-03-01
    If you completed the App Development with Salesforce DX module, you’re likely to see that you’re connected to a Trailhead Playground org. You may also see one or more scratch orgs you created to complete the hands-on challenge. If your Dev Hub is not connected, log in to it:
    sfdx force:auth:web:login -d -a DevHub
  2. Change to the dreamhouse-sfdx directory.
  3. Open sfdx-project.json in your favorite text editor.DreamHouse is an open-source project with many contributors. To ensure that you can successfully complete the challenge, let’s make sure your project file looks like this one to start out.
       "packageDirectories": [
             "path": "force-app",
             "default": true
       "namespace": "",
       "sfdcLoginUrl": "",
       "sourceApiVersion": "44.0"
  4. If necessary, delete some existing parameters, such as id, versionName, and versionNumber. Update the sourceApiVersion to match the version of the Salesforce CLI. Don’t forget to save!

Why Aren’t We Using a Namespace in This Example?

Although a package namespace is optional for unlocked packages, including one helps you keep the package components organized. However, because namespaces require some additional setup and forethought, we’re going to skip them in this unit.



If you are migrating metadata from your happy soup to an unlocked package, create your unlocked packages without a namespace. That way, when the metadata is moved from an unpackaged state to an unlocked package, the API name of the metadata elements doesn’t change.

Create the Package

When you downloaded the DreamHouse app from GitHub, you pulled all the source files into your project directory. You can now create the base package without further fanfare.



This section provides the workflow for creating a package using the DreamHouse sample repo. If you plan to complete the hands-on challenge at the end of this unit, be sure to hold off and follow its instructions, using this workflow as a reference as necessary.

  1. Create an unlocked package without a namespace, and supply the alias or username for your Dev Hub org if it’s not already set as the default:
    sfdx force:package:create --name dreamhouse --description "My Package" --packagetype Unlocked --path force-app --nonamespace --targetdevhubusername DevHub
    • --name is the package name. This name is an alias you can use when running subsequent packaging commands.
    • --path is the directory that contains the contents of the package.
    • --packagetype indicates which kind of package you’re creating, in this case, unlocked.
    The package alias is now associated with the Package ID (0Ho). You no longer have to remember cryptic packaging IDs! However, for those of you with a head for numbers, you can continue to use packaging IDs when running commands.
    === Ids
    NAME                  VALUE
    ───────────────────── ──────────────────
    Package Id           0Hoxxx
  2. Open sfdx-project.json. Boom! In packageDirectories, you can see the package name that you defined, with placeholders for the version name and version number. The command also creates a packageAliases section, which maps the package name (alias) to its corresponding package ID (0Ho).
       "packageDirectories": [
             "path": "force-app",
             "default": true,
             "package": "dreamhouse",
             "versionName": "ver 0.1",
             "versionNumber": "0.1.0.NEXT"
       "namespace": "",
       "sfdcLoginUrl": "",
       "sourceApiVersion": "44.0",
       "packageAliases": {
          "dreamhouse": "0Hoxxx"
    Tip Tip If you forget the package alias or package ID, you can list all the packages you created in your Dev Hub by running sfdx force:package:list.

Create a Scratch Org to Test Your Package Version

Let’s create a scratch org, in which to install the unlocked package, with the alias MyScratchOrg. Testing in a scratch org is a convenient way to perform the unit testing phase of the packaging development life cycle.

sfdx force:org:create --definitionfile config/project-scratch-def.json --durationdays 30 --setalias MyScratchOrg -v DevHub

Use the default scratch org definition, which creates a Developer Edition scratch org, the same edition as your Trailhead Playground. Notice that the duration is set to 30 days, giving you plenty of time to finish your work within a development sprint (or complete this Trailhead module).

Create the Package Version and Install It in Your Scratch Org

When you’re ready to release the package, you create a snapshot of it, called a package version. Installing the package version is similar to deploying metadata. Remember, once created, a package version serves as an immutable artifact containing a specific set of metadata.

  1. Open the sfdx-project.json with your favorite text editor to update the package version options.
  2. Change the versionName to Version 1.0, and the versionNumber to 1.0.0.NEXT.The force-app directory is the default (and only) package directory, so any source included in it becomes part of the package. Once updated, the sfdx-project.json file looks like this:
       "packageDirectories": [
             "path": "force-app",
             "default": true,
             "package": "dreamhouse",
             "versionName": "Version 1.0",
             "versionNumber": "1.0.0.NEXT"
       "namespace": "",
       "sfdcLoginUrl": "",
       "sourceApiVersion": "44.0",
       "packageAliases": {
          "dreamhouse": "0Hoxxx"
  3. Save the sfdx-project.json file.
  4. In the dreamhouse-sfdx directory, create the package version, which associates the metadata with the package.
    sfdx force:package:version:create -p dreamhouse -d force-app -k test1234 --wait 10 -v DevHub
    • -p is the package alias that maps to the package ID.
    • -d is the directory that contains the contents of the package.
    • -k is the installation key that protects your package from being installed by unauthorized individuals.
    It’s normal for the package version creation process to take several minutes.
    Successfully created the package version [08cxxx]. Subscriber Package Version Id: 04txxx.
    Package Installation URL:
    As an alternative, you can use the "sfdx force:package:install" command.
  5. Notice that the packageAliases section in sfdx-project.json has a new entry.
    "packageAliases": {
       "dreamhouse": "0Hoxxx",
       "dreamhouse@1.0.0-1": "04txxx"
  6. Use the package version alias to install the package version in the scratch org that you created earlier.
    sfdx force:package:install --wait 10 --publishwait 10 --package dreamhouse@1.0.0-1 -k test1234 -r -u MyScratchOrg
    It can take several minutes for a newly created package version to be available in the scratch org. The installation begins once the package version is available.
  7. After the package is installed, open the scratch org to view the package.
    sfdx force:org:open -u MyScratchOrg
  8. From Setup, enter Installed Packages in the Quick Find box and select Installed Packages. Shows the Installed Packages dialog with Because this is an unlocked package, you can make changes directly in the scratch org and pull down the updated metadata, then create a new package version. But for now, the DreamHouse app already has everything you need, so we can go ahead and release the package.

Release the Package Version

One feature we haven’t discussed yet is package status. Packages have beta status when you initially create them. You can’t install beta packages in a production org. This is a safeguard to make sure the package version you release is production ready. When you know that a version is ready for the world, you can promote the package version to released.

sfdx force:package:version:promote -p dreamhouse@1.0.0-1 -v DevHub

Install the Package Version in an Org

Last but not least, install the package version in your org. Remember, you can install beta package versions in scratch orgs, sandboxes, and Trailhead playgrounds (DE orgs). You can install a released package version in any org.

  1. To install the package version in to your Trailhead playground, log in to it.
    sfdx force:auth:web:login -a MyTP
    We suggest creating an alias for the Trailhead Playground, in this example, MyTP. Once you log in to an org, the CLI remembers your credentials. All you need to do is remember the org’s alias when issuing subsequent commands. If you don’t know the username and password for your Trailhead Playground, see Getting Your Username and Resetting Your Password.
  2. Install the package version in the Trailhead playground.
    sfdx force:package:install --wait 10 --publishwait 10 --package dreamhouse@1.0.0-1 -k test1234 -r -u MyTP
  3. Open your Trailhead playground.
    sfdx force:org:open -u MyTP
  4. In your Trailhead playground, from Setup, enter Installed Packages in the Quick Find box, then select Installed Packages.You also receive an email that confirms you successfully installed the unlocked package.
  5. Click dreamhouse, then View Components. When you click View Components for dreamhouse, you see a list of all package components.
  6. From App Launcher, find and select the DreamHouse app and check out some of its features.
Shows an example email message you receive when the dreamhouse package is successfully installed in the Trailhead playground.