sf-deployment-constraints

Enforce deployment safety — validation-only first, test coverage gates, metadata ordering, rollback readiness. Use when deploying or packaging ANY Salesforce metadata. Do NOT use for local dev or scratch org pushes.

Salesforce Deployment Constraints

When to Use

This skill auto-activates when deploying, promoting, or packaging Salesforce metadata. It enforces validation-only-first, test coverage gates, dependency ordering, and rollback readiness for all deployment artifacts.

Hard rules that MUST be followed when deploying, promoting, or packaging Salesforce metadata to any sandbox or production org. Violations are blocking.

Reference: @../_reference/DEPLOYMENT_CHECKLIST.md @../_reference/DEPRECATIONS.md


Never

  1. Never deploy without validation-only first. Run sf project deploy validate before every real deployment to production. Quick-deploy (sf project deploy quick --job-id <ID>) is only valid within 10 days and only if no Apex has been deployed to the org since validation.

  2. Never skip the test level flag. Every sf project deploy start to a shared org MUST include --test-level. Omitting it lets the platform pick a default that may be NoTestRun, which silently passes with zero coverage.

  3. Never deploy Profiles alongside other metadata. Profiles depend on every other metadata type (objects, fields, record types, Apex, permission sets). Deploy Profiles in a separate, final deployment step after all dependencies are confirmed in the target org.

  4. Never force-push to production. Do not use --ignore-errors or --ignore-conflicts against a production org. If the deployment fails, fix the root cause rather than suppressing errors. Force flags are acceptable only in developer sandboxes during active prototyping.

  5. Never deploy destructive changes without a pre-deploy snapshot. Before any --post-destructive-changes or --pre-destructive-changes deployment, retrieve the current state of affected components:

    sf project retrieve start \
        --manifest manifest/package.xml \
        --target-org prod \
        --output-dir backup/pre-deploy-$(date +%Y%m%d)
    
  6. Never use --use-most-recent for quick deploy in multi-team orgs. Another team's deployment between your validate and quick-deploy invalidates the job. Always pass --job-id explicitly.


Always

  1. Always validate before deploy.

    sf project deploy validate \
        --source-dir force-app \
        --test-level RunLocalTests \
        --target-org <org> \
        --wait 60
    

    Then quick-deploy using the returned job ID.

  2. Always specify an appropriate test level.

    Target EnvironmentRequired Test Level
    Developer sandbox (no Apex)NoTestRun acceptable
    Developer sandbox (with Apex)RunLocalTests
    Staging / UAT sandboxRunLocalTests
    ProductionRunLocalTests (minimum)
    Major release / full regressionRunAllTestsInOrg
    CI/CD PR validation (v66.0+)RunRelevantTests with @testFor
  3. Always check metadata dependency order. Deploy in this sequence; never deploy a later type before its dependency:

    1. CustomObject
    2. CustomField
    3. RecordType
    4. ValidationRule
    5. Layout
    6. ApexClass
    7. ApexTrigger
    8. LightningComponentBundle
    9. FlexiPage / App Page
    10. PermissionSet
    11. Profile (always last)
  4. Always have a rollback plan before production deploy.

    StrategyWhen
    git revert + full redeployCoupled multi-file changes
    Single-file restore from gitIsolated, dependency-free component
    Pre-deploy snapshot retrieveAny production deployment
    Package version rollbackUnlocked/managed package orgs
  5. Always confirm 75%+ org-wide code coverage before production. Run sf apex run test --test-level RunLocalTests --code-coverage locally and verify aggregate coverage meets the threshold. Individual deployed triggers must have > 0% coverage.

  6. Always include test classes in the deployment package. If deploying Apex classes or triggers, include their corresponding test classes in the same package.xml or --source-dir. Deploying production code without its tests causes coverage drift.


Anti-Pattern Table

Anti-PatternWhy It FailsCorrect Approach
Deploy directly to production without validationTest failures discovered mid-deploy; partial stateValidate first, then quick-deploy
Use NoTestRun for production Apex deploymentsSalesforce rejects or silently drops coverageUse RunLocalTests or RunRelevantTests
Deploy Profiles in the same package as objects/fieldsProfile references fail if dependencies missingDeploy Profiles separately after all dependencies
Use --ignore-errors on productionPartial metadata deployed; org left in broken stateFix errors, re-validate, re-deploy
Skip pre-deploy snapshot for destructive changesNo way to restore deleted metadataAlways sf project retrieve start first
Rely on --use-most-recent for quick deployAnother team's deploy invalidates your validationUse explicit --job-id
Deploy test classes separately from production codeCoverage numbers drift; tests may reference stale codeCo-deploy test and production classes together
Omit --test-level flag entirelyPlatform default may be NoTestRunAlways specify --test-level explicitly
Deploy dependent metadata out of order"Entity not found" errorsFollow the 11-step dependency order above
Single-file rollback for coupled changesBreaks dependencies between related classesgit revert the full commit and redeploy all affected files
Deploy Custom Labels after referencing Apex/LWCComponents fail to compile if label not yet in target orgInclude Custom Labels in same package or deploy them first
Deploy Report Types without underlying objectsReport Type references fail on missing custom objects/fieldsDeploy objects and fields before Report Types
Deploy Connected App with hardcoded consumer secretSecrets exposed in source control; revoked secrets break authUse Named Credentials or environment-specific Connected App config
Deploy Flow without testing in sandbox firstFlows fire on existing data immediately; no rollback for record changesAlways test Record-Triggered Flows in sandbox with representative data
Use sf project deploy start without --waitDetached deploy with no feedback; failures discovered lateAlways use --wait to monitor deployment progress inline

Quick Reference: Production Deploy Sequence

1. Pre-deploy snapshot   sf project retrieve start --manifest ... --output-dir backup/
2. Validate              sf project deploy validate --test-level RunLocalTests --wait 60
3. Confirm tests pass    sf project deploy report --job-id <ID>
4. Quick deploy          sf project deploy quick --job-id <ID> --wait 10
5. Smoke test            Execute post-deploy verification plan
6. Confirm or rollback   If issues found: git revert + redeploy from backup