

Custom Metadata, Custom Settings & Custom Labels with Apex
In any retail org, the ability to adjust prices on the fly without always code changes is a game‑changer. By combining Custom Metadata, Hierarchy Custom Settings and Custom Labels, we can build a robust discount engine that’s fully administrable by clicks, not code whenever it’s required. In this blog, we will walk through an end to end solution: applying standard discounts per product family via Custom Metadata, overriding them for specific profiles or users via Hierarchy Custom Settings and using a useful message via Custom Labels. We will see the complete Apex implementation, learn how to test it end‑to‑end and let’s understand this pattern very easily.
Business Requirement
Imagine our org sells three product lines ‘Electronics’, ‘Clothing’ and ‘Home & Kitchen’ and we want to:
- Grant a baseline discount to every customer, depending on the product family (for example, 5% on Electronics, 15% on Clothing, 10% on Home & Kitchen).
- Override that baseline for VIP profiles (20%) and for individual power users (25%).
- We can display a clear use case message like “Congratulations! A discount of 5.00% has been applied. Your price: 95.00” whenever a discount is applied or required.
Specifically, we want admins to update the discount percentages through the UI no deployments needed or apex changes.
Setting Up Custom Metadata: Product_Discount__mdt
Custom Metadata Types are perfect for business‑driven configuration that rarely changes but needs packaging between orgs. Here’s how we define ours:
- Type Label: Product Discount
- API Name: Product_Discount__mdt
- Fields:
- Product_Family__c (Text)
- Discount_Percentage__c (Number, scale = 2)

Once the type is deployed, create three metadata records (Setup → Custom Metadata Types → Product Discount → Manage Records):

| Label | Product Family | Discount Percentage |
| Electronics Discount | Electronics | 5.00 |
| Clothing Discount | Clothing | 15.00 |
| Home & Kitchen Discount | Home & Kitchen | 10.00 |




These records now live as metadata deployable, packageable and protected from any type of deletion like accidentally, manually or mistakenly.
Hierarchy Custom Setting: Discount_Override__c
Hierarchy Custom Settings let’s define defaults and then override them at the profile or user level. We will use this to boost discounts for VIPs and individual power users:
- Setting Label: Discount Override
- API Name: Discount_Override__c
- Fields:
- Override_Discount__c (Percent, scale = 2)

In Setup → Custom Settings → Discount Override → Manage, create:
- Profile‑Scoped Record: choose any VIP profile as required by business, set Override Discount = 20.
- User‑Scoped Record: choose the user that will require any advanced discounts, set Override Discount = 25.
Something like below screenshot:


Because of the blank org‑wide default, getInstance() will return null for any user without a profile or user record, ensuring that our metadata baseline (5/15/10) applies.
Custom Label: Discount_Message
Custom Labels make it trivial to support multiple languages and adjust UI text without code always. We need to Create:
- Name: Discount_Message
Value:
Congratulations! A discount of {0}% has been applied. Your price: {1}

The placeholders {0} and {1} that can be replaced at runtime with the computed percentage and the final price, respectively.
Apex Implementation
Below is the complete Apex class that threading everything together. It:
- Queries the metadata for the base discount.
- Checks for a profile or user‑level override.
- Calculates the final price.
Formats the message with the Custom Label.
public with sharing class DiscountService {
/**
* Calculates discounted price and returns a user-facing message.
*
* @param prod The Product2 record (must have Family populated)
* @param listPrice The standard list price of the product
* @return A Map<String, Object>:
* - 'discountedPrice': Decimal
* - 'message' : String
*/
public static Map<String, Object> applyDiscount(Product2 prod, Decimal listPrice) {
// 1. Lookup base discount from Custom Metadata
Decimal baseDiscount = 0;
Product_Discount__mdt meta = [
SELECT Discount_Percentage__c
FROM Product_Discount__mdt
WHERE Product_Family__c = :prod.Family
LIMIT 1
];
if (meta != null) {
baseDiscount = meta.Discount_Percentage__c;
}
// 2. Check for Profile/User override in Hierarchy Custom Setting
Discount_Override__c overrideCS = Discount_Override__c.getInstance();
if (overrideCS != null && overrideCS.Override_Discount__c != null) {
baseDiscount = overrideCS.Override_Discount__c;
}
// 3. Compute discounted price
Decimal discountedPrice = listPrice * (1 - (baseDiscount / 100));
// 4. Build message via Custom Label
String template = Label.Discount_Message;
String message = String.format(
template,
new List<String>{
baseDiscount.setScale(2).format(),
discountedPrice.setScale(2).format()
}
);
return new Map<String, Object>{
'discountedPrice' => discountedPrice.setScale(2),
'message' => message
};
}
}
A few notes on the code:
- We use prod.Family as the standard field API name is Family from product2 object.
- The SOQL against metadata will give us a single record LIMIT 1 ensures we don’t mistakenly get duplicates we may modify it as per requirements.
- getInstance() returns null if there’s no profile or user override (because we blank out the org default), so the metadata discount remains untouched.
- We format both numbers to two decimal places for consistency.
Manual Testing Steps(To check our logic going well)
To verify everything works as expected, follow these steps from the org:
- Ensure Product Records Exist
- In Setup → Object Manager → Product2, confirm we have at least one Electronics product whose Family = “Electronics.”

- Confirm Metadata & Settings
- Custom Metadata → Product Discount → Manage Records: ensure Electronics = 5.00, Clothing = 15.00, Home & Kitchen = 10.00.
- Custom Settings → Discount Override → Manage: only two records exist (profile VIP = 20%, user you = 25%).
- Verify Label
- Setup → Custom Labels: that Discount_Message label matches the template above.
- Setup → Custom Labels: that Discount_Message label matches the template above.
Run Anonymous Apex
Open Developer Console → Debug → Open Execute Anonymous, paste:
// Fetch an Electronics product
Product2 p = [SELECT Id, Family, Name FROM Product2 WHERE Family = 'Electronics' LIMIT 1];
Map<String,Object> result = DiscountService.applyDiscount(p, 100);
System.debug('Result → ' + result);

- As a non‑VIP user (no override):
- Expected output from script {discountedPrice=95.00, message=Congratulations! A discount of 5.00% has been applied. Your price: 95.00}


- As a VIP user (profile‑scoped override of 20%):
- Login as VIP, rerun → {discountedPrice=80.00, message=…20.00%…80.00}
- Login as VIP, rerun → {discountedPrice=80.00, message=…20.00%…80.00}
- As your user (user‑scoped override of 25%):
- Login as yourself, rerun → {discountedPrice=75.00, message=…25.00%…75.00}
- Edge Case: Unknown Family
- Update your anonymous script to query Family = ‘Automotive’ (no metadata record).
- Expected: metadata query returns no row, so baseDiscount remains 0; since no override exists, discountedPrice = 100.00 and message shows 0.00%.
Deploying to Lightning Components or Flows
- Lightning Web Component: call DiscountService.applyDiscount() in the JavaScript controller via an @AuraEnabled Apex method wrapper, then we can bind the returned message and discountedPrice to UI.
- Screen Flow: use an Apex action element, pass in the Product record and list price, then display the message in a Screen component.
Because the business users can update metadata records and settings in Production, we gain full flexibility without touching code or pushing another release.
Best Practices & Considerations
- Bulkification:
- If we ever need to process multiple products at once, refactor this into a bulk‑safe version that queries all required metadata in one SOQL and iterates through a list of products.
- Custom Metadata vs. Custom Settings:
- Custom Metadata is deployable and packageable; perfect for baseline values.
- Hierarchy Custom Settings let us scope overrides at the profile and user level.
- Localization:
- We can use Translation Workbench to localize Discount_Message in all supported languages.
- Security:
- Mark our Apex class with sharing to respect record‑level security.
- Avoid exposing sensitive pricing logic to unauthorized users by controlling which profiles can invoke this service.
- Error Handling:
- Consider adding try/catch around the SOQL in case someone inadvertently deletes the metadata type.
- Provide fallback behavior or log an error if the metadata query fails.
Conclusion
By leveraging Custom Metadata for standard rules, Hierarchy Custom Settings for overrides, and Custom Labels for UI messaging, we now have a fully configurable discount engine that any admin can manage. No more hard‑coded percentages, no more mid‑release bug fixes for a one‑off override, just clean, maintainable configuration and a straightforward Apex service. In under an hour, we will be able to deploy this pattern to any Salesforce org and empower our business users to adjust pricing logic on demand. Enjoy the newfound agility!






