Orientation
Content Processing
Search Infrastructure
Rendering and UI
Developer Tooling
How It Works
The following files were used as context for generating this wiki page:
The "Quick Start" subsystem facilitates the rapid scaffolding and initialization of Fumadocs-powered applications. Its primary goal is to abstract the complexity of configuring build tools, file-system watching, and dependency management across various framework environments (Next.js, Waku, Vite). By providing unified CLI-driven project generation and framework-specific adapter configurations, it ensures a consistent development experience regardless of the underlying stack.
The subsystem operates through a "generator-plugin" architecture. The entry point, create-app, interacts with the user via clack prompts to define project requirements, such as linting preferences, search engine solutions, and AI chat integration. Once initialized, it executes a series of plugin-based transformations—such as adding dependencies to package.json or injecting AI search components into layout files—ensuring the scaffolded environment adheres to project best practices.
Integration with existing projects occurs through specific framework adapters located in mdx/src/vite/index.ts and mdx/src/next/index.ts. These modules define core emitters that watch for configuration changes, handle MDX/Meta file compilation, and ensure the development server remains reactive to content updates. This design decouples the user-facing CLI experience from the complex build-time requirements of the Fumadocs framework.
The project generation mechanism starts with the bin.ts entry point in the create-app package. It uses a structured prompt group to gather user configuration, which is then passed to the create() function. The CLI handles complex decisions, such as whether to enable the /src directory for Next.js projects or which search solution (Orama/Orama Cloud) to utilize, based on the selected template.
// Example: CLI generation workflow in packages/create-app/src/bin.ts
await create({
packageManager: config.pm,
template: options.template,
outputDir: projectName,
installDeps: options.installDeps,
initializeGit: config.git,
plugins,
log: (message) => { info.message(message); },
});Sources: packages/create-app/src/bin.ts:272-282
The system also enforces a strict pre-flight check for target directories. If a directory already exists, it prompts for deletion and handles recursive removal of files via fs.rm to ensure a clean slate, preventing stale configuration leaks.
Sources: packages/create-app/src/bin.ts:319-326
The core functionality for integrating Fumadocs into a project is split between Vite and Next.js adapters. These adapters normalize configuration and provide lifecycle hooks for the development server.
createMDX): Injects custom webpack loaders for .mdx, .md, and .json files. It manages the pageExtensions configuration and initializes a FSWatcher to restart the development process when configPath changes.mdx): Implements Vite-specific plugins to handle file transformations. It filters out files from internal paths like virtual:vite-rsc to ensure compatibility with RSC-heavy environments.Note
The dev server watcher explicitly ignores the outDir during initialization to prevent infinite reload loops caused by the generator emitting files into the target folder.
Sources: packages/mdx/src/next/index.ts:138
The create-app generator supports a pluggable architecture using TemplatePlugin. These plugins (such as AI chat or Image generation) provide afterWrite hooks that execute after the initial scaffolding is complete.
For instance, the AI Chat plugin leverages the FumadocsComponentInstaller to fetch components from the remote registry, then uses ts-morph to inspect the existing DocsLayout in the user's project and programmatically inject the <AISearch> trigger.
// Example: Injecting AI Search logic in packages/create-app/src/plugins/ai.ts
const code = `<AISearch>
<AISearchPanel />
<AISearchTrigger ... />
</AISearch>`;
// ... logic to find DocsLayout and prepend AI componentsSources: packages/create-app/src/plugins/ai.ts:61-86
The development server for MDX content relies on a FSWatcher initialized inside initServer. This watcher triggers an initOrReload cycle when the source.config.ts file is modified.
watcher.on('all') detects file changes.path.resolve(file) matches the known configuration path.watcher.removeAllListeners() and watcher.close() to prevent race conditions during the reload.core.init() with the updated configuration.devServer() to restart the watch process with updated state.Sources: packages/mdx/src/next/index.ts:156-165
Sources: packages/create-app/src/bin.ts:231-270
The packages/mdx/src/runtime/dynamic.ts module provides a bridge between static content and runtime behavior. It uses an AsyncFunction constructor to execute compiled MDX code within a controlled, safe sandbox environment.
Important
The dynamic execution assumes the compiled code is safe. When passing fullScope, it merges user-defined scope with the default jsxRuntime, providing essential context for document hydration.
Sources: packages/mdx/src/runtime/dynamic.ts:31-41
This runtime dynamic loading is primarily used to serve content lazily, ensuring that large documentation sets do not overwhelm the initial memory footprint of the application. It creates internal head and body dictionaries that resolve content only upon request, effectively caching results after the first compilation of a file entry.
Sources: packages/mdx/src/runtime/dynamic.ts:90-91