loader

Salesforce Development Β· Configuration

Custom Settings vs Custom Metadata Types in Salesforce

Both let you store configuration instead of hard-coding it in Apex or Flow. The big difference is simple: custom metadata records deploy with your code, while custom settings records are data that has to be recreated in every org. That one fact decides most choices.

Custom Metadata Types

Configuration that ships with your code

  • Records are metadata, so they move with change sets, packages and the Metadata API
  • Supports picklists and relationships to objects, fields and other metadata types
  • Read-only to normal DML at runtime
  • Visible in Apex tests without extra setup
  • Usable in Apex, Flow, formulas and validation rules

Custom Settings

Data that can change at runtime

  • Comes in two types: List and Hierarchy
  • Hierarchy settings can hold different values per org, profile or user
  • Records can be created and updated with normal DML
  • Only the definition deploys. Records must be loaded separately in each org
  • Records aren’t visible in Apex tests unless the test creates them

Side-by-side comparison

FeatureCustom Metadata TypesCustom Settings
What the records areMetadataData
Records deploy with change sets and packagesYesNo, only the definition
Values per user or profileNo built-in hierarchyYes, with Hierarchy settings
Update records with DML in ApexNo. Use the Metadata API (async deploy)Yes
Picklist fieldsYesNo
Relationship fieldsYes, to objects, fields and other metadata typesNo
Read in Apex without SOQLgetAll(), getInstance()getInstance(), getValues(), getAll()
Use in formulas$CustomMetadata$Setup (Hierarchy only)
Use in FlowGet RecordsGet Records, plus $Setup for Hierarchy
Visible in Apex testsYesNo, create records in the test
Managed package protectionRecords can be protected and upgraded with the packageRecords stay with the subscriber org

Which one should you use?

Start from what the value is for:

Business rules, mappings or thresholds that should be the same in every org (tax rates by state, field mappings for an integration, routing rules)
Custom Metadata
Config that has to deploy from sandbox to production without anyone re-entering values
Custom Metadata
Settings shipped in a managed package that you want to update in later versions
Custom Metadata
A switch to bypass triggers, flows or validation rules for one user, like an integration user or a data migration
Hierarchy Custom Setting
Values your code writes back at runtime, like a last sync timestamp or a counter
Custom Setting
Secrets like API keys or passwords
Neither. Use Named Credentials

Our default: reach for custom metadata first. Use a hierarchy custom setting when you need per-user or per-profile values, or when the value has to change at runtime. Newer projects rarely need List custom settings, since custom metadata covers the same use with better deployment.

Reading them in Apex

Custom metadata

// Get one record by its DeveloperName
Tax_Rule__mdt rule = Tax_Rule__mdt.getInstance('California');
Decimal rate = rule.Rate__c;

// Get all records as a map keyed by DeveloperName
Map<String, Tax_Rule__mdt> rules = Tax_Rule__mdt.getAll();

Hierarchy custom setting

// Returns the most specific value: user, then profile, then org default
Automation_Bypass__c bypass = Automation_Bypass__c.getInstance();
if (bypass.Skip_Triggers__c) {
    return;
}

In a formula or validation rule

// Custom metadata
$CustomMetadata.Tax_Rule__mdt.California.Rate__c

// Hierarchy custom setting
$Setup.Automation_Bypass__c.Skip_Validation__c

Common mistakes

  • Expecting custom setting values to deploy. A change set moves the custom setting definition, but production starts with no records. Add loading the values to your deployment steps, or switch to custom metadata.
  • Tests failing in production only. Code that reads a custom setting gets nothing in a test unless the test inserts the record first.
  • Trying to update custom metadata with DML. It throws an error. Use Metadata.Operations.enqueueDeployment if you truly need runtime updates, or rethink whether it should be a custom setting.
  • Storing credentials in either one. Admins and sometimes users can read these values. Use Named Credentials and External Credentials instead.

Common questions

Do SOQL queries on custom metadata count toward governor limits?

Generally no, as long as the query doesn’t include long text area fields. The getAll() and getInstance() methods are the simplest option and use no SOQL at all.

Can admins edit custom metadata without a deployment?

Yes. Admins can edit records in Setup through Custom Metadata Types β€Ί Manage Records. It’s still metadata, so best practice is to make the change in a sandbox and deploy it.

Can I convert a custom setting to custom metadata?

There’s no one-click conversion. Create the custom metadata type with matching fields, load the records, update your Apex, flows and formulas to point at the new type, then retire the old setting.

Cleaning up hard-coded config in your org?

We help teams move logic into metadata-driven designs that deploy cleanly.

Talk to a Salesforce architect