PluginBench
Skill
Review
Audit score 70

platform-destructive-deploy

forcedotcom/sf-skills

Delete Salesforce metadata components safely with validation and production guardrails.

What is platform-destructive-deploy?

Executes destructiveChanges.xml workflows to remove custom objects, fields, Apex classes, flows, and other metadata from a Salesforce org. Use this when you need to delete components from an org as part of a release or cleanup. It validates changes first and requires explicit confirmation before touching production.

  • Scans local project for references to components before deletion
  • Generates destructiveChanges.xml manifests in standard Salesforce format
  • Validates destructive changes against the target org before execution
  • Gates production deployments with explicit user confirmation and component listing
  • Supports both pre-deploy and post-deploy deletion phases
  • Handles dependency detection and surfaces cascade impacts

How to install platform-destructive-deploy

npx skills add https://github.com/forcedotcom/sf-skills --skill platform-destructive-deploy
Prerequisites
  • Salesforce CLI (sf) installed and authenticated to target org
  • Valid sfdx-project.json with sourceApiVersion defined
  • Read/write access to manifest/ directory for destructiveChanges.xml files
  • Delete permissions on target org for the components being removed
Claude Code
Cursor
Windsurf
Cline

How to use platform-destructive-deploy

  1. 1.Specify which metadata components to delete (type and API name)
  2. 2.Review the local dependency scan results for references in Apex, flows, or configs
  3. 3.Confirm the generated destructiveChanges.xml manifest is correct
  4. 4.Run validation against the target org to check for blocking dependencies
  5. 5.For production: review the confirmation banner listing all components to be deleted and type explicit confirmation
  6. 6.Execute the destructive deploy and monitor for errors
  7. 7.Clean up local source files after successful deletion to keep source tracking accurate

Use cases

Good for
  • Removing deprecated custom objects and their associated fields from a production org
  • Deleting unused Apex classes or flows as part of a release cleanup
  • Permanently purging metadata components with explicit recycle-bin bypass
  • Coordinating field deletions while identifying dependent Apex code or flows that need updating first
  • Validating destructive changes in sandbox before applying to production
Who it's for
  • Salesforce developers managing metadata lifecycle
  • Release managers coordinating destructive changes across environments
  • Architects planning org cleanup and consolidation
  • Teams automating metadata removal in CI/CD pipelines

platform-destructive-deploy FAQ

What's the difference between pre-destructive and post-destructive changes?

Pre-destructive changes (destructiveChangesPre.xml) delete components before deploying new metadata, useful when replacing components. Post-destructive changes (destructiveChangesPost.xml) delete after deployment, useful when removing dependencies that would block the new deploy.

Can I delete a field that's still referenced in Apex code?

No. The validation phase will fail with a 'referenced by Apex' error. You must either update the Apex code first or include the Apex class deletion in the same destructive deploy.

What happens if I delete a custom field with data?

The data is moved to the recycle bin (recoverable for 15 days) unless you explicitly use --purge-on-delete. The skill will remind you of this impact before proceeding.

How do I know if my target is production?

The skill uses sf org display to classify the org as production, sandbox, scratch, or trial. Production orgs require explicit typed confirmation before any destructive deploy executes.

Can I skip validation to deploy faster?

No. The skill always validates first as a safety requirement. Validation catches blocking dependencies, permission issues, and managed-package constraints before any deletion occurs.

Full instructions (SKILL.md)

Source of truth, from forcedotcom/sf-skills.


name: platform-destructive-deploy description: "Execute the destructiveChanges.xml delete-and-deploy workflow against a Salesforce org. TRIGGER when the user asks to delete/remove a custom object, field, Apex class, flow, or any metadata component FROM an org, or to perform a 'destructive deploy' / removal as part of a release. Validates first and gates production with explicit confirmation. DO NOT TRIGGER for local file deletion (use Bash), or for net-new deploys (use platform-metadata-deploy)." allowed-tools:

  • Bash
  • Read
  • Write
  • Glob
  • Grep

Handling Destructive Changes

Coordinate metadata deletion against a Salesforce org via the destructiveChanges manifest. Runs in three phases: scope → validate → execute, with stricter guardrails for production.

Phase 1 — Scope the deletion

Step 1a — Gather the components to remove

Ask the user (or infer from context) which components to delete. For each, capture:

  • Metadata type (e.g. CustomObject, CustomField, ApexClass, Flow, PermissionSet)
  • API name (e.g. Project__c, Account.Status__c, MyController)

Step 1b — Local dependency scan (best-effort)

Before generating the manifest, scan the local project for references to each component. Use Grep over force-app/:

grep -rn "<componentApiName>" force-app/ --include='*.cls' --include='*.trigger' --include='*.xml' --include='*.js' --include='*.html'

If references are found:

  • List them to the user
  • Recommend either updating those references first OR removing them in the same destructive deploy
  • Do NOT proceed silently — surface the dependency risk

Step 1c — Generate destructiveChanges.xml

Write to manifest/destructiveChangesPre.xml (for pre-deploy deletion) or manifest/destructiveChangesPost.xml (for post-deploy deletion). Use the standard Salesforce metadata format:

<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
    <types>
        <members>Project__c</members>
        <members>OldThing__c</members>
        <name>CustomObject</name>
    </types>
    <types>
        <members>Account.Status__c</members>
        <name>CustomField</name>
    </types>
    <version>62.0</version>
</Package>

Use the API version from sfdx-project.json's sourceApiVersion.

Group components by metadata type (one <types> block per type). For namespaced fields, use Object.Field notation.

Phase 2 — Validate

ALWAYS validate before executing a destructive deploy:

sf project deploy validate \
  --pre-destructive-changes manifest/destructiveChangesPre.xml \
  --manifest manifest/package.xml \
  --target-org <alias> \
  --test-level RunLocalTests \
  --json

(For post-destructive: use --post-destructive-changes.)

If package.xml doesn't exist, create an empty one alongside (deletion-only deploy needs a package descriptor):

<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
    <version>62.0</version>
</Package>

If validation fails, surface errors and STOP. Common failure modes:

  • "Cannot delete: referenced by Apex/Flow/Layout" → component still has references
  • "Cannot delete: required for license" → managed-package or license dependency
  • "Insufficient access" → user lacks delete permission

Phase 3 — Execute

Production path

Confirm whether the target is production before executing. The reliable check is the gate's classifier (returns production|sandbox|scratch|trial|devhub|unknown):

sf org display --target-org <alias> --json | "${CLAUDE_PLUGIN_ROOT}/scripts/sf-deploy-gate" classify

If the classifier returns production:

  1. Display destructive confirmation banner (mirroring platform-quick-deploy)
  2. List EVERY component that will be deleted
  3. Require explicit "yes, delete from PRODUCTION" confirmation
  4. Reject --purge-on-delete unless the user types it explicitly

The PreToolUse hook (sf-deploy-gate destructive) will already block bare destructive commands against prod — surface that denial to the user, do not work around it.

Sandbox / Scratch path

sf project deploy start \
  --pre-destructive-changes manifest/destructiveChangesPre.xml \
  --manifest manifest/package.xml \
  --target-org <alias> \
  --json \
  --wait 30

Add --purge-on-delete only if the user explicitly asked to permanently delete (skip the recycle bin).

Phase 4 — Post-delete cleanup

After a successful destructive deploy:

  • Recommend a sf project retrieve start --metadata <Type>:<Name> is NOT useful (component is gone) — instead suggest cleaning up the local source:
    # Remove the now-deleted local files to keep source tracking accurate
    rm -rf force-app/main/default/<path-to-component>
    
  • If deleting a custom field with data, remind the user that data is gone (or in the recycle bin until purged)
  • Recommend running tests to confirm no runtime regressions

Rules

  • ALWAYS validate first; NEVER skip Phase 2
  • ALWAYS scan for local references; NEVER delete blindly
  • ALWAYS gate production with explicit user confirmation
  • NEVER add --purge-on-delete without explicit user request
  • NEVER use --ignore-errors on a destructive deploy
  • ALWAYS use the API version from sfdx-project.json, not a hardcoded value
  • If the user is deleting a field with required="true" or that's used in RecordType picklist values, surface the cascade impact before proceeding