Metadata API types, source format, package.xml, deploy/retrieve commands, and destructive changes workflow
From claude-sfdx-iqnpx claudepluginhub bhanu91221/claude-sfdx-iq --plugin claude-sfdx-iqThis skill uses the workspace's default tool permissions.
Designs and optimizes AI agent action spaces, tool definitions, observation formats, error recovery, and context for higher task completion rates.
Salesforce metadata is organized into types. Each type maps to a directory in source format.
| Metadata Type | Source Directory | Example |
|---|---|---|
| ApexClass | classes/ | AccountService.cls + .cls-meta.xml |
| ApexTrigger | triggers/ | AccountTrigger.trigger + .trigger-meta.xml |
| LightningComponentBundle | lwc/ | myComponent/myComponent.js |
| AuraDefinitionBundle | aura/ | myAuraComponent/myAuraComponent.cmp |
| CustomObject | objects/ | Custom_Object__c/ directory |
| CustomField | objects/<Object>/fields/ | Status__c.field-meta.xml |
| Layout | layouts/ | Account-Account Layout.layout-meta.xml |
| FlexiPage | flexipages/ | Account_Record_Page.flexipage-meta.xml |
| PermissionSet | permissionsets/ | Admin_Access.permissionset-meta.xml |
| Flow | flows/ | My_Screen_Flow.flow-meta.xml |
| CustomMetadata | customMetadata/ | Config.Setting__mdt.md-meta.xml |
| StaticResource | staticresources/ | myLibrary.resource + .resource-meta.xml |
| ApexPage | pages/ | MyVFPage.page + .page-meta.xml |
Decomposes metadata into granular files. A CustomObject is split into separate files per field, validation rule, list view, etc.
force-app/main/default/objects/Account/
Account.object-meta.xml
fields/
Status__c.field-meta.xml
Rating__c.field-meta.xml
listViews/
All_Accounts.listView-meta.xml
validationRules/
Require_Industry.validationRule-meta.xml
Single monolithic XML file per object. Used by the Metadata API directly.
src/objects/Account.object
Convert between formats:
# Source to MDAPI
sf project convert source --root-dir force-app --output-dir mdapi_output
# MDAPI to Source
sf project convert mdapi --root-dir mdapi_output --output-dir force-app
The manifest file specifies which metadata to retrieve or deploy.
<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
<types>
<members>AccountService</members>
<members>AccountTriggerHandler</members>
<name>ApexClass</name>
</types>
<types>
<members>AccountTrigger</members>
<name>ApexTrigger</name>
</types>
<types>
<members>Account.Status__c</members>
<members>Account.Rating__c</members>
<name>CustomField</name>
</types>
<types>
<members>My_Screen_Flow</members>
<name>Flow</name>
</types>
<types>
<members>Admin_Access</members>
<name>PermissionSet</name>
</types>
<version>62.0</version>
</Package>
<types>
<members>*</members>
<name>ApexClass</name>
</types>
Rule: Use wildcards only for retrieval in development. Production deployments should list explicit members.
# Generate manifest from source directory
sf project generate manifest --source-dir force-app --name package.xml
# Generate manifest from specific metadata
sf project generate manifest --metadata ApexClass:AccountService --metadata ApexTrigger:AccountTrigger
# Retrieve from manifest
sf project retrieve start --manifest manifest/package.xml --target-org myOrg
# Retrieve specific metadata
sf project retrieve start --metadata ApexClass:AccountService --target-org myOrg
# Retrieve entire source directory mapping
sf project retrieve start --target-org myOrg
# Retrieve with specific API version
sf project retrieve start --manifest manifest/package.xml --api-version 62.0
# Deploy from source directory
sf project deploy start --source-dir force-app --target-org myOrg
# Deploy from manifest
sf project deploy start --manifest manifest/package.xml --target-org myOrg
# Deploy specific metadata
sf project deploy start --metadata ApexClass:AccountService --target-org myOrg
# Validate only (check-only deploy, no changes applied)
sf project deploy start --source-dir force-app --target-org myOrg --dry-run
# Deploy and run tests
sf project deploy start --source-dir force-app --target-org myOrg --test-level RunLocalTests
# Deploy with specific tests
sf project deploy start --source-dir force-app --target-org myOrg --test-level RunSpecifiedTests --tests AccountServiceTest AccountTriggerTest
| Level | Description | When to Use |
|---|---|---|
NoTestRun | Skip tests | Sandbox deploy, non-Apex changes only |
RunSpecifiedTests | Run named tests | Deploy with targeted test coverage |
RunLocalTests | All non-managed tests | Production deploy (recommended) |
RunAllTestsInOrg | All tests including managed | Full validation (slow) |
Metadata types have dependencies. Deploy in the correct order to avoid failures.
Rule: When deploying fails due to dependency errors, check that referenced metadata is included in the deployment or already exists in the target org.
Deployable metadata records. Can be included in packages and deployed via change sets or CLI.
// Query Custom Metadata (does not count against SOQL governor limit)
List<Config_Setting__mdt> settings = [
SELECT DeveloperName, Value__c
FROM Config_Setting__mdt
WHERE IsActive__c = true
];
// Access a specific record
Config_Setting__mdt setting = Config_Setting__mdt.getInstance('API_Timeout');
String timeout = setting.Value__c;
Hierarchical Custom Settings -- values vary by user, profile, or org-wide default.
// Get for current user (checks user, then profile, then org default)
My_Hierarchy_Setting__c setting = My_Hierarchy_Setting__c.getInstance();
Boolean isEnabled = setting.Feature_Enabled__c;
// Get org default
My_Hierarchy_Setting__c orgDefault = My_Hierarchy_Setting__c.getOrgDefaults();
List Custom Settings -- like a simple custom object, stores a list of data.
Map<String, Country_Code__c> codes = Country_Code__c.getAll();
Country_Code__c us = Country_Code__c.getInstance('US');
| Factor | Custom Metadata Types | Hierarchical Custom Settings | List Custom Settings |
|---|---|---|---|
| Deployable | Yes (metadata) | No (data, needs post-deploy scripts) | No (data) |
| Packageable | Yes | Limited | Limited |
| Per-user values | No | Yes (user > profile > org) | No |
| SOQL limit | Does not count | Does not count | Does not count |
| Editable by admin | Yes (via Setup) | Yes (via Setup) | Yes (via Setup) |
| Available in formulas | Yes | Yes | No |
| Recommended for | App config, feature flags | User-level preferences | Simple lookup tables |
Rule: Prefer Custom Metadata Types for configuration that should be deployable. Use Hierarchical Custom Settings only when per-user or per-profile variation is needed.
Destructive changes remove metadata from the target org during deployment.
Run deletions before the deploy. Use when the deployment depends on something being removed first.
manifest/
package.xml (metadata to deploy)
destructiveChangesPre.xml (delete before deploy)
Run deletions after the deploy. Use when removing metadata that the existing code references (deploy updated code first, then delete).
manifest/
package.xml (metadata to deploy)
destructiveChangesPost.xml (delete after deploy)
<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
<types>
<members>OldHelperClass</members>
<members>DeprecatedService</members>
<name>ApexClass</name>
</types>
<types>
<members>Account.Old_Field__c</members>
<name>CustomField</name>
</types>
<version>62.0</version>
</Package>
# Deploy with post-destructive changes
sf project deploy start --manifest manifest/package.xml --post-destructive-changes manifest/destructiveChangesPost.xml --target-org myOrg
# Deploy with pre-destructive changes
sf project deploy start --manifest manifest/package.xml --pre-destructive-changes manifest/destructiveChangesPre.xml --target-org myOrg
Rules:
package.xml must still be present (can be empty with just the version)RunLocalTests to validate# Check-only deploy (validates but does not persist)
sf project deploy start --source-dir force-app --target-org myOrg --dry-run --test-level RunLocalTests
# Quick deploy after successful validation
sf project deploy start --use-most-recent --target-org myOrg
sf org login sfdx-url --sfdx-url-file authFile --alias myOrgsf project deploy start --dry-run --test-level RunLocalTestssf project deploy start --source-dir force-appsf apex run test --target-org myOrg --result-format human# Check what changed since last retrieve
sf project retrieve preview --target-org myOrg
# Check what needs to be deployed
sf project deploy preview --target-org myOrg
# Pull remote changes (scratch orgs and sandboxes with tracking)
sf project retrieve start --target-org myOrg
sfdx-project.json.