Add-on configuration
Configuration options per add-on
Add-on configuration
An add-on can expose configurable settings to the end user through a configurationSchema. The schema is a JSON Schema document that you upload in the Developer Platform. Once the add-on is published, eLab marketplace users open the Configure dialog on the add-on's detail page, and the schema is rendered as a form they fill in.
A typical use is to let users provide an API key or other per-user/per-group setting without the add-on author hardcoding it.
Where the settings are saved
A saved configuration is stored at the scope of the add-on's installation:
- Installation scope
USER— settings are saved per user. - Installation scope
GROUP— settings are saved per group. - Installation scope
SYSTEM— settings are saved once for the whole system (editable by admins only).
Uploading the configurationSchema
Upload the configurationSchema in the Code section of the add-on detail page in the Developer Platform. (For side-loading, see Testing configuration during side-loading.)
The Code section of the add-on detail page, showing the configurationSchema upload field.
Once the add-on is published, a Configure action appears on its detail page in the marketplace.
The marketplace add-on detail page with the Configure action available to the user.
Opening Configure renders the schema as a form. Users adjust the values to fit their needs; default values (see Default configuration values) are used as a starting point. The saved configuration is what the add-on reads at runtime in the eLab environment.
The Configure dialog rendering the schema as a form the user can fill in.
Configuration is persisted by the platform only after the add-on is published to the marketplace. While side-loading, nothing is stored on the server — see Testing configuration during side-loading for a pattern to exercise configuration-dependent code locally.
Permissible types and formats
Each property you declare in the configurationSchema is rendered as a form control in the marketplace Configure dialog. Rendering is handled by the JSON Editor library, so any valid JSON Schema construct it recognises is available to you.
Supported types and formats
Every property must declare a type. For string, an optional format selects a more specific input — format is passed straight through to the HTML <input type="…"> attribute, so any HTML5 input type works. The enum? column below indicates rows where the rendering also depends on an enum constraint being present.
type | format | enum? | Rendered as | Use for |
|---|---|---|---|---|
string | — | Single-line text input | Free-form text | |
string | — | yes | Dropdown (<select>) | Fixed-value choice |
string | password | <input type="password"> — input is obfuscated | API keys, secrets, tokens | |
string | email | <input type="email"> with browser validation | Email addresses | |
string | url | <input type="url"> with browser validation | Links | |
string | tel | <input type="tel"> | Phone numbers | |
string | search | <input type="search"> | Search strings | |
string | color | Colour picker | Hex colour value | |
string | date | Date picker | YYYY-MM-DD | |
string | datetime-local | Date-and-time picker | Local ISO timestamp | |
string | month | Month picker | YYYY-MM | |
string | week | Week picker | YYYY-Www | |
string | time | Time picker | HH:MM | |
string | textarea | Multi-line <textarea> | Long text | |
integer | — | Numeric input (whole numbers) | Integer values | |
integer | range | Slider — pair with minimum / maximum | Bounded whole-number value | |
number | — | Numeric input (decimals) | Floating-point values | |
number | range | Slider — pair with minimum / maximum | Bounded decimal value | |
boolean | — | Dropdown with "true" / "false" options | Uncommon — prefer the checkbox format below | |
boolean | checkbox | Checkbox | True/false toggle | |
array | — | Repeater list editor | Dynamic list of values (see also Multi-select from a fixed set below) | |
object | — | Nested group of controls | Structured/grouped configuration | |
null | — | (no control) | Valid JSON Schema, rarely useful here |
Example: obfuscating a sensitive field
To stop an API key or token being visible when a user pastes it into the Configure dialog, declare the property as a string with format: "password":
{
"apiKey": {
"type": "string",
"format": "password",
"title": "Provider API key",
"description": "Secret key used to authenticate with the external provider."
}
}Combined example
A realistic schema typically mixes several of the types and formats above:
{
"apiKey": {
"type": "string",
"format": "password",
"title": "Provider API key"
},
"logLevel": {
"type": "string",
"enum": ["debug", "info", "warn", "error"],
"title": "Log level",
"default": "info"
},
"notificationsEnabled": {
"type": "boolean",
"title": "Send notifications"
},
"retryCount": {
"type": "integer",
"minimum": 0,
"maximum": 10,
"title": "Retry attempts",
"required": false
}
}The uploaded file is a flat map of property-name → property-definition. Do not put a root-level "required": [...] array in the file — the marketplace wraps your file as the properties of an internal object, so a root-level entry would be treated as a property named required. To mark a single field as optional, set "required": false on that property (as shown on retryCount above).
Multi-select from a fixed set
To let users pick several values from a fixed list, combine array with uniqueItems: true and an items.enum whose items.type is string, number, or integer:
{
"enabledModules": {
"type": "array",
"uniqueItems": true,
"items": {
"type": "string",
"enum": ["inventory", "experiments", "protocols"]
}
}
}The control renders as a checkbox list when the enum has fewer than eight entries, and as a <select multiple> for longer enums. To force the checkbox rendering regardless of count, add "format": "checkbox" (singular) on the array property.
Validation and UI hints
The marketplace honours the standard JSON Schema constraints below. Use them to guide users and prevent invalid values being saved:
title— label shown above the control (falls back to the property key).description— helper text shown below the control.default— initial value before the user edits.required— every property in your schema is treated as required by default. To make a field optional, set"required": falseon that property itself (see theretryCountentry in the combined example above). A root-level"required": [...]array does not work here because the marketplace embeds your file as thepropertiesof an internal wrapper object.enum— restrict a field to a list of values (renders as a dropdown forstring).minLength/maxLength— character bounds for strings.pattern— regex validation for strings.minimum/maximum— numeric bounds forinteger/number.
Default configuration values
Alongside the configurationSchema, the Developer Platform offers a second upload: the default configuration. This is a plain JSON object whose keys match the properties declared in your schema and whose values populate the Configure dialog before the user edits anything. It is distinct from the per-property default keyword above — the schema-level default is a hint for an individual property, whereas this file provides the full initial instance shown to the user.
Uploading a default configuration is optional. Example matching the combined schema above:
{
"apiKey": "",
"logLevel": "info",
"notificationsEnabled": false,
"retryCount": 3
}The Developer Platform can also generate a sample default configuration file from your schema for you to use as a starting point.
Testing configuration during side-loading
The side-loading loader invokes your add-on's init() function with no arguments — it does not pass any configuration, read configurationSchema(), or open the Configure dialog. Those only exist in production, after the add-on is published. This means a configuration-dependent add-on cannot be exercised during side-loading without a small convention on your side.
The recommended pattern is to attach the schema and default values to your add-on's root variable, and to fall back to those defaults inside init() whenever no configuration argument is passed. In production the platform calls init(configuration, addonContext) — configuration is the saved configuration (or the default configuration if no per-user/group/system value has been saved yet), and addonContext is an object containing metadata such as the add-on's sdkPluginID and scope. If neither a saved configuration nor a default configuration exists, the platform passes configuration as undefined, so the same fallback covers both the side-loading case and the first-run production case.
var MY_ADDON = {};
(function (context) {
context.init = function (configuration, addonContext) {
// Use the configuration passed by the platform, or fall back to the
// defaults attached below if none was passed. This handles both
// side-loading (no argument) and the first-run production case
// (argument passed as undefined).
const cfg = configuration || context.configurationValues || {};
const { organizationName, showWelcomeMessage } = cfg;
// …the rest of your add-on…
};
})(MY_ADDON);
// ---- Side-loading-only scaffolding ----
// Same shape as the configurationSchema.json you will upload to the Developer Platform.
MY_ADDON.configurationSchema = function () {
return {
organizationName: {
type: 'string',
title: 'Organization name',
default: 'Default Organization'
},
showWelcomeMessage: {
type: 'boolean',
title: 'Show welcome message',
default: true
}
};
};
// Same shape as the defaultConfiguration.json you will upload to the Developer Platform.
MY_ADDON.configurationValues = {
organizationName: 'Acme Research Lab',
showWelcomeMessage: true
};Moving to the Developer Platform
When you are ready to publish, migrate the scaffolding to the two platform uploads:
- Copy the object returned by
MY_ADDON.configurationSchema()— the flat map of property definitions — into a file namedconfigurationSchema.jsonand upload it in the Code section of the add-on detail page. The platform re-injects it on the rootVar at sync time, so the localMY_ADDON.configurationSchema = function () { … }assignment can be removed from the uploaded script. - Copy the object assigned to
MY_ADDON.configurationValuesinto a file nameddefaultConfiguration.jsonand upload it as the Default configuration. The localMY_ADDON.configurationValues = { … }assignment is not read by the platform and can be removed too. - The fallback chain inside
init()(const cfg = configuration || context.configurationValues || {};) is worth keeping after publishing. In production it still protects against the first-run case — where the platform passesconfigurationasundefinedbecause neither a saved configuration nor a default configuration exists yet — and it also means you can return to side-loading the same code without edits.
Migrating from the legacy in-code configurationSchema
If you have done previous add-on development for eLab, you might have gotten used to declaring the configurationSchema inside the add-on code. This has been changed to the current way of uploading the configurationSchema in the Developer Platform, to make it more visible and easier to manage. The recipe below shows how the configurationSchema was previously set in the add-on code and which elements have to be removed from the code and moved to JSON Schema in the Developer Platform.
Updated 18 days ago