Fix: Fumadocs Not Working — Pages Not Found, Search Not Indexing, or MDX Components Missing
Quick Answer
How to fix Fumadocs documentation framework issues — Next.js App Router setup, content source configuration, sidebar generation, MDX components, search, OpenAPI integration, and custom themes.
The Problem
Fumadocs pages render as 404:
GET /docs/getting-started → 404 Not FoundOr the sidebar is empty:
Navigation panel shows no entries despite MDX files existingOr built-in components don’t render:
import { Callout } from 'fumadocs-ui/components/callout';
// Module not found: Can't resolve 'fumadocs-ui/components/callout'Why This Happens
Fumadocs is a Next.js documentation framework built on App Router. It uses content collections with a source adapter:
- Content source must be configured — Fumadocs reads MDX from a content source (file system, Contentlayer, or custom). Without a properly configured source, no pages are generated.
- The file-based routing requires
source.ts— Fumadocs generates routes from a source configuration file. The page tree (sidebar) is built from the file structure andmeta.jsonfiles. fumadocs-uiandfumadocs-coreare separate —fumadocs-corehandles content processing and routing.fumadocs-uiprovides the theme and components. Both must be installed.- MDX processing needs the Fumadocs remark/rehype plugins — code highlighting, callouts, and other features require specific plugins in the content source config.
Fix 1: Setup with Next.js
npm install fumadocs-core fumadocs-ui fumadocs-mdx// source.ts — content source configuration
import { docs, meta } from '@/.source';
export const source = docs.toFumadocsSource();// app/layout.tsx
import { RootProvider } from 'fumadocs-ui/provider';
import 'fumadocs-ui/style.css'; // Required CSS
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en" suppressHydrationWarning>
<body>
<RootProvider>{children}</RootProvider>
</body>
</html>
);
}// app/docs/layout.tsx — docs layout with sidebar
import { DocsLayout } from 'fumadocs-ui/layouts/docs';
import { source } from '@/lib/source';
export default function Layout({ children }: { children: React.ReactNode }) {
return (
<DocsLayout
tree={source.pageTree}
nav={{ title: 'My Docs' }}
>
{children}
</DocsLayout>
);
}// app/docs/[[...slug]]/page.tsx — docs page
import { source } from '@/lib/source';
import { notFound } from 'next/navigation';
import defaultMdxComponents from 'fumadocs-ui/mdx';
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 (
<article>
<h1>{page.data.title}</h1>
<MDX components={{ ...defaultMdxComponents }} />
</article>
);
}
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) return {};
return { title: page.data.title, description: page.data.description };
}Fix 2: Content Structure
content/docs/
├── index.mdx # /docs
├── meta.json # Root sidebar config
├── getting-started/
│ ├── meta.json # Group sidebar config
│ ├── index.mdx # /docs/getting-started
│ ├── installation.mdx # /docs/getting-started/installation
│ └── quick-start.mdx
├── guides/
│ ├── meta.json
│ ├── basic-usage.mdx
│ └── advanced.mdx
└── api/
├── meta.json
├── client.mdx
└── server.mdx// content/docs/meta.json — root sidebar order
{
"title": "Documentation",
"pages": [
"---Getting Started---",
"getting-started",
"---Guides---",
"guides",
"---API---",
"api"
]
}
// content/docs/getting-started/meta.json
{
"title": "Getting Started",
"pages": [
"index",
"installation",
"quick-start"
]
}---
title: Installation
description: How to install and configure the project
---
# Installation
## Prerequisites
You need Node.js 18+.
## Install
```bash
npm install my-package
## Fix 3: Built-In MDX Components
```mdx
---
title: Component Examples
---
import { Callout } from 'fumadocs-ui/components/callout';
import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
import { Step, Steps } from 'fumadocs-ui/components/steps';
import { Card, Cards } from 'fumadocs-ui/components/card';
import { Accordion, Accordions } from 'fumadocs-ui/components/accordion';
import { File, Folder, Files } from 'fumadocs-ui/components/files';
import { TypeTable } from 'fumadocs-ui/components/type-table';
## Callouts
<Callout>This is an informational note.</Callout>
<Callout type="warn">Be careful with this approach.</Callout>
<Callout type="error">This will cause data loss!</Callout>
## Tabs
<Tabs items={['npm', 'pnpm', 'yarn']}>
<Tab value="npm">
```bash
npm install my-package
```
</Tab>
<Tab value="pnpm">
```bash
pnpm add my-package
```
</Tab>
<Tab value="yarn">
```bash
yarn add my-package
```
</Tab>
</Tabs>
## Steps
<Steps>
<Step>
### Install dependencies
Run the install command.
</Step>
<Step>
### Configure the project
Create a configuration file.
</Step>
<Step>
### Start developing
Run the dev server.
</Step>
</Steps>
## Cards
<Cards>
<Card title="Quick Start" href="/docs/getting-started/quick-start">
Get up and running in 5 minutes.
</Card>
<Card title="API Reference" href="/docs/api">
Complete API documentation.
</Card>
</Cards>
## File Tree
<Files>
<Folder name="src" defaultOpen>
<Folder name="components">
<File name="Header.tsx" />
<File name="Footer.tsx" />
</Folder>
<File name="index.ts" />
</Folder>
<File name="package.json" />
</Files>
## Type Table
<TypeTable
type={{
name: { type: 'string', description: 'The user name', required: true },
email: { type: 'string', description: 'Email address' },
role: { type: "'admin' | 'user'", description: 'User role', default: "'user'" },
}}
/>Fix 4: Search Configuration
// Fumadocs includes built-in search powered by Flexsearch
// app/api/search/route.ts
import { source } from '@/lib/source';
import { createSearchAPI } from 'fumadocs-core/search/server';
export const { GET } = createSearchAPI('advanced', {
indexes: source.getPages().map((page) => ({
title: page.data.title,
description: page.data.description,
url: page.url,
id: page.url,
structuredData: page.data.structuredData,
})),
});// app/layout.tsx — enable search in the layout
import { RootProvider } from 'fumadocs-ui/provider';
<RootProvider
search={{
links: [
['Home', '/'],
['Docs', '/docs'],
],
}}
>
{children}
</RootProvider>Fix 5: Theme Customization
/* app/global.css — override Fumadocs theme */
:root {
--fd-primary: 234 89% 56%; /* HSL values for primary color */
--fd-background: 0 0% 100%;
--fd-foreground: 222 84% 5%;
--fd-muted: 210 40% 96%;
--fd-accent: 210 40% 96%;
--fd-border: 214 32% 91%;
}
.dark {
--fd-background: 222 84% 5%;
--fd-foreground: 210 40% 98%;
--fd-muted: 217 33% 17%;
--fd-border: 217 33% 17%;
}// app/docs/layout.tsx — customize nav and sidebar
import { DocsLayout } from 'fumadocs-ui/layouts/docs';
import { source } from '@/lib/source';
export default function Layout({ children }) {
return (
<DocsLayout
tree={source.pageTree}
nav={{
title: (
<div className="flex items-center gap-2">
<img src="/logo.svg" width={24} height={24} alt="Logo" />
<span className="font-bold">My Docs</span>
</div>
),
links: [
{ text: 'Blog', url: '/blog' },
{ text: 'GitHub', url: 'https://github.com/user/repo', external: true },
],
}}
sidebar={{
defaultOpenLevel: 1,
}}
>
{children}
</DocsLayout>
);
}Fix 6: OpenAPI Integration
npm install fumadocs-openapi// Generate API reference docs from OpenAPI spec
// scripts/generate-docs.mts
import { generateFiles } from 'fumadocs-openapi';
void generateFiles({
input: ['./openapi.json'],
output: './content/docs/api',
per: 'operation', // One page per operation
});// package.json
{
"scripts": {
"generate:api": "tsx scripts/generate-docs.mts",
"prebuild": "npm run generate:api"
}
}Still Not Working?
404 on all docs pages — check the catch-all route file exists at app/docs/[[...slug]]/page.tsx. The double brackets [[...slug]] are required for optional catch-all routing. Also verify source.getPage(params.slug) finds the page — log the slug to debug.
Sidebar is empty — meta.json files control sidebar ordering. Without them, pages appear in the sidebar but may be unsorted. Check that source.pageTree returns a non-empty tree. The content source must be properly configured to scan the correct directory.
MDX components not found — install fumadocs-ui and import from fumadocs-ui/components/*. Pass defaultMdxComponents from fumadocs-ui/mdx to the MDX component: <MDX components={{ ...defaultMdxComponents }} />.
Search returns no results — the search API route must exist at /api/search. Check that createSearchAPI receives indexed pages. Search indexes are built at request time from source.getPages(). Verify pages have structuredData in their data.
For related documentation issues, see Fix: Starlight Not Working and Fix: Nextra Not Working.
Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.
Was this article helpful?
Related Articles
Fix: Nextra Not Working — Pages Not Rendering, Sidebar Missing, or MDX Components Broken
How to fix Nextra documentation site issues — Next.js integration, _meta.json sidebar configuration, custom MDX components, search setup, theme customization, and static export.
Fix: Clerk Not Working — Auth Not Loading, Middleware Blocking, or User Data Missing
How to fix Clerk authentication issues — ClerkProvider setup, middleware configuration, useUser and useAuth hooks, server-side auth, webhook handling, and organization features.
Fix: Contentlayer Not Working — Content Not Generated, Types Missing, or Build Errors
How to fix Contentlayer and Contentlayer2 issues — content source configuration, document type definitions, MDX processing, computed fields, Next.js integration, and migration to alternatives.
Fix: Docusaurus Not Working — Build Failing, Sidebar Not Showing, or Plugin Errors
How to fix Docusaurus issues — docs and blog configuration, sidebar generation, custom theme components, plugin setup, MDX compatibility, search integration, and deployment.