Composable Storefront: How It Actually Works Under the Hood
The mental model that makes composable storefront development click: CMS-driven page composition, the CmsConfig component mapping, the real OCC call sequence behind a product page, SSR, and the team skills the stack demands.
Developers arriving at composable storefront from the accelerator world, or from generic Angular work, tend to stall on the same conceptual step: where do pages come from? There is no router config listing your storefront's pages, no template directory to browse. The answer (pages are assembled at runtime from CMS data via a component mapping) is the single most important idea in the stack, and once it lands, everything else is ordinary Angular. This guide builds that mental model, traces a real page load call by call, and lays out what a team needs to run this stack well.
A naming and licensing note up front: this is the technology formerly known as Project Spartacus. Since version 5.0 it ships as SAP Commerce Cloud, composable storefront: licensed Angular libraries delivered through SAP's repository channel to commerce customers (the open-source Spartacus repo remains frozen at 4.x). Architecture and extension model carried over; the community edition did not.
The Core Idea: CMS-Driven Composition#
In the accelerator, the server rendered pages: controllers gathered data, JSP templates produced HTML, state lived server-side. In composable storefront the browser (or the SSR process) runs an Angular app that asks commerce, via OCC, what the page is: which template, which slots, which CMS components with which data. Then it instantiates an Angular component for each CMS component and composes the page client-side.
The hinge between the two worlds is the CmsConfig mapping. Every feature module declares which CMS component types it can render:
@NgModule({
imports: [CommonModule, RouterModule, GenericLinkModule, MediaModule],
providers: [
provideDefaultConfig(<CmsConfig>{
cmsComponents: {
SimpleResponsiveBannerComponent: { component: BannerComponent },
BannerComponent: { component: BannerComponent },
SimpleBannerComponent: { component: BannerComponent },
},
}),
],
declarations: [BannerComponent],
exports: [BannerComponent],
})
export class BannerModule {}
Read it as a routing table from content to code: when the CMS page response contains a SimpleResponsiveBannerComponent, render BannerComponent. Three consequences follow, and they are the daily texture of composable development:
- Business users compose pages. Adding a banner to the homepage is a SmartEdit action, not a deployment, exactly as it was with the accelerator, because it is the same CMS underneath.
- Custom CMS component types need a mapping. A custom
FinancingWidgetComponentin your content catalog renders as nothing (plus a console warning) until an Angular component claims it in aCmsConfig. Those warnings are a feature; they are your gap list. - Overriding standard UI is configuration. Remapping a standard CMS component type to your own Angular component is the sanctioned customization path, not forking library code. The libraries are dependencies, never sources: extension happens through these mappings, outlets, and Angular's dependency injection, which is precisely what keeps version upgrades cheap.
Anatomy of a Product Page Load#
Watching the network tab on a PDP is the fastest education in the stack. The sequence, with the commerce-side controllers serving each call:
| Call | Purpose | Served by |
|---|---|---|
/occ/v2/{site}/cms/pages?... | The page: template, slots, component list. The composition blueprint | cmsocc PageController |
/occ/v2/{site}/products/300938?fields=name,purchasable,baseOptions(...) | First product data slice (above-the-fold essentials) | commercewebservices ProductsController |
/occ/v2/{site}/cms/components?...&productCode=300938 | Data for the CMS components the page listed (batched) | cmsocc ComponentController |
/occ/v2/{site}/languages, /currencies | Site context lists | MiscsController |
/occ/v2/{site}/users/anonymous/consenttemplates | Consent state (see the data protection guide) | ConsentsController |
/occ/v2/{site}/products/300938?fields=classifications | Later product slices: classifications, then references, then reviews | ProductsController |
Two patterns worth internalizing from the trace. First, product data arrives in slices: the framework requests narrow field sets as components need them rather than one giant DTO, which is why the fields parameter discipline matters so much for performance (and why caching by URL works). Second, CMS component data is fetched in batches keyed to what the page declared, so a page bloated with components is slow in a measurable, attributable way.
The Swagger documentation for your actual installation ({host}/occ/v2/swagger-ui.html locally) is the authoritative endpoint inventory; when a component needs data and no endpoint serves it, that is a gap for a custom OCC extension, and the OCC contract-hardening guide on this site covers how to own that surface properly.
SSR: The Part That Makes It Production-Grade#
Client-side composition alone would be an SEO and first-paint disaster. Server-side rendering runs the same Angular app on Node, delivers composed HTML for the first response (crawlers and humans both get real content fast), and hands off to the client app for everything after. On CCv2 this is first-class: the JavaScript storefront deploys from js-storefront/ in your repository onto dedicated nodes, SSR supported and configured through the platform's build machinery (see the first-deployment guide for the repository layout).
Operational notes that save pain: SSR code runs in Node, so components must not touch window or document outside platform-guarded paths (this is the most common custom-component SSR bug); SSR output is cacheable and should be cached; and when SSR is overloaded or fails, the platform falls back to serving the client-side app shell, which keeps the site up but silently degrades SEO and first paint, so monitor SSR health rather than assuming it.
Setting Up#
The path, condensed (the platform side assumes the OCC extensions are installed, which on modern versions are regular extensions, plus the sample data if you want the demo site):
- Provision access to the composable storefront libraries (SAP's repository channel; your commerce license covers it).
- Generate an Angular workspace at the supported Angular version for your storefront release (the compatibility matrix is strict; respect it).
- Add the libraries via schematics:
ng add @spartacus/schematics, choosing the features you need (B2B, product configurator, tracking, and so on are separate feature libraries; take only what you use, since every module is bundle size). - Configure the base: OCC base URL, base site, currencies, languages, and the context URL parameters (the same site-context machinery the store-specific pricing guide extends).
npm run startagainst your backend, or the sample data'selectronics-spasite.
From there, development is Angular with a commerce accent: feature modules, lazy loading per page type, RxJS everywhere (the framework's state is stream-based; fighting RxJS is fighting the framework), and the CmsConfig mappings as your integration point with content.
The Team This Stack Wants#
The skill split is real and worth staffing deliberately, because the composable model splits along it:
- Frontend: Angular (current major versions), RxJS with genuine fluency, TypeScript, HTML/CSS at production grade, plus the composable storefront's own concepts (this guide, then the official docs' module catalog).
- Backend: SAP Commerce service layer plus OCC extension development: new endpoints, DTO extensions,
fieldssupport, caching headers. The backend team's product is now an API, with API discipline to match. - Shared: the OCC contract. The single most effective process decision on composable projects is treating the contract as co-owned: schema changes reviewed by both sides, regression fixtures on both sides, and no informal "just add a field" changes. Every failed composable project post-mortem features that seam; every smooth one features it too, managed.
Where to Go Deep Next#
The concepts here unlock the rest of the stack's documentation, but three topics deserve prioritized study on any real project: routing and URL configuration (SEO-critical, and where multi-site setups get interesting), the outlets and component-override system (your actual customization toolkit day to day), and CDC/personalization integration points if your project uses them. And for teams arriving from an accelerator storefront: the migration has its own guide in this series, including the CMS inventory technique that turns "rewrite the frontend" into a component-by-component checklist.