Transformation 8 min read

Headless CMS at Scale: Governing 50+ Websites Without Losing Your Mind

CS
CELESDEV Solutions
Integration & Data Practice

The decision to go headless is straightforward. The decision of how to structure a headless CMS for a multi-brand, multi-market organisation serving 50+ websites from a single content backend — that's where complexity lives.

The client: a global manufacturing company with brands in 14 markets, each with local content requirements, translation workflows, and brand-specific design systems, but shared product data and corporate content. The technical stack: Contentful as the CMS, Next.js frontends, and an event-driven integration with the SAP stack described in our earlier article on Symfony Messenger.

The Governance Trap
Most headless CMS implementations fail not at the technical level but at the governance level. When 50 websites can each publish content independently, the question "who decides what the content model looks like?" becomes existential. Without clear ownership, the content model becomes a sprawl of legacy types that nobody dares to deprecate.

Content Modelling Governance

We established a Content Architecture Board — a lightweight governance layer with two roles. The Content Model Owner (central, one person) has final authority over the global content type schema in Contentful. The Content Leads (one per market/brand) can propose new content types but cannot create them without review.

Every content type is tagged with a lifecycle status: stable, experimental, or deprecated. Deprecated types have a sunset date and a migration path. This prevented the accumulation of abandoned types that plagued the pre-migration WordPress setup.

We also introduced a content type design review checklist covering: field naming consistency, required vs optional fields, localisation requirements, and reference relationship depth. Simple, but never previously existed.

Multi-Tenant API Design

Contentful's Content Delivery API is shared across all environments. At 50+ sites, naively calling the API from each frontend creates a significant request volume — and more importantly, inconsistent caching behaviour across markets.

We introduced a thin GraphQL aggregation layer between the frontends and Contentful. This layer handles: per-market content filtering, response caching with market-aware cache keys, locale normalisation, and product data enrichment from the SAP integration. Frontends call one endpoint with market context in the header; the aggregation layer handles all the Contentful complexity.

CDN Invalidation at Scale

The most technically interesting problem: when a product description changes in SAP, it propagates as an event, updates in Contentful, and must invalidate cached pages across 50+ frontends. With each page potentially cached in CloudFront at multiple edge nodes, naive tag-based invalidation was taking 8–12 minutes.

We redesigned the invalidation strategy using surrogate cache keys at the content-type level rather than the page level. A product update invalidates all pages that reference that product type in a single API call — reducing invalidation time to under 90 seconds for 95% of changes.

Key Takeaways
  • Establish content model governance before technical implementation
  • A content type lifecycle (stable/experimental/deprecated) prevents model sprawl
  • Introduce an aggregation layer to abstract CMS complexity from frontends
  • Design CDN invalidation strategy based on content type, not page URL
  • One Content Model Owner per organisation — committee governance kills model quality
Related Articles
Integration
Event-Driven Integration with Symfony Messenger and Redis Streams
Read article →
Integration
API Design First: Contract-Driven Development with OpenAPI and AsyncAPI
Read article →
Transformation
The Architect's Role in Digital Transformation: Beyond Technology Selection
Read article →