Multi-Site and Multi-Storefront Architecture on SAP Commerce Cloud
One platform, many faces: the BaseSite/BaseStore/catalog model that underpins every multi-site setup, composable storefront site resolution, and the CCv2 deployment mechanics for running multiple storefront apps, webroots, cookies, and DNS included.
Running several storefronts on one SAP Commerce instance is one of the platform's founding value propositions, and also one of its recurring sources of architectural mess, because "multi-site" is really three independent questions wearing one name: how the data is partitioned (sites, stores, catalogs), how requests are resolved to a site, and how the storefront applications are deployed. Projects that answer all three deliberately get a clean estate; projects that answer only the deployment question get a working demo and a governance problem. This guide takes the three in order, covering both composable and (for the installed base that still runs them) accelerator storefronts.
Layer 1: The Data Model Everyone Shares#
Whatever the frontend, the platform's site model is the same trio:
- CMSSite / BaseSite: the logical site: URL resolution, content catalogs, the unit OCC addresses as
/occ/v2/{baseSite}/... - BaseStore: the commercial configuration: currencies, languages, delivery countries, payment and delivery modes, warehouses. Sites reference stores; several sites can share one store
- Catalogs: product catalogs and content catalogs attached per site, with the sharing topology (single, shared, multi-layered) covered in depth by the content catalog guide in this series
The design questions to settle on a whiteboard before any ImpEx:
- What is actually different between the sites? Only content and branding: share the base store, share the product catalog, split content catalogs. Different assortments: separate product catalogs (or one catalog with visibility mechanics). Different commercial terms (currencies, fulfilment, payment): separate base stores. Working through this table site by site prevents both failure modes: the over-shared setup where France cannot have its own delivery modes, and the over-split one where a price change means six imports.
- Do carts and customers cross sites? Customer accounts are platform-global by default (one uid, usable on every site) but session carts, order history visibility, and consents are site-scoped in the standard flows. If the business expects "one account, one cart, everywhere", that is a requirement to design for explicitly, not an emergent property.
- Who operates what? The multi-site question is organizationally the multi-team question, and the catalog topology plus Backoffice permission model (catalog-version-scoped, per the content catalog guide) is where the org chart becomes configuration.
Promotion isolation belongs on this list too: with site-scoped promotions and carts that never mix sites, one KIE module per site is both correct isolation and a performance win (see the promotion engine guide).
Layer 2: Resolving Requests to Sites#
Composable storefront resolves the site from its context configuration: the baseSite can be static per deployed app, derived from URL parameters (the same urlParameters machinery the store-specific pricing guide extends), or resolved by URL pattern against the CMSSite definitions. The three deployment shapes, in increasing isolation:
| Shape | How | When |
|---|---|---|
| One app, many sites | Site resolved at runtime from URL/domain; one JS storefront build serves all | Sites share design language and release cadence; the cheapest to operate |
| One app, per-site configuration | Same codebase, environment-specific builds (different baseSite, theming, feature flags) | Shared code, divergent branding or feature sets |
| Separate apps | Independent Angular apps, possibly sharing component libraries | Genuinely different experiences or teams; the most freedom, double the maintenance |
The OCC layer needs no convincing either way: every call already carries the base site in its path, which is one of the quiet architectural gifts of headless: the multi-site question stops touching the API surface entirely.
Accelerator storefronts resolve sites via the URL patterns on the CMSSite plus the deployment layout below, and that is where the CCv2-specific mechanics live.
Layer 3: Deployment Mechanics on CCv2#
The installed-base scenario the original CX Works article addressed remains common: B2C and B2B accelerator storefronts (say yacceleratorstorefront and yb2bacceleratorstorefront) on one platform. Two viable layouts:
Option 1: Two webroots, one DNS name#
Both storefront webapps deploy to the storefront aspect under distinct context paths: https://shop.acme.com/b2c and https://shop.acme.com/b2b. The manifest carries four coordinated pieces:
- Extensions: both storefront extensions plus every addon, listed (or in the shared
localextensions.xml). And the step that breaks first-time setups: generated storefront extensions must be committed to Git. The CCv2 build consumes them; it does not runextgenoraddoninstallfor you. - storefrontAddons: each addon declared per storefront it installs into, with the template named:
{ "addon": "b2bacceleratoraddon", "storefront": "yb2bacceleratorstorefront", "template": "yacceleratorstorefront" },
{ "addon": "smarteditaddon", "storefront": "yb2bacceleratorstorefront", "template": "yacceleratorstorefront" }
- Webroots and webapps: per-storefront webroot properties (
yacceleratorstorefront.webroot=/b2c) mirrored bycontextPathentries in the aspect'swebappssection, alongsidemediaweb,hac, and friends. - Session cookies, the one everyone misses: two webapps on one host share a cookie namespace, and two Tomcat sessions fighting over one
JSESSIONIDat path/produces the maddening symptom of logging into one storefront logging you out of the other. Scope each storefront's session cookie to its own path:
{ "key": "spring.session.enabled", "value": "true" },
{ "key": "spring.session.yacceleratorstorefront.cookie.name", "value": "JSESSIONID" },
{ "key": "spring.session.yacceleratorstorefront.cookie.path", "value": "/b2c" },
{ "key": "spring.session.yb2bacceleratorstorefront.cookie.name", "value": "JSESSIONID" },
{ "key": "spring.session.yb2bacceleratorstorefront.cookie.path", "value": "/b2b" }
The layout's structural annoyance: nobody owns /. A customer entering the bare domain hits no storefront, so mitigate deliberately: a lightweight redirect rule at the CDN, or one storefront claiming the root context, with the knowledge that root-context claims come with their own path-collision fine print against mediaweb and the other shared webapps.
Option 2: One storefront per DNS name#
Both storefronts run at root context, distinguished by host: b2c.acme.com and b2b.acme.com, using per-endpoint configuration in Cloud Portal (separate endpoints, certificates, and IP filter sets per the first-deployment guide) mapped to the appropriate webapp. Cleaner URLs and full cookie isolation for free; the trade-offs are more endpoint administration and the historical wrinkle that shared admin webapps (HAC on the same aspect) need care about which host serves them; keeping admin tooling off customer-facing endpoints entirely (its own endpoint, deny-all plus admin filter) is the arrangement that avoids the whole class of problem.
Composable variant#
The same two shapes exist with JS storefronts: multiple apps under js-storefront/ each get their own build and endpoint, or one app serves multiple sites resolved at runtime. The manifest mechanics are simpler (no addon matrix, no JSP webroots), which is one more entry on the accelerator-exit ledger from the storefront strategy guide.
Cross-Cutting Concerns Worth a Checklist#
- Solr: one index per site where assortments differ, or shared indexes with site filtering where they do not; either way the indexing cadence multiplies by site count, so revisit the scheduling from the search guides
- Media: shared media folders across sites are fine; per-site media catalogs only when legal or organizational separation demands them
- Analytics: per-site GA4 properties or one property with a site dimension; decide before data flows (the analytics guide's warning about unfixable history applies per site)
- Emails: per-site sender domains and templates; the transactional email guide's DNS checklist runs once per sending domain
- Testing: every site is a test matrix row; automated journey tests parameterized by site are the only way this scales past three sites
The theme across all three layers: multi-site is cheap where you share deliberately and expensive where you share accidentally. The platform will happily let sites entangle themselves through a common catalog, a common cookie, or a common index; the architecture work is drawing the isolation lines on purpose, once, early.