Next.js 15 MDX support
In this part of the tutorial, we are finally going to add MDX (version 3) support to our Next.js 15 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.js MDX & markdown packages 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:
Missing mdx-components file
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
If you start the development server without mdx-components.tsx
in your project root, you will likely get this kind of error in your terminal (and in the browser if you open localhost:3000):
This error is because it is mandatory to have that file at the root of the project, even if you don't use it (yet)
To get rid of the error we need to create a 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)
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 4: we import the @next/mdx
package (that we installed in the previous chapter)
Lines 8 to 15: 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 37 and 38: 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
(and .jsx
) as an extension for your pages, then you can remove them from the list.
Line 41: 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 9: 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 38: 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
Valid markdown extensions
You can use another extension for your markdown pages if you prefer, for example you might prefer using *.markdown, *.mdown, *.mkd, ... they are all valid
In that case, make sure you make 2 changes in the next.config.ts
, for example to allow .md and .markdown as extensions but NOT mdx anymore, you would change the extension option to this:
And then the pageExtensions option to this:
Next.js 15 MDX Rust compiler
There is a brief chapter in the Next.js MDX documentation about enabling the experimental rust compiler when using MDX pages:
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
The most basic setup would look like this:
You can also specify which flavor of markdown that you want to use, as they mention in the Next.js configuration page about the Rust compiler for MDX documentation, there are currently 2 markdown flavors you can chose fromm commonmark and gfm
To enable mdxRS with github flavored markdown this is the configuration you would use:
No support for MDX plugins < Next.js 15.1
In Next.js 15 (and all versions before) if you try to use MDX (remark / rehype) plugins and have mdxRs enabled then they will silently fail to load. This is because the MDX Rust compiler can NOT read plugins written in Javascript.
In Next.js 15.1 you can still NOT use plugins (written in Javascript) if mdxRs is enabled (mdxRs is the next.config option that controls if the MDX compiler written in rust gets enabled), however @next/mdx added a new loader which will get used if you disable mdxRs. If you use the new loader you can even enable Turbopack (and have plugins still work).
This was just a short introduction to the state of plugins in combination with mdxRs, we will have a more in depth look at how to use plugins in the upcoming page about MDX plugins.
Installing the @mdx-js/loader package (when mdxRs is disabled)
This loader we are about to install, is only useful if are also using MDX plugins. If you don't plan on using any plugins like remark-table-of-contents or rehype-github-alerts, then you don't need this package and instead have to enable mdxRs by setting the option (in your next config) to true
To disable the MDX rust compiler (mdxjs-rs) we must set the next.config option to false, or you can comment it out (as by default it is set to false) like in this example:
If your mdxRs is disabled, you must install the optional (@mdx-js/loader) package:
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 buying me a coffee ☕ or sponsor ❤️ me on GitHub, as it will help me create more content and keep it free for everyone