Why multi-site needs a content sharing strategy
Section titled “Why multi-site needs a content sharing strategy”Organizations with multiple brands or regional sites often duplicate content across CMS instances. Legal disclaimers, product specifications, company bios, and support articles get copied between sites, creating maintenance nightmares when any shared content changes.
A single CMS instance with Graph delivery solves this by separating content ownership from content presentation. Shared content lives once in the CMS. Each brand site queries Graph for the content it needs and renders it with its own design system. Brand-specific content stays scoped to its site. Shared content updates propagate automatically.
Architecture overview
Section titled “Architecture overview”┌────────────────────────────────────────────────┐│ Single CMS Instance ││ ┌──────────┐ ┌──────────┐ ┌──────────────┐ ││ │ Brand A │ │ Brand B │ │ Shared │ ││ │ content │ │ content │ │ content │ ││ └──────────┘ └──────────┘ └──────────────┘ │└───────────────────────┬────────────────────────┘ │ publish events ▼┌────────────────────────────────────────────────┐│ Optimizely Graph ││ Indexes all content, queryable by site tag, ││ content type, locale, and custom properties │└──────────┬────────────────────┬────────────────┘ │ │ ▼ ▼ ┌──────────────┐ ┌──────────────┐ │ Brand A │ │ Brand B │ │ Frontend │ │ Frontend │ │ (Next.js) │ │ (Nuxt.js) │ │ brand-a.com │ │ brand-b.com │ └──────────────┘ └──────────────┘Step 1: Design the content model for multi-site
Section titled “Step 1: Design the content model for multi-site”Organize content in the CMS using a tagging strategy:
- Site-scoped content gets a
siteIdproperty (e.g., “brand-a”, “brand-b”) - Shared content gets a
shared: trueflag or asiteIdof “global” - Content types remain consistent across sites so Graph queries work uniformly
Create a content structure with top-level folders per brand plus a shared folder. Authors know where to create content, and Graph queries filter by site scope.
Step 2: Configure Graph queries per site
Section titled “Step 2: Configure Graph queries per site”Each frontend queries Graph with a site filter to receive only its content plus shared content:
query GetBrandPages($siteId: String!) { Page( where: { _or: [ { siteId: { eq: $siteId } }, { shared: { eq: true } } ] _metadata: { status: { eq: "Published" } } } ) { items { _metadata { key, displayName, url { default } } title body siteId } }}This query returns pages belonging to the requesting site plus all shared pages. Each frontend uses its own siteId variable.
Step 3: Build independent frontends
Section titled “Step 3: Build independent frontends”Each brand site has its own frontend application with its own design system. The frontends share the same Graph query patterns but apply different styling, layouts, and navigation structures.
Key architectural decisions:
| Concern | Approach |
|---|---|
| Routing | Each frontend defines its own URL structure |
| Design system | Separate component libraries per brand |
| Shared content rendering | Same content, different visual treatment |
| Deployment | Independent deployments per brand site |
Step 4: Handle content updates across sites
Section titled “Step 4: Handle content updates across sites”When shared content changes in the CMS, Graph re-indexes it automatically. Each frontend picks up the change on its next query (controlled by caching strategy — ISR, SSR, or cache invalidation webhooks).
For time-sensitive shared updates (legal notices, security alerts), configure Graph webhook notifications to trigger frontend revalidation immediately.
When to use this pattern
Section titled “When to use this pattern”This approach works best for organizations managing 2-10 brand sites with meaningful content overlap (30%+ shared content). If sites share less than 10% of content, separate CMS instances may be simpler. If you manage 50+ microsites, consider a template-driven approach instead.