CMS integration
A Propeller storefront does not require a CMS: commerce pages run entirely on the SDK. When you want editorial content (a homepage, landing pages, a blog), you connect a headless CMS. The integration keeps rendering and content-fetching separate, so you can change CMS without touching your shop.
The CMS layer ships in the Next.js Accelerator boilerplate. The Vue and Nuxt boilerplates do not include a CMS layer yet. The rendering packages exist for both frameworks, but the bundled providers and content routing are Next-only for now.
The layers
| Layer | Where it lives | Role |
|---|---|---|
| Contract | @propeller-commerce/propeller-v2-core-ui | Framework-agnostic types and two provider surfaces: the minimal CmsAdapter (getPage, getMenu, getGlobals) and the richer CmsProvider (adds page-slug enumeration, category banners, articles and image resolution), plus the page, block, menu and global types. |
| Rendering layer | propeller-v2-cms-react / -cms-vue | Renders a CmsPage's blocks and provides the adapter to your tree: CmsAdapterProvider, useCms, CmsPageRenderer, CmsBlock. Accepts a CmsAdapter. Ships no blocks of its own. |
| Provider | the Accelerator's lib/cms, or your own | Fetches content from one specific CMS and normalizes it to the contract types. In the Next.js boilerplate the Strapi, Prepr and generic providers ship in lib/cms and are activated by the CMS_PROVIDER environment variable, not installed as separate packages. |
| Blocks | your components | Brand-styled components you register per block type. |
The rendering layer and the provider are deliberately separate. The renderer (cms-react / cms-vue) only renders blocks and provides context; the provider only fetches and normalizes. Swap the CMS by swapping the provider, and your renderers and blocks stay the same.
How rendering works
The renderer dispatches each block to a component you supply through a renderers map keyed by block.type:
// React
import { CmsPageRenderer } from '@propeller-commerce/propeller-v2-cms-react';
import { HeroBlock, RichTextBlock, ProductCarouselBlock } from './cms-blocks';
const renderers = {
hero: HeroBlock,
'rich-text': RichTextBlock,
'product-carousel': ProductCarouselBlock,
};
<CmsPageRenderer page={page} renderers={renderers} />;
CmsBlock renders a single block the same way. Unknown block types render nothing in production, or a debug box when you pass debug. Mount CmsAdapterProvider once at the root so client components can call useCms() to reach the adapter; server-side data fetchers construct the adapter directly and pass the result into views.
Bridge blocks
A bridge block combines editorial content with commerce data: an editor sets a categoryId and a banner image in the CMS, and the block fetches the category name and product list from the SDK, then renders both together. Bridge blocks are your components, registered in the same renderers map. They are where CMS content and Propeller data meet.
Writing a provider for another CMS
Which contract you implement depends on where you plug in, and the two surfaces are not interchangeable today:
- Into the
cms-react/cms-vuerenderer (CmsAdapterProvider/useCms): implement the minimalCmsAdapter(getPage,getMenu,getGlobals). - Into the Next.js boilerplate's
lib/cms: implement the richerCmsProvider(theCmsAdaptersurface plus page-slug enumeration, category banners, articles and image resolution), and activate it withCMS_PROVIDER.
Either way your pages and blocks depend only on the contract types, never on the CMS's own response shape, so supporting a new CMS means writing one provider and nothing else.
With the Accelerator
When you scaffold the Next.js stack with --cms=strapi, --cms=prepr or --cms=cms, the matching provider in lib/cms is activated through the CMS_PROVIDER environment variable and a content catch-all route is wired up. With --cms=none, the homepage uses a built-in static layout and content slugs return 404. The commerce pages work fully without a CMS. See Routing for how content routes resolve.
See also
- Accelerator for selecting a CMS during scaffolding
- Routing for how content and commerce routes resolve
- Package docs: cms-react, cms-vue, core-ui