Skip to content

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 like Profile to read every component of that type), --manifest (a package.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 diff shows exactly what file-based retrieve had been dropping.
  • Active permissions only: With --active-only, the entries of Profile, PermissionSet and MutingPermissionSet that 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 (Hidden included), 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 CustomMetadata and CustomApplication).
  • 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 are bundle (LWC, Aura), matchingContentFile (Apex classes/triggers/pages/components, Visualforce), mixedContent (StaticResource, Document), and digitalExperience (DigitalExperienceBundle). Retrieve those with file-based retrieve (sf project retrieve start).

The write counterpart is sf hardis:mdapi:upsert.

Technical explanations
  • Input resolution: ComponentSetBuilder resolves --metadata / --manifest / --source-dir. Bare types and wildcards are expanded against the org via listMetadata.
  • Read: Components are grouped by type, chunked, and read with jsforce connection.metadata.read.
  • Active only filter: removeInactiveEntries runs 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 (readMetadata returns 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 as inactiveEntriesRemoved.
  • 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 into fields/ and recordTypes/).
  • Adapter rule: partitionCrudCompatibility resolves each type to its SDR adapter via RegistryAccess.getTypeByName(name).strategies.adapter. Types with adapter bundle, matchingContentFile, mixedContent, or digitalExperience are set aside as skipped; types with decomposed, 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/Name members; 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:

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

Comments