hardis:mdapi:read
Description
Command Behavior
Retrieves metadata from an org using the CRUD-based Metadata API (readMetadata), writing complete source files.
This is a standalone, manually invoked alternative to the file-based retrieve (sf hardis:org:retrieve:sources:metadata). It exists for metadata types that file-based retrieve returns incomplete when source tracking is not used, most notably Profile and PermissionSet: readMetadata returns the whole component (every object/field permission, Apex-class access, tab visibility), not just the parts tied to other components in the same package.
Key functionalities:
- Component selection: Choose what to read with
--metadata(e.g.Profile:Admin, or a bare type likeProfileto read every component of that type),--manifest(apackage.xml), or--source-dir(refresh the types/names already present in a local folder). - Complete components: Each component is read whole and written to standard source format, so a
git diffshows exactly what file-based retrieve had been dropping. - Active permissions only: With
--active-only, the entries ofProfile,PermissionSetandMutingPermissionSetthat grant nothing are left out of the files: field access with no read and no edit, object access with every flag false, Apex class, Visualforce page, Flow, custom permission, custom metadata type, custom setting and external data source access disabled, app not visible and not default, record type not visible, user permissions disabled. Tab visibilities (Hiddenincluded), layout assignments, login hours and login IP ranges are kept, except the tab settings of tabs that do not exist: the API returns one for every standard object, tab or not, and a deployment refuses them (You can't edit tab settings for X, as it's not a valid tab). Deploying such a file grants what it lists and revokes nothing. The VS Code Metadata Retriever uses it in its Auto mode, the default, for Profiles. - Chunking: Reads are batched to respect the CRUD Metadata API limit (10 components per call, 200 for
CustomMetadataandCustomApplication). - Supported types are adapter-gated: Compatibility is decided by the metadata type's @salesforce/source-deploy-retrieve registry adapter (
strategies.adapter). Only pure-XML types round-trip through the CRUD Metadata API; types whose source carries non-XML content (code, binaries, multi-file bundles) are reported as skipped with a warning. The incompatible adapters arebundle(LWC, Aura),matchingContentFile(Apex classes/triggers/pages/components, Visualforce),mixedContent(StaticResource,Document), anddigitalExperience(DigitalExperienceBundle). Retrieve those with file-based retrieve (sf project retrieve start).
The write counterpart is sf hardis:mdapi:upsert.
Technical explanations
- Input resolution:
ComponentSetBuilderresolves--metadata/--manifest/--source-dir. Bare types and wildcards are expanded against the org vialistMetadata. - Read: Components are grouped by type, chunked, and read with jsforce
connection.metadata.read. - Active only filter:
removeInactiveEntriesruns on each read result before it is serialized. In a permission type, an entry is dropped when it has at least one boolean field and all of them are false (readMetadatareturns booleans or"true"/"false"strings, both are handled). Entries without a boolean field are kept. Tab settings (tabVisibilities,tabSettings) are compared with the tabs of the org (SELECT Name FROM TabDefinition): the ones that name no existing tab are dropped. When the org can not be queried, a warning says so and they are all kept. The number of dropped entries is returned per component asinactiveEntriesRemoved. - Conversion: Read results are serialized to metadata-format XML (
fast-xml-parser), then converted to source format with@salesforce/source-deploy-retrieve's public converter, which handles per-type decomposition (e.g. CustomObject intofields/andrecordTypes/). - Adapter rule:
partitionCrudCompatibilityresolves each type to its SDR adapter viaRegistryAccess.getTypeByName(name).strategies.adapter. Types with adapterbundle,matchingContentFile,mixedContent, ordigitalExperienceare set aside as skipped; types withdecomposed,default, or no adapter (e.g.CustomObject,Profile,PermissionSet,Layout,CustomMetadata,CustomApplication) are processed. Unknown type names are treated as compatible so the API call (not the guard) surfaces the real error. - Limitations: Folder-based types (Report, Dashboard, EmailTemplate) require explicit
Folder/Namemembers; bare-type expansion does not enumerate folders yet.
Agent Mode
Supports non-interactive execution with --agent:
sf hardis:mdapi:read --metadata Profile,PermissionSet --agent
In agent mode (and in CI), interactive prompts are skipped. You must pass at least one of --metadata, --manifest, or --source-dir; the command never prompts for what to read.
Learn by doing
The free Salesforce DevOps with sfdx-hardis course runs this command, click by click, on an org of your own, in these labs:
- Lab 2.6 - Permission sets, profiles and why a grant disappears
- Lab 2.8 - Recover from committing the wrong metadata
Parameters
| Name | Type | Description | Default | Required | Options |
|---|---|---|---|---|---|
| active-only | boolean | Leave out the Profile, PermissionSet and MutingPermissionSet entries that grant nothing (all their flags false), and the tab settings of tabs that do not exist | |||
| agent | boolean | Run in non-interactive mode for agents and automation | |||
| chunk-size | option | Components read per API call (max 10, or 200 for CustomMetadata/CustomApplication) | |||
| debug -d |
boolean | Activate debug mode (more logs) | |||
| flags-dir | option | Import flag values from a directory. | |||
| ignore-errors | boolean | Report component failures but exit with code 0 | |||
| json | boolean | Format output as json. | |||
| manifest -x |
option | Path to a package.xml listing the metadata to read | |||
| metadata -m |
option | Metadata to read, as Type or Type:Name (e.g. Profile, "Profile:Admin"). Repeatable. | |||
| output-dir | option | Directory where source files are written. When set, all files are written here instead of being refreshed in place in the project package directories (default: the project default package directory) | |||
| skipauth | boolean | Skip authentication check when a default username is required | |||
| source-dir | option | Local source path whose components should be re-read from the org | |||
| target-org -o |
option | Username or alias of the target org. Not required if the target-org configuration variable is already set. |
true | ||
| websocket | option | Websocket host:port for VsCode SFDX Hardis UI integration |
Examples
$ sf hardis:mdapi:read --metadata Profile
$ sf hardis:mdapi:read --source-dir force-app/main/default/profiles
$ sf hardis:mdapi:read --metadata "Profile:Admin" --metadata PermissionSet
$ sf hardis:mdapi:read --manifest manifest/package.xml
$ sf hardis:mdapi:read --metadata Profile --active-only
$ sf hardis:mdapi:read --metadata Profile,PermissionSet --agent