Introduction

Learn how to use Fumadocs MDX in your documentation

What is this?

Fumadocs MDX is the official content source of Fumadocs. It parses frontmatter and is bundled with many MDX plugins for building a good documentation site.

This package uses Fumadocs core.

Installation

Install Dependencies

npm install fumadocs-mdx @types/mdx

Configuration

Add the plugin to your next.config.mjs file.

import { createMDX } from 'fumadocs-mdx/next';
 
const withMDX = createMDX();
 
/** @type {import('next').NextConfig} */
const config = {
  reactStrictMode: true,
};
 
export default withMDX(config);

It generates a .source folder in root directory once you start the dev server or start building the app.

The folder contains all parsed files, you should add it to .gitignore.

ESM Only

The Next.js config must be a .mjs file since Fumadocs is ESM-only.

Configure Fumadocs MDX by creating a source.config.ts file.

source.config.ts
import { defineDocs } from 'fumadocs-mdx/config';
 
export const { docs, meta } = defineDocs({
  dir: 'content/docs',
});

Post Install

You can add a post install script to generate types before executing CLI tools (e.g. ESLint).

package.json
{
  "scripts": {
    "postinstall": "fumadocs-mdx"
  }
}

Resolve Files

To integrate with Fumadocs, create:

lib/source.ts
import { docs, meta } from '@/.source';
import { createMDXSource } from 'fumadocs-mdx';
import { loader } from 'fumadocs-core/source';
 
export const source = loader({
  baseUrl: '/docs',
  source: createMDXSource(docs, meta),
});

We imported the .source folder with @/.source, you can also change it to your own import alias..

Start Server

next dev

A .source folder should be created. You can log and see if it is loaded correctly.

See Pages Conventions to learn how to organize your pages.

Usage

Generally, you'll interact with Fumadocs MDX through the Source loader API. You can see the type definitions to find available properties.

To render the page, obtain the page from source and render the MDX component (page.data.body).

import { notFound } from 'next/navigation';
import { source } from '@/lib/source';
import defaultMdxComponents from 'fumadocs-ui/mdx';
 
const page = source.getPage(['slugs']);
if (!page) notFound();
 
const MDX = page.data.body;
 
// set your MDX components with `components` prop
<MDX components={{ ...defaultMdxComponents }} />;

Eventually, it will look like:

page.tsx (Fumadocs UI)
import { source } from '@/lib/source';
import {
  DocsPage,
  DocsBody,
  DocsTitle,
  DocsDescription,
} from 'fumadocs-ui/page';
import { notFound } from 'next/navigation';
import defaultMdxComponents from 'fumadocs-ui/mdx';
import { metadataImage } from '@/lib/metadata';
 
export default async function Page(props: {
  params: Promise<{ slug?: string[] }>;
}) {
  const params = await props.params;
  const page = source.getPage(params.slug);
  if (!page) notFound();
 
  const MDX = page.data.body;
 
  return (
    <DocsPage toc={page.data.toc} full={page.data.full}>
      <DocsTitle>{page.data.title}</DocsTitle>
      <DocsDescription>{page.data.description}</DocsDescription>
      <DocsBody>
        <MDX components={{ ...defaultMdxComponents }} />
      </DocsBody>
    </DocsPage>
  );
}
 
export async function generateStaticParams() {
  return source.generateParams();
}
 
export async function generateMetadata(props: {
  params: Promise<{ slug?: string[] }>;
}) {
  const params = await props.params;
  const page = source.getPage(params.slug);
  if (!page) notFound();
 
  return metadataImage.withImage(page.slugs, {
    title: page.data.title,
    description: page.data.description,
  });
}

FAQ

Built-in Properties

These properties are exported from MDX files by default.

PropertyDescription
frontmatterFrontmatter
tocTable of Contents
structuredDataStructured Data, useful for implementing search

MDX Plugins

See MDX Options.

Edit on GitHub

Last updated on

On this page