Skip to content
MDX logo
v1.5.9GitHub logoTwitter logo
GitHub logoTwitter logo


MDX (the library), at its core, transforms MDX (the syntax) to JSX. It receives an MDX string and outputs a JSX string. It does this by parsing the MDX document to a syntax tree and then generates a JSX document from that tree. The JSX document is typically evaluated later through something like Babel or webpack. You can extend MDX by passing plugins that change the tree to customize how the JSX string is created.

Table of Contents

Async API

By default, MDX is asynchronous because plugins can be asynchronous themselves! This means that plugins can request data, read from the file system. Anything! You should use the async API, unless you have very good reasons to use the sync API.

You can use the library directly:

var mdx = require('@mdx-js/mdx')
const content = `
# Hello, world!
const transpile = async () => {
const jsx = await mdx(content)
return jsx

With more complex input, we can see more interesting output:

import TomatoBox from 'tomato-box'
export author = "Fred Flintstone"
export default = props => <main {...props} />
# Hello, world!
Here is a paragraph
<TomatoBox />
import TomatoBox from 'tomato-box'
const MDXLayout = props => <main {...props} />
const layoutProps = {
author: 'Fred Flintstone'
export default function MDXContent(props) {
return (
<div name="wrapper" components={components}>
<MDXLayout {...layoutProps} {...props}>
<h1>{`Hello, world!`}</h1>
<p>{`Here is a paragraph`}</p>
<TomatoBox />
MDXContent.isMDXComponent = true

This is pretty powerful because the output is rather readable. The only weird part is the string escaping from Markdown content:

<h1>{`Hello, world!`}</h1>

It’s not super readable, but it makes sure you can write content that wouldn’t be valid JSX syntax!

Sync API

MDX processes everything asynchronously by default. In certain cases this behavior might not be desirable.

If you’re using the MDX library directly, you might want to process an MDX string synchronously. It’s important to note that if you have any async plugins, they will be ignored.

const fs = require('fs')
const mdx = require('@mdx-js/mdx')
const mdxText = fs.readFileSync('hello.mdx', 'utf8')
const jsx = mdx.sync(mdxText)

MDX’s runtime package has example usage.


If you want to extract data from a MDX file, you can access the compiler directly:

const {createCompiler} = require('@mdx-js/mdx')
const detectFrontmatter = require('remark-frontmatter')
const vfile = require('vfile')
const visit = require('unist-util-visit')
const remove = require('unist-util-remove')
const yaml = require('yaml')
const file = vfile(`
title: Hello, MDX
I <3 Markdown and JSX
function extractFrontmatter() {
return function transformer(tree, file) {
visit(tree, 'yaml', function visitor(node) { = yaml.parse(node.value)
remove(tree, 'yaml')
mdxCompiler = createCompiler({
remarkPlugins: [detectFrontmatter, extractFrontmatter]
mdxCompiler.process(file, function done(err, file) {
// { title: "Hello, MDX" }
Edit this page on GitHub