Dynamic Routes with MDX in Next.js 13 ?

A cool astronaut

I am currently learning about the new app directory introduced in Next.js 13. To gain some practical experience with it, I decided to use it to build this website. However, this is also my first time dealing with MDX and parsing markdown in general. While I have tried some guides, I haven't found a clear explanation on how to make it work with the app directory while using dynamic routes. So I decided to write this post to document my journey and hopefully help someone else who is struggling with the same issue.

Context

Here is a setup what I am working with.

app
├── content
│   ├── dynamically-load-mdx-nextjs13.mdx
│
├── blog
    ├── page.jsx
    ├── [title]
        └── page.jsx

In this setup, I have a blog route that picks up all the files and titles from the content directory and displays them in the page.jsx file. Additionally, I have a dynamic route under [title]->page.jsx that displays the content of the file with the same name as the title. Everything is working fine, except for the dynamic route. I am not able to render the MDX file as a component.

Issue

Unfortunately, using MDX with dynamic routes isn't straightforward. While it's easy to work with static routes, as shown in the official docs. Beta docs link

import HelloWorld from "./hello.mdx";

export default function Page() {
  return <HelloWorld />;
}

Now this works fine, but it's not dynamic. And this does not work with dynamic routes because we don't know the exact name in advance, and even if we did, we can't import it like this.

export default function BlogPost({props:{title}})
{
  import Content from `../../content/${title}.mdx`
  return <Content />
}

Alteast for me it kept giving me error that we can't use import inside a function.

Solution

Then I came across @next/dynamic, which is used to dynamically import components. So I tried this:

import dynamic from "next/dynamic";
export default async function Post({ params: { title } }) {
  const Content = await getPostData(title);
  return <div>{<Content />}</div>;
}

async function getPostData(title) {
  return dynamic(() => import(`../../content/${title}.mdx`));
}

So, we use the dynamic function to import the component and then render it. This works, but I am still not sure if this is the right way to go about it.

PLEASE NOTE

If you try to render MDX like this, you won't be able to use any of the next components like Image, Link, etc. They all error out giving something on the lines of :

TypeError: Cannot read property 'useContext' of null nextjs

Thus defeating the purpose of using MDX in the first place. I am sure there is a way to fix this and I am making some very trivial mistake. In any case, I am still looking for a better solution.

If you have some idea or a link to a guide or something, please use the following link to answer this question. I shared this on Stack Overflow as well.

Stack Overflow Link.