or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

index.mddocs/

@next/mdx

@next/mdx is a Next.js plugin that enables seamless integration of MDX (Markdown with JSX) files into Next.js applications. It offers dual transformation support through both Rust-based and JavaScript-based MDX processing, configurable file extensions, custom MDX component providers, and full compatibility with both Next.js Pages Router and App Router architectures.

Package Information

  • Package Name: @next/mdx
  • Package Type: npm
  • Language: JavaScript/TypeScript
  • Installation: npm install @next/mdx (peer dependencies @mdx-js/loader and @mdx-js/react are optional)

Core Imports

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

For ES modules:

import withMDX from '@next/mdx';

Basic Usage

Simple Configuration

// next.config.js
const withMDX = require('@next/mdx')();

module.exports = withMDX({
  pageExtensions: ['js', 'jsx', 'ts', 'tsx', 'md', 'mdx'],
});

With Configuration Options

// next.config.js
const withMDX = require('@next/mdx')({
  extension: /\.mdx?$/,
  options: {
    remarkPlugins: [],
    rehypePlugins: [],
  },
});

module.exports = withMDX({
  pageExtensions: ['js', 'jsx', 'ts', 'tsx', 'md', 'mdx'],
});

App Router Setup

For Next.js App Router, create an mdx-components.js file at the root:

// mdx-components.js
export function useMDXComponents(components) {
  return {
    h1: ({ children }) => <h1 style={{ fontSize: '2rem' }}>{children}</h1>,
    ...components,
  };
}

Architecture

@next/mdx integrates MDX support into Next.js through several key components:

  • Configuration Transformer: The main withMDX function transforms Next.js config to support MDX files
  • Dual Compilation: Supports both JavaScript-based (@mdx-js/loader) and Rust-based (mdxRs) MDX compilation
  • Webpack Integration: Automatically configures webpack rules for MDX file processing
  • Turbopack Support: Specialized configuration for Next.js Turbopack builds
  • Component Resolution: Configures MDX component provider resolution through multiple fallback paths

Dual Loader System

@next/mdx uses two different loaders based on configuration:

  1. JavaScript Loader (mdx-js-loader.js): Default loader using @mdx-js/loader

    • Full ecosystem compatibility with remark/rehype plugins
    • Dynamic string-based plugin resolution
    • ES module and CommonJS plugin support
  2. Rust Loader (mdx-rs-loader.js): High-performance loader for Rust-based compilation

    • Faster compilation through Next.js experimental.mdxRs option
    • Source map generation using native source-map package
    • Limited plugin ecosystem compared to JavaScript loader

The loader selection is automatic:

  • Rust loader when experimental.mdxRs is enabled in Next.js config
  • JavaScript loader otherwise (default)

Both loaders configure the same provider import source resolution: next-mdx-import-source-file

Capabilities

Main Configuration Function

Creates a Next.js configuration transformer that adds MDX support to your Next.js application.

function withMDX(options?: NextMDXOptions): (config: NextConfig) => NextConfig;

interface NextMDXOptions {
  /** 
   * A webpack rule test to match files to treat as MDX.
   * @default /\.mdx$/
   */
  extension?: RuleSetConditionAbsolute;
  
  /**
   * The options to pass to MDX compiler.
   */
  options?: Options & {
    remarkPlugins?: (
      | string
      | [name: string, options: any]
      | NonNullable<Options['remarkPlugins']>[number]
    )[] | Options['remarkPlugins'];
    rehypePlugins?: (
      | string
      | [name: string, options: any] 
      | NonNullable<Options['rehypePlugins']>[number]
    )[] | Options['rehypePlugins'];
  };
}

type WithMDX = (config: NextConfig) => NextConfig;

Usage Examples:

// Basic usage
const withMDX = require('@next/mdx')();
module.exports = withMDX();

// With custom file extensions
const withMDX = require('@next/mdx')({
  extension: /\.(md|mdx)$/,
});

// With MDX plugins
const withMDX = require('@next/mdx')({
  options: {
    remarkPlugins: [
      'remark-gfm',
      ['remark-toc', { heading: 'Contents' }],
    ],
    rehypePlugins: [
      'rehype-slug',
      'rehype-autolink-headings',
    ],
  },
});

// With existing Next.js config
const withMDX = require('@next/mdx')();
module.exports = withMDX({
  reactStrictMode: true,
  pageExtensions: ['js', 'jsx', 'ts', 'tsx', 'md', 'mdx'],
  webpack: (config, options) => {
    // Custom webpack config
    return config;
  },
});

Rust-based Compilation (Experimental)

Enable faster Rust-based MDX compilation through Next.js experimental features.

// next.config.js
const withMDX = require('@next/mdx')({
  options: {
    // MDX options here
  },
});

module.exports = withMDX({
  experimental: {
    mdxRs: true, // Enable Rust-based compilation
  },
});

Advanced Rust Configuration:

module.exports = withMDX({
  experimental: {
    mdxRs: {
      mdxType: 'gfm', // or 'commonMark' (default)
      // Additional mdx-rs specific options
    },
  },
});

Note: The mdxRs configuration accepts different options than the JavaScript loader. The mdxType option supports 'gfm' for GitHub Flavored Markdown or 'commonMark' (default) for standard CommonMark parsing.

MDX Components Configuration

Configure custom MDX components through the mdx-components.js file:

// mdx-components.js (for App Router)
export function useMDXComponents(components) {
  return {
    // Override built-in components
    h1: ({ children }) => <h1 className="custom-heading">{children}</h1>,
    p: ({ children }) => <p className="custom-paragraph">{children}</p>,
    
    // Add custom components
    CustomCallout: ({ children, type }) => (
      <div className={`callout callout-${type}`}>{children}</div>
    ),
    
    // Spread existing components
    ...components,
  };
}
// _app.js (for Pages Router)
import { MDXProvider } from '@mdx-js/react';

const components = {
  h1: ({ children }) => <h1 className="custom-heading">{children}</h1>,
  // ... other components
};

export default function App({ Component, pageProps }) {
  return (
    <MDXProvider components={components}>
      <Component {...pageProps} />
    </MDXProvider>
  );
}

File Extension Configuration

Configure which file extensions should be processed as MDX:

// Default: only .mdx files
const withMDX = require('@next/mdx')();

// Support both .md and .mdx files
const withMDX = require('@next/mdx')({
  extension: /\.mdx?$/,
});

// Custom pattern for specific files
const withMDX = require('@next/mdx')({
  extension: /\.(mdx|md)$/,
});

Plugin System Integration

Configure remark and rehype plugins for content transformation:

const withMDX = require('@next/mdx')({
  options: {
    // Remark plugins (markdown processing)
    remarkPlugins: [
      'remark-gfm',              // GitHub Flavored Markdown
      'remark-toc',              // Table of contents
      ['remark-slug', { prefix: 'user-content-' }], // Custom slug generation
    ],
    
    // Rehype plugins (HTML processing)  
    rehypePlugins: [
      'rehype-slug',             // Add IDs to headings
      'rehype-autolink-headings', // Add links to headings
      ['rehype-prism-plus', {    // Syntax highlighting
        ignoreMissing: true,
      }],
    ],
  },
});

Dynamic Plugin Loading:

Plugins can be loaded dynamically using string references, which @next/mdx resolves automatically:

const withMDX = require('@next/mdx')({
  options: {
    remarkPlugins: [
      'remark-gfm',                    // String reference
      ['remark-toc', { heading: 'Contents' }], // String with options
    ],
  },
});

Turbopack Configuration

When using Next.js with Turbopack (via TURBOPACK=1 environment variable), @next/mdx automatically configures special Turbopack rules:

// Automatic Turbopack configuration when TURBOPACK environment is detected
{
  turbopack: {
    rules: {
      '#next-mdx': {
        loaders: [loader], // Uses the same loader (JS or Rust)
        as: '*.tsx',       // Treats MDX files as TypeScript React files
      },
    },
    conditions: {
      '#next-mdx': {
        path: extension,   // Uses the same extension pattern
      },
    },
    resolveAlias: {
      'next-mdx-import-source-file': '@vercel/turbopack-next/mdx-import-source',
    },
  }
}

Key Turbopack Features:

  • Rule-based Processing: MDX files are processed with a dedicated #next-mdx rule
  • TypeScript Compilation: MDX files are treated as *.tsx files for compilation
  • Specialized Import Resolution: Uses @vercel/turbopack-next/mdx-import-source for component resolution
  • Automatic Detection: Configuration is applied automatically when process.env.TURBOPACK is detected

Types

These types require the following imports from external packages:

import type { NextConfig } from 'next';
import type { Options } from '@mdx-js/loader';
import type { RuleSetConditionAbsolute } from 'webpack';

NextMDXOptions Interface

interface NextMDXOptions {
  /**
   * A webpack rule test to match files to treat as MDX.
   * @default /\.mdx$/
   * @example /\.mdx?$/ // Support both .md and .mdx files
   */
  extension?: RuleSetConditionAbsolute;

  /**
   * The options to pass to MDX compiler.
   * @see https://mdxjs.com/packages/mdx/#api
   */
  options?: Options & {
    remarkPlugins?: (
      | string
      | [name: string, options: any]
      | NonNullable<Options['remarkPlugins']>[number]
    )[] | Options['remarkPlugins'];
    
    rehypePlugins?: (
      | string
      | [name: string, options: any]
      | NonNullable<Options['rehypePlugins']>[number]
    )[] | Options['rehypePlugins'];
  };
}

WithMDX Type

type WithMDX = (config: NextConfig) => NextConfig;

Dependencies

The package has the following dependencies and peer dependencies:

{
  "dependencies": {
    "source-map": "^0.7.0"
  },
  "peerDependencies": {
    "@mdx-js/loader": ">=0.15.0",
    "@mdx-js/react": ">=0.15.0"
  },
  "peerDependenciesMeta": {
    "@mdx-js/loader": { "optional": true },
    "@mdx-js/react": { "optional": true }
  }
}

Error Handling

@next/mdx provides error handling for MDX compilation issues:

  • Compilation Errors: MDX syntax errors are reported with file location and context
  • Plugin Errors: Issues with remark/rehype plugins are caught and reported
  • Module Resolution: Missing dependencies or incorrect plugin references are handled gracefully

Common error scenarios:

// Plugin not found - will throw resolution error
const withMDX = require('@next/mdx')({
  options: {
    remarkPlugins: ['non-existent-plugin'], // Error: Cannot resolve plugin
  },
});

// Invalid MDX syntax in .mdx files will be reported during build
// with file location and specific syntax error details