Quick Start: Unlocked Packages

Get Ready to Create Your First Unlocked Package

Salesforce DX provides a new set of tools and processes to streamline the development lifecycle for Salesforce developers. The tools focus on team development and automation, and the notion of modular, package-based development, which is a game change for customers and Salesforce Independent Software Vendors.

This page has notes that are an introduction to Unlocked Packages as a mechanism for managing change to the internal business apps you build.

What Is an Unlocked Package?

  • A software package is a container you fill with metadata
    • Contains a set of related features, customizations, and schema
    • Salesforce offers several types of packages, each with unique characteristics
    • This page focuses on a special package type, an Unlocked Package, which is well suited for internal business apps
  • Unlocked packages help you add, edit, and remove metadata in your org in a trackable way
    • You can apply your source and metadata to multiple orgs, and upgrade Salesforce apps easier and faster
    • Packages encapsulate all the metadata changes and updates you plan to make
  • Unlocked packages grant a lot of flexibility:
    • Admins can make changes directly in production in response to emergency change requests because metadata from unlocked packages can be modified in production orgs
    • This flexibility requires responsibility - make sure the governance structures are in place to prevent cases where package updates overwrite changes that admins make directly in production

Configure Your Environment

  • The steps that follow require:
    1. A new Trailhead Playground
    2. Username credentials for the Trailhead org
    3. Enable Dev Hub in the Trailhead org, Enable Unlocked Packages and Second-Generation Managed Packages in the Trailhead org
      • Setup > Quick Find > Dev Hub
    4. A GitHub account
    5. Salesforce CLI on your computer
  • After you build your unlocked package, you test it in a scratch org, and eventually in more permanent orgs, like sandboxes
    • This quick start involves installing the package in your Trailhead org
  • Once steps 1-5 above are complete, log in to the Trailhead org using Salesforce CLI
    • Give the Trailhead org an alias, as follows: sfdx auth:web:login --setalias MyTP
    • The, run sfdx force:org:list to confirm the credentials were stored locally
    • Now, whenever you run a command from the CLI and use --setalias MyTP, it performs the operation against your Trailhead org

Download the Sample App from GitHub

  • Clone the repository here

Create a GIPHY App

  • Follow the instructions on the Trailhead module, linked here, to create an account and an app

Create, Test, and Deploy Your Unlocked Package

Build and Test the Project in a Scratch Org

  1. Navigate into the GIFter directory
  2. Log into the Deb Hub org using sfdx auth:web:login --setdefaultdevhubusername --setalias DevHub
  3. Create a scratch org using sfdx force:org:create --setdefaultusername --definitionfile config/project-scratch-def.json
    This line creates a ready-to-use scratch org and set it as the default for your project workspace
    The response will be similar to the following:
Successfully created scratch org: 00D1100000BvDK3EAN, username: [email protected]
  1. Next, push all your source from the force-app folder in to the new scratch org using sfdx force:source:push
    The response will be similar to the following.

=== Pushed Source
STATE  FULL NAME                             TYPE                  PROJECT PATH
─────  ────────────────────────────────────  ────────────────────  ─────────────────────────────────────────────────────────────────────────
Add    GIFter                                CustomApplication     force-app/main/default/applications/GIFter.app-meta.xml
Add    SearchGIPHY/SearchGIPHY.auradoc       AuraDefinitionBundle  force-app/main/default/aura/SearchGIPHY/SearchGIPHY.auradoc
Add    SearchGIPHY/SearchGIPHY.cmp           AuraDefinitionBundle  force-app/main/default/aura/SearchGIPHY/SearchGIPHY.cmp
Add    SearchGIPHY/SearchGIPHY.cmp           AuraDefinitionBundle  force-app/main/default/aura/SearchGIPHY/SearchGIPHY.cmp-meta.xml
Add    SearchGIPHY/SearchGIPHY.css           AuraDefinitionBundle  force-app/main/default/aura/SearchGIPHY/SearchGIPHY.css
Add    SearchGIPHY/SearchGIPHY.design        AuraDefinitionBundle  force-app/main/default/aura/SearchGIPHY/SearchGIPHY.design
Add    SearchGIPHY/SearchGIPHY.svg           AuraDefinitionBundle  force-app/main/default/aura/SearchGIPHY/SearchGIPHY.svg
Add    SearchGIPHY/SearchGIPHYController.js  AuraDefinitionBundle  force-app/main/default/aura/SearchGIPHY/SearchGIPHYController.js
Add    SearchGIPHY/SearchGIPHYHelper.js      AuraDefinitionBundle  force-app/main/default/aura/SearchGIPHY/SearchGIPHYHelper.js
Add    SearchGIPHY/SearchGIPHYRenderer.js    AuraDefinitionBundle  force-app/main/default/aura/SearchGIPHY/SearchGIPHYRenderer.js
Add    ChatterHelper                         ApexClass             force-app/main/default/classes/ChatterHelper.cls
Add    ChatterHelper                         ApexClass             force-app/main/default/classes/ChatterHelper.cls-meta.xml
Add    GIPHY                                 CspTrustedSite        force-app/main/default/cspTrustedSites/GIPHY.cspTrustedSite-meta.xml
Add    GIFter                                FlexiPage             force-app/main/default/flexipages/GIFter.flexipage-meta.xml
Add    GIFter_UtilityBar                     FlexiPage             force-app/main/default/flexipages/GIFter_UtilityBar.flexipage-meta.xml
Add    GIFter                                PermissionSet         force-app/main/default/permissionsets/GIFter.permissionset-meta.xml
Add    GiphyMedia0                           RemoteSiteSetting     force-app/main/default/remoteSiteSettings/GiphyMedia0.remoteSite-meta.xml
Add    GiphyMedia1                           RemoteSiteSetting     force-app/main/default/remoteSiteSettings/GiphyMedia1.remoteSite-meta.xml
Add    GIPHY                                 StaticResource        force-app/main/default/staticresources/GIPHY.resource
Add    GIPHY                                 StaticResource        force-app/main/default/staticresources/GIPHY.resource-meta.xml
Add    jquery360                             StaticResource        force-app/main/default/staticresources/jquery360.js
Add    jquery360                             StaticResource        force-app/main/default/staticresources/jquery360.resource-meta.xml
Add    GIFter                                CustomTab             force-app/main/default/tabs/GIFter.tab-meta.xml
  1. There’s a permission set named GIFter that you use to govern access to the GIFter app. Assign to the default user in the scratch org using sfdx force:user:permset:assign --permsetname GIFter
  2. The following line can be used to open the GIFter app directly: sfdx force:org:open --path lightning/n/GIFter

Create the Unlocked Package

  • There are two parts to a package:
    1. Package: manifest about what you’re going to create
    2. Package Version: snapshot in time of the metadata and code that relates to what you’re building and installing

  • Step 1 is to create the package, which contains info that’s unlikely to change, like the name and description. Steps to complete this follow.
  1. Open sfdx-project.json in a text editor.
{
  "packageDirectories": [
    {
      "path": "force-app",
      "default": true
    }
  ],
  "namespace": "",
  "sfdcLoginUrl": "https://login.salesforce.com",
  "sourceApiVersion": "55.0"
}

  1. Delete existing parameters like id, versionName and versionNumber as needed.
  1. Create the package using sfdx force:package:create --name GIFter --description "Using GIPHY to find GIFs and post to Chatter" --path force-app --packagetype Unlocked --targetdevhubusername DevHub
    The output will be similar to the following:

  1. As needed, you can check the package alias or package ID created in your Dev Hub by running sfdx force:package:list

Create the Package Version

  • Next step is to create a specific version of the package, which is the artifact that’s installed into various orgs. As you make updates to the app, you create new package versions that contain the updated source.
    • Commands below may need to be updated to substitute your specific info
  1. Open the sfdx-project.json file. The package:create command has updated the file to include important details about the package. Ex:
    • packageDirectories shows the package name, with placeholders for versionName and versionNumber
    • packageAliases maps the package name (alias) to its corresponding package ID (starts with 0Ho)
    • versionName is up to the developer, and isn’t required to change with each new version that’s created
    • versionNumber auto-increments based on the use of the NEXT keyword
    • Remaining items can be left alone
{
  "packageDirectories": [
    {
      "path": "force-app",
      "default": true,
      "package": "GIFter",
      "versionName": "ver 0.1",
      "versionNumber": "0.1.0.NEXT",
      "versionDescription": "Using GIPHY to find GIFs and post to Chatter"
    }
  ],
  "namespace": "",
  "sfdcLoginUrl": "https://login.salesforce.com",
  "sourceApiVersion": "55.0",
  "packageAliases": {
    "GIFter": "0HoDn000000fxtgKAA"
  }
}
  1. As examples, imagine you’re ready to release the first version of GIFter, so you update:
    • versionName to Summer ‘22 and
    • versionNumber to 1.0.0.NEXT.
    • See below. Save.
{
  "packageDirectories": [
    {
      "path": "force-app",
      "default": true,
      "package": "GIFter",
      "versionName": "Summer '22",
      "versionNumber": "1.0.0.NEXT",
      "versionDescription": "Using GIPHY to find GIFs and post to Chatter"
    }
  ],
  "namespace": "",
  "sfdcLoginUrl": "https://login.salesforce.com",
  "sourceApiVersion": "55.0",
  "packageAliases": {
    "GIFter": "0HoDn000000fxtgKAA"
  }
}
  1. Create your package version with sfdx force:package:version:create --package GIFter --path force-app --installationkey test1234 --wait 10 --targetdevhubusername DevHub.
  2. This operation can take several minutes. When done, the output will be similar to that shown below. It provides the necessary information to install this package version in an org.

Install and Test the Package Version in a Scratch Org

  • Best practice is to install the newly-created package in a Scratch Org before putting it into any Sandbox orgs or Production orgs. Steps to do this follow:
  1. Create the scratch org: sfdx force:org:create --setdefaultusername --definitionfile config/project-scratch-def.json
  2. Install the package into the scratch org using the alias for the package version: sfdx force:package:install --wait 10 --publishwait 10 --package [email protected] --installationkey test1234 --noprompt. Once done, it will show this message: Successfully installed package [04t_xxx]
  3. Assign the permission set: sfdx force:user:permset:assign --permsetname GIFter
  4. Open the scratch org and see if things worked as expected: sfdx force:org:open --path lightning/n/GIFter

Install the Package Version in Your Trailhead Playground (TP)

  • Next, install the package version into your Trailhead. It uses several of the same commands.
  1. Install the package, targeting your TP: sfdx force:package:install --targetusername MyTP --wait 10 --package [email protected] --installationkey test1234 --noprompt
  2. Assign the permission set: sfdx force:user:permset:assign --permsetname GIFter --targetusername MyTP
  3. Open the org and run the app: sfdx force:org:open --path lightning/n/GIFter --targetusername MyTP

Update Your Unlocked Package

  • The company is going to grow and change over time, as will your apps. Unlocked packages provide a robust and easy way to test, package, and deploy changes to your apps. Here’s the steps to test changes:
  1. sfdx force:org:create -s -f config/project-scratch-def.json
  2. sfdx force:source:push
  3. sfdx force:user:permset:assign -n GIFter
  4. sfdx force:org:open -p lightning/n/GIFter
  • More practically:
  1. Change the sfdx-project.json file again to update the versionNumber to reflect the new version of the package. Minor changes might result in incrementing the versionNumber to 1.1.0.
{
   "packageDirectories": [
      {
         "path": "force-app",
         "default": true,
         "package": "GIFter",
         "versionName": "Summer '22",
         "versionNumber": "1.1.0.NEXT"
      }
   ],
   "namespace": "",
   "sfdcLoginUrl": "https://login.salesforce.com",
   "sourceApiVersion": "55.0",
   "packageAliases": {
      "GIFter": "0Hoxxx",
      "[email protected]": "04txxx"
   }
}
  1. Create a package version containing your app with updated source: sfdx force:package:version:create -p GIFter -d force-app -k test1234 --wait 10 -v DevHub
  2. Install and test the package version in a fresh scratch org:
  • sfdx force:org:create -s -f config/project-scratch-def.json
  • sfdx force:package:install --wait 10 --publishwait 10 --package [email protected] -k test1234 --noprompt
  • sfdx force:user:permset:assign -n GIFter
  • sfdx force:org:open -p lightning/n/GIFter

Update Your Unlocked Package

Install New Package Version in Your Trailhead Playground (TP)

  1. Install the package version in the TP: sfdx force:package:install -u MyTP --wait 10 --package [email protected] -k test1234 --noprompt
  2. Open your TP and run the app: sfdx force:org:open -p lightning/n/GIFter -u MyTP

  • To check the installed version of your packages, go to:
    • Setup > Quick Find > “Installed Packages” > Installed Packages, then select, for example, GIFter