← Back to Architecture Patterns
Architecture Pattern

📝 Marketing Site + CMS

The most common Vercel architecture: a headless CMS (Sanity, Contentful, Storyblok) connected to Next.js with ISR. Editors publish content, webhooks trigger targeted revalidation, and the site stays fast globally — with zero full rebuilds.

How It Works

1

Editor publishes in CMS

Content editor updates a blog post, landing page, or banner in Sanity/Contentful. Clicks 'Publish'.

2

CMS fires webhook

CMS sends a POST request to /api/revalidate with the content type and slug.

3

revalidateTag() runs

API route calls revalidateTag('blog-post-123') — only the affected page regenerates, not the entire site.

4

Next request gets fresh page

The next user hitting that URL gets the regenerated page, served from CDN. All other pages unaffected.

Key Vercel Features

ISR + Webhooks

On-demand revalidation via revalidateTag(). Only the changed page regenerates. A 10K-page site revalidates one page in seconds.

👁️ Draft Mode

Editors bypass ISR cache to preview unpublished content. Essential for editorial workflows — see changes before they go live.

🔗 Preview Deployments

Every PR gets a live preview URL. Design and content teams review real running pages, not Figma mockups.

🖼️ next/image

Auto WebP/AVIF conversion, responsive sizing, lazy loading. Hero images get priority prop for fast LCP.

✏️ next/font

Self-hosted fonts with zero layout shift. Google Fonts or custom fonts loaded with font-display: swap.

📊 Speed Insights

Real-user Core Web Vitals. Track actual visitor experience, not synthetic lab scores. Critical for SEO.

Webhook Revalidation — Code

// app/api/revalidate/route.ts
import { revalidateTag } from 'next/cache';
import { NextRequest, NextResponse } from 'next/server';

export async function POST(request: NextRequest) {
  const secret = request.headers.get('x-webhook-secret');
  if (secret !== process.env.REVALIDATION_SECRET) {
    return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
  }

  const body = await request.json();
  const { type, slug } = body;

  // Targeted revalidation — only affected pages
  revalidateTag(`${type}-${slug}`);   // e.g., 'blog-post-123'
  revalidateTag(type);                  // e.g., 'blog' (listing page)
  revalidateTag('homepage');            // homepage shows latest posts

  return NextResponse.json({ revalidated: true, tags: [type, slug] });
}

// In your page component:
async function getBlogPost(slug: string) {
  const post = await fetch(`https://cdn.sanity.io/...`, {
    next: { tags: ['blog', `blog-${slug}`] }
  });
  return post.json();
}

Popular CMS Options

CMSBest ForVercel Integration
SanityDeveloper-friendly, real-time collaboration, GROQ query languageFirst-class Vercel integration. Visual Editing, webhook revalidation, Draft Mode.
ContentfulEnterprise content management, structured content, rich APIWebhook → revalidateTag(). Preview API for Draft Mode. GraphQL or REST.
StoryblokVisual editor for non-technical users, block-based contentVisual Editor integration. Webhooks for revalidation. Bridge for live preview.
PayloadSelf-hosted, full control, TypeScript-native, open-sourceCan run on Vercel Postgres. API routes for content delivery. Full customization.
WordPress (headless)Existing WordPress content, familiar editing experienceWPGraphQL → Next.js ISR. Webhook plugin for revalidation on publish.