Salesforce deployment approach from scratch in 2021

  1. Unlocked package evolution
  2. Application Life Cycle
  3. Deployment Strategy
  4. Development Strategy

Unlocked package evolution

Change set problems

  1. Object dependency such as you need to deploy objects and field before your code or you need to bundle with your code as know as prerequisite object. As a consequence, missing object, redeploy change set and time of validation are usually jobs you need to get it done! 😵
  2. The waiting period for change set deployment lead to overnight. 😭
  3. Other reasons, we cannot track the source of change and who edited on this object and already deploy or not. That effect my team need to create another document for planning for deployment. 😿

Try to solve problems from communities and Salesforce

  • That means you will not have ability to see the code inside the package.
  • It is hard for developers to track the issue in production org.
  • Also, don’t have version control to manage this.
  • Single big package limited.
  • It is hard for developers to track the issue in production org
  • Single big package limited.

Application Life cycle

Application Lifecycle management of salesforce
Application Life Cycle - Picture by Trailhead

Deployment strategy

I. Change Set Development Model

  • Tracking everyone’s changes
  • Keeping all the development and testing environments in sync
  • Creating and deploying change sets multiple times because of errors and differences between environments

II. Org-Based Development Model

  • This process is using a repository to store our metadata in Salesforce. These can help, developers can track changes. Similar to change sets, the release artifact is a set of metadata changes to apply to the production org
  • This process mitigates another pain point: creating and deploying change sets multiple times because of errors and differences between environments.

III. Package Development Model

Source of truth
Screenshot from Trailhead


  1. Visual Studio Code
  2. Install Salesforce extension pack -> link
  3. Version control <- I will use GitLab
  4. Activate your Developer Edition Org or Trailhead Org

Summary Step:

  1. Create project with manifest in visual by:
  2. Create your scratch org and push your code to scratch org
  3. Push you code to version control
  4. Update your code
  5. After you push your code to the repository, GitLab CI will run by create scratch Org and push your code to the scratch org and CI will run apex test in the scratch org.
  6. After Apex Test pass, CI job will transfer to CD to create a new package version
  7. Consequently, the step deploy your new package version will be manual jobs to install your version to production

Detail Step:

I — Create a project with manifest in visual by:

  1. Open the VS Code editor and from the Command Palette, run SFDX: Create Project with Manifest.
  2. CTRL (CMD) + Shift + P and type SFDX: Create project with Manifest
  3. Select Standard Project
  4. Define your project name
  5. Select directory and click Create project
Create SFDX Project
Directory path

II — Create your scratch org and push your code to scratch org

  1. Please check your org enable Dev Hub or not. If not, Please follow:
    - Go to Set up in your org
    - Search Field from the setup menu (Typing Dev hub) and select Dev Hub. This menu will be under Development
    - Enable Dev Hub
    Enable Unlocked Packages and Second-Generation Managed Packages
  2. Go to Visual Studio Code and authorize you dev hub with your local machine
    - Command Palette, run SFDX: Authorized a Dev Hub
    - Run commands sfdx force:auth:web:login -d -a DevHub
  3. Create your scratch Org
    - Command Palette, run SFDX: Create a Default Scratch Org
    - Define your definition, file select default (config/project-scratch-def.json) ENTER
    Set alias for you scratch Org MyScratchOrg
    Define the number of expiration day between 1–30 days Type 7 and Enter
    Run commands sfdx force:org:create --definitionfile config/project-scratch-def.json --durationdays 30 --setalias MyScratchOrg -v DevHub
  4. Create your code. For example, I will use GIPHY trailhead
    - Download code from
    - You can copy the code from force-app/main/default/ in the GIPHY repository to your project in visual studio
    - Create GIFter API
    - Reference Read more
  5. Push your code to scratch
    - Using Command palette, Run SFDX: Push Source to Default Scratch Org or SFDX: Push Source to Default Scratch Org and Override Conflicts (to override all metadata). Or run in terminal sfdx force:source:push
    - For GIFter App, You should add permission to your users by run in Terminalsfdx force:user:permset:assign -n GIFter
    - Validate your code by Open you scratch Org
    - Command palette SFDX: Open default org or sfdx force:org:open -u MyScratchOrg or run with default app GIFTer by sfdx force:org:open -p lightning/n/GIFter
The result of push your code to org
Picture after you open your org

III — Push you code to version control

  • Run command
    sfdx force:package:create --name "<YOUR PACKAGENAME>" --path force-app --packagetype Unlocked
    – name: unlocked package name that should be the same with sfdx-project.json
    –path: directory for create package
    –pakcagetype: Unlocked because we want to create unlocked package
  • After you create unlocked, you will get updates in file sfdx-project.json like JSON below
"packageDirectories": [
"path": "force-app",
"default": true
"namespace": "",
"sfdcLoginUrl": "",
"sourceApiVersion": "51.0"
"packageDirectories": [
"path": "force-app",
"default": true,
"package": "GIFTer",
"versionName": "ver 0.1",
"versionNumber": "0.1.0.NEXT"
"namespace": "",
"sfdcLoginUrl": "",
"sourceApiVersion": "51.0",
"packageAliases": {
"GIFTer": "0Ho---------------"
  1. Go to GitLab and create your repository
cd existing_folder
git init
git remote add origin <REPOSITORY PATH>
git add .
git commit -m "Initial commit"
git push -u origin master
  • DEVHUB_AUTH_URL: force://PlatformCLI::<Hash coded>
    - You can get AUTH URL by command
    sfdx force:org:display --targetusername <your email> --verbose
    - Please copy value of the role Sfdx Auth Url to value field in Gitlab Ex. force://PlatformCLI::<Hash coded>

Update your code and run test class

  1. Command palette SFDX: Create Apex Class and select a default folder class name AnimalsHttpCalloutMock and TestChatterHelper
global class AnimalsHttpCalloutMock implements HttpCalloutMock {
// Implement this interface method
global HTTPResponse respond(HTTPRequest request) {
// Create a fake response
HttpResponse response = new HttpResponse();
response.setHeader('Content-Type', 'application/json');
response.setBody('{"animals": ["majestic badger", "fluffy bunny", "scary bear", "chicken", "mighty moose"]}');
return response;
private class TestChatterHelper {
@isTest static void testMain() {
Test.setMock(HttpCalloutMock.class, new AnimalsHttpCalloutMock());
// This causes a fake response to be sent
// from the class that implements HttpCalloutMock.
// Verify that the response received contains fake values

// Call method to test
String url = '';
String res = ChatterHelper.getChatterGroups(url, 'chatterText');

sfdx force:source:push
sfdx force:package:version:create -p “GIFTerPackage” -d force-app -k test1234 --wait 10 --codecoverage
"packageDirectories": [
"path": "force-app",
"default": true,
"package": "GIFTer",
"versionName": "ver 0.1",
"versionNumber": "0.1.0.NEXT"
"namespace": "",
"sfdcLoginUrl": "",
"sourceApiVersion": "51.0",
"packageAliases": {
"GIFTer": "0H---------------",
"GIFTer@0.1.0-1": "04---------------"
sfdx force:package:install — wait 10 — publishwait 10 — package “GIFTerPackage@0.1.0–1” -k test1234 –r
sfdx force:package:version:promote -p “GIFTerPackage@0.1.0–1

IV — GitLab CI running after push your code

V — APEX test and create version

VI — Deploy your package to production

GitLab CI pipeline
Packaged was installed in your Salesforce org
Objects in your Salesforce org

Summary Command:

Developed your unlocked package with other

Manual step for promote package to production

Development strategy

  1. Git flow: link which has 3 main branches which are the main branches, Supporting branches, and feature branches. These will complicate you to manage package release.
  2. Trunk-based development or GitHub flow: which have only One branch for development because when you deploy your code to UAT or production, you just install the version. You can try to see it on youtube at 23.30.
  • To solve the problem of the big package: You need to separate the package by modules, function or release, and so on.
  • That will create a new issue of dependency for each module.
    For example, Module A is the main package, Module B needs Module A, and Module C needs Module A and B.
    That is mean you need to design a module to represent a package (a Module = a package)
  • Next problem “How can I design modules?”: And I found a youtube for design main or child package.
  • A repository in version control should be a repository to a package. (That is means A Module = A package = a repository). For easier to manage CI/CD and dependencies.




Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Tackling SQL in interviews

Configuring multi-tenant Cloud Pak for Data environment on OpenShift

In memory of CKS exam

Embedded Systems Project 6: Serial Communications

What's your NCAA?

3 days playing with Rust (and I love it!)

Git structure, functionalities, and commands

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store


More from Medium

(Tutorial) CDP Ingestion API SalesForce Integration Process

What Is Development Velocity and How Do You Measure It?

Focusing Beyond CI/CD

How to Perform a Static Analysis?