DEV Community

Cover image for Using Custom Metadata in Apex to Replace Hardcoded Configuration Values
Thisura Manjitha Samarakoon
Thisura Manjitha Samarakoon

Posted on

Using Custom Metadata in Apex to Replace Hardcoded Configuration Values

In many Salesforce projects, developers often start by hardcoding configuration values (like API URLs, keys, or feature toggles) directly into Apex classes. While this might seem quick and simple at first, it creates long-term maintenance problems.

  • Changing values requires code edits and deployments.
  • Supporting multiple environments or services becomes tricky.
  • Non-developers (like admins) cannot update these values.

A much better approach is to use Custom Metadata Types (CMDT) to externalize configurations. This keeps your Apex clean, makes maintenance easier, and empowers admins to manage settings without touching code.

Example Use Case: Cloud Integration Endpoints

Let’s take the example of integrating Salesforce with multiple cloud storage providers. Initially, you might write something like this.

private final static String uploadEndpoint   = 'https://.../s3-salesforce-integration'; 
private final static String downloadEndpoint = 'https://.../s3-salesforce-integration-download'; 
private final static String deleteEndpoint   = 'https://.../s3-salesforce-integration-delete'; 
Enter fullscreen mode Exit fullscreen mode

This works fine until you add more providers (Google Drive, OneDrive, etc.) or need to update the URLs.

Defining Custom Metadata

To make this flexible, create a Custom Metadata Type (e.g. Integration_Config__mdt) with fields like:

  • Upload_Endpoint__c
  • Download_Endpoint__c
  • Delete_Endpoint__c

Then, create records for each provider.

  • AWS
  • Google
  • OneDrive

The Pitfall - Initialization Error

My first attempt to pull metadata into Apex looked like this.

Integration_Config__mdt awsConfig = Integration_Config__mdt.getInstance('AWS'); 

private static final String uploadEndpoint   = awsConfig.Upload_Endpoint__c; 
private static final String downloadEndpoint = awsConfig.Download_Endpoint__c; 
private static final String deleteEndpoint   = awsConfig.Delete_Endpoint__c; 
Enter fullscreen mode Exit fullscreen mode

But Salesforce gave an error on deployment.

Variable does not exist: awsConfig

That’s because you can’t directly use a runtime fetched variable (getInstance) to initialize static final variables at the class level.

The Solution - Static Initializer Block

The correct way is to use a static initializer block, which executes once when the class is loaded.

private static final String uploadEndpoint; 
private static final String downloadEndpoint; 
private static final String deleteEndpoint; 

static { 
    Integration_Config__mdt awsConfig = Integration_Config__mdt.getInstance('AWS'); 

    if (awsConfig != null) { 
        uploadEndpoint   = awsConfig.Upload_Endpoint__c; 
        downloadEndpoint = awsConfig.Download_Endpoint__c; 
        deleteEndpoint   = awsConfig.Delete_Endpoint__c; 
    } 
} 
Enter fullscreen mode Exit fullscreen mode

Now the values are dynamically loaded from metadata and available across all methods.

Before vs After

1. Hardcoded Configuration (Rigid & Risky)

Apex Class
├── Upload URL -> hardcoded
├── Download URL -> hardcoded
└── Delete URL -> hardcoded

  • Requires redeployment for every change.
  • Hard to scale for multiple providers.
  • Not manageable by admins.

2. Metadata-Driven Configuration (Flexible & Scalable)

Custom Metadata (Integration_Config_mdt)
├── Record: AWS
│ ├── Upload_Endpoint
c
│ ├── Download_Endpoint
c
│ └── Delete_Endpoint
_c
├── Record: Google
├── Record: OneDrive
└── ...

Apex Class
└── Reads values dynamically using static block

  • Values stored in metadata records.
  • Easy to update without touching code.
  • Supports multiple configurations.
  • Admin friendly.

Key Takeaways

  • Avoid hardcoding any configuration values (URLs, IDs, toggles, etc.) in Apex.
  • Use Custom Metadata Types to make your code flexible and environment friendly.
  • Remember, static variables that depend on metadata should be initialized inside a static block, not inline.

With this approach, you’ll make your Apex code more maintainable, scalable, and admin friendly whether you’re managing API endpoints, feature flags, or any other configuration values.

Top comments (0)