forcedotcom/sf-skills3 files

Platform Custom Metadata Type Generate

Use to create, generate, or validate Salesforce Custom Metadata Type metadata — the __mdt object, fields, and deployable records. Trigger on custom metadata types, CMDT, __mdt objects, .md-meta.xml files, or cross-org reference/config data; also admin-maintained mapping/lookup/crosswalk tables (config that changes without a deploy belongs in a CMDT, never hardcoded in Apex/Flow), and CMDT deploy errors. DO NOT TRIGGER for Custom Settings (use platform-custom-setting-generate), business-record objects (use platform-custom-object-generate), or secrets/API keys (use a Named Credential).

Specification
Skill ID
forcedotcom/sf-skills/platform-custom-metadata-type-generate
Publisher
forcedotcom
Repository
sf-skills
Installs
0
Files
3
Synced
Sep 23, 2026
How to use it

Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.

forcedotcom/sf-skills/platform-custom-metadata-type-generateInstalls these files
  • SKILL.md
  • references/cmdt-records.md
  • scripts/sanitize-developer-name.sh

What this skill tells the agent

Salesforce Custom Metadata Type Generator and Validator

When to Use This Skill

Use this skill when you need to:

  • Create a Custom Metadata Type (__mdt)
  • Generate or validate CMDT fields, including MetadataRelationship fields
  • Generate CMDT records as deployable .md-meta.xml files
  • Troubleshoot CMDT deployment errors

1. Overview and Purpose

A Custom Metadata Type produces two separate artifact families, and most requests need both:

ArtifactPathMetadata type
Type definitionobjects/<Name>__mdt/<Name>__mdt.object-meta.xmlCustomObject
Fieldsobjects/<Name>__mdt/fields/<Field>__c.field-meta.xmlCustomField
RecordscustomMetadata/<Name>.<Record>.md-meta.xmlCustomMetadata

API name suffix: __mdt on the type; fields still end in __c.

The defining advantage over a custom setting: CMDT records are metadata and therefore deploy between orgs. When a user says configuration should "ship with the package" or "be the same in every org," CMDT is the right answer.

The root element is `<CustomObject>`, but almost none of a custom object's rules apply. sharingModel, nameField, and deploymentStatus are required or normal on a regular custom object and are hard errors here. Do not carry assumptions across from platform-custom-object-generate.

2. Syntactic Essentials — Type Definition (Tier 1)

Required and Allowed Elements

ElementRequirementNotes
<label>RequiredSingular UI name
<pluralLabel>RequiredOmitting it gives Must specify a non-empty plural label for the CustomObject
<visibility>Always includePublic, or Protected/PackageProtected only in dev/sandbox/scratch (Section 6)
<description>Always includeWhat this type configures and who owns it

<pluralLabel> being required here but forbidden on a custom setting is the most commonly inverted rule between the two families. Neither failure mentions the other family's rule.

Forbidden Elements

Every element below produces Cannot specify: <element> for Custom Metadata Type — reusing a regular custom object's skeleton (with sharingModel, deploymentStatus, a nameField block, or enableSearch) is the usual cause:

sharingModel, nameField, deploymentStatus, enableActivities, enableReports, enableHistory, enableSearch

CORRECT — minimum valid __mdt type:

<?xml version="1.0" encoding="UTF-8"?>
<CustomObject xmlns="http://soap.sforce.com/2006/04/metadata">
  <label>Partner Tier</label>
  <pluralLabel>Partner Tiers</pluralLabel>
  <description>Discount and threshold configuration per partner tier. Ships with the package; edited by the revenue ops team.</description>
  <visibility>Public</visibility>
</CustomObject>

3. Field Rules

This skill owns the CMDT-specific deltas only — the type allowlist, fieldManageability, and MetadataRelationship below. For generic field mechanics (<fullName> derivation, <label>, <description>, <inlineHelpText>, precision/scale, <length>, visibleLines), follow platform-custom-field-generate.

Supported Field Types

Checkbox, Date, DateTime, Email, Number, Percent, Phone, Picklist, Text, TextArea, LongTextArea, Url, plus MetadataRelationship.

Unsupported Field Types

Currency, AutoNumber, MasterDetail, Summary, Location, Time, EncryptedText, Html, MultiselectPicklist. Each fails with a precise, well-formed error:

Type {TypeName} of CustomMetadataField {Object}__mdt.{Field}__c is not supported for the Entity {Object}__mdt

(There is no trailing period.) Example: Type Currency of CustomMetadataField Partner_Tier__mdt.Discount__c is not supported for the Entity Partner_Tier__mdt

Currency is the common trap — it works on a custom setting but not here. Use Number with <precision>/<scale> and put the currency in the label or help text.

Formula fields are unsupported, but they break the pattern above. A <formula> element on an otherwise legal type gives only:

Invalid data type.

Lookup is silently coerced — CRITICAL

<type>Lookup</type> on a __mdt does not fail when its referenceTo resolves to a real sObject: the deploy is green and the platform silently rewrites the field to MetadataRelationship. A later retrieve shows a field the user never wrote:

<type>MetadataRelationship</type>   <!-- was deployed as Lookup -->

Always write `MetadataRelationship` explicitly. Emitting Lookup produces a green deploy and a source-vs-org mismatch that churns in git the first time anyone retrieves. (Reproduced on a live deploy: a resolvable Lookup returns as MetadataRelationship; a non-resolvable referenceTo is cleanly rejected.)

MetadataRelationship

Three targets, all valid. referenceTo selects which.

<referenceTo>PurposeExtra requirement
Another __mdt typeLink two custom metadata typesMust be a different type
EntityDefinitionPoint at an sObjectNone
FieldDefinitionPoint at a fieldRequires `<metadataRelationshipControllingField>`
<?xml version="1.0" encoding="UTF-8"?>
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
  <fullName>Target_Field__c</fullName>
  <label>Target Field</label>
  <type>MetadataRelationship</type>
  <referenceTo>FieldDefinition</referenceTo>
  <metadataRelationshipControllingField>Partner_Tier__mdt.Target_Object__c</metadataRelationshipControllingField>
  <relationshipLabel>Target Field</relationshipLabel>
  <relationshipName>Target_Field</relationshipName>
</CustomField>

The controlling field must be an EntityDefinition relationship on the same type, referenced as Type__mdt.Field__c. Omitting it gives Metadata relationships to Field Definition require a controlling field.

Self-references are impossible. Pointing a MetadataRelationship at its own parent type fails with Cannot add a self-lookup relationship child with cascade or restrict options to the object itself (verbatim from a live __mdt deploy) — use a second type.

<fieldManageability>

Optional. It defaults to `DeveloperControlled` — do not add it unless the user wants a different value. Valid values are DeveloperControlled, SubscriberControlled, and Locked.

It is valid only on __mdt fields. On a regular custom object field or a custom setting field:

Field manageability cannot be set on this entity.

4. CMDT Records (.md-meta.xml)

Filename convention

Write customMetadata/<TypeNameWithout__mdt>.<RecordDeveloperName>.md-meta.xml.

customMetadata/Partner_Tier.Bronze_AMER.md-meta.xml

The __mdt suffix in the filename also deploys and creates a real record, so it is tolerated — but Salesforce's retrieve normalizes to the no-suffix form, so always write it without __mdt to avoid git churn (detail in references/cmdt-records.md).

Required namespaces

All three are mandatory on the root element — xsi:type on values will not resolve without them.

<CustomMetadata xmlns="http://soap.sforce.com/2006/04/metadata"
                xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

xsi:type mapping — every value needs one

Field typeCorrect xsi:typeExample value
Checkboxxsd:booleantrue
Datexsd:date2024-01-15
DateTimexsd:dateTime2024-01-15T10:30:00.000Z
Number, Percentxsd:double42.0
Text, TextArea, LongTextAreaxsd:stringsome text
Email, Phone, Urlxsd:stringa@b.com
Picklist`xsd:string`Beta
MetadataRelationship → EntityDefinitionxsd:stringAccount

More from forcedotcom

Use this skill in a project

Open any RiverX project, search the Skills panel for forcedotcom/sf-skills/platform-custom-metadata-type-generate, and install it in one click.

Use this skill