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
| Feature | Custom Metadata Types | Custom Settings |
|---|---|---|
| What the records are | Metadata | Data |
| Records deploy with change sets and packages | Yes | No, only the definition |
| Values per user or profile | No built-in hierarchy | Yes, with Hierarchy settings |
| Update records with DML in Apex | No. Use the Metadata API (async deploy) | Yes |
| Picklist fields | Yes | No |
| Relationship fields | Yes, to objects, fields and other metadata types | No |
| Read in Apex without SOQL | getAll(), getInstance() | getInstance(), getValues(), getAll() |
| Use in formulas | $CustomMetadata | $Setup (Hierarchy only) |
| Use in Flow | Get Records | Get Records, plus $Setup for Hierarchy |
| Visible in Apex tests | Yes | No, create records in the test |
| Managed package protection | Records can be protected and upgraded with the package | Records stay with the subscriber org |
Which one should you use?
Start from what the value is for:
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__cCommon 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.enqueueDeploymentif 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.
