Salesforce Custom Metadata Types Advanced Patterns for Real-World Architectures
Introduction:
- Salesforce projects evolve fast, and the “rules of the game” change even faster—pricing tiers, routing logic, approver lists, discount thresholds, country tax rates, feature toggles. Hard-coding these rules in Apex or scattering them across Validation Rules and Flows le Pattern 3: Routing and mapping tables:ads to brittle systems and expensive redeployments.
- Custom Metadata Types (CMDT) solve this by turning configuration into deployable metadata. Instead of editing and redeploying code for every small business change, admins can update configuration records, and developers can structure code to read those rules dynamically.
- This article goes beyond the basics to share field-tested advanced patterns, when to use CMDT vs. alternatives, and common pitfalls to avoid—all with a keep-it-simple mindset for beginners who want to build like pros.
What Custom Metadata Types Are & Why They Matter:
Custom Metadata Types allow creation of custom, deployable configuration schemas—plus records that travel with your metadata. Think of CMDT as “configuration blueprints” (the type) and “configuration rows” (the records). These records are:
- They can be deployed across environments (Dev → QA → UAT → Prod).
- Queryable from Apex, Flow, and even referenced in formulas and default values.
- Versionable in source control, just like fields and objects.
- Visible to tests without SeeAllData, making unit tests more reliable.
In short, CMDT turns configuration into first-class metadata, unlocking safer deployments, cleaner code, and admin-friendly changes without constant developer intervention.
CMDTs store configuration as metadata, not data. That single distinction unlocks several advantages:
- Deployability: CMDT records move with your packages, change sets, or CI/CD pipelines. No more post-deploy spreadsheets with “Please insert these rows in prod.”
- Testability: Apex tests can access CMDT records without special annotations, enabling deterministic tests that validate configuration-dependent behavior.
- Performance and safety: Once loaded per transaction and cached appropriately, CMDT lookups are fast and governor-safe when used thoughtfully.
- Flexibility: Admins can update configuration to adjust behavior without code changes, reducing release friction.
When should CMDTs be used:
- Configuration must be portable.
- Observable in source control.
- Central to application logic.
Reserve custom settings for niche hierarchy use cases where user- or profile-specific values are critical, and keep custom labels focused on UI text—not business rules.
Pattern 1: Strategy through metadata (replace if-else trees):
The anti-pattern: long chains of if-else logic that choose “what to do” based on environment, feature, record state, or org preference.
The pattern: define a Strategy__mdt type with fields like Key (unique handle), ClassName (whitelisted invocable), Active (toggle), and Priority (execution order). In Apex, load the active records, sort by Priority, and dispatch behavior by ClassName—validated against a known allowlist or interface to avoid unsafe reflection. This gives admins live control over which strategies are active, enables A/B tests in sandboxes, and makes production rollbacks a metadata change instead of a code rollback. It’s the Strategy/Factory pattern with configuration as the source of truth.
When should Pattern-1 be used:
- Lead routing strategies that evolve frequently
- Country- or segment-specific tax, pricing, or discount logic
- Multi-step evaluation pipelines where order matters
Pattern 2: Trigger entry criteria as metadata:
The anti-pattern: changing trigger behavior requires code edits just to tweak “when to run.”
The pattern: define a Criteria_Set__mdt (ObjectName, Active) and child Criterion__mdt (relationship to set, FieldAPIName, Operator, Value, Active). In triggers, pull the active set for the object, translate each Criterion into a predicate, and evaluate records against it. By moving entry conditions into metadata, admins can toggle criteria safely, and developers keep trigger bodies lightweight and maintainable.
Tips:
- Use standardized operators (Equals, NotEquals, Contains, GreaterThan, etc.) and validate inputs in Apex.
- Cache the compiled predicates per transaction.
- Log which criteria fired for observability.
Pattern 3: Routing and mapping tables:
The anti-pattern: buried CASE statements and nested ifs for value translation (e.g., “if Industry = X, owner = Y, else if…”).
The pattern: create a Mapping__mdt with SourceValue, TargetValue, OptionalAttributes (free-form JSON or structured fields), and Active. At runtime, load and cache all mapping rows into a Map<String, Mapping__mdt> for O(1) lookups. This works for:
- Territory, queue, or user assignments (Lead/Case routing)
- Country/state → currency, tax rate, SLA level
- External field name → internal API name mappings for integrations
Because mappings are metadata, a deployment can safely change routing for a go-live—or revert it fast.
Pattern 4: Formula defaults and central thresholds:
The anti-pattern: hard-coded numbers in formulas (quotas, caps, multipliers) sprinkled across objects.
The pattern: move thresholds and constants to CMDT, then reference them in formula fields and default values. When the business changes a cap or threshold, update the metadata record—no object edits, no code deploys, and no forgotten copies. This reduces “magic numbers,” centralizes governance, and keeps logic consistent across objects and flows.
Pattern 5: Feature flags and progressive delivery:
The anti-pattern: releasing risky features by code deployed alone, without a kill switch.
The pattern: Feature_Toggle__mdt with fields like Key, IsEnabled, OptionalRampPercent, and OptionalScope (e.g., profile or permset). Gate Apex/Flow/Validation behavior behind these flags. Launch with IsEnabled = false, activate progressively, and turn off instantly if needed. A feature flag framework using CMTs gives ops control without emergency redeployments.
Pattern 6: Test data without SeeAllData:
The anti-pattern: brittle tests that rely on org data or labels to simulate configuration.
The pattern: write tests that read CMDT records directly. Because CMDT records are available in tests by default, builders can assert strategy selection, mapping accuracy, and feature flags without noisy setup code. Keep a stable baseline of CMDT test records in source control so tests are deterministic across environments
Extended implementation documentation:
- Access and security: CMDTs can be permissioned. In multi-team orgs, grant read access only to relevant groups; in managed packages, protect sensitive defaults while allowing subscribers to add their own records. Never store secrets in CMDT—use Named Credentials or shielded alternatives.
- Modeling relationships: Use Metadata Relationship fields between CMDT types to model hierarchies (e.g., Criteria Set → Criterion) instead of denormalizing with text keys. This improves integrity and discoverability in Setup.
- Caching and governor safety: Bulk-load all needed records once per transaction, then cache in a static map or service layer. Avoid per-record SOQL calls. Consider a simple in-memory “Config” class with lazy initialization.
- CI/CD and versioning: Treat CMTs as first-class citizens—commit types and records in version control, code-review changes, and deploy them through the same pipeline as Apex and Flows. Keep environment-specific rows in separate folders or branches and document promotion steps.
- Observability: Add lightweight logging for “which strategy/criteria/flag applied” to enable faster support and debugging. Consider a debug-only header or platform event for tracing in lower environments.
A working reference model:
- Define metadata types:
- Strategy__mdt: Key (unique), ClassName (text), Active (checkbox), Priority (number)
- Feature_Toggle__mdt: Key, IsEnabled, RampPercent (number, optional), Scope (text or metadata relationship)
- Mapping__mdt: SourceValue, TargetValue, Attributes__c (long text), Active
- Criteria_Set__mdt: ObjectName, Active
- Criterion__mdt: Set (metadata relationship), FieldAPIName, Operator, Value, Active
- Build a Config service:
- On first call, query each relevant type, validate for duplicates/inactive conflicts, and cache maps like:
- strategiesByKey, sortedStrategies
- featureByKey
- mappingsBySource
- criteriaByObject, criteriaBySet
- Expose typed getters for Apex and Flow (Invocable Methods for Flow access).
- On first call, query each relevant type, validate for duplicates/inactive conflicts, and cache maps like:
- Use across layers:
- Triggers: consult Criteria_Set to decide whether to run, then delegate to services/strategies.
- Services: look up mappings to route records; call strategies by key to resolve behavior.
- Flows: expose invocables to evaluate flags and mappings; keep flow logic declarative and metadata-driven.
Frequent mistakes and their solutions:
Overloading custom labels for logic: labels are for UI text and localization, not routing or thresholds. Move logic to CMDTs and keep labels clean.
- Unbounded queries: repeated SOQL on CMDTs in loops wastes limits. Always bulk-load and cache.
- Secrets in metadata: never store tokens or passwords in CMDTs. Use Named Credentials and appropriate encryption/compliance controls.
- Using CMDT for transactional data: CMDTs are configuration. Keep orders, events, or logs in standard/custom objects instead.
Conclusion:
- Custom Metadata Types turn hard‑coded rules into deployable, version‑controlled configuration, enabling faster, safer releases and simpler lifecycle management across environments.
- Modeling strategies, trigger criteria, mappings, feature flags, and thresholds as metadata reduces code churn and lets teams adapt behavior without redeploying code, improving agility and governance.
- A lightweight configuration service that bulk‑loads and caches CMDT records per transaction keeps solutions governor‑safe, testable, and cleanly separated from business logic.
Treat CMDTs as first‑class assets: secure access, avoid storing secrets, track changes in source control, and define clear rollback plans—yielding cleaner architecture and lower technical debt. For teams exploring advanced configurations, partnering with a reliable Salesforce development company in USA can ensure smoother adoption and long-term scalability.
related blog
