Dev guideRecipesAPI ReferenceChangelog
Dev guideRecipesUser GuidesNuGetDev CommunityOptimizely AcademySubmit a ticketLog In
Dev guide

Headless architecture patterns

Design modern headless solutions using Optimizely Graph as your content API for flexible, scalable frontend architectures.

Headless architecture decouples content management from content presentation, enabling flexible, scalable digital experiences. Optimizely Graph serves as the content API layer, delivering structured content to any frontend technology or platform.

This guide focuses on architectural decisions: understanding rendering patterns (SSG, SSR, CSR, Hybrid), choosing the right approach for your use case, and understanding the tradeoffs. For implementation code and framework setup, see Dynamic frontend integration.

Core architectural patterns

API-first content delivery

Graph acts as your content API, exposing all content through a unified GraphQL endpoint. This approach enables:

  • Frontend flexibility – Build with any framework (React, Vue, Angular, Next.js, etc.)
  • Platform independence – Deliver to web, mobile, IoT, or custom applications
  • Team autonomy – Frontend and content teams work independently
  • Technology evolution – Swap frontend technologies without touching content infrastructure

Pattern 1: Static site generation (SSG)

Generate static HTML at build time by querying Graph for all content. This pattern delivers the fastest page loads and best SEO.

When to use:

  • Content changes infrequently (blogs, marketing sites, documentation)
  • Performance and SEO are critical
  • You can rebuild the site when content updates
  • Traffic is high (pre-rendering reduces server load)

When NOT to use:

  • Content updates constantly (news sites with breaking updates)
  • Personalized content for each user
  • Large sites with 100,000+ pages (build times become prohibitive)

Architecture:

Content Authors → CMS → Graph Sync → Optimizely Graph
                                            ↓
                                    Build-time queries
                                            ↓
                               Static Site Generator (Next.js, Gatsby, etc.)
                                            ↓
                                    Static HTML + Assets
                                            ↓
                                          CDN

How it works:

  1. At build time, query Graph for all content
  2. Generate HTML files for each page
  3. Deploy static files to CDN
  4. Users receive pre-rendered HTML (instant load)
  5. Optionally use ISR (Incremental Static Regeneration) to rebuild pages periodically

Tradeoffs:

  • Fastest: Pre-rendered HTML, no server processing
  • Best SEO: Search engines crawl HTML directly
  • Cheapest: Static hosting is inexpensive
  • Stale content: Pages show old content until next build
  • Long builds: Large sites can take minutes/hours to rebuild

Implementation: See Dynamic frontend integration for Next.js getStaticProps() and Gatsby examples.

Pattern 2: Server-side rendering (SSR)

Render pages on demand at request time by querying Graph. This pattern balances performance with real-time content updates.

When to use:

  • Content updates frequently (e-commerce inventory, news, stock prices)
  • Personalized content for each user (user-specific recommendations)
  • SEO is important but content can't be pre-built
  • Dynamic routing based on real-time data

When NOT to use:

  • High traffic sites (server cost increases with traffic)
  • Content rarely changes (SSG is faster and cheaper)
  • Client-side personalization is sufficient

Architecture:

User Request → Next.js/Nuxt Server → Query Graph → Render HTML → Response
                                           ↑
                                    Optimizely Graph

How it works:

  1. User requests a page
  2. Server queries Graph for fresh content
  3. Server renders HTML with current data
  4. HTML sent to user
  5. Repeat for each request

Tradeoffs:

  • Always fresh: Content is current on every page load
  • Good SEO: Search engines receive fully rendered HTML
  • Personalization: Can customize per user/session
  • Slower: Each request waits for Graph query + rendering
  • Expensive: Server costs scale with traffic
  • TTFB: Time to first byte is higher than SSG

Implementation: See Dynamic frontend integration for Next.js getServerSideProps(), Nuxt, and other SSR framework examples.

Pattern 3: Client-side rendering (CSR)

Fetch content from Graph directly in the browser. This pattern provides the most dynamic, app-like experience.

When to use:

  • Building single-page applications (SPAs)
  • Personalized, user-specific content
  • Interactive dashboards or tools
  • SEO is not critical for the content

Architecture:

User → SPA (React/Vue) → Client-side Graph queries → Update UI
              ↓
       Optimizely Graph

For React/Vue/Angular implementation examples with Apollo Client, see Dynamic frontend integration.

Pattern 4: Hybrid (SSG + CSR)

Combine static generation for the page shell with client-side fetching for dynamic content. This pattern optimizes both performance and interactivity.

When to use:

  • Page structure is stable but content updates frequently
  • Mix of static and personalized content
  • Need fast initial page load with dynamic features

Strategy:

  • Use SSG (getStaticProps) for stable layout, navigation, footer
  • Use CSR (client-side queries) for user-specific or frequently changing content
  • Combine ISR for periodic updates to static content

For implementation examples, see Dynamic frontend integration (React/Next.js sections).

Choosing the right pattern

Decision framework

Ask these questions to choose your rendering pattern:

1. How often does content change?

  • Rarely (weekly/daily) → SSG
  • Frequently (hourly) → SSR or Hybrid
  • Constantly (real-time) → CSR or SSR

2. Is SEO critical?

  • Yes, essential → SSG or SSR
  • Somewhat important → SSR or Hybrid
  • Not important → CSR

3. Is content personalized per user?

  • No → SSG
  • Yes, but client-side is OK → Hybrid (SSG + CSR)
  • Yes, must be server-rendered → SSR

4. What's your traffic level?

  • High traffic → SSG (lowest cost)
  • Medium traffic → SSR or Hybrid
  • Low traffic → Any pattern works

5. What's your content volume?

  • Small site (<1000 pages) → SSG
  • Large site (10,000+ pages) → SSR or Hybrid
  • Massive site (100,000+ pages) → SSR or selective SSG

Best practices

1. Query optimization

  • Use fragments for reusable field sets across queries
  • Request only needed fields to reduce payload size
  • Implement pagination for large result sets
  • Leverage Graph's indexing by filtering on indexed fields

For query implementation patterns, see Personalized search and filtering.

2. Error handling

Implement robust error handling for Graph queries. For framework-specific error handling patterns (React error boundaries, Vue error handlers, etc.), see Dynamic frontend integration.

Key practices:

  • Validate HTTP response status
  • Check for GraphQL errors in response
  • Provide fallback content
  • Log errors for monitoring
  • Display user-friendly error messages

3. Authentication and security

  • Store Graph credentials in environment variables
  • Never expose secrets or non-public tokens in client-side code (single keys for read-only public content are the exception)
  • Use server-side proxies for client-side queries if needed
  • Implement rate limiting to prevent abuse

4. Caching strategies

  • SSG: Cache at CDN level (long TTL)
  • SSR: Use incremental static regeneration (ISR) or stale-while-revalidate
  • CSR: Implement client-side caching with Apollo Client or React Query

See Caching best practices for detailed guidance.

Pattern comparison matrix

FactorSSGSSRCSRHybrid
Initial Load Speed⚡⚡⚡ Fastest⚡⚡ Fast⚡ Slower⚡⚡ Fast
SEO✅ Excellent✅ Excellent❌ Poor✅ Good
Content Freshness❌ Stale until rebuild✅ Always fresh✅ Always fresh✅ Fresh
Server Cost💰 Cheapest💰💰💰 Most expensive💰💰 Medium💰💰 Medium
Complexity🟢 Simple🟡 Medium🟢 Simple🔴 Complex
Personalization❌ No✅ Yes✅ Yes✅ Yes
Build Time🕐 Can be slow⚡ None⚡ Fast🕐 Medium
Scales WithContent volumeTrafficTrafficBoth

Best for:

  • SSG: Blogs, marketing sites, documentation, portfolios
  • SSR: E-commerce (pricing/inventory), news sites, dashboards with auth
  • CSR: Admin panels, internal tools, SPAs where SEO doesn't matter
  • Hybrid: Large sites with mixed content (static pages + dynamic features)

Common pitfalls

1. Wrong pattern for the use case

Problem: Using SSG for frequently changing content

  • Result: Users see stale content, and the site requires frequent rebuilds

Solution: Choose SSR or Hybrid for dynamic content


Problem: Using CSR for content that needs SEO

  • Result: Search engines can't index your content

Solution: Use SSG or SSR to render HTML server-side


2. Not considering build times

Problem: Using SSG for a 50,000-page site

  • Result: 2-hour build times, deploys fail

Solution: Use SSR or selective SSG (only pre-render popular pages)


3. Over-fetching data

Problem: Requesting all fields when only a few are needed

  • Result: Slow queries, large payloads

Solution: Request only required fields in GraphQL queries (see Personalized search)


4. Not leveraging ISR

Problem: Full site rebuild on every content change

  • Result: Long deployment times

Solution: Use Incremental Static Regeneration (ISR) to rebuild pages on demand

Next steps


Did this page help you?