Skip to main content

Custom Metadata vs Custom Settings in Salesforce: Complete Architecture Guide

In plain words: Custom Metadata Types (CMDT) are treated like code and configuration—their records migrate automatically during deployments via CI/CD, change sets, or packages. Custom Settings are treated like database data—their records stay in the org where you create them unless you manually insert or export them using data migration tools.

Managing custom application configurations, API endpoint keys, feature flags, and business mappings is a standard requirement for Salesforce architectures. Salesforce provides two primary features for storing key-value pairs and app configurations without creating standard custom objects: Custom Metadata Types (CMDT) and Custom Settings. Choosing the right tool depends on deployment needs, governor limits, and whether you require hierarchical overrides.

1. Custom Metadata Types (CMDT)

Custom Metadata Types (__mdt) extend standard Salesforce metadata architecture to custom application records. Unlike traditional database objects, both the schema definition and the underlying records are treated as metadata.

  • Deployable Configuration Records: Because CMDT records are true metadata, you can deploy them directly across sandboxes and production orgs using Salesforce CLI (sf project deploy), GitHub CI/CD pipelines, change sets, or managed packages.
  • Zero-Cost SOQL & Apex Static Methods: You can query CMDT using standard SOQL, or retrieve records instantly without consuming SOQL query limits using native Apex methods like My_Metadata__mdt.getInstance('DeveloperName') or My_Metadata__mdt.getAll().
  • Relationship Mapping: CMDT supports entity definition relationships, field definition relationships, and metadata-to-metadata lookups, enabling complex data models and dynamic mappings.
  • Formula Field & Validation Rule Access: You can reference CMDT directly in formula fields, validation rules, and Flow Builder without writing Apex code ($CustomMetadata.Type__mdt.Record.Field__c).
Real-World Example: Reading Custom Metadata in Apex Without SOQL
Fetching third-party API configurations instantly using native static methods:
// 1. Fetch a single record by DeveloperName (0 SOQL queries consumed)
Payment_Gateway_Setting__mdt stripeConfig = Payment_Gateway_Setting__mdt.getInstance('Stripe_Production');

if (stripeConfig != null) {
    String endpointUrl = stripeConfig.Endpoint_URL__c;
    Integer timeoutSeconds = Integer.valueOf(stripeConfig.Timeout_Seconds__c);
    System.debug(LoggingLevel.INFO, 'Stripe Endpoint: ' + endpointUrl);
}

// 2. Fetch all records in memory as a map
Map<String, Payment_Gateway_Setting__mdt> allGateways = Payment_Gateway_Setting__mdt.getAll();

2. Custom Settings

Custom Settings (__c) are data-backed tables stored in the application cache. Salesforce provides two variations: List Custom Settings and Hierarchy Custom Settings.

  • Hierarchy Custom Settings: Allows you to define values at the Organization Default level, and override those values at the Profile or specific User level. This is ideal for user-specific feature toggles, personalization settings, or bypassing validation rules for integration user accounts.
  • List Custom Settings: Provides org-wide static data cached at the application tier. Note: Salesforce strongly recommends using Custom Metadata Types instead of List Custom Settings for all new development.
  • Cache Access Methods: Custom Settings provide instant, non-SOQL access via methods like Custom_Setting__c.getInstance() and Custom_Setting__c.getOrgDefaults().
Real-World Example: Using Hierarchy Custom Settings for User-Level Feature Toggles
Bypassing automated validation triggers for data migration users:
// Evaluates the hierarchy: User -> Profile -> Org Default
Automation_Bypass_Setting__c bypass = Automation_Bypass_Setting__c.getInstance();

if (!bypass.Bypass_Validation_Rules__c) {
    // Execute standard validation logic
    validateRecordRules(newRecords);
}
360 Architecture Comparison Card:
  • Deployment Nature: Custom Metadata records deploy via Metadata API / CI/CD; Custom Setting records require data migration tools (e.g., Data Loader).
  • Hierarchy Support: Custom Metadata does not support user/profile hierarchies; Hierarchy Custom Settings excel at user-level overrides.
  • Declarative Support: Custom Metadata is accessible natively in Validation Rules, Formulas, and Flows via $CustomMetadata; Custom Settings are accessible via $Setup.
  • Test Class Isolation: Custom Metadata records are visible in Apex unit tests automatically without SeeAllData=true; Custom Settings records must be inserted inside test methods.

3. Decision Matrix: Which One Should You Choose?

Core Rule: Use Hierarchy Custom Settings only when you need profile- or user-level configuration overrides. Use Custom Metadata Types for everything else (business mappings, API routes, app configurations, and deployable rules).
  • Select Custom Metadata Types if:
    • Configurations must move across sandboxes and production environments automatically during releases.
    • You need to package configurations inside AppExchange Managed Packages.
    • You need to reference metadata definitions directly inside standard formula fields, validation rules, or Flows.
    • You want test classes to have direct access to configuration records without inserting test data in every test class.
  • Select Hierarchy Custom Settings if:
    • You need dynamic values that differ per User, Profile, or Organization level (e.g., enabling beta features for specific users or bypassing triggers for system administrators).

4. Common Traps & Best Practices

Developer Trap: Performing Synchronous DML on Custom Metadata
Because Custom Metadata records are metadata, you cannot execute standard Apex DML (insert, update, delete) directly on __mdt records at runtime. Updating CMDT records programmatically requires deploying changes asynchronously using the Metadata.Operations namespace. If runtime data changes frequently via user input, use a standard custom object instead.
  • Avoid Unnecessary SOQL on Custom Metadata: Always use the built-in static methods (getInstance() or getAll()) rather than writing SOQL queries against __mdt. Static methods retrieve cached data without counting against your 100 synchronous SOQL limit.
  • Enable List Custom Settings in Setup: In newer Salesforce orgs, List Custom Settings are disabled by default. If required, navigate to Setup > Schema Settings and enable Manage List Custom Settings Type.
  • Protect Sensitive Credentials: Neither Custom Settings nor Custom Metadata encrypt sensitive secrets natively. Always use Named Credentials or External Credentials for storing authentication tokens, API secrets, and endpoint passwords.

Summary

Both Custom Metadata Types and Custom Settings provide fast, memory-cached configuration management in Salesforce. By choosing Custom Metadata for deployable business rules and packaging, and reserving Hierarchy Custom Settings for profile- and user-specific overrides, you maintain a clean, high-performance architecture across your environments.