Skip to main content

Overview

Fumadocs Core is built on a modular, plugin-based architecture that separates concerns between content loading, page tree generation, and framework integration. The architecture enables framework-agnostic documentation sites with powerful content management capabilities.

Core Components

The Fumadocs Core architecture consists of four primary layers:
1

Content Layer

Source adapters transform raw content files into a unified virtual file system
2

Processing Layer

Plugins transform and enhance content during the build process
3

Page Tree Layer

The page tree builder generates hierarchical navigation structures
4

Framework Layer

Framework adapters integrate with Next.js, React Router, and other frameworks

Architecture Diagram

Virtual File System

At the heart of Fumadocs is an in-memory virtual file system that normalizes content from various sources:
packages/core/src/source/storage/file-system.ts
export class FileSystem<File> {
  files = new Map<string, File>();
  folders = new Map<string, string[]>();

  read(path: string): File | undefined {
    return this.files.get(path);
  }

  readDir(path: string): string[] | undefined {
    return this.folders.get(path);
  }

  write(path: string, file: File): void {
    if (!this.files.has(path)) {
      const dir = dirname(path);
      this.makeDir(dir);
      this.readDir(dir)?.push(path);
    }
    this.files.set(path, file);
  }
}
The virtual file system provides a consistent API regardless of whether content comes from the local filesystem, a CMS, or a remote API.

Content Storage

Content files are normalized into two types stored in ContentStorage:
interface ContentStoragePageFile<Config> {
  path: string;
  absolutePath?: string;
  format: 'page';
  slugs: string[];
  data: Config['pageData'];
}

Plugin System

Fumadocs uses a powerful plugin system for extending functionality:
packages/core/src/source/loader.ts
interface LoaderPlugin<Config> {
  name?: string;
  enforce?: 'pre' | 'post';
  
  // Modify loader configuration
  config?: (config: ResolvedLoaderConfig) => ResolvedLoaderConfig | void;
  
  // Transform content storage after loading
  transformStorage?: (context: { storage: ContentStorage }) => void;
  
  // Transform generated page tree
  transformPageTree?: PageTreeTransformer;
}

Built-in Plugins

Fumadocs Core includes several essential plugins:

Slugs Plugin

Generates URL slugs from file paths with proper encoding for non-ASCII characters

Icon Plugin

Resolves icon references from icon libraries like Lucide

Fallback Transformer

Creates fallback page trees for localized content

Status Badges

Adds status indicators (Beta, Deprecated, etc.) to pages

Loader System

The loader() function is the entry point for processing content:
packages/core/src/source/loader.ts
export function loader<Config, I18n>(
  source: Source<Config>,
  options: LoaderOptions<{ source: Config; i18n: I18n }>
): LoaderOutput {
  // 1. Build content storage (virtual file system)
  const storage = i18n 
    ? createContentStorageBuilder(config).i18n() 
    : createContentStorageBuilder(config).single();
  
  // 2. Run plugins to transform storage
  for (const plugin of plugins) {
    plugin.transformStorage?.({ storage });
  }
  
  // 3. Build page tree from storage
  const pageTree = new PageTreeBuilder(storage, options).root();
  
  // 4. Return loader output with utility functions
  return {
    pageTree,
    getPage,
    getPages,
    getPageTree,
    // ... more utilities
  };
}
The loader returns an object with methods for:
  • getPage() - Retrieve page by slugs
  • getPages() - List all pages (optionally filtered by language)
  • getPageTree() - Get navigation tree for a locale
  • getPageByHref() - Resolve relative file paths and URLs
  • generateParams() - Generate static params for SSG
  • serializePageTree() - Serialize for non-RSC environments

Framework Abstraction

Fumadocs abstracts framework-specific APIs through a unified provider:
packages/core/src/framework/index.tsx
interface Framework {
  usePathname: () => string;
  useParams: () => Record<string, string | string[]>;
  useRouter: () => Router;
  Link?: FC<LinkProps>;
  Image?: FC<ImageProps>;
}

export function FrameworkProvider({ children, ...framework }: Framework) {
  return (
    <FrameworkContext value={framework}>
      {children}
    </FrameworkContext>
  );
}
This enables Fumadocs UI components to work with Next.js, React Router, TanStack Router, and Waku without modification.
import { FrameworkProvider } from 'fumadocs-core/framework';
import { usePathname, useParams, useRouter } from 'next/navigation';
import NextLink from 'next/link';
import NextImage from 'next/image';

<FrameworkProvider
  usePathname={usePathname}
  useParams={useParams}
  useRouter={useRouter}
  Link={NextLink}
  Image={NextImage}
/>

URL Generation

The loader generates URLs based on slugs and i18n configuration:
packages/core/src/source/loader.ts
export function createGetUrl(baseUrl: string, i18n?: I18nConfig) {
  const baseSlugs = baseUrl.split('/');

  return (slugs: string[], locale?: string) => {
    const hideLocale = i18n?.hideLocale ?? 'never';
    let urlLocale: string | undefined;

    if (hideLocale === 'never') {
      urlLocale = locale;
    } else if (hideLocale === 'default-locale' && locale !== i18n?.defaultLanguage) {
      urlLocale = locale;
    }

    const paths = [...baseSlugs, ...slugs];
    if (urlLocale) paths.unshift(urlLocale);

    return `/${paths.filter((v) => v.length > 0).join('/')}`;
  };
}
Slugs are automatically URI-encoded by the slugs plugin to support non-ASCII characters in URLs.

Type Safety

Fumadocs maintains end-to-end type safety:
import { loader } from 'fumadocs-core/source';
import { source } from './source';

const docs = loader({
  source,
  baseUrl: '/docs',
});

// Fully typed based on your source configuration
type PageType = InferPageType<typeof docs>;
type MetaType = InferMetaType<typeof docs>;

Performance Optimizations

Page trees are generated lazily and cached, only building when first accessed.
Pages are indexed by slugs and paths for O(1) lookup performance.
The plugin system supports incremental transformations for fast rebuilds.
Framework adapters are separate entry points for optimal bundle sizes.

Next Steps

Content Sources

Learn about source adapters and content loading

Page Tree

Understand page tree structure and navigation

Routing

Explore URL generation and routing strategies

Plugin Development

Build custom plugins to extend Fumadocs

Build docs developers (and LLMs) love