Gatsby Transformer Remark vs Plugin MDX: Choosing the Right Markdown Engine

Use gatsby-transformer-remark for static Markdown content that only needs HTML conversion, and choose gatsby-plugin-mdx when you need to embed React components directly in your Markdown files using JSX syntax.

The Gatsby ecosystem provides two primary pathways for processing Markdown content, each serving distinct architectural needs. Understanding the difference between gatsby-transformer-remark and gatsby-plugin-mdx is essential for optimizing your site's build process and content authoring experience. Both plugins transform source files into GraphQL nodes, but they differ fundamentally in parsing engines, node types, and component interoperability according to the Gatsby source code.

Core Architectural Differences

The primary distinction lies in the parsing engine and output format. According to packages/gatsby-transformer-remark/gatsby-node.js and packages/gatsby-plugin-mdx/src/gatsby-node.ts, gatsby-transformer-remark operates as a pure transformer plugin, while gatsby-plugin-mdx functions as both a transformer and page creator.

Feature gatsby-transformer-remark gatsby-plugin-mdx
Input format Pure Markdown (.md, .markdown) MDX – Markdown with embedded JSX (.mdx, optionally .md when configured)
Node type MarkdownRemark Mdx
Parsing engine remark MDX v2 (via @mdx-js/mdx)
Component support No native JSX; requires dangerouslySetInnerHTML or additional plugins Native JSX support; imports React components directly
GraphQL fields html, excerpt, frontmatter, tableOfContents body, excerpt, frontmatter, headings, tableOfContents
Page creation Requires manual page creation in gatsby-node.js Auto-creates pages for .mdx files in src/pages

How gatsby-transformer-remark Works

In packages/gatsby-transformer-remark/gatsby-node.js, the plugin implements the onCreateNode API to transform File nodes into MarkdownRemark nodes. It uses the remark ecosystem for parsing, allowing you to extend functionality through gatsby-remark-* plugins.

Configuration and Usage

Configure the plugin in gatsby-config.js with remark-specific options:

// gatsby-config.js
module.exports = {
  plugins: [
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `blog`,
        path: `${__dirname}/blog`,
      },
    },
    {
      resolve: `gatsby-transformer-remark`,
      options: {
        footnotes: true,
        gfm: true,
        plugins: [
          {
            resolve: `gatsby-remark-prismjs`,
            options: { classPrefix: "language-" },
          },
        ],
      },
    },
  ],
};

GraphQL Schema for MarkdownRemark

Query MarkdownRemark nodes to access the generated HTML:

{
  allMarkdownRemark(sort: { frontmatter: { date: DESC } }) {
    edges {
      node {
        id
        frontmatter {
          title
          date(formatString: "MMMM DD, YYYY")
        }
        html
        excerpt(pruneLength: 200)
      }
    }
  }
}

How gatsby-plugin-mdx Works

According to packages/gatsby-plugin-mdx/src/gatsby-node.ts, this plugin creates Mdx nodes and handles MDX compilation using MDX v2. It supports both .mdx and .md extensions (when configured) and integrates deeply with React's component model.

MDX v2 Architecture

The plugin uses @mdx-js/mdx to compile Markdown with JSX into executable JavaScript. This allows you to import and use React components directly within your content files.

Configuration with gatsbyRemarkPlugins and mdxOptions

Configure MDX processing in gatsby-config.mjs (ESM format recommended):

// gatsby-config.mjs
import { dirname } from "path";
import { fileURLToPath } from "url";

const __dirname = dirname(fileURLToPath(import.meta.url));

export default {
  plugins: [
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `pages`,
        path: `${__dirname}/src/pages`,
      },
    },
    {
      resolve: `gatsby-plugin-mdx`,
      options: {
        extensions: [`.mdx`, `.md`],
        gatsbyRemarkPlugins: [
          {
            resolve: `gatsby-remark-images`,
            options: { maxWidth: 800 },
          },
        ],
        mdxOptions: {
          remarkPlugins: [require("remark-gfm")],
          rehypePlugins: [require("rehype-slug")],
        },
      },
    },
  ],
};

GraphQL Schema for Mdx

Query Mdx nodes to access the raw body and headings:

{
  mdx(frontmatter: { slug: { eq: "/about" } }) {
    frontmatter {
      title
    }
    body
    excerpt
    headings {
      depth
      value
    }
  }
}

Rendering MDX Content

Unlike gatsby-transformer-remark, which provides pre-rendered HTML, MDX content renders as React children in your page templates:

// src/templates/mdx-page.jsx
export default function MdxPage({ data: { mdx }, children }) {
  return (
    <main>
      <h1>{mdx.frontmatter.title}</h1>
      {children} {/* rendered MDX components */}
    </main>
  );
}

When to Use Each Plugin

Choosing between these plugins depends entirely on your content strategy and interactivity requirements.

Use gatsby-transformer-remark when:

  • Your content consists of static Markdown without interactive elements.
  • You need the html field for RSS feeds, email templates, or SEO meta descriptions that require raw HTML strings.
  • You rely on the extensive gatsby-remark-* plugin ecosystem for image optimization, syntax highlighting, or automatic link generation.
  • Performance is critical for large content volumes where JSX compilation overhead is unnecessary.

Use gatsby-plugin-mdx when:

  • You want to embed React components directly in content files for interactive demos, live code editors, or dynamic data visualizations.
  • Your content authors need JSX/TSX support for custom layouts, shortcodes, or component composition.
  • You are building marketing pages, tutorials, or documentation that mixes prose with interactive UI elements.
  • You want to leverage MDX v2's modern architecture with direct access to remarkPlugins and rehypePlugins via mdxOptions.

Migration Considerations

If you are migrating from gatsby-transformer-remark to gatsby-plugin-mdx, be aware of breaking changes introduced in v4 of the MDX plugin. According to the source code in packages/gatsby-plugin-mdx/src/gatsby-node.ts, version 4 was rewritten to use MDX v2 and removed legacy options including defaultLayouts, mediaTypes, and jsFrontmatterEngine.

To migrate successfully:

  1. Replace defaultLayouts with shadowing or explicit component imports in MDX files.
  2. Move remark plugins from gatsby-transformer-remark configuration to the gatsbyRemarkPlugins or mdxOptions.remarkPlugins arrays.
  3. Update GraphQL queries to use Mdx instead of MarkdownRemark and replace html references with body or component rendering logic.

Summary

  • gatsby-transformer-remark converts pure Markdown files into MarkdownRemark nodes with pre-rendered html, ideal for static blogs and RSS feeds.
  • gatsby-plugin-mdx compiles MDX files into Mdx nodes with JSX support, enabling React component embedding for interactive content.
  • Both plugins can coexist in the same project when content is separated into different source directories.
  • Choose gatsby-transformer-remark for performance-critical static content and gatsby-plugin-mdx for component-rich, interactive documentation or marketing pages.

Frequently Asked Questions

Can I use both gatsby-transformer-remark and gatsby-plugin-mdx in the same Gatsby site?

Yes, both plugins can coexist in the same project. Configure gatsby-source-filesystem to source different directories for each plugin, ensuring that gatsby-transformer-remark processes pure Markdown files while gatsby-plugin-mdx handles .mdx files. This setup allows you to maintain a traditional blog with the remark transformer while using MDX for interactive documentation pages.

Why did my GraphQL queries break after switching from gatsby-transformer-remark to gatsby-plugin-mdx?

The plugins expose different GraphQL node types. gatsby-transformer-remark creates MarkdownRemark nodes with an html field containing pre-rendered HTML strings. gatsby-plugin-mdx creates Mdx nodes where content is accessed via body (raw MDX source) or rendered as React children in page templates. Update your queries to target allMdx or mdx instead of allMarkdownRemark, and replace html references with body or component rendering logic.

Does gatsby-plugin-mdx support all gatsby-remark-plugins?

Yes, gatsby-plugin-mdx supports most gatsby-remark-* plugins through the gatsbyRemarkPlugins configuration option. These plugins run during the remark phase of MDX processing. However, you must explicitly configure them in the gatsby-plugin-mdx options rather than in a separate transformer configuration. Note that some remark plugins may behave differently with MDX v2's syntax tree, so test compatibility when migrating from gatsby-transformer-remark.

Which plugin offers better build performance for large content sites?

For sites with thousands of static Markdown files and no interactive components, gatsby-transformer-remark typically offers faster build times because it generates static HTML strings without the overhead of JSX compilation and React component wrapping. gatsby-plugin-mdx incurs additional processing costs to compile MDX into executable JavaScript, which becomes worthwhile only when you need the interactivity and component composition that MDX provides. For pure content sites, the remark transformer remains the performance-optimal choice.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →