--- name: mdx-bundler description: Use mdx-bundler 10.x to bundle MDX on Node, preserve frontmatter, and understand the separate React-dependent client consumption helpers. --- Verified against mdx-bundler@10.1.1 on 2026-09-08. 2 of 2 examples executed. # mdx-bundler ## Scope and version This skill covers `mdx-bundler` `^10.0.0` (the 10.x line, including 10.0.0 through 10.1.1). Node 18 or newer is required. Version 10.1.0 added JSX-runtime support, and 10.1.1 fixed explicit typings. Install the bundler and esbuild: ```sh npm install --save mdx-bundler esbuild ``` The package uses the esbuild binary and has a dependency that requires working `node-gyp` setup. ## Server-side bundling Import `bundleMDX` from the package root. It returns a promise resolving to `{code, frontmatter, matter}`: - `code` is the bundled module source as a string. - `frontmatter` is the parsed gray-matter frontmatter object. - `matter` is the complete gray-matter result. Use `source` for an in-memory MDX string. Use `files` for in-memory imported files. The files map can contain relative imports such as `./demo.tsx`. ```ts pmcp-example import assert from 'node:assert/strict' import {bundleMDX} from 'mdx-bundler' const result = await bundleMDX({ source: `--- title: Hello --- # Wahoo `, }) assert.equal(result.frontmatter.title, 'Hello') assert.match(result.code, /Wahoo/) assert.equal(typeof result.matter, 'object') ``` An imported in-memory component is bundled together with the MDX source: ```ts pmcp-example import assert from 'node:assert/strict' import {bundleMDX} from 'mdx-bundler' const result = await bundleMDX({ source: `# Demo import Demo from './demo' `, files: { './demo.tsx': ` import * as React from 'react' export default function Demo() { return
Neat demo!
} `, }, }) assert.equal(typeof result.code, 'string') assert.ok(result.code.length > 0) assert.equal(result.frontmatter && typeof result.frontmatter, 'object') ``` The documented options are `source` or `file`, `files`, `mdxOptions`, `esbuildOptions`, `globals`, `cwd`, `grayMatterOptions`, `bundleDirectory`, and `bundlePath`. `source` and `file` are alternatives: do not provide both. A `file` is read from disk and needs an appropriate `cwd` for relative imports. ## Consuming bundled code The bundling API is the Node/server/build side. Browser or SSR consumption uses the separate client entry points: - `mdx-bundler/client` exports `getMDXComponent` and `getMDXExport`. - `mdx-bundler/client/jsx` exports `getMDXComponent` for the JSX-runtime setup. The documented usage is in a React application. `getMDXComponent` creates the default component, while `getMDXExport` returns the evaluated module-shaped exports, including the default component and named exports: ```tsx import * as React from 'react' import {getMDXComponent} from 'mdx-bundler/client' function Post({code}: {code: string}) { const Component = React.useMemo(() => getMDXComponent(code), [code]) return } ``` ```js import * as React from 'react' import {getMDXExport} from 'mdx-bundler/client' function MDXPage({code}) { const mdxExport = getMDXExport(code) console.log(mdxExport.toc) const Component = React.useMemo(() => mdxExport.default, [code]) return } ``` These client helpers are not standalone examples for the installation shown above: loading `mdx-bundler/client` reaches for React, and a direct script with only the package and esbuild installed fails when React is unavailable. Exercise these helpers in the React application or SSR environment that consumes the bundle. `getMDXComponent` evaluates bundled code with `new Function`; treat bundled code as executable code and do not use this client path for untrusted content without an appropriate security boundary. ## JSX runtime configuration Version 10.1.x documents JSX-runtime configuration through `jsxConfig` and the `mdx-bundler/client/jsx` entry point. The documented configuration entries are `jsxLib`, `jsxDom`, and `jsxRuntime`. Use this path when configuring the MDX bundle for the JSX runtime rather than assuming the older client helper shape is the only supported option. ## Common mistakes and version traps - **Running on an old Node version:** v10 requires Node 18 or newer. The v9 call shape may look familiar, but v10's runtime and dependency requirements still apply. - **Expecting `bundleMDX` in the browser:** bundling uses the esbuild binary and belongs on the Node/server/build side. Send the generated `code` to a client or SSR environment instead. - **Providing both `source` and `file`:** these are mutually exclusive inputs. Choose the in-memory source or the disk-backed file. - **Forgetting `cwd` for file-based relative imports:** `file` reads from disk; set `cwd` so relative imports resolve from the intended location. - **Using `describe`, `it`, or `expect` in a direct script:** this package does not provide test-runner globals. The runnable examples use only programmatic APIs and `node:assert/strict`. - **Assuming frontmatter dates are parsed as dates:** the v10 release notes warn that `remark-mdx-frontmatter` no longer parses dates. Account for the value exposed in `frontmatter` accordingly. - **Assuming Cloudflare Workers can run the full package:** Workers cannot run the esbuild binary or `eval`/similar evaluation. Run bundling elsewhere or investigate a WASM-based approach. - **Missing esbuild executable lookup in Next.js/Webpack:** those environments may need `ESBUILD_BINARY_PATH` configured before calling `bundleMDX`. - **Copying only the old default-component recipe:** `getMDXExport` is the module-shaped alternative, and v10.1.x also documents the JSX-runtime configuration and `client/jsx` entry point. The client helpers require the React-consuming environment rather than functioning as bare standalone scripts with only the bundler installation. ## Not covered This skill does not cover the complete shapes of every option (`mdxOptions`, `esbuildOptions`, `globals`, `grayMatterOptions`, `bundleDirectory`, or `bundlePath`), custom remark/rehype plugin configuration, detailed React rendering setup, the additional React installation/configuration needed by the client helpers, deployment-specific `ESBUILD_BINARY_PATH` values, WASM alternatives, or the internal generated-code format. The research also does not establish the exact `jsxConfig` object type beyond the documented `jsxLib`, `jsxDom`, and `jsxRuntime` entries.