
Commerce App Business Config
- 66 installs
- 13 repo stars
- Updated August 4, 2026
- adobe/aio-commerce-sdk
commerce-app-business-config is a Claude Code skill that manages typed merchant-configurable settings in the businessConfig.schema of an Adobe Commerce app.
About
commerce-app-business-config manages custom business configuration in an Adobe Commerce app built with the aio-commerce-sdk. A developer uses it to add, modify, or remove merchant-configurable settings exposed through Commerce Admin. It creates typed config fields (text, password, email, url, tel, boolean, list) in the businessConfig.schema of app.commerce.config.ts and applies per-type validation before writing. It requires a base app initialized with commerce-app-init.
- Adds merchant-configurable settings to an Adobe Commerce app
- Creates typed config fields in businessConfig.schema rendered in Commerce Admin
- Enforces per-type validation rules before writing config
Commerce App Business Config by the numbers
- 66 all-time installs (skills.sh)
- Ranked #3,104 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
commerce-app-business-config capabilities & compatibility
- Capabilities
- commerce config · admin config fields · config validation
- Use cases
- api development
- Pricing
- Free
What commerce-app-business-config says it does
Manage custom business configuration in an Adobe Commerce app.
Each entry in the schema defines one merchant-configurable setting that Commerce Admin will render as a UI field.
npx skills add https://github.com/adobe/aio-commerce-sdk --skill commerce-app-business-configAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 66 |
|---|---|
| repo stars | ★ 13 |
| Last updated | August 4, 2026 |
| Repository | adobe/aio-commerce-sdk ↗ |
What it does
Add typed merchant-configurable settings to an Adobe Commerce app's businessConfig.schema, rendered in Commerce Admin.
Who is it for?
Adding, modifying, or removing merchant-configurable settings (config fields) exposed through Commerce Admin.
Skip if: Configuring other extensibility domains like webhooks or events, which have their own skills.
When should I use this skill?
A user wants to add or change admin config fields or store configuration in an Adobe Commerce app.
What you get
Typed, validated config fields written into app.commerce.config.ts's businessConfig.schema.
- typed businessConfig.schema entries in app.commerce.config.ts
By the numbers
- 7 field types (list, text, password, email, url, tel, boolean)
- requires Node.js 22+
Files
Configure Commerce App Business Config
Adds or modifies the businessConfig.schema array in an existing app.commerce.config.ts. Each entry in the schema defines one merchant-configurable setting that Commerce Admin will render as a UI field. Other extensibility domains (webhooks, events) are added separately via their own skills.
Prerequisites
- Verify the app is scaffolded and initialized, not merely that the config exists. Require both:
app.commerce.config.tspresent in the project root, and- the project initialized — signalled by the generated
src/commerce-extensibility-1/directory and installednode_modules(the@adobe/aio-commerce-lib-appdependency). - If
app.commerce.config.tsis missing, stop and invokecommerce-app-initfirst (it writes the config, then runs init). - If the config is present but the project is not initialized (no
src/commerce-extensibility-1/ornode_modules), runnpx @adobe/aio-commerce-lib-app initbefore continuing. Init is idempotent — it finds the existing config, skips the interactive prompts, installs dependencies, and generates the project files.
Step 1 — Understand intent
For each setting the user wants to expose, gather:
- Name — machine identifier for the field (used as the config key read by the app at runtime)
- Type — one of:
list,text,password,email,url,tel,boolean - Label (optional) — human-readable label shown in Admin
- Description (optional) — help text shown alongside the field in Admin
- Default value (optional, type-dependent — see constraints in Step 2)
- For
listfields additionally: `selectionMode` ("single"or"multiple") and `options` (each with alabelandvaluestring)
Step 2 — Derive config values
Apply the following per-type validation rules before writing. Surface any issues to the user before proceeding.
| Field | Constraint |
|---|---|
name | Required, non-empty string |
type | Required; one of list, text, password, email, url, tel, boolean |
label | Optional string |
description | Optional string |
list.selectionMode | Required for list fields: "single" or "multiple" |
list.options | Required for list fields; each option needs both label and value strings |
list/single default | Required; must match one of the option value strings (non-empty) |
list/multiple default | Optional array of strings (defaults to []); each element must match an option value |
text default | Optional string (defaults to "") |
password default | Must be "" — any non-empty default is rejected to prevent secrets in config |
email default | Optional; "" or a fully valid email address |
url default | Optional; "" or a fully valid absolute URL |
tel default | Optional; "" or matches /^\+?[0-9\s\-()]+$/ (digits, spaces, hyphens, parens, optional +) |
boolean default | Optional boolean (defaults to false) |
businessConfig.schema must contain at least one field — an empty array is rejected at build time.
Step 3 — Update app.commerce.config.ts
Add (or merge into) the top-level businessConfig.schema array, preserving all other domains. If the config already has a businessConfig key, append to businessConfig.schema rather than replacing it.
Minimal examples:
businessConfig: {
schema: [
// Password (masked input — API keys, secrets)
{ name: "api_key", type: "password", label: "API Key", default: "" },
// Single-select list
{
name: "region", type: "list", selectionMode: "single",
label: "Region",
options: [{ label: "EU", value: "eu" }, { label: "US", value: "us" }],
default: "eu", // required; must match an option value
},
// Boolean toggle
{ name: "debug_mode", type: "boolean", label: "Enable Debug Mode", default: false },
// Dynamic list — options resolved at runtime via a factory that receives the action's params.
// Required `default` factory for single-select; optional for multiple (falls back to []).
{
name: "paymentMethod", type: "dynamicList", selectionMode: "single",
label: "Default Payment Method",
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,
},
],
}See assets/business-config.ts for the full reference showing all field types.
Step 4 — Register the extension point
Run init so that commerce/configuration/1 is added to app.config.yaml and install.yaml, and the required @adobe/aio-commerce-lib-config dependency is installed. This is idempotent — safe to run even if the extension is already registered.
npx @adobe/aio-commerce-lib-app initStep 5 — Validate
Build the project to confirm the updated config is valid:
aio app buildA build failure with a validation error points directly to the offending field.
Reading config in runtime actions
Use @adobe/aio-commerce-lib-config to read the values merchants set in Commerce Admin. The library must be initialized with the generated schema on every action invocation before any config call.
Basic pattern
import {
initialize,
getConfigurationByKey,
getConfiguration,
byCodeAndLevel,
} from "@adobe/aio-commerce-lib-config";
// Schema is generated by `aio app build` into .generated/configuration-schema.json
// under the commerce-configuration-1 extension; adjust the relative path for your action.
import schema from "../../.generated/configuration-schema.json" with { type: "json" };
export async function main(params) {
await initialize({ schema });
// Read a single field — config is null if the key has never been set
const { config } = await getConfigurationByKey(
"api_key", // the `name` from your schema
byCodeAndLevel("global", "global"), // scope
);
const apiKey = config?.value ?? "";
// Read all fields for a scope
const { config: allConfig } = await getConfiguration(
byCodeAndLevel("global", "global"),
);
// allConfig is an array of { name, value, origin } entries
return { statusCode: 200, body: { success: true } };
}Scope selectors
| Selector | When to use |
|---|---|
byCodeAndLevel("global", "global") | App-wide settings — applies to all stores |
byCodeAndLevel(storeCode, "store_view") | Per store view (most specific) |
byCode(storeCode) | Resolves using the default level for the scope |
byScopeId(scopeId) | When you have the scope's numeric ID from Commerce |
Values inherit from parent scopes — a field not set on store_view falls back to store, website, then global.
Password fields
aio app build generates AIO_COMMERCE_CONFIG_ENCRYPTION_KEY automatically into .env the first time it encounters a password field (and validates it on subsequent builds). No manual setup needed.
To decrypt values at runtime, the key must be available to the action. Wire it as an input in the action's ext.config.yaml:
inputs:
AIO_COMMERCE_CONFIG_ENCRYPTION_KEY: $AIO_COMMERCE_CONFIG_ENCRYPTION_KEYWith the key in place, getConfigurationByKey returns the plaintext value — no extra decryption code needed.
Common Issues
- `list/single` default missing: Single-select list fields require a
default— it can't be omitted. It must exactly match one of the optionvaluestrings. - `defineConfig` not found: Ensure
@adobe/aio-commerce-lib-appis installed anddefineConfigis imported from@adobe/aio-commerce-lib-app/config.
Quality Bar
aio app buildcompletes without errors
Chaining
After aio app build passes:
- Add webhook interceptors — invoke
commerce-app-webhooksto intercept Commerce operations before or after they execute - Add event subscriptions — invoke
commerce-app-eventingto subscribe to Commerce or external events
References
- assets/business-config.ts — Reference config showing all field types with inline constraint comments
import { defineConfig } from "@adobe/aio-commerce-lib-app/config";
export default defineConfig({
metadata: {
id: "my-commerce-app", // alphanumeric + hyphens only, max 100 chars
displayName: "My Commerce App", // shown in App Management UI, max 50 chars
description: "A Commerce app built with aio-commerce-sdk.", // max 255 chars
version: "1.0.0", // Major.Minor.Patch only, no pre-release identifiers
},
businessConfig: {
schema: [
// Single-select list — merchant picks one value from a fixed set
{
name: "shipping_provider", // required, non-empty; used as config key at runtime
type: "list",
selectionMode: "single", // "single" or "multiple"
label: "Shipping Provider", // optional; shown as field label in Admin
description: "Select the active shipping provider.", // optional; shown as help text
options: [
// required for list fields; each option needs both label and value
{ label: "FedEx", value: "fedex" },
{ label: "UPS", value: "ups" },
{ label: "DHL", value: "dhl" },
],
default: "fedex", // required for single; must exactly match one of the option values
},
// Multi-select list — merchant picks one or more values
{
name: "enabled_payment_methods",
type: "list",
selectionMode: "multiple",
label: "Enabled Payment Methods",
options: [
{ label: "Credit Card", value: "cc" },
{ label: "PayPal", value: "paypal" },
{ label: "Apple Pay", value: "apple_pay" },
],
default: ["cc", "paypal"], // optional array; defaults to []; each must match an option value
},
// Text — free-form string input
{
name: "store_code",
type: "text",
label: "Store Code",
description: "Internal identifier for this store.",
default: "", // optional string; defaults to ""
},
// Password — masked input for secrets; shown as *** in Admin
{
name: "api_key",
type: "password",
label: "API Key",
description: "Secret key for the external service.",
default: "", // must be "" — non-empty defaults are rejected to prevent secrets in config
},
// Email — validated email address input
{
name: "notification_email",
type: "email",
label: "Notification Email",
default: "", // "" or a fully valid email address (e.g. "admin@example.com")
},
// URL — validated absolute URL input
{
name: "webhook_endpoint",
type: "url",
label: "Webhook Endpoint",
default: "", // "" or a fully valid absolute URL (e.g. "https://service.example.com/hook")
},
// Tel — phone number input
{
name: "support_phone",
type: "tel",
label: "Support Phone",
default: "", // "" or matches /^\+?[0-9\s\-()]+$/ (e.g. "+1 (800) 555-0100")
},
// Boolean — toggle switch
{
name: "debug_mode",
type: "boolean",
label: "Enable Debug Mode",
default: false, // optional boolean; defaults to false
},
// Dynamic list — options resolved at runtime via a factory.
// Use when option values depend on merchant-specific data (e.g. payment
// methods enabled in the merchant's Commerce store). Any credentials the
// factory uses must be declared as `inputs` for the action that resolves
// the schema in that action's `ext.config.yaml`.
{
name: "default_payment_method",
type: "dynamicList",
selectionMode: "single",
label: "Default Payment Method",
// Receives the action's runtime params; may be sync or async.
// Example: `await fetchPaymentMethods(params.PAYMENT_API_KEY)` then
// map each entry to `{ label, value }`.
options: () => [{ label: "Credit Card", value: "cc" }],
// Required for single-select; optional for "multiple" (defaults to []).
default: (resolvedOptions) => resolvedOptions[0].value,
},
],
},
});
{
"skill_name": "commerce-app-business-config",
"evals": [
{
"id": 1,
"prompt": "My Commerce app needs to call an external tax service. Add a business config field so merchants can enter their tax service API key in Commerce Admin.",
"expected_output": "The agent adds a businessConfig.schema entry of type 'password' to app.commerce.config.ts. The entry has a name, type: 'password', and default: ''. No non-empty default is set. aio app build completes without errors.",
"assertions": [
"app.commerce.config.ts contains a businessConfig.schema array",
"At least one entry has type: 'password'",
"The password entry has default: '' (empty string only)",
"The password entry has a non-empty name field",
"aio app build completes without errors"
]
},
{
"id": 2,
"prompt": "Add two settings to my Commerce app: a dropdown so merchants can choose their region (EU, US, or APAC), and a toggle to enable or disable a beta feature.",
"expected_output": "The agent adds two businessConfig.schema entries: one of type 'list' with selectionMode 'single', three options, and a valid default matching one of the option values; and one of type 'boolean' with default false. aio app build completes without errors.",
"assertions": [
"app.commerce.config.ts contains a businessConfig.schema array with at least two entries",
"One entry has type: 'list' and selectionMode: 'single'",
"The list entry has an options array with at least one { label, value } entry",
"The list entry default matches one of the option values",
"One entry has type: 'boolean'",
"aio app build completes without errors"
]
},
{
"id": 3,
"prompt": "Set up business config for my Commerce app with the following merchant settings: a notification email address, the URL of an external fulfillment service, a support phone number, and a free-text field for a custom store identifier.",
"expected_output": "The agent adds four businessConfig.schema entries of types email, url, tel, and text respectively. All have name and type fields. Defaults are '' or omitted. After build passes, the agent suggests commerce-app-webhooks or commerce-app-eventing as next steps.",
"assertions": [
"app.commerce.config.ts contains a businessConfig.schema array with at least four entries",
"One entry has type: 'email'",
"One entry has type: 'url'",
"One entry has type: 'tel'",
"One entry has type: 'text'",
"aio app build completes without errors",
"Agent mentions commerce-app-webhooks or commerce-app-eventing as next steps"
]
}
]
}
Related skills
FAQ
What field types are supported?
text, password, email, url, tel, boolean, and list.
Is a base app required?
Yes. It requires an app scaffolded and initialized with commerce-app-init, signalled by app.commerce.config.ts plus the generated src/commerce-extensibility-1/ directory.