Skip to content

Fix: Fumadocs Not Working — Pages Not Found, Search Not Indexing, or MDX Components Missing

FixDevs ·

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 Found

Or the sidebar is empty:

Navigation panel shows no entries despite MDX files existing

Or 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 and meta.json files.
  • fumadocs-ui and fumadocs-core are separatefumadocs-core handles content processing and routing. fumadocs-ui provides 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 emptymeta.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.

F

FixDevs

Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.

Was this article helpful?

Related Articles