Change sets are the most common Salesforce deployment method. They're built into Setup, they're visual, and they work without any CLI tooling. But change sets have a fundamental limitation: they have no version history. Every deployment is a manual push from one org to another, with no record of what was deployed when.
Packages solve this. A Salesforce package is a versioned container for metadata. You build a version, test it, promote it, and install it into any org. The installed org knows exactly which version it's running, and upgrades are a controlled, auditable process.
First-gen vs second-gen packages
Salesforce has two generations of the packaging system.
First-generation packages (1GP) were created through the Setup UI in a dedicated packaging org. They're still in use — many managed packages in AppExchange are 1GP — but new development should not use them. The tooling is limited, and they don't integrate with modern development workflows.
Second-generation packages (2GP) are the current model. They're built entirely with Salesforce CLI, source-driven from your SFDX project, and managed through a Developer Hub org. 2GP integrates with Git, CI pipelines, and scratch orgs. This is the model this session covers.
Package types
Unlocked packages
Unlocked packages are for building org-specific solutions — metadata that belongs to your org rather than a distributable product.
- No namespace required
- Full control over which components are included
- Components are visible and editable in the subscriber org (within package dependencies)
- Best for teams using SFDX to manage org customisation
- Can be deleted from an org without leaving orphaned metadata
Think of an unlocked package as a change set done correctly: version-controlled, testable, and installable via a single command rather than manually configured each time.
Managed packages
Managed packages are for ISV distribution — building a product that installs in customer orgs, typically sold or distributed through AppExchange.
- Namespace required — prefixes all components in subscriber orgs
- Apex code is compiled and obfuscated — subscribers cannot read source
- Supports upgrade management: push new versions to all subscriber orgs
- Cannot be uninstalled once dependencies exist in the subscriber org
Prerequisites: Developer Hub and SFDX project
Before creating a package, you need:
- Developer Hub enabled — go to Setup → Dev Hub and enable it in your production or designated Dev Hub org
- CLI connected to Dev Hub —
sf org login web --set-default-dev-hub - SFDX project — created with
sf project generate --name MyProject
All package commands reference your Dev Hub. The Dev Hub maintains the registry of packages and versions associated with your organisation.
The five-step package workflow
Step 1: sf package create
This adds a package definition to your sfdx-project.json. The --path flag specifies which source directory belongs to this package. Everything in force-app will be included when you create a version.
Step 2: Add your metadata
Your source code, custom objects, flows, and other metadata live in the package directory. Develop in a scratch org connected to this project. All changes are pulled back to source before creating a version.
Step 3: sf package version create
This is the build step. Salesforce creates a scratch org, deploys your source, runs your full Apex test suite, and — if tests pass — generates a package version ID (04t record) and an install URL.
The --installation-key-bypass flag skips the key requirement. Use this for internal testing; for production versions, set an installation key instead.
The --wait 10 flag waits up to 10 minutes for the async build to complete. For complex packages, increase this value.
Step 4: sf package install
Installs the package version into the target org. The 04t value is the package version ID returned from step 3. You can also use the subscriber package version URL. The --wait flag handles the async installation job.
Step 5: sf package version promote
This marks the version as Released, making it installable in production orgs. This is a one-way transition — you cannot demote a promoted version back to beta. Hold versions in beta until QA is complete and sign-off is received.
Package dependencies
If your package metadata depends on components from another package, declare the dependency in sfdx-project.json:
On install, Salesforce resolves the dependency chain. If the dependency isn't already in the target org, the install fails with a clear error telling you which package to install first.
Package installation keys
Installation keys add a security gate to unlocked packages. Set at version create time:
Anyone installing this version must provide the key. This prevents unauthorised installs while still allowing controlled distribution.
When to use each deployment model
| Model | Best for | Avoid when |
|---|---|---|
| Change sets | Small, infrequent changes, single production org, no CLI setup | Team development, frequent releases, multi-org |
| SFDX source deploy | Team development with Git, no versioning requirements | Same metadata needs to travel to many orgs |
| Unlocked package | Multi-org deployment, version history, CI pipeline | Ad-hoc, one-off changes |
| Managed package | AppExchange, external distribution, ISV product | Internal org customisation |
Testing strategy
Package versioning has a built-in quality gate: the version create command runs your full Apex test suite. If tests fail, the version doesn't build. This means your test suite is not optional when working with packages.
Recommended approach:
- Develop in a scratch org with the package directory as source
- Write Apex tests as you go — minimum 75% coverage per class, but aim higher
- Create a beta version and install in a dedicated QA scratch org
- Run regression testing in the QA org
- On sign-off, promote the version to Released
- Install the Released version in production
Any issue found after promotion requires a new version. There is no patch mechanism for released versions — plan your release cycle accordingly.
Session 85 — Packaged Deployment
realsyllabus.com