Skip to content
Commerce Boilerplate

Configuration

The AEM Commerce boilerplate requires configuration to connect to your Adobe Commerce instance and customize the storefront behavior.

The boilerplate uses multiple configuration files depending on your deployment stage:

  • Local development - Copy of the demo configuration for Commerce backend connection
  • Production deployment - Configuration Service with template files for site setup
  • Drop-in initialization - Initializer files in scripts/initializers/

Which endpoints you set depends on your Commerce backend:

  • Adobe Commerce as a Cloud Service — Set only commerce-endpoint to the GraphQL endpoint URL for that service.
  • Adobe Commerce Optimizer — Set commerce-endpoint to the Adobe Commerce Optimizer GraphQL URL for the catalog, and set commerce-core-endpoint to your Commerce core endpoint URL (for example, Commerce PaaS or another Adobe Commerce host you manage).

For full details and examples, see Storefront configuration.

For local development, you can use the demo configuration for the boilerplate as a starting point. The live demo configuration is available at https://main--aem-boilerplate-commerce--hlxsites.aem.live/config.json and connects to the sample Commerce backend for the boilerplate:

{
"public": {
"default": {
"commerce-core-endpoint": "https://www.aemshop.net/graphql",
"commerce-endpoint": "https://www.aemshop.net/cs-graphql",
"commerce-assets-enabled": false,
"headers": {
"all": {
"Store": "default"
},
"cs": {
"Magento-Store-Code": "main_website_store",
"Magento-Store-View-Code": "default",
"Magento-Website-Code": "base",
"x-api-key": "4dfa19c9fe6f4cccade55cc5b3da94f7",
"Magento-Environment-Id": "f38a0de0-764b-41fa-bd2c-5bc2f3c7b39a"
}
},
"analytics": {
"base-currency-code": "USD",
"environment": "Testing",
"environment-id": "f38a0de0-764b-41fa-bd2c-5bc2f3c7b39a",
"store-code": "main_website_store",
"store-id": 1,
"store-name": "Main Website Store",
"store-url": "https://www.aemshop.net",
"store-view-code": "default",
"store-view-id": 1,
"store-view-name": "Default Store View",
"website-code": "base",
"website-id": 1,
"website-name": "Main Website"
},
"plugins": {
"picker": {
"rootCategory": "YOUR_ROOT_CATEGORY_ID"
}
}
}
}
}
  • Configuration Service (Recommended) - Use the Configuration Service, which stores configuration at https://admin.hlx.page/config/{ORG}/sites/{SITE}/public.json. This approach allows configuration updates without code deployments and is the preferred method for all production sites. See the Config Service setup guide for details.

    If you previously committed config.json to your main branch, you must complete these steps before the Configuration Service takes effect. Edge Delivery serves a config.json file from the repository before it falls back to the Configuration Service, so copying settings into the service alone is not enough until the repository file is gone.

    1. Copy all values from the public section of your repository config.json. That object is what you publish as public.json in the Configuration Service.

    2. POST that JSON to https://admin.hlx.page/config/{ORG}/sites/{SITE}/public.json using the Configuration Service API. Authenticate the request and set the body as described in the Config Service setup guide and the Admin API reference .

    3. Delete config.json from the repository and merge that change into main. After the file no longer exists on main, the CDN can resolve configuration from the Configuration Service instead of the repository copy.

    4. When you verify in a browser, clear session storage for your site in Developer Tools (Application → Session storage), then reload. The storefront caches configuration in session storage, so clearing it avoids stale values after you switch sources. For caching behavior and timing, see Storefront configuration.

  • Repository-based config (local dev and branch testing only) - A config.json file in your repository root is useful for local development and testing on feature branches. Edge Delivery Services will serve this file at /config.json and it will override the Configuration Service. Do not use this approach for production — remove or exclude config.json from your main branch.

The boilerplate includes template configuration files with placeholders for your site setup:

Comprehensive site configuration template for production deployment:

{
"version": 1,
"code": {
"owner": "{ORG}",
"repo": "{REPO}",
"source": {
"type": "github",
"url": "https://github.com/{ORG}/{REPO}"
}
},
"content": {
"source": {
"url": "{CONTENT_SOURCE}",
"type": "onedrive"
}
},
"folders": {
"/products/": "/products/default"
},
"cdn": {
"live": {
"host": "main--{SITE}--{ORG}.aem.live"
},
"preview": {
"host": "main--{SITE}--{ORG}.aem.page"
}
},
"headers": {},
"public": {
"default": {
"commerce-core-endpoint": "{ENDPOINT}",
"commerce-endpoint": "{CATALOG_ENDPOINT}",
"headers": {
"all": {
"Store": "default"
},
"cs": {
"Magento-Store-Code": "{STORE_CODE}",
"Magento-Store-View-Code": "{STORE_VIEW_CODE}",
"Magento-Website-Code": "{WEBSITE_CODE}",
"x-api-key": "{COMMERCE_API_KEY}",
"Magento-Environment-Id": "{COMMERCE_ENVIRONMENT_ID}"
}
},
"analytics": {
"aep-ims-org-id": "{IMS_ORG_ID}",
"aep-datastream-id": "{DATASTREAM_ID}",
"base-currency-code": "USD",
"environment": "Production",
"store-id": "{STORE_ID}",
"store-name": "Main Website Store",
"store-url": "{DOMAIN}",
"store-view-id": "{STORE_VIEW_ID}",
"store-view-name": "Default Store View",
"website-id": "{WEBSITE_ID}",
"website-name": "Main Website"
},
"plugins": {
"picker": {
"rootCategory": "{YOUR_ROOT_CATEGORY_ID}"
}
}
}
},
"robots": {
"txt": "User-agent: *\nAllow: /\nDisallow: /drafts/\nDisallow: /enrichment/\nDisallow: /tools/\nDisallow: /plugins/experimentation/\n\nSitemap: https://{DOMAIN}/sitemap-index.xml"
},
"access": {
"admin": {
"role": {
"config_admin": ["{ADMIN_USER_EMAIL}"]
},
"requireAuth": "auto"
}
}
}

Replace the {PLACEHOLDER} values with your actual configuration.

Content indexing configuration for generating sitemap and enrichment data:

version: 1
indices:
sitemap:
target: /sitemap.json
exclude:
- 'drafts/**'
- 'enrichment/**'
- 'fragments/**'
- 'products/**'
properties:
title:
select: head > meta[property="og:title"]
value: |
attribute(el, 'content')
image:
select: head > meta[property="og:image"]
value: |
attribute(el, 'content')
description:
select: head > meta[name="description"]
value: |
attribute(el, 'content')
template:
select: head > meta[name="template"]
value: |
attribute(el, 'content')
robots:
select: head > meta[name="robots"]
value: |
attribute(el, 'content')
lastModified:
select: none
value: parseTimestamp(headers["last-modified"], "ddd, DD MMM YYYY hh:mm:ss GMT")
enrichment:
target: /enrichment/enrichment.json
include:
- '**/enrichment/**'
properties:
title:
select: head > meta[property="og:title"]
value: |
attribute(el, 'content')
products:
select: head > meta[name="enrichment-products"]
values: |
match(attribute(el, 'content'), '([^,]+)')
categories:
select: head > meta[name="enrichment-categories"]
values: |
match(attribute(el, 'content'), '([^,]+)')
positions:
select: head > meta[name="enrichment-positions"]
values: |
match(attribute(el, 'content'), '([^,]+)')

Sitemap generation configuration:

sitemaps:
default:
source: /sitemap.json
destination: /sitemap-content.xml
lastmod: YYYY-MM-DD

The sitemap reads from the generated sitemap.json (created by default-query.yaml) and outputs an XML sitemap.

Configure individual drop-ins in scripts/initializers/:

import { initializers } from '@dropins/tools/initializer.js';
import { initialize, setEndpoint } from '@dropins/storefront-cart/api.js';
import { initializeDropin } from './index.js';
import { CORE_FETCH_GRAPHQL, fetchPlaceholders } from '../commerce.js';
await initializeDropin(async () => {
// Set Fetch GraphQL (Core)
setEndpoint(CORE_FETCH_GRAPHQL);
// Fetch placeholders
const labels = await fetchPlaceholders('placeholders/cart.json');
const langDefinitions = {
default: {
...labels,
},
};
// Initialize cart
return initializers.mountImmediately(initialize, { langDefinitions });
})();