Render MDX with Next.JS

Libraries Needed


LibraryLink
next-mdx-remotehttps://www.npmjs.com/package/next-mdx-remote
gray-matterhttps://www.npmjs.com/package/gray-matter
  1. Create MDX files inside /pages/posts dir.

  2. Inside getStaticProps function in index.tsx file, we will read the posts dir, and then read each file and extract all front-matter from each file using the gray-matter library.

export async function getStaticProps() {
// Read the directory
const files = await fs.readdir(path.join("pages/posts"));
// Read each file and extract frontMatter
const posts = await Promise.all(
files.map(async (file) => {
const mdWithMeta = await fs.readFile(
path.join("pages/posts", file),
"utf-8"
);
const { data: frontMatter } = matter(mdWithMeta);
return {
frontMatter,
slug: file.split(".")[0],
};
})
);
return {
props: {
posts,
},
};
}
  1. Map the posts props in the UI like this.
{posts.map((post) => (
<Link href={/post-[slug]} key={post.slug}>
<a style={{ display: "block" }}>{post.frontMatter.title}</a>
</Link>
))}
  1. Create a /pages/posts/[slug].tsx file.
export async function getStaticPaths() {
const files = fs.readdirSync(path.join("pages/posts"));
// Generating slugs
const paths = files.map((filename) => {
return {
params: {
slug: filename.replace(".mdx", ""),
},
};
});
return {
paths,
fallback: false,
};
}
export const getStaticProps = async ({ params: { slug } }) => {
const markdownWithMeta = await fs.readFileSync(
path.join("pages/posts", slug + ".mdx"),
"utf8"
); // Read each file
const { data: frontMatter, content } = matter(markdownWithMeta); // Extract front-matter
const mdxSource = await serialize(content); // Serialize content
return {
props: {
frontMatter,
slug,
mdxSource,
},
};
};
💡

Note:

getStaticProps (Static Generation) - Fetches data at build time

getStaticPaths (Static Generation) - Specify dynamic routes to pre-render pages based on data

getServerSideProps (Server side rendering) - Fetches data on each request
  1. Inside the JSX, use MDXRemote component to render mdx data.
import { serialize } from "next-mdx-remote/serialize";
import { MDXRemote } from "next-mdx-remote";
export default function Post(props: any) {
return (
<div>
<div>
<MDXRemote {...props.mdxSource} />
</div>
</div>
);
}