Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .markdownlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ MD033:
- RedoclyAPIBlock
- Resources
- SuperHero
- Tab
- InlineAlert
- GetCredential
- Details
Expand Down
124 changes: 109 additions & 15 deletions src/pages/app-management/configuration-schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ This `businessConfig` schema contains the following properties:
| `type` | string | Yes | Field type. See [Supported types](#supported-field-types). |
| `default` | varies | No | Default value. Must match the field type. |
| `description` | string | No | Help text displayed below the field. |
| `options` | array | Conditional | Required for `list`. Defines available options to be displayed in the dropdown list. |
| `selectionMode` | string | Conditional | Required for `list`. Set to `single` for standard dropdown or `multiple` to allow multiple selections. |
| `options` | array or function | Conditional | Required for `list` and `dynamicList`. For `list`, an array of `{ label, value }` objects. For `dynamicList`, an async function that receives runtime action `params` and returns that array. |
| `selectionMode` | string | Conditional | Required for `list` and `dynamicList`. Set to `single` for standard dropdown or `multiple` to allow multiple selections. |
| `env` | array | No | Limits the field to **PaaS** (`paas`) or **SaaS** (`saas`). To enable the field to all environments, omit the field or specify both values. |

## Supported field types
Expand All @@ -87,6 +87,7 @@ The following field types are available for your `businessConfig` schema:
| `tel` | string | Phone number input with format validation |
| `url` | string | URL input with validation |
| `list` | string | Dropdown with preconfigured options |
| `dynamicList` | string | Dropdown with options resolved at runtime. Requires `@adobe/aio-commerce-lib-config` version **1.6.0** or later. See [Dynamic list fields](#dynamic-list-fields). |

### Password field encryption

Expand Down Expand Up @@ -179,6 +180,28 @@ For fields that allow multiple selections, set `selectionMode` to `multiple` and
}
```

### Dynamic list fields

Use `dynamicList` when dropdown options depend on data that is only available at runtime—for example, payment methods returned by an external API. The `options` property must be an async function that receives the runtime action `params` and returns an array of `{ label, value }` objects. You can set `default` to a function that receives the resolved options and returns the default value.

```js
{
name: "paymentMethod",
label: "Default Payment Method",
type: "dynamicList",
selectionMode: "single",
options: async (params) => {
const methods = await fetchPaymentMethods(params.SOME_API_KEY);
return methods.map((m) => ({ label: m.title, value: m.code }));
},
default: (resolvedOptions) => resolvedOptions[0].value,
}
```

When your schema includes a `dynamicList` field, the `options` function may read values from runtime action inputs (such as API keys). Add those inputs to every action that calls `initialize`, including the generated `app-config` and `config` actions. See [Configure action inputs for dynamic lists](#configure-action-inputs-for-dynamic-lists).

Because `dynamicList` options are resolved at runtime, `initialize` must be **awaited** and passed the action `params`. See [Initialize with and without dynamic lists](#initialize-with-and-without-dynamic-lists).

## Scope tree synchronization

Apps with `businessConfig` use a scope tree (Global, Commerce websites, stores, and store views) when merchants configure settings in App Management. That tree reflects Adobe Commerce scope structure **as of the last sync**. It is **not** kept in lockstep with Commerce automatically.
Expand All @@ -205,48 +228,119 @@ Your `app.commerce.config` is validated each time you run a `generate` command (

## Retrieve configuration at runtime

Use `getConfigurationByKey` from the configuration library (together with `getConfiguration` and `setConfiguration` when you need full documents or writes) to access configuration values in your runtime actions.
Use `getConfiguration`, `getConfigurationByKey`, and `setConfiguration` from `@adobe/aio-commerce-lib-config` to read or write configuration values in your App Builder runtime actions.

<InlineAlert variant="info" slots="text"/>

Every runtime action that calls `getConfiguration`, `getConfigurationByKey`, or `setConfiguration` must call `initialize` first. Initialization is **per action invocation**; not once per deployment. If you add a new action that uses any of those three methods, add `initialize` at the start of that action’s `main` handler as well.

The schema is held in memory only for that invocation. If you omit `initialize`, those configuration functions throw errors. See [Initialization](https://github.com/adobe/aio-commerce-sdk/blob/main/packages/aio-commerce-lib-config/docs/usage.md#initialization) in the configuration library usage guide.

#### Initialize with and without dynamic lists

<Tab orientation="horizontal" slots="heading, content" repeat="2"/>

### Without dynamicList

When your schema has **no** `dynamicList` fields, call `initialize` synchronously at the start of the action. You can pass the schema from your root `app.commerce.config` file or from the generated JSON file:

```js
import { initialize } from "@adobe/aio-commerce-lib-config";
import schema from "path/to/your/generated/config-schema.json";

export async function main(params) {
initialize({ schema });
}
```

Before you run `getConfiguration`, `getConfigurationByKey`, or `setConfiguration`, call `initialize` with your generated configuration schema. The schema is kept in memory for that action invocation. Import the generated `configuration-schema.json` from your `commerce/configuration/1` extension (the path relative to your action depends on your project layout).
### With dynamicList

If you skip `initialize`, see [Initialization](https://github.com/adobe/aio-commerce-sdk/blob/main/packages/aio-commerce-lib-config/docs/usage.md#initialization) in the configuration library usage guide for more information.
When your schema includes a `dynamicList` field (requires `@adobe/aio-commerce-lib-config` version **1.6.0** or later), `options` and `default` are resolved at runtime. **Await** `initialize` and pass the action `params`. Use the live schema from `app.commerce.config` (not the generated JSON) so async `options` and `default` functions remain available:
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This mentions "not the generated JSON" as if it was an option. I would emphasize that using the generated JSON is not an option in the first place because it doesn't get generated at all (when using dynamicList), because a JSON can't hold a function value.


```js
import { initialize } from "@adobe/aio-commerce-lib-config";
import appConfig from "#app.commerce.config";
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add a comment that this #app.commerce.config is only available when using dynamicList? I'll try to make it work also when it's not present as it would not be a breaking change, but in the meantime, just in case.


export async function main(params) {
await initialize({ schema: appConfig.businessConfig.schema, params });
}
```

A **scope selector** tells the library which node in the scope tree to read or write. That tree can include **Adobe Commerce** scopes (such as websites and store views, each with a scope code and a **level** in the hierarchy), **custom scopes** you create in App Management (code only; see below), **global** scope, and other nodes that your app or merchants configure.

When the target scope has both a code and a level, which is typical for Commerce store and website scopes, use `byCodeAndLevel`.

The following examples show only the configuration calls. In your action, run `initialize` before these calls. For a full runtime action example, see [Using configuration in runtime actions](https://github.com/adobe/aio-commerce-sdk/blob/main/packages/aio-commerce-lib-config/docs/usage.md#using-configuration-in-runtime-actions) in the usage guide.

```js
import { getConfigurationByKey, byCodeAndLevel } from "@adobe/aio-commerce-lib-config";
import { initialize, getConfigurationByKey, byCodeAndLevel } from "@adobe/aio-commerce-lib-config";
import appConfig from "#app.commerce.config";

async function main(params) {
initialize({ schema: appConfig.businessConfig.schema });

const storeCode = params.store_code || "default";
const storeLevel = params.store_level || "store_view";

// Use values in your app logic
const { config: { value: endpoint } } = await getConfigurationByKey("api-endpoint", byCodeAndLevel(storeCode, storeLevel));
const { config: { value: apiKey } } = await getConfigurationByKey("api-key", byCodeAndLevel(storeCode, storeLevel), {
encryptionKey: params.AIO_COMMERCE_CONFIG_ENCRYPTION_KEY,
});
}
```

**Custom scopes** created in the App Management UI are identified by **code only**. They do not define a separate **level** in the tree. For those scopes you must use **`byCode("your-custom-scope-code")`**. `byCodeAndLevel` is not used for custom scopes because there is no level to pass. See the configuration library [usage](https://github.com/adobe/aio-commerce-sdk/blob/main/packages/aio-commerce-lib-config/docs/usage.md) for more information.
Custom scopes created in the App Management UI are identified by **code only**. They do not define a separate level in the tree. For those scopes you must use `byCode("your-custom-scope-code")`. `byCodeAndLevel` is not used for custom scopes because there is no level to pass. See the configuration library [usage](https://github.com/adobe/aio-commerce-sdk/blob/main/packages/aio-commerce-lib-config/docs/usage.md) for more information.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to add the byWebsiteId, byStoreId and byStoreViewId and we support also?
@iivvaannxx it was released right?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good point, I forgot we added those (and yes, they were released last week). @danidelcar Find documentation of them here, they are not a critical thing, so don't sweat it.


```js
import { getConfigurationByKey, byCode } from "@adobe/aio-commerce-lib-config";
import { initialize, getConfigurationByKey, byCode } from "@adobe/aio-commerce-lib-config";
import appConfig from "#app.commerce.config";
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution there, as said in the comment above, this alias only works for now thanks to the code generation path executed when at least one dynamicList field is present.


async function main(params) {
initialize({ schema: appConfig.businessConfig.schema });

const { config: { value: endpoint } } = await getConfigurationByKey(
"api-endpoint",
byCode("your-custom-scope-code"),
);
const { config: { value: endpoint } } = await getConfigurationByKey(
"api-endpoint",
byCode("your-custom-scope-code"),
);
}
```

### Global scope and selectors

`getConfiguration`, `getConfigurationByKey`, and `setConfiguration` accept an **optional** scope selector. When you omit it, the library resolves the **global** scope.

### Configure action inputs for dynamic lists

When a `dynamicList` field reads runtime inputs (for example, `params.SOME_API_KEY`), declare those inputs on every action that calls `initialize`—including generated App Management actions and any custom runtime actions that use `@adobe/aio-commerce-lib-config`.

<Tab orientation="horizontal" slots="heading, code" repeat="2"/>

### app-config

```yaml
# src/commerce-extensibility-1/ext.config.yaml
actions:
app-config:
# ... other settings
inputs:
LOG_LEVEL: $LOG_LEVEL
SOME_API_KEY: $SOME_API_KEY
```

### config

```yaml
# src/commerce-configuration-1/ext.config.yaml
actions:
config:
# ... other settings
inputs:
LOG_LEVEL: $LOG_LEVEL
SOME_API_KEY: $SOME_API_KEY
```

Define the corresponding variable in your `.env` file (for example, `SOME_API_KEY=your-key`). Never commit `.env` to version control.

Repeat this step for **each custom runtime action** that calls `initialize` when your schema includes `dynamicList` fields.

For more patterns and API detail, see the configuration library [usage](https://github.com/adobe/aio-commerce-sdk/blob/main/packages/aio-commerce-lib-config/docs/usage.md) documentation in the Adobe Commerce SDK repository.

## Tutorial
Expand Down
8 changes: 8 additions & 0 deletions src/pages/app-management/initialize-app.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,14 @@ The initialization process:
* Generates all required artifacts (`commerce/configuration/1` resources are only generated when `businessConfig` is defined)
* Updates `app.config.yaml` and `install.yaml` with the appropriate extension references. Creates these files if they do not exist.

## Initialize the configuration library in runtime actions

When your app defines `businessConfig`, each App Builder runtime action that calls `getConfiguration`, `getConfigurationByKey`, or `setConfiguration` must run `initialize` before any of those three methods.

If your schema includes `dynamicList` fields, you must **await** `initialize` and pass runtime action `params`. See [Initialize with and without dynamic lists](./configuration-schema.md#initialize-with-and-without-dynamic-lists) and [Configure action inputs for dynamic lists](./configuration-schema.md#configure-action-inputs-for-dynamic-lists).

See [Retrieve configuration at runtime](./configuration-schema.md#retrieve-configuration-at-runtime) for an example.

## CLI commands

The library provides the following CLI commands. Replace `npx` with your package manager of preference, using the below equivalents:
Expand Down
12 changes: 12 additions & 0 deletions src/pages/app-management/troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,18 @@ Only Admin users whose **role** includes the **App Management** resource can use

For the full association and installation workflow, see [Manage your app](https://experienceleague.adobe.com/en/docs/commerce/app-management/manage-app/manage-app).

## Initialize the configuration library in runtime actions

When your app defines `businessConfig`, each App Builder runtime action that calls `getConfiguration`, `getConfigurationByKey`, or `setConfiguration` must run `initialize` before any of those three methods.
Comment thread
danidelcar marked this conversation as resolved.

An error message appears when you do not call `initialize` before any of those three methods:

```text
Schema not initialized. Call initialize({ schema }) before using configuration functions.
```

See [Retrieve configuration at runtime](./configuration-schema.md#retrieve-configuration-at-runtime) for an example.

## Local Adobe Commerce instances

App Management is **not supported** for local Adobe Commerce development instances. Association, installation, and workflows in the Admin require an Adobe Commerce deployment that App Management can integrate with.
Expand Down
6 changes: 3 additions & 3 deletions src/pages/contributors.json
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,7 @@
"https://avatars.githubusercontent.com/u/47715589?v=4",
"https://avatars.githubusercontent.com/u/71198017?v=4"
],
"lastUpdated": "5/28/2026"
"lastUpdated": "6/1/2026"
},
{
"page": "/app-management/define-app",
Expand All @@ -506,7 +506,7 @@
"https://avatars.githubusercontent.com/u/12731225?v=4",
"https://avatars.githubusercontent.com/u/47715589?v=4"
],
"lastUpdated": "5/22/2026"
"lastUpdated": "6/1/2026"
},
{
"page": "/app-management/installation/",
Expand Down Expand Up @@ -558,7 +558,7 @@
"https://avatars.githubusercontent.com/u/12731225?v=4",
"https://avatars.githubusercontent.com/u/47715589?v=4"
],
"lastUpdated": "5/22/2026"
"lastUpdated": "5/29/2026"
},
{
"page": "/config",
Expand Down
Loading