---
title: MDX Remote
description: 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.

<Callout type='warn' title="Be Careful">

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

</Callout>

## Setup

```package-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:

```tsx
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:

```tsx
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.
