Valence is a sophisticated engine and allowing users to tailor it exactly how they need it is intrinsic to its value.

Each extension should be designed with these users in mind, and built from the ground up to have flexibility where it needs to.

We’ve provided quite a bit of framework to support your development effort, and you can focus on what’s unique and special about your extension while mostly staying out of boilerplate and orchestration.

Both Adapters and Filters can be user-configurable, and as you’d expect you declare support for this functionality by implementing certain interfaces:

Adapter interfaces:


You might implement both of these if your Adapter can both send and receive data.

Filter interfaces:


Once you implement one of the configuration-related interfaces, you’ll see some standardized methods be required. They fall into three groups:

  • Asking your extension for information about how it can be configured

  • Asking your extension to explain what a particular configuration does

  • Handing configuration details to your extension at runtime

You will never be responsible for storing configuration data between runs, or knowing where to go find it. At runtime Valence hands you exactly the configuration information you need, when you need it.


We always want users to be in the driver’s seat and understand what their engine is doing. Explaining your configurations is a really important part of helping users to understand the effects of their decisions. Take time to design a thoughtful and clear response to your implemented explain method.

Example Explain Method
public String explainFilterConfiguration(String configurationData) {

        try {
                Configuration config = buildConfiguration(configurationData);

                String message = 'A source field called <strong>{0}</strong> will be added to each record that is actually a sub-object built as follows:<ul>{1}</ul>';

                List<String> entries = new List<String>();

                for(ConfigField configField : config.fields) {
                        entries.add(String.format('<li><strong>{0}</strong> (Value comes from <strong>{1}</strong>)</li>', new List<Object>{
                                String.join(configField.sourcePath, '.')

                return String.format(message, new List<Object>{
                        String.join(entries, '')
        catch(Exception e) {
                return '<p class="slds-theme_error">The configuration for this Filter is malformed.</p>';


We’ve briefly discussed how to consume configuration data at runtime in your Apex class, but how does the User see, create, and modify configuration data for your extension?

Valence offers you the choice of either of these approaches:

  1. Handing Valence a structured representation of your configuration that Valence will build into a simple web form and allow Users to populate.

  2. Defining a custom Lightning component that Valence will instantiate and embed in its user interface for Users to interact with when they choose to configure your extension.

Both are equally viable. If your configuration is nuanced or complex, or needs to pull extra data in (such as populating picklist fields) you’ll want to go with a custom component.

The user will be able to configure your extension differently for each Link (or even each Mapping in the case of certain Filter extensions). Valence will store the configuration data provided by the User, and hand it to your Apex class at the appropriate moments.

Configuration Hierarchy

There are special fields on Adapter__mdt and Filter__mdt that allow you to specify additional configuration values. The format should be a JSON object with key value pairs (nested objects are fine).

You can use this layer of configuration to set up default values or configuration values that are independent of any particular Link.

During execution, Valence will merge any configurations that were defined by the user at the Link level with the configurations on these two custom metadata types, with the Link-level configurations overriding the independent values in case of a conflict (this allows you to have admin users override your default values per-Link if need be).

The configuration data handed to your extension at runtime will be the merge result of these two different layers of configuration data.