- SalesforceChaCha
- Posts
- 💃 Guide to DI with CMDT 🕺
💃 Guide to DI with CMDT 🕺
Not sure what that means? Read this!
Good morning, Salesforce Nerds! I’ve got a story most devs can relate to …
It was a perfectly ordinary Tuesday. ☀️
You'd just finished your second coffee and were neck-deep in Apex, trying to configure API endpoints for five external systems yet again.
You glance over your shoulder. Todd from Marketing is talking about pivoting to a “new vendor strategy.” Again. 🤦
You sigh and crack open the IntegrationConfig.cls
file. It’s an archaeological site of hardcoded maps, enums, and if-else
branches that rival the Amazon rainforest in complexity.
But not today. ❌
Today, we inject elegance. Today, we refactor with purpose. Today, we custom metadata our way to sanity. ✊

TABLE OF CONTENTS
Guide to DI with CMDT
A PROVEN PATTERN
WHAT IS DEPENDENCY INJECTION, REALLY?
Dependency Injection (DI) is a design pattern that lets you decouple your classes from the concrete implementations they depend on.
Huh? 🤔
Well, instead of your code knowing which service to use, it asks for one to be handed to it - typically by reading from a config or framework that wires everything together. 🤘
In the Salesforce world, DI isn’t built into the platform like in Spring or .NET Core, but guess what?
We’re clever enough to make it work - with Custom Metadata Types (CMDTs).
TIGHT VS LOOSE COUPLING
THE PROBLEM AND SOLUTION
Let’s say your org integrates with multiple external CRMs - each with a different base URL, API key, and retry policy. 🔗
You might be tempted to do this:
public class CrmService {
public static String getEndpoint(String systemName) {
if (systemName == 'ACME') {
return 'https://api.acme-crm.com';
} else if (systemName == 'BetaCorp') {
return 'https://beta.api.crm.biz';
} else {
throw new AuraHandledException('Unknown system!');
}
}
}
Congratulations, you’ve just married your logic to your configuration. 😭😭
And guess what?
When the endpoint changes, Todd is submitting a ticket for you, not updating it himself.
Don’t let Todd control you like that. Use Custom Metadata Types (CMDT).
CMDTs allow you to store configuration data that behaves like metadata - deployed via change sets, unlocked packages, or metadata API (**cough** Gearset **cough**) , and cached efficiently by the platform. 🔥
Here’s how you redesign your solution:
1️⃣ Create a CMDT: External_System_Config__mdt
Fields:
System_Name__c
,Base_URL__c
,API_Key__c
,Timeout_Seconds__c
2️⃣ Populate it via metadata deploy or Setup UI. Each record represents a different system config.
3️⃣ Inject that data into your Apex logic:
public class CrmServiceFactory {
public static CrmService getService(String systemName) {
External_System_Config__mdt config =
[SELECT Base_URL__c, API_Key__c FROM External_System_Config__mdt WHERE System_Name__c = :systemName LIMIT 1];
return new CrmService(config.Base_URL__c, config.API_Key__c);
}
}
Now, your service is cleanly separated from the how of configuration. ✨
You can test it. You can reuse it. You can scale it.
And Todd? Todd can submit a config change instead of waking you up from your developer nap. 😴
BREAKING IT DOWN
KEY CONCEPTS
Now that we’ve escaped the if/else jungle and embraced the serenity of Custom Metadata Types, let’s break down the architectural anatomy behind it all.
These core concepts are the building blocks of a clean, scalable, and injection-friendly solution in Apex.
Concept | What It Means in Salesforce |
---|---|
🔗 Dependency | A service your class needs (e.g., endpoint URL) |
📥️ Injection | Getting that service/config from outside the class |
⚙️ Custom Metadata | Your injection source (config lives here) |
🏭️ Factory Class | Optional wrapper to centralize creation logic |
📦️ Decoupling | Your new best friend |
MAINTAINABILITY & SCALABILITY
WHY THIS MATTERS
So. Much. 👈️
Let’s say you’re integrating with an email validation service. Today it’s MailChimp. Tomorrow it’s SnailChimp.
Next week it’s probably a blockchain-powered carrier pigeon service. 🤷
With CMDT and DI, you don’t care.
You simply:
Add a new CMDT record for the new provider
Deploy it with your next release
Never touch the Apex logic
Magic? Nope. Just architecture. 🤙
What about Unit Testing? 🧪
Because your logic is no longer tangled up in hardcoded values, you can easily mock your configuration.
@isTest
private class CrmServiceTest {
@isTest
static void testServiceInjection() {
CrmService svc = new CrmService('https://mock.url', 'FAKEKEY123');
Test.startTest();
svc.sendData(...);
Test.stopTest();
// assert your outcomes
}
}
We’ll dig deeper into test strategies (including mocking and stubbing) in a future article- so stay tuned for that! 📅
Besides impressing your fellow devs (and probably scaring Todd), dependency injection helps you:
📉 Reduce the risk of regression bugs
🎁 Simplify logic for easier maintenance
🏗️ Make your org more configurable and scalable
Hardcoding is easy today, but expensive tomorrow. 🚫
This pattern flips that around.
ADOPT A SMARTER ARCHITECTURE
FINAL THOUGHTS
Custom Metadata-based dependency injection isn’t just a cool trick - it’s a strategy.
It’s how you future-proof your integrations, keep your Apex logic tidy, and finally stop that avalanche of if/else
madness. 😌
So next time you see a class tightly coupled to an API endpoint, raise an eyebrow and whisper, “You could’ve injected that.”
Because you're not just writing code anymore - you’re designing systems. 👌
And Todd? He’s just updating metadata now.
Happy coding, y’all ✌️
SOUL FOOD
Today’s Principle
“Dependency injection enables you to separate behavior from construction, making your code more modular, testable, and flexible.”
and now....Salesforce Memes



What did you think about today's newsletter? |