Custom Metadata & Configuration
Custom Metadata is configuration—not a database shortcut
Configuration is part of the application
Custom Metadata Types solve an important Salesforce problem: application behaviour often needs to vary without hard-coded values scattered through Apex, Flow and formulas. Salesforce stores their records as metadata, so the type and records can travel with the application. That makes configuration portable and reviewable—when teams treat it as part of the product.
The JSBC Labs position is that custom metadata is executable architecture. A routing record, eligibility threshold or feature policy can change which records are updated, which integration is called or which users receive an experience. Its XML may look less dramatic than an Apex class, but its blast radius can be just as large. Configuration needs engineering ownership, testing and a release path.
Draw the metadata and data boundary
The first design decision is whether the value describes the application or records what is happening in the business. Salesforce's architecture guidance distinguishes Custom Metadata Types, which are stored as metadata, from Custom Settings, which are stored as data. A stable country-to-processing-policy map describes behaviour. A customer's current fulfilment state, a retry counter or today's exchange rate is operational data.
Use custom metadata for relatively stable, deployable rules that should accompany a version of the application. Use ordinary objects or a fit-for-purpose external store when values need transactional create, update and delete operations, frequent runtime changes, user-level ownership, history or high-volume relationships. Choosing metadata merely to avoid a query or custom object replaces one cost with a much harder lifecycle problem.
Design a schema, not a bag of flags
A type containing `Enabled`, `Mode`, `Value1` and `Value2` gives teams apparent flexibility while hiding meaning. Consumers must know which fields matter for each record, invalid combinations multiply and a harmless edit can activate an impossible state. The result is a weakly typed mini-database whose rules exist only in the code that happens to read it.
Model one coherent configuration concept per type. Give fields domain names, clear descriptions and constrained values. Use required fields, picklists, metadata relationships and validation rules where they express genuine invariants. Include an explicit status or effective model only when the application implements those semantics consistently. If reviewers cannot explain a record without opening its consumer code, the contract is not yet clear enough.
Separate defaults from environment differences
Teams frequently need the same behaviour across environments with a small number of differences. Copying arbitrary production records into every org encourages drift; branching Apex on sandbox names makes the environment part of business logic. Prefer a stable configuration identity and a documented precedence model: packaged or source-controlled defaults, then the minimum permitted environment-specific override.
Make fallback behaviour deliberate. Missing configuration should not quietly select the most permissive option, a production endpoint or an unlimited threshold. Decide which settings can use a safe default and which must stop the capability with an actionable diagnostic. Keep authentication material out of ordinary custom metadata: Salesforce provides Named Credentials and External Credentials to separate endpoints, authentication protocols, principals and encrypted tokens from application code.
A record edit can be a release
Custom metadata records can be deployed, but they can also be edited by authorised administrators in Setup. That convenience creates two change paths unless governance closes the gap. A production edit may alter behaviour immediately, bypass source control and disappear at the next deployment. A repository-only policy can be equally impractical when operations genuinely needs a controlled runtime switch.
Classify each type. Source-controlled configuration should change by pull request, automated validation and deployment. Operationally managed configuration needs named owners, restricted access, approval, audit evidence, rollback values and a reconciliation process back to source. Avoid mixing both modes in one type. The important control is not whether an admin can click Edit; it is whether every effective value has an authoritative home and recoverable history.
Stable names are public contracts
Apex, Flow, formulas and validation rules can reference custom metadata. Developer names and field APIs therefore become contracts between configuration and consumers. Renaming a label may be cosmetic; changing an identifier, deleting a record or repurposing a field can break several automation technologies at once. The dependency is wider than the team that created the type.
Use durable identifiers based on business meaning rather than today's organisational chart. Add new values before removing old ones, deploy consumers that understand both, migrate references and retire the old contract in a later release. Search source, Flow definitions, formulas and validation rules during impact analysis. Version the configuration model when interpretation changes; do not silently give an established field a new meaning.
Centralise resolution and validation
When every class queries a type and implements its own fallback, the application develops several definitions of the same configuration. One consumer treats a missing record as disabled, another throws an exception and a third selects the first available row. Repeated reads also obscure transaction cost and make it difficult to identify which settings influenced an outcome.
Put configuration access behind a small resolver or service with typed methods. It should apply precedence, validate required combinations, return explicit outcomes and cache only with a defined scope and invalidation model. Log configuration identity or version with operational results, not sensitive values. Salesforce Well-Architected guidance recommends configuration-driven behaviour and warns against repetitive configuration queries and caching without an invalidation strategy.
Test configurations, not only code paths
Salesforce makes custom metadata visible to Apex tests without `SeeAllData=true`, allowing tests to exercise deployed application configuration. That is useful, but it can also make tests accidentally depend on whichever records happen to be in the project. A passing test may prove only the default row, while production contains several regions, channels and exception policies.
Define a configuration test matrix: normal values, boundaries, missing records, inactive records, conflicting precedence and invalid combinations rejected by validation. Keep production-intended records in source and use deliberate test-specific patterns only where alternatives are required. Add static checks that every referenced identifier exists and integration tests proving the same rule across Apex, Flow and formulas. Test the rollback configuration as well as the preferred one.
Do not turn configuration into mutable state
A dangerous pattern begins with one operational value—last-run time, remaining quota, current owner or retry count—placed beside stable settings. Soon runtime processes need to update metadata, concurrency becomes ambiguous and support teams expect database-like behaviour from a deployment artifact. The type now carries both application definition and changing business state, with neither lifecycle handled well.
Keep observations and state in data stores designed for transactions, reporting, retention and recovery. Keep secrets in credential features designed to protect them. Keep custom metadata focused on the durable policies used to interpret state. This separation makes deployment predictable and lets operations repair data without rewriting the application contract. Convenience at the first read is not a substitute for correct ownership over years of change.
Operate configuration as a product surface
Maintain an inventory of custom metadata types, their purpose, owner, consumers, authority and change mode. Review broad Setup permissions and package manageability. Provide a diagnostic view showing resolved non-secret settings, their source and validation status. Alert on missing critical configuration and include configuration diffs in release evidence so production changes are visible beside code and Flow changes.
Custom Metadata Types let teams move behaviour out of code while keeping it deployable. That does not make configuration free-form or low risk. The healthy pattern is a narrow metadata model, explicit boundaries, controlled changes, typed access, comprehensive tests and observable resolution. Treat it with that discipline and configuration becomes leverage. Treat it as an easy table and it becomes invisible technical debt.
Official references
- Salesforce Trailhead: Get Started with Custom Metadata Types
- Salesforce Trailhead: Create and Manage Custom Metadata Types
- Salesforce Architects: Architecture Basics
- Salesforce Developers: Testing Custom Metadata Types
- Salesforce Architects: Resource and Cost Optimization Architecture Patterns
- Salesforce Developers: Get Started with Named Credentials
- Salesforce CLI: Generate Custom Metadata Records