Deployment Strategies & Packaging
📖 Concept
Deployment is how you move your code and configuration from development to production. Understanding different deployment methods and when to use each is critical for enterprise development.
Deployment methods:
Change Sets (Legacy)
- Point-and-click deployment between related orgs
- Manual selection of components
- No version control, no rollback
- Limited: one-way, no dependency tracking
- Still used in some enterprise orgs
SFDX CLI Deployment (Modern)
sf project deploy start— deploy source format- Supports test level specification
- Dry-run validation before actual deploy
- Scriptable, can be part of CI/CD
Metadata API (Programmatic)
- Lower-level API for deployment
- Used by tools like ANT, Jenkins plugins
- Package.xml manifest defines components
Unlocked Packages (Recommended)
- Modular deployment units
- Versioned, immutable
- Dependency tracking
- Upgrade and rollback support
Managed Packages (ISV)
- For AppExchange distribution
- Namespace isolation
- IP protection
- Upgrade paths for customers
Deployment test levels:
NoTestRun — No tests (sandbox only)
RunSpecifiedTests — Run specific test classes
RunLocalTests — Run all non-managed tests
RunAllTestsInOrg — Run ALL tests including managed
Deployment best practices:
- Always validate (dry-run) before deploying to production
- Deploy during low-traffic hours
- Have a rollback plan (destructive changes manifest)
- Test in full-copy sandbox before production
- Use deployment validation windows for large orgs
- Document all deployment steps and dependencies
💻 Code Example
1// Deployment Configuration & Scripts23// 1. package.xml — Manifest for Metadata API deployment4<?xml version="1.0" encoding="UTF-8"?>5<Package xmlns="http://soap.sforce.com/2006/04/metadata">6 <types>7 <members>AccountController</members>8 <members>OpportunityService</members>9 <name>ApexClass</name>10 </types>11 <types>12 <members>AccountTrigger</members>13 <name>ApexTrigger</name>14 </types>15 <types>16 <members>accountDetailCard</members>17 <members>contactList</members>18 <name>LightningComponentBundle</name>19 </types>20 <types>21 <members>Account.My_Custom_Field__c</members>22 <name>CustomField</name>23 </types>24 <version>59.0</version>25</Package>2627// 2. destructiveChanges.xml — For removing components28<?xml version="1.0" encoding="UTF-8"?>29<Package xmlns="http://soap.sforce.com/2006/04/metadata">30 <types>31 <members>DeprecatedClass</members>32 <name>ApexClass</name>33 </types>34 <version>59.0</version>35</Package>3637// 3. CI/CD Pipeline Script (GitHub Actions example)38// .github/workflows/salesforce-ci.yml39name: Salesforce CI/CD40on:41 pull_request:42 branches: [main, develop]43 push:44 branches: [main]4546jobs:47 validate:48 runs-on: ubuntu-latest49 steps:50 - uses: actions/checkout@v45152 - name: Install SFDX53 run: npm install @salesforce/cli --global5455 - name: Authenticate56 run: |57 echo "${{ secrets.SFDX_AUTH_URL }}" > auth.txt58 sf org login sfdx-url --sfdx-url-file auth.txt --alias target-org5960 - name: Deploy (Validate Only)61 run: |62 sf project deploy start \63 --target-org target-org \64 --dry-run \65 --test-level RunLocalTests \66 --wait 306768 - name: Check Code Coverage69 run: |70 sf apex run test \71 --target-org target-org \72 --code-coverage \73 --result-format json > test-results.json7475 deploy:76 needs: validate77 if: github.ref == 'refs/heads/main'78 runs-on: ubuntu-latest79 steps:80 - uses: actions/checkout@v48182 - name: Install & Auth83 run: |84 npm install @salesforce/cli --global85 echo "${{ secrets.PROD_AUTH_URL }}" > auth.txt86 sf org login sfdx-url --sfdx-url-file auth.txt --alias prod8788 - name: Deploy to Production89 run: |90 sf project deploy start \91 --target-org prod \92 --test-level RunLocalTests \93 --wait 609495// 4. Deployment validation script96// scripts/validate-deployment.sh97#!/bin/bash98set -e99100echo "=== Validating Deployment ==="101102# Check test coverage103COVERAGE=$(sf apex run test --synchronous --code-coverage --json | jq '.result.summary.orgWideCoverage' -r)104echo "Current coverage: $COVERAGE"105106MIN_COVERAGE="80%"107if [ "$COVERAGE" \< "$MIN_COVERAGE" ]; then108 echo "ERROR: Coverage $COVERAGE is below minimum $MIN_COVERAGE"109 exit 1110fi111112# Validate deployment113sf project deploy start --dry-run --test-level RunLocalTests --wait 30114115echo "=== Validation Passed ==="
🏋️ Practice Exercise
Deployment Practice:
- Create a Change Set in a sandbox and deploy it to another sandbox
- Write a package.xml manifest for a complete feature (classes, triggers, LWC, objects)
- Set up a CI/CD pipeline using GitHub Actions with scratch org creation and testing
- Create an Unlocked Package and install it in a target org
- Write a destructiveChanges.xml to remove deprecated components
- Deploy with different test levels and compare execution times
- Set up a full deployment pipeline: feature branch → QA → UAT → Production
- Write a pre-deployment validation script that checks coverage and component counts
- Create a rollback strategy for a complex deployment
- Document your team's release management process with detailed steps
⚠️ Common Mistakes
Deploying to production without sandbox validation — always test in a full copy sandbox first
Not specifying test level for production deployments — RunLocalTests is required for production. Forgetting causes deployment failure
Using Change Sets for complex deployments — Change Sets don't handle dependencies well. Use SFDX CLI or packages for anything beyond simple changes
Not having a rollback plan — some deployments can't be undone (data changes, deleted fields). Always plan for rollback before deploying
Deploying during business hours — production deployments should happen during maintenance windows to minimize user impact
💼 Interview Questions
🎤 Mock Interview
Mock interview is powered by AI for Deployment Strategies & Packaging. Login to unlock this feature.