Access Custom Metadata Records Programmatically

Use SOQL to access your custom metadata types and to retrieve the API names of the records of those types.

Required Editions

Available in: Salesforce Classic and Lightning Experience

Available in: Enterprise, Performance, Unlimited, and Developer Editions

You can create, edit, and delete custom metadata type records from installed packages in: Group and Professional Editions

User Permissions Needed
To create or edit custom metadata types: Author Apex

Apex code can create, read, and update (but not delete) custom metadata records, as long as the metadata is subscriber-controlled and visible from within the code's namespace. DML operations aren’t allowed on custom metadata in the Partner or Enterprise APIs. With unpackaged metadata, both developer-controlled and subscriber-controlled access behave the same: like subscriber-controlled access. For information about the Custom Metadata Type__mdt sObject, see Custom Metadata Type__mdt in the Object Reference for Salesforce . Refer to Trust, but Verify: Apex Metadata API and Security to learn more about package access in developer-controlled and subscriber-controlled orgs.

The following example declares the Apex variable custMeta of the custom metadata type MyCustomMetadataType__mdt, which is in your namespace.

MyCustomMetadataType__mdt custMeta;

Declare the custMeta variable of the custom metadata type TheirCustomMetadataType__mdt, which isn’t in your namespace but is in the their_ns namespace.

their_ns__TheirCustomMetadataType__mdt custMeta;

The following example is a simple query that returns standard and custom fields for all records of the Threat_Tier_Mapping custom metadata type and accesses some of their fields.

Threat_Tier_Mapping__mdt[] threatMappings = [SELECT MasterLabel, QualifiedApiName, Field_Mapping__c ,Minimum_Support_Level__c FROM Threat_Tier_Mapping__mdt];

for (Threat_Tier_Mapping__mdt threatMapping : threatMappings) {
    System.debug(threatMapping.MasterLabel + ‘: ‘ +
                 threatMapping.Field_Mapping__c + ‘ from ‘ +
                 threatMapping.Team_Building_to_SFA_Field_Mapping__c + ‘ to ‘
                 threatMapping.Minimum_Support_Level__c);
}

To provide an entity that looks more like a Schema.SObjectDescribeResult than SOQL, make the Apex class vacations.ThreatTierMappingDescribeResult encapsulate the information queried from vacations__ThreatTierMappingDescribeResult__mdt. Then create the class vacations.Vacations with methods such as:

vacations.ThreatTierMappingDescribeResult describeThreatTierMappings(String qualifiedApiName) {
    Threat_Tier_Mapping__mdt threatMapping = [SELECT <fields> FROM Threat_Tier_Mapping__mdt WHERE QualifiedApiName = :qualifiedApiName];
    return new ThreatTierMappingDescribeResult(<fieldValues>);
}

In the preceding example, <fields> refers to the fields you want to include in the describe and <fieldValues> refers to the values of those fields.

The next example uses a metadata relationship that references another custom metadata type, Team_Building_to_SFA_Field_Mapping__mdt, to do a simple right outer join.

ThreatTierMapping threatMapping = 
    [SELECT MasterLabel, Team_Building_to_SFA_Field_Mapping__r.MasterLabel FROM Threat_Tier_Mapping__mdt WHERE QualifiedApiName=‘Easy_Vacations’];

System.debug(threatMapping.MasterLabel + ‘ is part of ‘ + Team_Building_to_SFA_Field_Mapping__r.MasterLabel);

The following example shows a left outer join starting from EntityDefinition. This query uses a relationship field called Team_Building_Object__c on Team_Building_to_SFA_Field_Mapping__mdt. The child relationship name of this relationship field is Field_Mappings_From.

for (EntityDefinition entity : allObjects) {
    System.debug(‘Processing mappings for: ‘ + entity.QualifiedApiName);
    for (Team_Building_to_SFA_Field_Mapping__mdt fieldMapping : entity.FieldMappingsFrom__r) {
    System.debug(‘  Field ‘ + fieldMapping.Team_Building_Field__c + 
        ‘ has mapping ‘ + fieldMapping.QualifiedApiName);
    }
}