Orientation
Content Processing
Search Infrastructure
Rendering and UI
Developer Tooling
How It Works
The following files were used as context for generating this wiki page:
Remote MDX is a specialized subsystem within the Fumadocs ecosystem that enables the dynamic compilation and execution of MDX content, typically outside of the primary build-time bundler context. By decoupling the MDX processor from static build steps, it allows for on-demand rendering, remote content fetching, and runtime evaluation of Markdown documents. This is essential for applications requiring highly flexible content delivery, such as CMS-backed documentation or platform-agnostic content rendering where source files may not be available to the compiler until runtime.
The subsystem bridges the gap between raw text content (stored as strings or files) and React-based UI components. It achieves this by providing a unified dynamic entry point that handles the initialization of the compiler core, mapping document collections to lazy-loading entries, and executing the compiled MDX via custom-built AsyncFunction wrappers. This architecture supports advanced features like frontmatter transformation, cached file reads, and structured data extraction, ensuring consistency between build-time and runtime content environments.
Interacting with the broader Fumadocs system, Remote MDX leverages existing remark and rehype plugin pipelines. Its design favors "pre-compilation" where possible—compiling content into a serialized JavaScript format—which allows runtime components to simply hydrate the result rather than re-running heavy transformation chains. This performance-oriented approach ensures that even "dynamic" content maintains the efficiency expected of statically generated documentation.
The Remote MDX pipeline processes content by transforming raw source strings into executable JavaScript representations. This process is orchestrated by buildMDX, which utilizes @mdx-js/mdx to create a Processor instance configured according to the global Fumadocs settings.
Sources: packages/mdx/src/runtime/dynamic.ts:75-81, packages/mdx/src/loaders/mdx/build-mdx.ts:92-102
The buildMDX function is the primary gatekeeper, ensuring that all plugins and post-processing steps (such as remark-include) are applied correctly before the content is serialized. The executeMdx helper then uses an AsyncFunction constructor to instantiate the compiled code string into a runnable object. This allows the system to treat the output of an MDX file as a standard, dynamic module that can be injected with specific React scopes and runtimes.
The dynamic utility coordinates how individual documents within a collection are exposed for runtime access. By using convertLazyEntries, it wraps file content processing into asynchronous factory functions (head and body getters).
Note
The body getter uses a caching strategy where (cachedResult ??= compile(entry)) ensures that a specific document is only compiled once per lifecycle, preventing redundant expensive CPU operations during concurrent requests.
Sources: packages/mdx/src/runtime/dynamic.ts:91-91
The system distinguishes between doc and docs collection types, applying appropriate metadata resolution via getDocCollection. When an entry is accessed, it triggers the file-system-based compilation process, reading the physical file from info.fullPath and processing it through the runtime MDX builder.
The runtime execution layer uses the executeMdx function to handle the final conversion of compiled strings to interactive components. It establishes an isolated scope by merging user-provided context with the default JSX runtime.
Sources: packages/mdx/src/runtime/dynamic.ts:32-45
By creating a function via new AsyncFunction(...Object.keys(fullScope), compiled), the system dynamically generates a closure that treats the MDX-compiled source as if it were a local module. This mechanism bypasses the need for manual file system writes in high-performance runtime environments.
The index-file plugin is responsible for generating the glue code that bridges static configuration with dynamic entry points. It works by inspecting the internal Core state and emitting TypeScript files that register collections to the runtime.
Sources: packages/mdx/src/plugins/index-file.ts:121-157
The emit loop systematically creates server.ts, dynamic.ts, and browser.ts entry points. The selection of which collections to include is performed by evaluating isDynamic(collection), a check that ensures only collections specifically flagged for runtime compilation are subjected to the dynamic index generation logic.
Remote MDX maintains strict invariants when handling frontmatter, especially in dynamic collections. The core.transformFrontmatter method is the centralized point for this, ensuring that data validation (via Zod schemas) and plugin-based transformations are always applied before the data touches the compiler.
Caution
If a collection defines a schema, it MUST pass validation during the transformFrontmatter phase. Failure to do so at runtime will result in an Error thrown early in the pipeline, preventing partially malformed data from ever entering the rendering loop.
Sources: packages/mdx/src/core.ts:153-169
Below is a simplified example demonstrating how one would invoke the dynamic loader to access a document collection at runtime.
import { dynamic } from 'fumadocs-mdx/runtime/dynamic';
// 1. Initialized with config exports, core options, and server runtime settings
const runtime = await dynamic(
configExports,
{ environment: 'runtime', configPath: './source.config.ts', outDir: '.source' },
{ doc: { passthroughs: ['extractedReferences'] } }
);
// 2. Fetch a document from the collection
const docEntry = await runtime.doc('blog', '/base/path', [
{
info: { path: 'example.mdx', fullPath: './content/example.mdx' },
data: { title: 'Hello World' }
}
]);Sources: packages/mdx/src/runtime/dynamic.ts:47-123