OrgTidePricingGuideLearnSign inGet started

← Learn

Custom metadata types vs. custom settings: which one, when

August 4, 2026

Both exist to keep configuration out of your code. Both look similar in Setup. And picking the wrong one is the kind of mistake you discover months later, mid-deploy, when your config didn't come along. Here's the decision, shortest version first.

The one fact that decides most cases

Custom metadata type records are metadata. Custom settings values are data.

That single distinction drives everything: a custom metadata type (__mdt) deploys with its records - retrieve it, deploy it, package it, and the configuration arrives in the target org ready to use. A custom setting deploys as an empty container: the definition moves, the values stay behind, and someone has to recreate them in every sandbox, every staging org, and production - by hand, by data loader, or by a script someone has to remember to run.

If your configuration should travel through your pipeline like code - integration endpoints per environment, feature switches, threshold values, mapping tables - default to custom metadata types. This is also Salesforce's own steer; custom settings predate them by years.

What else custom metadata gets you

  • Zero-cost reads. Fetch records with YourType__mdt.getAll() / getInstance() and it costs you nothing against SOQL limits - the platform serves them from cache. Config lookups in triggers and loops stop being a governor-limit conversation.
  • Referenceable in more places. Validation rules, formulas, and flows can read custom metadata directly; your admin can see the config that drives behavior instead of archaeology through Apex constants.
  • Protected components work for both, but packaging is where custom metadata shines: an ISV can ship config records inside a package and update them with new versions.

Where custom settings still win

Custom settings aren't legacy - they keep two real jobs:

  • Values your code needs to write. Apex cannot DML a __mdt record inside a normal transaction (updating custom metadata requires a Metadata API call - asynchronous and awkward). A custom setting is a plain sObject: read it, update it, done. Anything like "store the timestamp of the last successful sync" belongs in a custom setting (or a regular object), never custom metadata.
  • Per-user and per-profile overrides. A hierarchy custom setting resolves values through org → profile → user, out of the box. "Debug logging on, but only for these two users" is one hierarchy setting and zero code. Custom metadata has no equivalent without building your own resolution logic.

(List custom settings - the non-hierarchy kind - have almost no remaining niche; if you're reaching for one, a custom metadata type is nearly always the better answer.)

The decision in three questions

  • Does Apex need to write it at runtime? → Custom setting (or a normal object).
  • Should different users/profiles see different values? → Hierarchy custom setting.
  • Everything else - config that should version, deploy, and arrive with your code? → Custom metadata type.

The expensive failure mode is always the same: a feature works perfectly in the sandbox, deploys clean, and breaks in production because a custom setting arrived empty. If the value's absence would break the org, that value wants to be metadata.

---

OrgTide's Build generates both - and when it creates a custom metadata type, the config records deploy with it, so what you approve in the diff is exactly what arrives in the org. What Build can generate →

More from the learn hub

Custom metadata types vs. custom settings: which one, when · OrgTide