Solving CommonJS vs ES Modules Issues in Next.js MDX Integration

This blog post highlights a potential issue you might face when using @next/mdx package to integrate Markdown markup language with Next.js. There's a small mistake in the official Next.js instructions. The issue stems from the lack of clear instructions for setting up the next.config.mjs file using ES modules (import statements) instead of CommonJS (require statements).

The Problem

Markdown is a simple way to write text that can be formatted for the web. MDX lets you use JSX in your markdown content. It works perfectly with Next.js, letting you write clear content and even add interactive elements like buttons or charts. There's a small snag you might encounter when following the official Next.js guide for setting up @next/mdx package. The instructions, at this time, have a step that can cause errors, especially for new Next.js projects using App Router.

The Culprit: require vs. import

The instructions tell you to use require in next.config.js file to add the next/mdx package as below.

// next.config.js

const withMDX = require("@next/mdx")();

/** @type {import('next').NextConfig} */
const nextConfig = {
  // Configure `pageExtensions` to include MDX files
  pageExtensions: ["js", "jsx", "mdx", "ts", "tsx"],
  // Optionally, add any other Next.js config below
};

module.exports = withMDX(nextConfig);

Here's the catch: when using next.config.mjs, which relies on ES modules, you need to use import instead of require. Attempting to use require results in the following error:

ReferenceError: require is not defined in ES module scope, you can use import instead

This mismatch can cause errors for people creating new projects with App Router, which uses next.config.mjs file by default instead of next.config.js.

The Fix: Using import

To solve this and get Next.js working with MDX, replace require with import in your next.config.mjs file. Here's the corrected version:

// next.config.mjs

import createMDX from "@next/mdx";

/** @type {import('next').NextConfig} */
const nextConfig = {
  // Configure `pageExtensions` to include markdown and MDX files
  pageExtensions: ["js", "jsx", "md", "mdx", "ts", "tsx"],
  // Optionally, add any other Next.js config below
};

const withMDX = createMDX({
  // Add markdown plugins here, as desired
});

// Merge MDX config with Next.js config
export default withMDX(nextConfig);

A Call to Update the Documentation

The Next.js documentation is generally excellent, but this slight discrepancy can be confusing. It's important for the Next.js team to keep the instructions updated, especially as more projects move to the default next.config.mjs file.

In the meantime, this blog post should help you navigate this potential issue. With the above instructions in place, you'll be well on your way to creating engaging content experiences with Next.js and MDX.

So remember this tip, leverage the power of MDX, and happy Next.js development!