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).
- Skill ID
- forcedotcom/sf-skills/platform-custom-metadata-type-generate
- Publisher
- forcedotcom
- Repository
- sf-skills
- Installs
- 0
- Files
- 3
- Synced
- Sep 23, 2026
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
MetadataRelationshipfields - Generate CMDT records as deployable
.md-meta.xmlfiles - Troubleshoot CMDT deployment errors
1. Overview and Purpose
A Custom Metadata Type produces two separate artifact families, and most requests need both:
| Artifact | Path | Metadata type |
|---|---|---|
| Type definition | objects/<Name>__mdt/<Name>__mdt.object-meta.xml | CustomObject |
| Fields | objects/<Name>__mdt/fields/<Field>__c.field-meta.xml | CustomField |
| Records | customMetadata/<Name>.<Record>.md-meta.xml | CustomMetadata |
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, anddeploymentStatusare required or normal on a regular custom object and are hard errors here. Do not carry assumptions across fromplatform-custom-object-generate.
2. Syntactic Essentials — Type Definition (Tier 1)
Required and Allowed Elements
| Element | Requirement | Notes |
|---|---|---|
<label> | Required | Singular UI name |
<pluralLabel> | Required | Omitting it gives Must specify a non-empty plural label for the CustomObject |
<visibility> | Always include | Public, or Protected/PackageProtected only in dev/sandbox/scratch (Section 6) |
<description> | Always include | What 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> | Purpose | Extra requirement |
|---|---|---|
Another __mdt type | Link two custom metadata types | Must be a different type |
EntityDefinition | Point at an sObject | None |
FieldDefinition | Point at a field | Requires `<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.xmlThe __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 type | Correct xsi:type | Example value |
|---|---|---|
| Checkbox | xsd:boolean | true |
| Date | xsd:date | 2024-01-15 |
| DateTime | xsd:dateTime | 2024-01-15T10:30:00.000Z |
| Number, Percent | xsd:double | 42.0 |
| Text, TextArea, LongTextArea | xsd:string | some text |
| Email, Phone, Url | xsd:string | a@b.com |
| Picklist | `xsd:string` | Beta |
MetadataRelationship → EntityDefinition | xsd:string | Account |
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.
