A Next.js plugin that enables seamless integration of MDX (Markdown with JSX) files into Next.js applications
npx @tessl/cli install tessl/npm-next-mdx@15.5.00
# @next/mdx
1
2
@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.
3
4
## Package Information
5
6
- **Package Name**: @next/mdx
7
- **Package Type**: npm
8
- **Language**: JavaScript/TypeScript
9
- **Installation**: `npm install @next/mdx` (peer dependencies `@mdx-js/loader` and `@mdx-js/react` are optional)
10
11
## Core Imports
12
13
```javascript
14
const withMDX = require('@next/mdx');
15
```
16
17
For ES modules:
18
19
```javascript
20
import withMDX from '@next/mdx';
21
```
22
23
## Basic Usage
24
25
### Simple Configuration
26
27
```javascript
28
// next.config.js
29
const withMDX = require('@next/mdx')();
30
31
module.exports = withMDX({
32
pageExtensions: ['js', 'jsx', 'ts', 'tsx', 'md', 'mdx'],
33
});
34
```
35
36
### With Configuration Options
37
38
```javascript
39
// next.config.js
40
const withMDX = require('@next/mdx')({
41
extension: /\.mdx?$/,
42
options: {
43
remarkPlugins: [],
44
rehypePlugins: [],
45
},
46
});
47
48
module.exports = withMDX({
49
pageExtensions: ['js', 'jsx', 'ts', 'tsx', 'md', 'mdx'],
50
});
51
```
52
53
### App Router Setup
54
55
For Next.js App Router, create an `mdx-components.js` file at the root:
56
57
```javascript
58
// mdx-components.js
59
export function useMDXComponents(components) {
60
return {
61
h1: ({ children }) => <h1 style={{ fontSize: '2rem' }}>{children}</h1>,
62
...components,
63
};
64
}
65
```
66
67
## Architecture
68
69
@next/mdx integrates MDX support into Next.js through several key components:
70
71
- **Configuration Transformer**: The main `withMDX` function transforms Next.js config to support MDX files
72
- **Dual Compilation**: Supports both JavaScript-based (@mdx-js/loader) and Rust-based (mdxRs) MDX compilation
73
- **Webpack Integration**: Automatically configures webpack rules for MDX file processing
74
- **Turbopack Support**: Specialized configuration for Next.js Turbopack builds
75
- **Component Resolution**: Configures MDX component provider resolution through multiple fallback paths
76
77
### Dual Loader System
78
79
@next/mdx uses two different loaders based on configuration:
80
81
1. **JavaScript Loader** (`mdx-js-loader.js`): Default loader using `@mdx-js/loader`
82
- Full ecosystem compatibility with remark/rehype plugins
83
- Dynamic string-based plugin resolution
84
- ES module and CommonJS plugin support
85
86
2. **Rust Loader** (`mdx-rs-loader.js`): High-performance loader for Rust-based compilation
87
- Faster compilation through Next.js `experimental.mdxRs` option
88
- Source map generation using native source-map package
89
- Limited plugin ecosystem compared to JavaScript loader
90
91
The loader selection is automatic:
92
- Rust loader when `experimental.mdxRs` is enabled in Next.js config
93
- JavaScript loader otherwise (default)
94
95
Both loaders configure the same provider import source resolution: `next-mdx-import-source-file`
96
97
## Capabilities
98
99
### Main Configuration Function
100
101
Creates a Next.js configuration transformer that adds MDX support to your Next.js application.
102
103
```typescript { .api }
104
function withMDX(options?: NextMDXOptions): (config: NextConfig) => NextConfig;
105
106
interface NextMDXOptions {
107
/**
108
* A webpack rule test to match files to treat as MDX.
109
* @default /\.mdx$/
110
*/
111
extension?: RuleSetConditionAbsolute;
112
113
/**
114
* The options to pass to MDX compiler.
115
*/
116
options?: Options & {
117
remarkPlugins?: (
118
| string
119
| [name: string, options: any]
120
| NonNullable<Options['remarkPlugins']>[number]
121
)[] | Options['remarkPlugins'];
122
rehypePlugins?: (
123
| string
124
| [name: string, options: any]
125
| NonNullable<Options['rehypePlugins']>[number]
126
)[] | Options['rehypePlugins'];
127
};
128
}
129
130
type WithMDX = (config: NextConfig) => NextConfig;
131
```
132
133
**Usage Examples:**
134
135
```javascript
136
// Basic usage
137
const withMDX = require('@next/mdx')();
138
module.exports = withMDX();
139
140
// With custom file extensions
141
const withMDX = require('@next/mdx')({
142
extension: /\.(md|mdx)$/,
143
});
144
145
// With MDX plugins
146
const withMDX = require('@next/mdx')({
147
options: {
148
remarkPlugins: [
149
'remark-gfm',
150
['remark-toc', { heading: 'Contents' }],
151
],
152
rehypePlugins: [
153
'rehype-slug',
154
'rehype-autolink-headings',
155
],
156
},
157
});
158
159
// With existing Next.js config
160
const withMDX = require('@next/mdx')();
161
module.exports = withMDX({
162
reactStrictMode: true,
163
pageExtensions: ['js', 'jsx', 'ts', 'tsx', 'md', 'mdx'],
164
webpack: (config, options) => {
165
// Custom webpack config
166
return config;
167
},
168
});
169
```
170
171
### Rust-based Compilation (Experimental)
172
173
Enable faster Rust-based MDX compilation through Next.js experimental features.
174
175
```javascript
176
// next.config.js
177
const withMDX = require('@next/mdx')({
178
options: {
179
// MDX options here
180
},
181
});
182
183
module.exports = withMDX({
184
experimental: {
185
mdxRs: true, // Enable Rust-based compilation
186
},
187
});
188
```
189
190
**Advanced Rust Configuration:**
191
192
```javascript
193
module.exports = withMDX({
194
experimental: {
195
mdxRs: {
196
mdxType: 'gfm', // or 'commonMark' (default)
197
// Additional mdx-rs specific options
198
},
199
},
200
});
201
```
202
203
**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.
204
205
### MDX Components Configuration
206
207
Configure custom MDX components through the `mdx-components.js` file:
208
209
```javascript
210
// mdx-components.js (for App Router)
211
export function useMDXComponents(components) {
212
return {
213
// Override built-in components
214
h1: ({ children }) => <h1 className="custom-heading">{children}</h1>,
215
p: ({ children }) => <p className="custom-paragraph">{children}</p>,
216
217
// Add custom components
218
CustomCallout: ({ children, type }) => (
219
<div className={`callout callout-${type}`}>{children}</div>
220
),
221
222
// Spread existing components
223
...components,
224
};
225
}
226
```
227
228
```javascript
229
// _app.js (for Pages Router)
230
import { MDXProvider } from '@mdx-js/react';
231
232
const components = {
233
h1: ({ children }) => <h1 className="custom-heading">{children}</h1>,
234
// ... other components
235
};
236
237
export default function App({ Component, pageProps }) {
238
return (
239
<MDXProvider components={components}>
240
<Component {...pageProps} />
241
</MDXProvider>
242
);
243
}
244
```
245
246
### File Extension Configuration
247
248
Configure which file extensions should be processed as MDX:
249
250
```javascript { .api }
251
// Default: only .mdx files
252
const withMDX = require('@next/mdx')();
253
254
// Support both .md and .mdx files
255
const withMDX = require('@next/mdx')({
256
extension: /\.mdx?$/,
257
});
258
259
// Custom pattern for specific files
260
const withMDX = require('@next/mdx')({
261
extension: /\.(mdx|md)$/,
262
});
263
```
264
265
### Plugin System Integration
266
267
Configure remark and rehype plugins for content transformation:
268
269
```javascript
270
const withMDX = require('@next/mdx')({
271
options: {
272
// Remark plugins (markdown processing)
273
remarkPlugins: [
274
'remark-gfm', // GitHub Flavored Markdown
275
'remark-toc', // Table of contents
276
['remark-slug', { prefix: 'user-content-' }], // Custom slug generation
277
],
278
279
// Rehype plugins (HTML processing)
280
rehypePlugins: [
281
'rehype-slug', // Add IDs to headings
282
'rehype-autolink-headings', // Add links to headings
283
['rehype-prism-plus', { // Syntax highlighting
284
ignoreMissing: true,
285
}],
286
],
287
},
288
});
289
```
290
291
**Dynamic Plugin Loading:**
292
293
Plugins can be loaded dynamically using string references, which @next/mdx resolves automatically:
294
295
```javascript
296
const withMDX = require('@next/mdx')({
297
options: {
298
remarkPlugins: [
299
'remark-gfm', // String reference
300
['remark-toc', { heading: 'Contents' }], // String with options
301
],
302
},
303
});
304
```
305
306
### Turbopack Configuration
307
308
When using Next.js with Turbopack (via `TURBOPACK=1` environment variable), @next/mdx automatically configures special Turbopack rules:
309
310
```javascript { .api }
311
// Automatic Turbopack configuration when TURBOPACK environment is detected
312
{
313
turbopack: {
314
rules: {
315
'#next-mdx': {
316
loaders: [loader], // Uses the same loader (JS or Rust)
317
as: '*.tsx', // Treats MDX files as TypeScript React files
318
},
319
},
320
conditions: {
321
'#next-mdx': {
322
path: extension, // Uses the same extension pattern
323
},
324
},
325
resolveAlias: {
326
'next-mdx-import-source-file': '@vercel/turbopack-next/mdx-import-source',
327
},
328
}
329
}
330
```
331
332
**Key Turbopack Features:**
333
334
- **Rule-based Processing**: MDX files are processed with a dedicated `#next-mdx` rule
335
- **TypeScript Compilation**: MDX files are treated as `*.tsx` files for compilation
336
- **Specialized Import Resolution**: Uses `@vercel/turbopack-next/mdx-import-source` for component resolution
337
- **Automatic Detection**: Configuration is applied automatically when `process.env.TURBOPACK` is detected
338
339
## Types
340
341
These types require the following imports from external packages:
342
343
```typescript
344
import type { NextConfig } from 'next';
345
import type { Options } from '@mdx-js/loader';
346
import type { RuleSetConditionAbsolute } from 'webpack';
347
```
348
349
### NextMDXOptions Interface
350
351
```typescript { .api }
352
interface NextMDXOptions {
353
/**
354
* A webpack rule test to match files to treat as MDX.
355
* @default /\.mdx$/
356
* @example /\.mdx?$/ // Support both .md and .mdx files
357
*/
358
extension?: RuleSetConditionAbsolute;
359
360
/**
361
* The options to pass to MDX compiler.
362
* @see https://mdxjs.com/packages/mdx/#api
363
*/
364
options?: Options & {
365
remarkPlugins?: (
366
| string
367
| [name: string, options: any]
368
| NonNullable<Options['remarkPlugins']>[number]
369
)[] | Options['remarkPlugins'];
370
371
rehypePlugins?: (
372
| string
373
| [name: string, options: any]
374
| NonNullable<Options['rehypePlugins']>[number]
375
)[] | Options['rehypePlugins'];
376
};
377
}
378
```
379
380
### WithMDX Type
381
382
```typescript { .api }
383
type WithMDX = (config: NextConfig) => NextConfig;
384
```
385
386
### Dependencies
387
388
The package has the following dependencies and peer dependencies:
389
390
```json { .api }
391
{
392
"dependencies": {
393
"source-map": "^0.7.0"
394
},
395
"peerDependencies": {
396
"@mdx-js/loader": ">=0.15.0",
397
"@mdx-js/react": ">=0.15.0"
398
},
399
"peerDependenciesMeta": {
400
"@mdx-js/loader": { "optional": true },
401
"@mdx-js/react": { "optional": true }
402
}
403
}
404
```
405
406
## Error Handling
407
408
@next/mdx provides error handling for MDX compilation issues:
409
410
- **Compilation Errors**: MDX syntax errors are reported with file location and context
411
- **Plugin Errors**: Issues with remark/rehype plugins are caught and reported
412
- **Module Resolution**: Missing dependencies or incorrect plugin references are handled gracefully
413
414
Common error scenarios:
415
416
```javascript
417
// Plugin not found - will throw resolution error
418
const withMDX = require('@next/mdx')({
419
options: {
420
remarkPlugins: ['non-existent-plugin'], // Error: Cannot resolve plugin
421
},
422
});
423
424
// Invalid MDX syntax in .mdx files will be reported during build
425
// with file location and specific syntax error details
426
```