Fumadocs

Manual Installation

Create a new fumadocs project from sketch.

Getting Started

Create a new Next.js application with create-next-app, and install required packages.

npm install fumadocs-ui fumadocs-core

Configuration

You can choose a content source you prefer.

There is a list of supported sources:

You have to configure the library correctly following their setup guide before continuing.

Root Layout

Wrap the entire application inside Root Provider.

import { RootProvider } from 'fumadocs-ui/provider';
import type { ReactNode } from 'react';
 
export default function RootLayout({ children }: { children: ReactNode }) {
  return (
    <html lang="en">
      <body>
        <RootProvider>{children}</RootProvider>
      </body>
    </html>
  );
}

Styles

Import the pre-built stylesheet in the root layout.

layout.tsx
import 'fumadocs-ui/style.css';

It doesn't come with a default font, you may choose one from next/font.

Layout

Create a new catch-all route /app/docs/[[..slugs]] for our docs, and give it a proper layout.

app/docs/layout.tsx
import { DocsLayout } from 'fumadocs-ui/layout';
import { pageTree } from '@/app/source';
import type { ReactNode } from 'react';
 
export default function RootDocsLayout({ children }: { children: ReactNode }) {
  return (
    <DocsLayout tree={pageTree} nav={{ title: 'My App' }}>
      {children}
    </DocsLayout>
  );
}

pageTree refers to Page Tree, it should be provided by your content source.

Page

For the page.tsx, it may vary depending on your source. You should configure static rendering with generateStaticParams and metadata with generateMetadata.

Wrap your content in the Page component.

app/docs/[[...slug]]/page.tsx
import { getPage, getPages } from '@/app/source';
import type { Metadata } from 'next';
import { DocsPage, DocsBody } from 'fumadocs-ui/page';
import { notFound } from 'next/navigation';
 
export default async function Page({
  params,
}: {
  params: { slug?: string[] };
}) {
  const page = getPage(params.slug);
 
  if (page == null) {
    notFound();
  }
 
  const MDX = page.data.exports.default;
 
  return (
    <DocsPage toc={page.data.exports.toc} full={page.data.full}>
      <DocsBody>
        <h1>{page.data.title}</h1>
        <MDX />
      </DocsBody>
    </DocsPage>
  );
}
 
export async function generateStaticParams() {
  return getPages().map((page) => ({
    slug: page.slugs,
  }));
}
 
export function generateMetadata({ params }: { params: { slug?: string[] } }) {
  const page = getPage(params.slug);
 
  if (page == null) notFound();
 
  return {
    title: page.data.title,
    description: page.data.description,
  } satisfies Metadata;
}

Use the default document search based on Flexsearch.

app/api/search/route.ts
import { getPages } from '@/app/source';
import { createSearchAPI } from 'fumadocs-core/search/server';
 
export const { GET } = createSearchAPI('advanced', {
  indexes: getPages().map((page) => ({
    title: page.data.title,
    structuredData: page.data.exports.structuredData,
    id: page.url,
    url: page.url,
  })),
});

Learn more about Document Search.

Done

You can start the dev server and start writing content.

Last updated on

On this page

Edit on Github