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.
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.
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.
You could store MDX in any CMS as a text field. But Sanity gives us three things that make the combination special:
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.
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."
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 key to making MDX work at scale is a well-maintained component library. Ours includes:
Every component is:
Here's how content flows from editor to production:
Build times for a 500-page site: ~90 seconds. Incremental rebuilds: ~3 seconds.
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.
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.
The Studio preview must match production rendering exactly. Any drift erodes editorial trust. We run automated preview-vs-production comparison tests nightly.
This architecture works best when:
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.