After years of building enterprise sites with various CMS and content layer combinations, we've landed on an architecture we keep coming back to: MDX content authored in Sanity Studio, rendered through a shared React component library. Here's why it works and how we set it up.

The Problem with Rich Text

Every headless CMS gives you some form of rich text editor. And every one of them has the same fundamental limitation: the output is just formatted text. Bold, italic, headings, lists, links. Maybe embedded assets.

But modern content isn't just formatted text. It's interactive components: pricing tables, comparison charts, code playgrounds, embedded videos with custom controls, CTAs with A/B variants, tabbed content sections. Try expressing any of that in a WYSIWYG editor.

The traditional solution is "structured content" — break everything into rigid content types with specific fields. But this trades flexibility for structure, and editorial teams hate it. They want to write freely, dropping in interactive elements where they make sense, not filling out form fields.

Enter MDX

MDX is Markdown with JSX. You write content in Markdown (which editors already know) and embed React components inline:

# Getting Started

Here's a quick overview of our pricing:

<PricingTable plan="enterprise" />

And here's how our architecture compares:

<ComparisonChart data={architectureData} />

The content is readable, editable, and — critically — renderable through your existing component library. Every component is version-controlled, tested, and reusable across pages.

Why Sanity (Not Just Any CMS)

You could store MDX in any CMS as a text field. But Sanity gives us three things that make the combination special:

Portable Text as the Foundation

Sanity's Portable Text format is an AST (Abstract Syntax Tree) rather than HTML or Markdown. This means we can extend it with custom block types that map directly to our MDX components. The editor gets a rich, visual editing experience; the output is clean, structured data.

Custom Studio Components

Sanity Studio is React-based, so we can build custom editor components that preview exactly how an MDX component will render. Editors insert a <PricingTable /> block and see a live preview right in the editor. No more "publish and check."

Real-Time Collaboration

Multiple editors working on the same document simultaneously, with live cursors and conflict resolution. For content teams that work in parallel, this is table stakes — but surprisingly few CMS platforms do it well.

The Component Library

The key to making MDX work at scale is a well-maintained component library. Ours includes:

  • Layout components: Grids, columns, sections, spacers
  • Content components: Callouts, quotes, code blocks, tables
  • Interactive components: Tabs, accordions, toggles, tooltips
  • Media components: Images with lazy loading, video embeds, galleries
  • Data components: Charts, pricing tables, comparison matrices
  • CTA components: Buttons, forms, newsletter signups (with A/B support)

Every component is:

  1. Documented with props, examples, and usage guidelines
  2. Tested with unit tests and visual regression tests
  3. Accessible by default (WCAG 2.1 AA)
  4. Responsive across all breakpoints
  5. Themeable via design tokens

The Build Pipeline

Here's how content flows from editor to production:

  1. Author writes in Sanity Studio using Portable Text + custom blocks
  2. Sanity stores as structured JSON (Portable Text AST)
  3. Build step converts Portable Text → MDX string
  4. MDX compiler transforms to React components
  5. Next.js renders with the shared component library
  6. CDN serves static pages (ISR for dynamic content)

Build times for a 500-page site: ~90 seconds. Incremental rebuilds: ~3 seconds.

Gotchas & Lessons

Component Versioning

When you update a component's API, all existing content using it needs to still work. We handle this with prop defaults and deprecation warnings — never break backward compatibility without a migration plan.

Editor Training

Not every editor is comfortable with component syntax, even simplified MDX. We provide a component picker in Studio that inserts components with default props, so editors never need to write JSX by hand.

Preview Accuracy

The Studio preview must match production rendering exactly. Any drift erodes editorial trust. We run automated preview-vs-production comparison tests nightly.

Is This Right for You?

This architecture works best when:

  • You have a React-based frontend (Next.js, Remix, Gatsby)
  • Content includes interactive/dynamic elements beyond basic rich text
  • Multiple teams contribute content with consistent design
  • You need enterprise-grade content governance

If you're publishing simple blog posts with basic formatting, this is overkill. Use Markdown and be happy.

But if you're building content-rich sites that need to scale — in content volume, editorial team size, and component complexity — MDX + Sanity is the best architecture we've found.