Check-only release and quick deploy

Validate a release candidate against an org with sfp release --checkonly, then commit that validation by id with --quickdeploy.

A release can be split into two runs of sfp release against the same org:

  1. --checkonly deploys the release candidate once in check-only mode and returns the validated deploy id. Nothing is committed to the org.
  2. --quickdeploy commits that validation by id with the Metadata API deployRecentValidation. Salesforce does not compile the payload again or run its tests again. The post-deployment steps and the release bookkeeping then run as they do for a plain release.
sfp release --releasecandidate core:Release-2.0.0 --targetorg production \
  --repository myorg/myrepo --checkonly --json > validation.json

sfp release --releasecandidate core:Release-2.0.0 --targetorg production \
  --repository myorg/myrepo \
  --quickdeploy "$(jq -r '.releases[0].packages[0].deployId' validation.json)" \
  --payload-fingerprint "$(jq -r '.releases[0].packages[0].payloadFingerprint' validation.json)" \
  --json

Eligibility

Both flags apply the same rule, before any call to the org. The release must have:

  • exactly one release definition
  • exactly one package in that definition's deployment queue, after skipDeployOnOrgs and ignoreOnStage are applied
  • a source or diff package

Unlocked packages install as package versions and data packages load through SFDMU; neither has a check-only mode. A release that breaks the rule exits with code 1 and one of the reason codes MULTIPLE_RELEASE_DEFINITIONS, MULTIPLE_PACKAGES or INELIGIBLE_PACKAGE_TYPE.

--checkonly and --quickdeploy cannot be combined with each other or with --dryrun.

Validating with --checkonly

The run fetches the artifact, compares the installed version (skipIfAlreadyInstalled), applies the component checksum skip, and then deploys once in check-only mode. Tests follow the plain release: production always runs them, and a sandbox runs them only when the environment's policy or --runtests asks.

Salesforce only quick deploys a validation that ran tests. On a sandbox, pass --runtests with --checkonly; a validation that ran no tests returns quickDeployEligible: false with NO_TESTS_RUN.

None of the following runs during a check-only release:

  • installation of external package dependencies (a missing dependency fails the validation)
  • promotion
  • pre- and post-deployment scripts, permission set assignment and deployers
  • the artifact commit to the org, deployment tracking and the environment baseline
  • release metadata publishing and changelog generation (--generatechangelog is ignored)
  • release.* and package.installation.* webhooks

The top-level checkOnly block in the JSON output carries outcome, an optional reasonCode and a message:

OutcomeExitMeaning
validated0The check-only deployment succeeded and deployId is set
nothing-to-validate0The package is already installed (ALREADY_INSTALLED) or has no components to deploy (NO_COMPONENTS_TO_DEPLOY)
validation-failed1The deployment failed (DEPLOYMENT_FAILED) or a dependency is not installed (MISSING_PACKAGE_DEPENDENCIES)
rejected1The release is not eligible

The package entry in releases[].packages[] adds deployId, testLevel, testSummary, validatedAt, quickDeployEligible and payloadFingerprint. quickDeployEligible is true only for a successful validation that ran at least one test; otherwise quickDeployIneligibleReason is VALIDATION_FAILED, NO_DEPLOYMENT or NO_TESTS_RUN.

payloadFingerprint is a hash of the package name, version, source commit and the artifact's component checksums. It is computed without an org call, so the quick deploy can confirm that it is committing the validated artifact. sfp keeps no state between the two runs; pass the id and the fingerprint yourself.

Committing with --quickdeploy

--quickdeploy takes the deployId and requires --payload-fingerprint. The run fetches the artifact, then stops without an org call when the release is not eligible or when the fetched artifact's fingerprint differs from --payload-fingerprint (FINGERPRINT_MISMATCH). It then checks that external package dependencies are installed, without installing them (MISSING_PACKAGE_DEPENDENCIES).

Any deployment that reaches the org after the validation invalidates the id, so nothing that deploys runs before the commit:

  • pre-deployment permission sets, the preDeployment script and the pre-deployers are skipped, and each skip is logged
  • the payload is not rebuilt. Salesforce commits exactly what it validated, including reconciled profiles

After the commit, post-deployment permission sets, post-deployers, the postDeployment script and the artifact commit run in their normal order. Deployment tracking, the environment baseline, release metadata, the changelog and the webhooks follow, as for a plain release.

When the package is already installed at that version, the id is not used and the outcome is nothing-to-deploy.

When Salesforce rejects the id

Salesforce refuses a validated id (sf:INVALID_ID_FIELD) when:

  • another deployment reached the org after the validation
  • the id was already quick deployed
  • the validation failed or ran no tests
  • the id does not belong to a check-only deployment
  • the validation is older than 10 days

The refusal comes before anything is committed.

  • By default, the release fails with QUICK_DEPLOY_REJECTED and Salesforce's message. The org, the artifact record and the environment baseline are unchanged; run a plain release to deploy the candidate.
  • With --quickdeploy-fallback, sfp deploys the same artifact in full instead, with its complete lifecycle including the pre-deployment steps. The outcome is fell-back, and the message carries Salesforce's reason.

An id that Salesforce does not know (INVALID_DEPLOY_ID), and a quick deploy that Salesforce accepted and that then failed (DEPLOYMENT_FAILED), fail the release. Neither falls back.

The top-level quickDeploy block in the JSON output carries outcome, an optional reasonCode, a message and the validatedDeployId:

OutcomeExitMeaning
quick-deployed0Salesforce committed the validated payload
fell-back0The id was rejected and the package was deployed in full
nothing-to-deploy0The package is already installed or has nothing to deploy
rejected1The release is not eligible, the fingerprint differs, a dependency is missing, or Salesforce rejected the id without --quickdeploy-fallback
failed1The id is unknown or the deployment failed

The package entry in releases[].packages[], and the release history recorded on sfp server, add quickDeploy with the validatedDeployId, the deployId of the commit (or of the full deployment after a fallback), the outcome and, when Salesforce refused the id, its reason.

On this page