- The fundamental differences between Custom Metadata Types, Custom Settings, and Custom Objects as configuration stores
- Why Custom Metadata Types are the preferred choice for most configuration scenarios in modern Salesforce development
- When Custom Settings are still the right tool — and the limits that constrain them
- The performance characteristics of each mechanism and how they differ under load
- A decision matrix for mapping your use case to the right configuration storage mechanism
The Configuration Storage Problem
Every Salesforce implementation has business rules, thresholds, and configuration values that need to be stored somewhere and read by Apex, Flows, and validation rules. Tax rates, SLA thresholds, integration endpoints, feature flags, routing rules — these are the configuration layer of your application. Where you store them has implications for how they're deployed, how they perform, and how easily they change.
Three Salesforce mechanisms exist for this purpose, and they are frequently chosen interchangeably without understanding their different architectural characteristics. Choosing Custom Settings when Custom Metadata Types are appropriate, or vice versa, creates technical debt that surfaces at deployment time, scale, or audit time.
Before choosing a configuration storage mechanism, ask: "How will this configuration travel between environments?" If the answer is "via metadata deployment (change set, SF CLI, package)," use Custom Metadata Types. If the answer is "it's environment-specific and should never be deployed automatically," Custom Settings may be appropriate. Custom Objects follow regular data migration patterns. The deployment model is the first architectural differentiator.
Custom Settings: Hierarchy Data Close to the Platform
Custom Settings are Salesforce's original configuration mechanism. They come in two types: Hierarchy (per-org, per-profile, or per-user settings with cascading defaults) and List (key-value pairs accessible org-wide). List Custom Settings are accessible via ClassName.getInstance(name) from Apex and in formula fields via $Setup.FieldName__c.
What Custom Settings Do Well
Hierarchy Custom Settings are the right tool for configuration that genuinely varies by user or profile. If your application behaves differently for users in different profile groups — different default values, different feature enablement — Hierarchy Custom Settings provide a clean, platform-native mechanism for this differentiation. The hierarchy (Org → Profile → User) means you set a default at org level and override only where needed.
Custom Settings are also appropriate for environment-specific configuration that should NOT travel between environments: integration endpoints (sandbox vs production), API keys per environment, feature flags that are on in UAT but off in production. Because Custom Settings data is not part of the metadata deployment, it stays put when you deploy — which is intentional for these use cases.
Custom Settings Limits
The 10MB total data limit for Custom Settings org-wide is the most commonly hit constraint. For configurations that are small (a few dozen records, simple fields), this is rarely an issue. For configurations that grow — lookup tables, routing rules, tax matrices — the 10MB limit becomes a real constraint. Custom Settings also do not support relationship fields (no lookups to other objects), which limits their expressiveness for complex configuration structures.
// Apex: Reading Custom Settings at runtime
// Hierarchy: org-level default, with profile/user overrides
MyAppSettings__c settings = MyAppSettings__c.getInstance();
Decimal taxRate = settings.DefaultTaxRate__c;
// List Custom Settings: by name
IntegrationEndpoint__c endpoint =
IntegrationEndpoint__c.getInstance('Production_ERP');
String url = endpoint.BaseURL__c;
// Formula field access (no Apex required):
// $Setup.MyAppSettings__c.DefaultTaxRate__c
Custom Metadata Types: Configuration That Belongs in Your Package
Custom Metadata Types (CMT) are Salesforce's modern replacement for many Custom Settings use cases. The critical architectural difference: CMT records are metadata, not data. They are part of your org's metadata model, deployed via change sets and the Metadata API, included in packages, and visible in version-controlled source as XML files.
CMT records travel with your deployments automatically. When you promote from sandbox to production, your CMT records come with the metadata deployment — no separate data migration step required. This makes CMT records the right choice for any configuration that should be consistent across environments and that is part of your application's behaviour definition.
CMT Capabilities Beyond Custom Settings
CMTs support relationship fields — a CMT record can have a lookup to another CMT record, or a metadata relationship to a standard Salesforce metadata type (like a Field or Object definition). This enables complex, relational configuration structures that Custom Settings cannot express. A routing rules configuration that maps Account industry to an assigned team, where teams are themselves CMT records, is clean and elegant in CMT. In Custom Settings, it requires a workaround.
CMT records also do not count toward the custom object limit (200 per org) — they have their own separate limit. You can create as many CMT types and records as your use case requires without impacting your object count budget.
In any new Salesforce implementation or feature, default to Custom Metadata Types for configuration storage unless you have a specific reason for Custom Settings (environment-specific data, per-user hierarchy, small dataset that benefits from formula field access). CMT's deployability and packageability are advantages that almost always outweigh Custom Settings' simpler access model.
Custom Objects: Full CRUD With All the Tradeoffs
Custom Objects are the most powerful configuration mechanism — full CRUD operations, relationship support, workflow automation, reporting, page layouts — but they carry the highest operational overhead. Records in custom objects are data, not metadata: they require data migration to move between environments, they count toward your custom object limit, and they consume storage quota.
Custom Objects are the right choice for configuration that needs to be managed by business users at runtime — not deployed by developers. Approval routing configurations that a business administrator updates monthly, SLA definitions that change with contract renewals, pricing tiers that marketing adjusts per campaign — these are configuration that benefits from Salesforce's full UI, validation rules, workflows, and data management capabilities.
When to Use Custom Objects for Configuration
Use Custom Objects when: the configuration changes frequently and needs to be updated by non-developers in production, the configuration requires relationships to transactional data (e.g. a configuration record related to specific Accounts or Products), or the volume of configuration records is large enough that the 10MB Custom Settings limit is a concern and CMT deployment overhead is impractical for frequent changes.
When business users can edit configuration data in production, you lose the safety net of environment promotion review. A misconfigured SLA threshold or routing rule created directly in production can affect every new transaction immediately. If you use Custom Objects for configuration, implement approval processes for critical configuration changes, maintain a backup snapshot before major updates, and define clear ownership of who can modify each configuration object.
Performance Differences That Aren't in the Documentation
All three mechanisms read from different sources with different performance profiles. Custom Settings data is cached in the application server layer after the first access in a transaction — subsequent reads within the same transaction are served from cache at near-zero cost. This is why Custom Settings are particularly efficient in validation rules and formula fields that execute on every record operation.
Custom Metadata Types are also cached — CMT records are loaded into the application server's metadata cache and remain there until the cache is invalidated (typically by a metadata deployment). For Apex code that reads CMT records in a loop, the second and subsequent reads are from cache, not from database. However, the initial SOQL query against CMT records does consume from the transaction's SOQL query limit (100 per transaction).
Custom Objects are standard SOQL queries against the database — no special caching. Reading configuration from a Custom Object in Apex requires a SOQL query that consumes Governor Limits. For configuration accessed in high-frequency triggers (every Account update, every Opportunity stage change), reading from a Custom Object in every transaction is both Governor-Limit-expensive and potentially performance-impacting. Use Platform Cache as a caching layer for Custom Object configuration in these scenarios.
Decision Matrix
Map your use case to the right mechanism:
Use Custom Metadata Types when: configuration must travel with code deployments, configuration should be in version control as metadata, the package must include the configuration, or the configuration is structural/relational (complex CMT-to-CMT relationships).
Use Custom Settings when: configuration is environment-specific (sandbox vs production endpoints), the configuration varies by user or profile (Hierarchy type), it needs to be accessible in formula fields without SOQL, or the dataset is very small and change frequency is very low.
Use Custom Objects when: business users need to manage configuration in production UI without developer involvement, configuration needs approval workflows or change history, the configuration relates to transactional records, or the volume is too large for Custom Settings limits and too dynamic for CMT deployments.
Migrating from Custom Settings to CMT is straightforward for the data but requires refactoring all code that uses getInstance() to SOQL-based CMT queries. Migrating from Custom Objects to CMT requires a data export and metadata import, plus code refactoring. Neither migration is technically complex, but both require a full regression test of any logic that reads the configuration. Do the migration in a sandbox with proper test coverage before attempting production.
Governance and Lifecycle Management
Each mechanism requires different governance. CMT records are part of the metadata deployment pipeline and should follow your change management process — a change to a routing rule CMT record is as significant as a code change and should have the same review and approval pathway. Track CMT record changes in your version control system (they appear as XML file changes in the source format) and include them in pull request reviews.
Custom Settings in production should have a documented owner per setting and a change log. Since Custom Settings data isn't automatically captured in version control or deployment logs, the only audit trail is your own documentation or Salesforce Shield's audit logs. Custom Object configuration changes can be tracked via the standard Salesforce audit trail (Setup Audit Trail for setup changes, Field History Tracking for field-level changes).
Key Takeaways
- The primary differentiator between the three mechanisms is deployment model: CMT records are metadata (travel with deployments), Custom Settings are data (stay in each org), Custom Objects are data (require explicit migration)
- Custom Metadata Types are the preferred default for new configuration design — deployable, packageable, version-controllable, and they don't consume the custom object limit
- Custom Settings are appropriate for environment-specific configuration and per-user/profile hierarchy settings — their formula field access and caching make them efficient for high-frequency reads
- Custom Objects provide the richest UI and governance capabilities for configuration managed by business users — but require explicit data governance and don't automatically travel between environments
- CMT and Custom Settings are cached after initial access; Custom Object configuration requires a SOQL query on every read and should use Platform Cache for high-frequency access
- Migrating from Custom Settings or Custom Objects to CMT (or vice versa) is achievable but requires code refactoring and regression testing — get the decision right at design time
Checkpoint: Test Your Understanding
1. A developer needs to store routing rules that map Account Industry to an assigned support team. These rules must be deployed via change set from sandbox to production and versioned in Git. Which mechanism should they use?
2. What is the key architectural reason Custom Settings are appropriate for storing integration endpoint URLs that differ between sandbox and production?
3. A business operations team needs to manage SLA threshold configurations that change frequently and require an approval process before going live. Which mechanism is most appropriate?
Discussion & Feedback