Fumadocs

MDX Remote

Compiled Markdown/MDX content on demand.

Introduction

Fumadocs offers the MDX Remote package, it is a helper to integrate Markdown/MDX content sources with Fumadocs. You can think it as a next-mdx-remote with built-in plugins for Fumadocs.

Be Careful

The Passed MDX content must be trusted as it allows code execution by default.

Setup

npm install @fumadocs/mdx-remote

The main feature it offers is the MDX Compiler, it can compile MDX content to JSX nodes. Since it doesn't use a bundler, there's some limitations:

  • Images have to be optimized at runtime.
  • No imports and exports in MDX files.

With RSC

It's compatible with Server Components. For example:

import { createCompiler } from '@fumadocs/mdx-remote';
import { getPage } from './my-content-source';
import { DocsBody, DocsPage } from 'fumadocs-ui/layouts/docs/page';
import { getMDXComponents } from '@/components/mdx';

const compiler = createCompiler({
  // options
});

export default async function Page({ params }: PageProps<'/docs/[[...slug]]'>) {
  const { slug } = await params;
  const page = getPage(slug);
  const { toc, body: MdxContent } = await compiler.compile({
    source: page.content,
  });

  return (
    <DocsPage toc={toc}>
      <DocsBody>
        <MdxContent components={getMDXComponents()} />
      </DocsBody>
    </DocsPage>
  );
}

Without RSC

Without Server Components, you can enable skipRender and pass the compiled code to client instead:

import { createCompiler } from '@fumadocs/mdx-remote';
import { executeMdxSync } from '@fumadocs/mdx-remote/client';
import { DocsBody, DocsPage } from 'fumadocs-ui/layouts/docs/page';
import { getPage } from './my-content-source';
import { useMemo } from 'react';
import { getMDXComponents } from '@/components/mdx';

const compiler = createCompiler({
  // options
});

// e.g. where you generate loader data
async function serverPayload(slugs?: string[]) {
  const page = getPage(slugs);
  const { compiled, frontmatter } = await compiler.compile({
    source: page.content,
    skipRender: true,
  });

  return { compiled, frontmatter };
}

function Page() {
  // read compiled code from server payload
  const { compiled } = useLoaderData();
  const { default: MdxContent, toc } = useMemo(() => executeMdxSync(compiled), [compiled]);

  return (
    <DocsPage toc={toc}>
      <DocsBody>
        <MdxContent components={getMDXComponents()} />
      </DocsBody>
    </DocsPage>
  );
}

The frontmatter property returned by compile() is not validated, you may use a library like zod to validate its data type.

Images

On serverless platforms like Vercel, the original public folder (including static assets like images) will be removed after production build. The MDX compiler might no longer be able to access local images in public.

When referencing images, make sure to use a URL.

How is this guide?

Last updated on

On this page