Remark LLMs
Generate markdown for LLM consumption with customizable placeholders
The remarkLLMs plugin stringifies the processed Markdown AST to plain Markdown, the output is generated as an ESM export. This is useful for feeding content to LLMs, search indexing, or other text-based processing.
Usage
Fumadocs MDX
Enable includeProcessedMarkdown in your collection config, Fumadocs MDX runs remarkLLMs internally when this is set.
import { defineDocs } from 'fumadocs-mdx/config';
import { type LLMsOptions } from 'fumadocs-core/mdx-plugins/remark-llms';
const llmsOptions: LLMsOptions = {
// options...
};
export default defineDocs({
docs: {
postprocess: {
includeProcessedMarkdown: llmsOptions,
},
},
});The stringified Markdown is exported as _markdown and available via getText('processed'), see Collections for details.
MDX Compiler
When using the MDX Compiler (or a custom pipeline), add the plugin:
import { compile } from '@mdx-js/mdx';
import { remarkLLMs, type LLMsOptions } from 'fumadocs-core/mdx-plugins/remark-llms';
const llmsOptions: LLMsOptions = {
// The output will be exported as `_markdown`
as: '_markdown',
};
const vfile = await compile('...', {
remarkPlugins: [[remarkLLMs, llmsOptions]],
});Placeholders
Placeholders let you keep certain MDX components in the stringified output as special tokens instead of dropping or inlining them. That way you can:
- Rehydrate those tokens later via
renderPlaceholder(). - Generate a better Markdown representation with runtime data.
Using mdxAsPlaceholder
List component names to treat as placeholders:
import { type LLMsOptions } from 'fumadocs-core/mdx-plugins/remark-llms';
const llmsOptions: LLMsOptions = {
mdxAsPlaceholder: ['Callout', 'Card'],
};In the exported Markdown, <Callout> and <Card> will appear as placeholder tokens, like:
\0{"name": "Callout", ...}\0Using stringify
For full control, use the stringify option and with the placeholder() helper:
import { placeholder, type LLMsOptions } from 'fumadocs-core/mdx-plugins/remark-llms';
const llmsOptions: LLMsOptions = {
stringify(node, parent, state, info) {
if (node.type === 'mdxJsxFlowElement' && node.name === 'MyPage') {
return placeholder(node, parent, state, info);
}
},
};Rendering Placeholders
Use renderPlaceholder() from the runtime module to replace placeholder tokens with custom output:
import { renderPlaceholder } from 'fumadocs-core/mdx-plugins/remark-llms.runtime';
const markdown = await getExportedMarkdown(); // e.g. from _markdown
const rendered = await renderPlaceholder(markdown, {
async Callout({ name, attributes, children }) {
// note: you can also fetch data here
const data = await fetchData();
return `[${attributes.type ?? 'info'}] ${children}`;
},
Card({ attributes, children }) {
return `**${attributes.title}**\n\n${children}`;
},
});Each renderer receives PlaceholderData:
nameattributeschildren(the stringified child content).
Example
# Getting started
<Callout type="tip">Hello **world**.</Callout>
Some paragraph.Options
Prop
Type
How is this guide?
Last updated on
