DEV Community

Cover image for MDX or rich-text JSON — the call you can't undo
Samer Alsayegh for Draftbase

Posted on Originally published at draftbase.co AI-assisted

MDX or rich-text JSON — the call you can't undo

Most "MDX vs rich text" posts frame it as a formatting choice. It's actually a security boundary, and almost nobody mentions the CVE.

Store MDX when developers write the content and it needs React components inline. Store rich text when non-technical editors own the page and need a WYSIWYG toolbar. That's the whole decision — both handle headings, bold, links, and images fine, so the real difference is what sits in the database column: MDX is one plain string that compiles to a JavaScript component, rich text is a nested JSON tree of typed nodes that never gets compiled at all.

The portability question runs backwards from what most guides assume. MDX pulled out of a CMS is still a plain string — move it anywhere and the prose survives, only the JSX component tags need re-registering. A rich text tree is portable in theory and painful in practice: Contentful's tree shape and Sanity's tree shape are different, so moving between them means writing a serializer per node type, plus another for every embedded reference. That's a converter project, not a git mv.

Here's the part that gets skipped: MDX from a CMS is remote code, not inert data. Rich text JSON just gets walked and rendered — nothing executes. MDX compiles, and if any editor can submit MDX that your server compiles, you're running content-authored code server-side. This already happened: next-mdx-remote versions 4.3.0 through 5.0.0 allowed arbitrary code execution during React server-side rendering of untrusted MDX (CVE-2026-0969, disclosed February 2026). Version 6.0.0 fixed it by blocking JavaScript expressions by default. The rule that follows is short — trusted authors, MDX is fine; untrusted or public submissions, block expressions or store rich text instead.

Rich text still wins outright for three real cases: non-technical editors who want a toolbar and a compile error is a support ticket; multi-channel output, since one JSON tree serializes to HTML, PDF, mobile, or plain text where MDX assumes a JSX runtime on the other end; and real-time co-editing, which needs a structured tree underneath to merge live edits at all.

The option most comparisons skip entirely: keep structure out of the prose. Author, date, tags, hero image — none of that belongs in a content blob, it belongs in typed fields you can query and validate. The prose field then only holds prose, and the format question gets a lot smaller.

Full breakdown — the comparison table, the component-allowlist security model, and what actually breaks in production for each format: https://draftbase.co/mdx-editor/vs/mdx-vs-rich-text

More on this in r/draftbase_cms: https://reddit.com/r/draftbase_cms

Draftbase templates hold typed fields for structure and a richText field that stores plain MDX beside them. Hobby is free, Startup is $49/mo.

Top comments (0)