Next.js MDX support
In this part of the tutorial, we are finally going to add MDX (version 3) support to our project by using next/mdx
Why use markdown (MDX)?
As a developer, using Markdown to format content makes sense, as most of us probably already know Markdown because we have been using it when formatting our project READMEs, or when opening Issues or participating in Discussions on GitHub, or when formatting questions and answers on Stack Overflow, or even in messages on a Discord server
This is why I chose to use MDX (markdown + JSX) for this "static Next.js blog" project
Adding MDX support to our Next.js project
To add MDX support to the Next.js blog, I will use @next/mdx, which is an MDX package by the same team that is behind Next.js, but other alternatives work well too, I listed some of them in the @next/mdx alternatives chapter in my MDX post
You can also create your own package, in which case I recommend you start by reading the Deep Dive: How do you transform markdown into HTML? section of the Next.js "Markdown and MDX" documentation
If you want to get more background information about MDX, I recommend checking out my MDX post
@next/mdx is stable, and I had no significant problems using it for this project, there are however a series of open Issues on GitHub, I recommend having a brief look at the @next/mdx issues search on GitHub to have an idea of what might not work or just have a look at the list when you have the feeling something is not working as it should
@next/mdx installation
First, we will add the @next/mdx
package and the MDX types to our Next.js project, the @next/mdx package will add support for MDX files to our Next.js project, to install the package execute the following command in your VSCode terminal:
MDX support setup
First, we need to create a new file called mdx-components.tsx
in the root of our project (or the ./src
folder if you have configured your project to use the ./src
folder)
Adding the file is very important, I see a lot of posts of developers struggling with the first steps of getting MDX support to work in their Next.js project, and 90% of the cases are because they have not added the mdx-components.tsx
file, without mdx-components.tsx
in Next.js 13 you will get an error that says Module not found: Can't resolve 'next-mdx-import-source-file' and in Next.js 14 you will get a bunch of node_modules/@mdx-js/react/lib related errors in your terminal, so it is mandatory to have that file at the root of the project, even if you don't use it (yet)
Then add the following content:
If you chose to put all your files into an ./src
folder, then you need to put the mdx-components.tsx
file into the ./src
folder and not the root of the project
Now we need to update the content of our next.config.mjs
file (in the root of our project) to this:
This configuration file is probably much shorter than the one you have in your project (if you followed my previous chapters)
I have omitted what we added in the CSP chapter and the Sentry setup so as not to have to display a huge file, but the structure is still the same, so you should be able only to copy the relevant parts (the ones that are highlighted using a different background color)
Line 3: we import the @next/mdx
package (that we installed in the previous chapter)
Lines 7 to 13: we configure @next/mdx by passing an object to createMdx; via the options, we add support for remark plugins and rehype plugins (we will add a bunch of those plugins later)
Lines 34 and 35: we tell Next.js what extensions are valid page extensions, the pages we created so far had a .tsx
extension, but the new MDX pages we will now add will have the .mdx
extension, as you can see we add a bunch more here to cover all use cases. If for example, you are sure you won't use .js
as an extension, then you can remove it from the list.
Line 38: we use the withMDX function we just created and pass our nextConfigOptions to it, which will return a configuration with MDX support
Adding markdown support (optional)
The configuration we just did adds support for MDX in pages that have the extension *.mdx
, if you want also to add support for markdown pages with the *.md
extension, then add the extension in 2 places like so:
Line 8: we add the extension to the MDX configuration, the regex we use works because we added a question mark behind the x of mdx meaning the x is optional, so md and mdx both are valid extension
Line 35: we add md
to the pageExtensions
list
It is important to add your new extension to both the MDX configuration and the Next.js pageExtensions
If you don't also add the extension to the createMDX extension option, then @next/mdx won't be able to parse the content of your file
If you don't add your markdown extension to the pageExtensions, then the Next.js app router will not be able to find your file, and it will show a 404
You can use another extension for your markdown pages if you prefer, for example you might prefer using *.markdown, *.mdown, *.mkd, ...
In that case make again sure you make the change in 2 places, let's assume we want to use .markdown instead if .md as extension for our markdown pages, then we would change our code to this for the parser:
And then the Next.js pageExtensions to this:
No Rust compiler for MDX (yet)
The Next.js MDX documentation tells us to enable the experimental Rust compiler for MDX:
Next.js supports a new MDX compiler written in Rust. This compiler is still experimental and is not recommended for production use. To use the new compiler, you need to configure next.config.js when you pass it to withMDX
Unfortunately, the documentation did not clearly state that plugins do NOT work if you turn on mdxRs (yet), then there was a ticket and they fixed the docs Docs: Note that needs to turn off mdxRs when using MDX plugins but shortly after they removed the warning again 😭, long story short (no matter if it is in the docs) you can't use plugins when also using mdxRs
When Next.js mentions the Rust compiler then they are talking about SWC, mdxRs the Rust compiler for MDX is the mdxjs-rs package, it uses the markdown-rs package to parse markdown and SWC for everything that is javascript
It is the mdxjs-rs README that has the information that plugins are not supported yet, their readme states that:
This project does not yet support plugins
There is a support ticket you may want to subscribe to if you are interested in getting notifications about the progress for plugin support in markdown-rs: Enable custom plugins #32
Disabling mdxRs and installing @mdx-js/loader instead
Later in this tutorial, we will add several plugins, which is why we are going to turn mdxRs off for now by setting the experimental mdxRs configuration option to false, but also add a comment as to why, so that in the future as soon as support for plugins gets shipped, we just need to turn it on:
Of course, if you don't plan on using any plugins like remark-gfm or rehype-pretty-code, then you can turn mdxRs on by setting the option to true
Now that we have disabled mdxRs, we also need to install the MDX webpack plugin manually using the following command:
This webpack plugin will handle parsing MDX and is a replacement for the MDX rust compiler we just disabled
In Next.js 13, the @mdx-js/loader webpack plugin was a dependency of @next/mdx and would get installed when you install @next/mdx
However, since version 14, you need to install the plugin manually as the dependency is now marked as optional
MDX page type (optional)
The following file is not mandatory, but it doesn't hurt to add the right type for MDX pages (I found this in the Next.js "app-dir-mdx" example on GitHub), so (if it doesn't exist already) I recommend creating a types
folder in the root of your project and adding a mdx.d.ts
file with the following content:
Because we used create next app in our tsconfig.json, we already have the following include in our tsconfig.json
(if it isn't in your tsconfig.json, then you need to add it), which means that *.d.ts
files will get included when typescript does the compilation:
Tips when using MDX
Now that our MDX setup is done, you might be interested in a few tips that make life easier when writing MDX / markdown in VSCode, if you do check out the "VSCode markdown (and MDX) related tips" chapter in the VSCode post
Congratulations 🎉 you now have MDX support added to your project using next/mdx, in other parts of this tutorial, we will further extend that setup by adding several valuable plugins and learning how to use custom react components to fully benefit from what MDX has to offer
If you liked this post, please consider making a donation ❤️ as it will help me create more content and keep it free for everyone