Fumadocs

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.

source.config.ts
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:

  1. Rehydrate those tokens later via renderPlaceholder().
  2. 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", ...}\0

Using 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:

  • name
  • attributes
  • children (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

On this page