Skip to main content

Custom Metadata vs Custom Settings in Salesforce: Complete Architecture Guide

Updated Add a comment
💬 In plain words: The golden rule for Salesforce configuration is simple: Metadata DEPLOYS, Settings CHANGE, and Labels TRANSLATE. Custom Metadata Types carry their records automatically through deployments (perfect for app config). Custom Settings store org or user-specific data that you can toggle instantly at runtime (perfect for bypass switches). Custom Labels store text that needs to be translated for the user interface.

Hardcoding values like API endpoints, delivery fees, or trigger bypasses directly into Apex is a massive architectural anti-pattern. When business rules change, hardcoded values force you to rewrite code, run tests, and wait for a release window. To keep configuration out of your code, Salesforce provides three primary tools: Custom Metadata Types (CMDT), Custom Settings, and Custom Labels. Knowing exactly when to use each prevents deployment headaches and governor limit crashes.

📌 Key Points

  • Custom Metadata Types (__mdt): Both the schema and the records are metadata. They move flawlessly via CI/CD, change sets, or packages.
  • Custom Settings (__c): Behave like database tables. The structure deploys, but the records stay behind. Use them for user-level or profile-level overrides.
  • Custom Labels: Up to 5,000 text values used specifically for multi-language UI translation via Translation Workbench.
  • Zero SOQL Cost: Both CMDT and Custom Settings can be read using native cache methods (getInstance() or getAll()), meaning they cost 0 against your 100 SOQL query limit.
Salesforce Architecture: Custom Metadata Types vs Custom Settings vs Custom Labels

📦 1. Custom Metadata Types (The Deployable Config)

Custom Metadata Types are the modern standard for application configuration. Because both the object definition and the records themselves are metadata, they deploy automatically. You do not have to run data loads via Data Loader after pushing code to production.

  • Relationships: CMDT supports metadata-to-metadata lookups and entity definition relationships (e.g., mapping a specific config to the Account object).
  • Test Class Friendly: CMDT records are automatically visible inside Apex unit tests. You do not need to use SeeAllData=true or insert dummy records to test them.
  • Declarative Access: You can reference them directly in Validation Rules, Formulas, and Flows using the $CustomMetadata global variable.
📌 CMDT Apex Example: Fetching API configurations instantly without burning a SOQL query.
// Fetch a single record by its DeveloperName from the cache
Payment_Gateway_Setting__mdt stripeConfig = Payment_Gateway_Setting__mdt.getInstance('Stripe_Production');

if (stripeConfig != null) {
    System.debug('Stripe Endpoint: ' + stripeConfig.Endpoint_URL__c);
}

⚙️ 2. Custom Settings (The Runtime Data)

While Salesforce strongly encourages CMDT for most use cases, Custom Settings—specifically Hierarchy Custom Settings—still reign supreme in one specific area: Contextual Overrides.

Hierarchy Custom Settings allow you to define a default value for your entire Organization, but then override that value for a specific Profile or individual User. Custom Metadata cannot do this.

🎬 Real-Life Scenario: The Data Load Bypass
You are running a massive data migration and need to disable validation rules and Apex triggers, but only for the Integration User.

If you use Custom Metadata, you have to turn off the triggers for everyone, pausing the entire business. Instead, create a Hierarchy Custom Setting called Automation_Bypass__c with a checkbox field. You check the box specifically for the "Integration Profile".
// Apex automatically resolves the hierarchy: User -> Profile -> Org Default
Automation_Bypass__c bypass = Automation_Bypass__c.getInstance();

if (!bypass.Bypass_Apex_Triggers__c) {
    // Execute standard trigger logic safely
    processRecords(Trigger.new);
}

You can even use this exact same setting in your declarative Validation Rules by referencing $Setup.Automation_Bypass__c.Bypass_Validation_Rules__c.

🛑 3. Critical Traps & Developer Best Practices

⚠ DEVELOPER TRAP: You Cannot Perform Synchronous DML on Custom Metadata
Because CMDT records are true metadata, you cannot run standard insert, update, or delete DML statements on them in Apex. Changing them programmatically requires firing off an asynchronous deployment using the Metadata.Operations namespace. If your business users need to edit configuration data frequently in real-time, you must use a standard Custom Object or a List Custom Setting instead.
🧠 CORE RULE: Never use Custom Settings or Custom Metadata to store passwords, API secret keys, or authentication tokens. They are not natively encrypted. Always use Salesforce Named Credentials or External Credentials for secrets.
🧭 360 Architecture Decision Card
  • Reach for Custom Metadata when: Configurations must deploy with your package or change set, you need to map relationships, or you are building feature toggles for environments (Sandbox vs. Prod).
  • Reach for Hierarchy Custom Settings when: You need runtime toggle switches that differ per User or Profile (like trigger bypasses).
  • Reach for Custom Labels when: You are displaying text to a user on a Lightning component or Visualforce page, and that text must translate via the Translation Workbench.
  • Reach for a Custom Object when: The configuration needs to be edited daily by non-admin business users via a standard Salesforce tab (and you accept the SOQL cost).

🎤 4. Core Interview Q&A

Q: What breaks when business users ask to edit Custom Metadata "business rules" themselves in production?

🎯 Say this: Custom Metadata requires the Customize Application system permission to edit manually, which is a massive security risk to grant to a standard business user. Furthermore, updating them from code requires a complex asynchronous metadata deployment. To solve this, you must migrate business-editable rules to a standard Custom Object (which respects standard CRUD/FLS profiles), while reserving CMDT strictly for developer-managed application configuration.

Q: Why do Salesforce architects say List Custom Settings are deprecated?

Answer: List Custom Settings function almost exactly like Custom Metadata Types, but with a fatal flaw: their records do not deploy. If you build an app relying on List Custom Settings, you have to manually upload a CSV of the data into every new sandbox and production environment. Custom Metadata solved this entirely, rendering List Custom Settings obsolete for new development.

🔗 5. Follow-Up Question

Q: How do you access these Custom Labels and Custom Metadata values inside a Lightning Web Component (LWC)?

Answer: In LWC, you do not need to burn Apex calls to fetch Custom Labels. You simply import them at the top of your JavaScript file using import labelName from '@salesforce/label/c.My_Label';. For Custom Metadata, however, you currently must use an Apex wire method (@wire) or call an Apex controller that fetches the CMDT via getAll() and returns it to your component.

Was this article helpful?

Have a question or spotted a mistake? Ask here about this article

Found this guide useful? Buy me a coffee (opens in a new tab)

Comments

Questions, corrections and your own experience are all welcome.