DEV Community

Cover image for Gatsby - Switching from Markdown to MDX
Chris Otto
Chris Otto

Posted on • Originally published at on

Gatsby - Switching from Markdown to MDX

I recently rewrote my old Wordpress site hosted through GoDaddy to a Gatsby site hosted with Netlify. Originally I tried hand-rolling my site but it was taking way too long to get everything I wanted implemented. Gatsby starter templates to the rescue! The template I chose had everything I was looking for tags, search, blog, and a contact form. The few remaining features I was looking for social links, projects page and an about page I can add over time.

The template was using the out of the box Gatsby approach of just plain markdown files. To supercharge my posts and components I needed to switch to MDX.

Making The Switch 🎉

Using MDX in Gatsby requires a few different packages. First things first, install them.

npm install --save @mdx-js/mdx @mdx-js/react gatsby-plugin-feed-mdx gatsby-plugin-mdx
Enter fullscreen mode Exit fullscreen mode


In the gatsby-config.js rename the section of the exports from gatsby-transofrmer-remark to gatsby-plugin-mdx. This tells Gatsby to use the plugin for MDX and stop using the transformer for just plain markdown files. Rename the plugins node to gatsbyRemarkPlugins and keep the plugins that you had before (there are one or two exceptions to this but we’ll cover them later). I wanted the plug into work with both MDX and MD to start and to use the templates that I already had.

        extensions: [`.mdx`, `.md`],
        defaultLayouts: {
          posts: require.resolve('./src/templates/PostTemplate.js'),
          page: require.resolve('./src/templates/PageTemplate.js'),
          tags: require.resolve('./src/templates/TagTemplate.js'),
Enter fullscreen mode Exit fullscreen mode


If you have your setup to publish out an RSS feed you will need to switch to this package, this is the other plugin the gatsby-config.js that we need to rename. Adjust your feed query to be from allMarkdownRemark to allMdx.

- serialize: ({ query: { site, allMarkdownRemark } }) => {
- return => {
+ serialize: ({ query: { site, allMdx } }) => {
+ return => {
Enter fullscreen mode Exit fullscreen mode

Change All Your Queries

We need to make the above change to all of the queries within the site. If you have a query that is just markdownRemark the MDX version of that is just mdx. This can be a bit tedious but don’t worry it isn’t that bad.

- posts: allMarkdownRemark(
+ posts: allMdx(

- page: markdownRemark(fields: { slug: { eq: $slug } }) {
+ page: mdx(fields: { slug: { eq: $slug } }) {
-      html
+      body
Enter fullscreen mode Exit fullscreen mode

Change Components and Props

Now that all the queries have been updated we need to pass the updated query results to our components and make sure they are correctly updated in our props. One example of what this change looks like is below, from a BodyText component that came with the template I used.

Instead of using dangerouslySetInnerHTML with MDX we need to use this component. For what I need it to do I just need to wrap the body returned from the GraphQL query in the component and it will render the MDX content for me.

import { MDXRenderer } from 'gatsby-plugin-mdx'
Enter fullscreen mode Exit fullscreen mode

Change the props for the component to use body instead of html

- const { html, theme } = props
+ const { body, theme } = props
Enter fullscreen mode Exit fullscreen mode

Use the MDXRenderer component to render the result to the page.

- <div className="bodytext" dangerouslySetInnerHTML={{ __html: html }} />
+ <div className="bodytext">
+   <MDXRenderer>{body}</MDXRenderer>
+ </div>
Enter fullscreen mode Exit fullscreen mode

Change the propTypes for the component from html to body.

- html: PropTypes.string.isRequired,
+ body: PropTypes.string.isRequired,
Enter fullscreen mode Exit fullscreen mode

Just by applying those and similar changes depending on the component I was able to update all of them in a short period of time.

Remove old packages

After making all those changes your Gatsby page should be up and running with MDX. You can transition all of your old MD to MDX if you want otherwise, keep the options for extensions the same and they should render correctly. Now it’s time to remove the packages that are not being used anymore.

npm uninstall gatsby-plugin-feed gatsby-transformer-remark
Enter fullscreen mode Exit fullscreen mode


There a few gotchas along the way that tripped me up for a little bit and may be specific to the way I have things set up but wanted to call them out here.

MDX Doesn’t Render Code Blocks Syntax Highlighting

One thing I didn’t know about MDX before making the switch was that it didn’t render code blocks out of the box. However, there are a few options to pick from to handle this and I went with adding PrismJS and using one of the CSS files that they have for how the blocks look. If you’re curious about this, I highly recommend checking out the gatsby-remark-prismjs plugin.

Jest Snapshot Test Stopped Working

I had an existing Jest Snapshot test that was testing the article component which has a header, a body, and styles for them. The body portion of the test started failing after the switch and I needed to include an exclude in my jest configuration for ignoringgatsby-plugin-mdx. It was preloading some items that Jest didn’t expect.

- transformIgnorePatterns: [`node_modules/(?!(gatsby)/)`],
+ transformIgnorePatterns: ['node_modules/(?!(gatsby|gatsby-plugin-mdx)/)'],
Enter fullscreen mode Exit fullscreen mode

If you’ve made the switch to using MDX from Gatsby I’d be curious how your experience was. If you hit some of the same hiccups that I did or if you used any other packages/solutions for handling the code block rendering.

Top comments (5)

dance2die profile image
Sung M. Kim • Edited

Thank you for the post, Chris. Your site,, looks very polished and fast.

I forgot where I read it and that's why I went with MDX from the get-go during WP -> Gatsby migration.

I should've kept track of what the errors/incompatibilities were and shared it in public...

chrisotto profile image
Chris Otto

Thanks Sung it's mostly the template I started with 😂.

boywithsilverwings profile image
Agney Menon

For the thing with code snippets, isn't it the same with normal markdown? For syntax highlighting you would need to add in some form of gatsby-remark plugins, Right?

chrisotto profile image
Chris Otto • Edited

Code blocks syntax highlighting works out of the box with normal markdown files. But yeah in order to implement the PrismJS plugin in gatsby-plugin-mdx I added the gatsby-remark-prismjs plugin to the gatsbyRemarkPlugins options node. You could create your own with prism-react-renderer too. I just went with the plugin to start to get over to MDX quicker.

Gatsby Plugin MDX Doc

MDX JS Syntax Highlighting Guide

boywithsilverwings profile image
Agney Menon

oh! you meant inside the markdown files and not the website itself?