By Paul Scanlon

MDX 2 Breaking changes and gatsby-plugin-mdx v4 (Content)

If you’re upgrading to v4 of gatsby-plugin-mdx you’ll likely run into errors. Both MDX 2 and v4 of the plugin are major releases and inline with semantic versioning guidelines, breaking changes are to be expected.

Both Gatsby and MDX have documented the changes and you can find more information about the changes on the following links.

Breaking Changes to Content

In this post I’ll only be covering the changes to content that you’ll need to make. Stay tuned for a full migration post, it’s on its way!

The Misleading Error

If you’ve gone ahead and upgraded the plugin to v4 and started your development server, you’ll probably see an error like this.


Module build failed (from ./node_modules/gatsby/dist/utils/babel-loader.js):
SyntaxError: /Users/paulscanlon/tests/gatsby-mdx-2-breaking-content-changes/content/posts/2022/01/post-one.mdx:
Invalid left-hand side in prefix operation. (1:2)

> 1 | ---
    |   ^
  2 | title: This is post one
  3 | ---

This is slightly misleading. Whilst MDX does indeed surface the file that contains the error, E.g: post-one.mdx, it points to the frontmatter, this isn’t the actual error.

The Actual Error

The actual error will likely be somewhere in your content. Both the docs linked above explain that MDX will error if any, left angle brackets "<", or left curly braces "{" are found that are either, unescaped or used without expressions.

< left angle bracket unescaped

✅ \< left angle bracket escaped

✅ "<" left angle bracket with expressions

❌ { left curly brace unescaped

✅ \{ left curly brace escaped

✅ "{" left curly brace with expressions

Finding The Characters

Finding the above characters can be a little tricky though. Depending on the size of your project, the length of your blog posts, and where in your file system you’ve saved your .mdx files, can all make the job of finding and replacing these characters quite bothersome. Here’s two approaches you might find helpful.

It might be tempting to reach for VS Code’s built in search, however, you’ll notice in the diagram below that when I search for "<" or "{" (position 1, and 2), the search matches all instances of both these characters.

VS Code Basic Search

This isn’t that helpful since the search will match legitimate uses for these characters (position 2, and 3). You may also notice this basic search matches characters in all file types, not just characters found in .mdx files.

You may have never noticed this, I hadn’t, but, to the right of the search there’s a little file icon with a + next to it (position 1), this opens up what I’ll be referring to as Advanced Search.

VS Code Advanced Search

You can still enter a character to match (position 2) and i’ve also added "*.md, mdx" to the “files to include” input (position 3). This helps with getting more specific about where you’re searching.

The Advanced Search view provides a little more context about which files the matches are in, and on what line they occur (position 4).

I’ve found this easier to read and pick out the characters that will need changes, moreover, you can edit the files right there in the search results.


ESLint Parser/Plugin for MDX, helps you lint all ES syntaxes

This approach is less visual but it’s a good way to double, double check you’ve caught all the changes before starting your development server again.

Install Dependencies

The eslint-mdx install guide doesn’t mention you’ll also need to install eslint FYI.

npm install es-lint eslint-plugin-mdx --save-dev


Create a new file at the root of your project called .eslintrc and add the following code. I lifted this straight from the usage example in the repository README.

// .eslintrc

  "extends": ["plugin:mdx/recommended"],
  // optional, if you want to lint code blocks at the same time
  "settings": {
    "mdx/code-blocks": true,
    // optional, if you want to disable language mapper, set it to `false`
    // if you want to override the default language mapper inside, you can provide your own
    "mdx/language-mapper": {}


Now add the following script to your package.json.

// package.json

"scripts": {
  "lint": "eslint . --ext md,mdx"


With both the .eslintrc file created and the lint script added to package.json you can run the following in your terminal

npm run lint

This should produce an error which you can use to find the problem character in the problem file. The error tells you which line the error occurred but it’s not always overly clear which character caused the error.

One other thing to note about this approach. eslint exits after the first error so you won’t get to see all errors, only one error at a time.

  17:12  error  Parsing error: Could not parse expression with acorn: Expecting Unicode escape sequence \uXXXX

✖ 1 problem (1 error, 0 warnings)

error Command failed with exit code 1.
info Visit for documentation about this command.

And that’s it. I’ve used both of these approaches to upgrade a few sites now and whilst breaking changes of this nature can be quite frustrating, once you get into a groove it’s not so bad.

If you have anu further suggestions for ways to find problem characters please leave a comment below.


Further Reading

Here are the links from both MDX and Gatsby again which detail all the breaking changes.


Leave a reaction and let me know how I'm doing.

  • 0
  • 0
  • 0
  • 0
  • 0
Powered byNeon