Introduction Learn how to use Fumadocs MDX in your documentation
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.
npm pnpm yarn bun
npm install fumadocs-mdx @types/mdx
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.
import { defineDocs } from 'fumadocs-mdx/config' ;
export const { docs , meta } = defineDocs ( {
dir : 'content/docs' ,
} ) ;
You can add a post install script to generate types before executing CLI tools (e.g. ESLint).
{
" scripts " : {
" postinstall " : "fumadocs-mdx"
}
}
To integrate with Fumadocs, create:
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..
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.
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:
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 ,
} ) ;
}
These properties are exported from MDX files by default.
Property Description frontmatter
Frontmatter toc
Table of Contents structuredData
Structured Data, useful for implementing search
See MDX Options .