Skip to main content

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 LWC sample app and install it in a Trailhead Playground.

Why We Love Package Development

We think packaging is one of the most exciting features for Salesforce Platform developers. It’s on par with some well-known disruptive innovations, such as sliced bread, the mobile phone, and video streaming services. 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 lifecycle. It’s compatible with the features of Salesforce DX: projects, CLI commands, and scratch orgs were built specifically with packaging in mind.
  • Encapsulates all the changes you're 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 first and second-generation managed packages.
  • Supports continuous integration and continuous delivery because the packaging CLI commands enable each step in the deployment pipeline to be fully automated.

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 a Salesforce DX project in source 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.

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

Configure Your Environment

Before you can get to the good stuff, let’s set up a new Trailhead Playground and enable the Dev Hub and packaging in it. 


Note: If you are following along with the steps in this section, you'll need to create another new Trailhead Playground when you start the hands-on challenge.

  1. To create a new Trailhead Playground, locate the hands-on challenge at the end of this unit. Click the playground information to the left of the Launch button.
    Then select, Create Playground.

    Note: While it's possible to reuse an existing Trailhead Playground, starting with a fresh playground ensures you are working with a clean environment.
  2. After creating a new Trailhead Playground, click Launch to open the playground. Then ensure you know both the username and password for the playground. You’ll need this information in an upcoming step.
    See Getting Your Username and Resetting Your Password.
  3. From Setup in your Trailhead Playground, enter Dev Hub in the Quick Find box and select Dev Hub. Click Enable Dev Hub and then click Enable Unlocked Packages and Second-Generation Managed Packages.
  4. Create a GitHub account, if you don't already have one.
  5. Install Salesforce CLI on your computer.

“Git” the DreamHouse Source Code

For demonstration purposes, let’s pretend that you’re building and delivering the DreamHouse LWC 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 LWC sample repo. DreamHouse LWC is a stand-alone application that incorporates many features available in Salesforce Platform. It uses Lightning Web Components, Apex, 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 LWC 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 lifecycle.

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 Lightning Web Components (LWC) app.

In a command window, change to the directory where you want to put the source code, then run this command.

git clone

The git clone command creates the dreamhouse-lwc folder using the Salesforce DX project structure, and contains a DX project file and a scratch org definition file. Because the DreamHouse LWC 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.

Configure Your Package

  1. Your Trailhead Playground is also your Dev Hub org. To create a package, we need to first authorize to your Dev Hub org, and log in to it.
    sf org login web --set-default-dev-hub --alias DevHub
  2. In the command window, let’s double check that the Dev Hub org is connected.
    sf 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. 
    === Orgs
         ALIAS       USERNAME                             ORG ID              CONNECTED STATUS
    ───  ──────────  ───────────────────────────────      ──────────────────  ────────────────
    (D)  DevHub                 00DB0000000Ige5MAC  Connected
         MyTP    00D6A000000fH8CUAU  Connected
         TestingOrg                     00D4x000006sFonEAE  Connected
    ALIAS            USERNAME                             ORG ID              EXPIRATION  DATE
    ────────         ───────────────────                  ──────────────────  ────────────────
    Scratch1                     00DZ000000N8ItoMAF  2021-02-24
  3. Change to the dreamhouse-lwc directory on your computer.
  4. Open sfdx-project.json in your favorite text editor and make a note of the sourceApiVersion number.
  5. DreamHouse LWC is an open-source project with many contributors. To ensure that you can successfully complete the challenge, replace the contents of the sfdx-project.json file with the following code.
       "packageDirectories": [
             "path": "force-app",
             "default": true
       "namespace": "",
       "sfdcLoginUrl": "",
       "sourceApiVersion": "58.0"
  6. Ensure that the sourceApiVersion number in the code snippet matches the version number you noted from the original file. If it doesn't, then update the sourceApiVersion number.

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 cloned the DreamHouse LWC 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 LWC sample repo.

  1. From a terminal or command prompt, change to the dreamhouse-lwc directory.
  2. 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:
    sf package create --name dreamhouse --description "My Package" --package-type Unlocked --path force-app --no-namespace --target-dev-hub 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.
  3. 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": "58.0",
       "packageAliases": {
          "dreamhouse": "0Hoxxx"

If you forget the package alias or package ID, you can list all the packages associated with your Dev Hub by running sf 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 lifecycle.

sf org create scratch --definition-file config/project-scratch-def.json --duration-days 30 --alias MyScratchOrg --target-dev-hub DevHub

This command uses the default scratch org definition file, and 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": "58.0",
       "packageAliases": {
          "dreamhouse": "0Hoxxx"
  3. Save the sfdx-project.json file.
  4. In the dreamhouse-lwc directory, create the package version, which associates the metadata with the package.
    The Apex code in unlocked packages must meet a minimum 75% code coverage requirement, before the package can be installed in a production org. We didn’t calculate code coverage in this example, because we know this sample Dreamhouse LWC repo doesn’t have enough Apex test coverage.
    sf package version create --package dreamhouse --installation-key test1234 --wait 10 --target-dev-hub 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.
  5. It’s normal for the package version creation process to take several minutes. You see status messages that tell you what’s going on. When the package version creation is complete, you see this message.
    Successfully created the package version [08cxxx]. Subscriber Package Version Id: 04txxx.
    Package Installation URL:
    As an alternative, you can use the "sf package install" command.
  6. Notice that the packageAliases section in sfdx-project.json has a new entry.
    "packageAliases": {
       "dreamhouse": "0Hoxxx",
       "dreamhouse@1.0.0-1": "04txxx"
  7. Use the package version alias to install the package version in the scratch org that you created earlier.
    sf package install --wait 10 --publish-wait 10 --package dreamhouse@1.0.0-1 --installation-key test1234 --no-prompt --target-org 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. When the package install is complete, you see this message. Successfully installed package [04t3XXX]
  8. After the package is installed, open the scratch org to view the package.
    sf org open --target-org MyScratchOrg
  9. From Setup, enter Installed Packages in the Quick Find box and select Installed PackagesShows 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 LWC 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.

The Dreamhouse LWC sample repo we’re using in this unit evolves and may not always have enough Apex tests to meet the 75%  code coverage requirement. So we’ll skip promotion and continue on using the beta package version you created.

Here’s what the package version promotion command looks like, but if you try this command right now, you’ll get an error message.

sf package version promote --package dreamhouse@1.0.0-1 --target-dev-hub 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. Typically at this stage, you'll install the package version in a sandbox, but for this exercise, we're going to install the package in your Trailhead Playground.

  1. To install the package version in to your Trailhead playground, you must first add it to your list of authorized orgs.
    you must first add it to your list of authorized orgs.
    sf org login web --alias 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.
    sf package install --wait 10 --publish-wait 10 --package dreamhouse@1.0.0-1 --installation-key test1234 --no-prompt --target-org MyTP
  3. Open your Trailhead playground.
    sf org open --target-org 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 ComponentsWhen 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.
Keep learning for
Sign up for an account to continue.
What’s in it for you?
  • Get personalized recommendations for your career goals
  • Practice your skills with hands-on challenges and quizzes
  • Track and share your progress with employers
  • Connect to mentorship and career opportunities