---
title: "Local Markdown Dev"
description: "\"Local Markdown Dev\" provides the infrastructure for Fumadocs to handle local Markdown and MDX content, including storage management, compilation pipelines, and a development-time hot-reloading mec..."
last_updated: "2026-07-02T09:46:39.366312+00:00"
canonical_url: "https://www.doc0.dev/docs/e8872a72-1909-479c-b585-dc74c6e26726/technical/developer-tools/local-markdown-dev"
---

<details>
<summary>Relevant source files</summary>

The following files were used as context for generating this wiki page:

- [packages/local-md/src/eval-estree-expression/index.ts](https://github.com/blade47/fumadocs/blob/main/packages/local-md/src/eval-estree-expression/index.ts)
- [packages/local-md/src/dev/node-server.ts](https://github.com/blade47/fumadocs/blob/main/packages/local-md/src/dev/node-server.ts)
- [packages/local-md/src/dev/react-client.ts](https://github.com/blade47/fumadocs/blob/main/packages/local-md/src/dev/react-client.ts)
- [packages/local-md/src/index.ts](https://github.com/blade47/fumadocs/blob/main/packages/local-md/src/index.ts)
- [packages/core/src/content/md.ts](https://github.com/blade47/fumadocs/blob/main/packages/core/src/content/md.ts)
- [packages/local-md/src/md/renderer.ts](https://github.com/blade47/fumadocs/blob/main/packages/local-md/src/md/renderer.ts)
- [packages/local-md/src/dev/node-client.ts](https://github.com/blade47/fumadocs/blob/main/packages/local-md/src/dev/node-client.ts)
- [packages/local-md/package.json](https://github.com/blade47/fumadocs/blob/main/packages/local-md/package.json)
- [packages/preview/src/cli/commands.ts](https://github.com/blade47/fumadocs/blob/main/packages/preview/src/cli/commands.ts)
- [packages/core/src/mdx-plugins/remark-llms.ts](https://github.com/blade47/fumadocs/blob/main/packages/core/src/mdx-plugins/remark-llms.ts)
- [packages/preview/src/components/hot-reload.tsx](https://github.com/blade47/fumadocs/blob/main/packages/preview/src/components/hot-reload.tsx)
- [packages/mdx/src/loaders/mdx/remark-include.ts](https://github.com/blade47/fumadocs/blob/main/packages/mdx/src/loaders/mdx/remark-include.ts)
- [packages/mdx/src/runtime/server.ts](https://github.com/blade47/fumadocs/blob/main/packages/mdx/src/runtime/server.ts)
- [packages/core/src/source/llms.ts](https://github.com/blade47/fumadocs/blob/main/packages/core/src/source/llms.ts)
- [packages/local-md/src/js/executor-virtual.ts](https://github.com/blade47/fumadocs/blob/main/packages/local-md/src/js/executor-virtual.ts)
- [packages/preview/src/lib/source/watcher.ts](https://github.com/blade47/fumadocs/blob/main/packages/preview/src/lib/source/watcher.ts)
- [packages/preview/src/waku.server.tsx](https://github.com/blade47/fumadocs/blob/main/packages/preview/src/waku.server.tsx)
- [packages/local-md/src/bin.ts](https://github.com/blade47/fumadocs/blob/main/packages/local-md/src/bin.ts)
- [packages/asyncapi/src/server/index.tsx](https://github.com/blade47/fumadocs/blob/main/packages/asyncapi/src/server/index.tsx)
- [packages/asyncapi/src/ui/components/markdown.tsx](https://github.com/blade47/fumadocs/blob/main/packages/asyncapi/src/ui/components/markdown.tsx)
- [packages/local-md/src/dev/shared.ts](https://github.com/blade47/fumadocs/blob/main/packages/local-md/src/dev/shared.ts)
- [packages/local-md/src/md/compiler.ts](https://github.com/blade47/fumadocs/blob/main/packages/local-md/src/md/compiler.ts)
- [packages/preview/src/components/markdown.tsx](https://github.com/blade47/fumadocs/blob/main/packages/preview/src/components/markdown.tsx)
- [packages/local-md/src/client.ts](https://github.com/blade47/fumadocs/blob/main/packages/local-md/src/client.ts)
- [packages/openapi/src/ui/components/markdown.tsx](https://github.com/blade47/fumadocs/blob/main/packages/openapi/src/ui/components/markdown.tsx)
- [packages/local-md/src/storage.ts](https://github.com/blade47/fumadocs/blob/main/packages/local-md/src/storage.ts)
- [packages/core/src/mdx-plugins/remark-llms.runtime.ts](https://github.com/blade47/fumadocs/blob/main/packages/core/src/mdx-plugins/remark-llms.runtime.ts)
- [packages/preview/src/lib/md.ts](https://github.com/blade47/fumadocs/blob/main/packages/preview/src/lib/md.ts)
- [packages/local-md/tsdown.config.ts](https://github.com/blade47/fumadocs/blob/main/packages/local-md/tsdown.config.ts)
- [packages/local-md/src/js/executor.ts](https://github.com/blade47/fumadocs/blob/main/packages/local-md/src/js/executor.ts)
</details>

"Local Markdown Dev" provides the infrastructure for Fumadocs to handle local Markdown and MDX content, including storage management, compilation pipelines, and a development-time hot-reloading mechanism. By bridging raw filesystem content with the documentation framework, it allows for efficient content scanning, caching, and dynamic revalidation during development.

The subsystem is architected around a central storage engine that manages file parsing and invalidation. It exposes interfaces for both static and dynamic sources, enabling developers to integrate filesystem-based documentation into their sites seamlessly. It maintains a robust separation of concerns between raw content parsing, Markdown compilation (using `remark` and `rehype`), and runtime execution of code embedded within documentation files.

In addition to core compilation, this component introduces a WebSocket-based development server. This server facilitates communication between the filesystem and the client, ensuring that any modifications to source files automatically trigger UI refreshes via `router.refresh()`. This architecture addresses the latency and manual re-run overhead typical in documentation development, offering a high-performance experience that remains compatible with modern JavaScript environments.

## Storage and File Management
The storage layer handles the discovery and parsing of local documentation files. It interacts with the filesystem via glob patterns to create a representation of pages and metadata, providing an invalidation mechanism that is crucial for the dev-server functionality.

```typescript
// Accessing file storage and invalidation
const storage = createStorage(config);
// ... later, triggered by watcher events:
storage.invalidateCache(absolutePath);
```
Sources: [packages/local-md/src/storage.ts:25-140](https://github.com/blade47/fumadocs/blob/main/packages/local-md/src/storage.ts#L25-L140), [packages/local-md/src/index.ts:171](https://github.com/blade47/fumadocs/blob/main/packages/local-md/src/index.ts#L171)

## Markdown Compilation Pipeline
The compilation system is modular, supporting different configurations for standard Markdown and MDX. It utilizes `remark` and `rehype` plugin architectures to process documents into AST or JS outputs.

> [!IMPORTANT]
> The compiler handles MDX files by generating JS functions, while standard Markdown files are processed into HAST trees for efficient execution.

Sources: [packages/local-md/src/md/compiler.ts:62-162](https://github.com/blade47/fumadocs/blob/main/packages/local-md/src/md/compiler.ts#L62-L162)

## Virtual JavaScript Execution
For Markdown files that require executing code (e.g., dynamic components), the subsystem includes a virtual JS engine (`executorVirtual`). This is an implementation of `estree-util-build-jsx` logic that evaluates AST nodes within a controlled context, bypassing the need for a full Node.js `vm` module, which is beneficial for edge-runtime compatibility.

```mermaid
flowchart TD
    A["visit(node, context)"] --> B{node.type}
    B --> C["Call handler<br>(e.g. Identifier, ObjectExpression)"]
    C --> D["Bind patterns/scope"]
    D --> E["Return evaluated value"]
```
Sources: [packages/local-md/src/eval-estree-expression/index.ts:82-837](https://github.com/blade47/fumadocs/blob/main/packages/local-md/src/eval-estree-expression/index.ts#L82-L837), [packages/local-md/src/js/executor-virtual.ts:7-21](https://github.com/blade47/fumadocs/blob/main/packages/local-md/src/js/executor-virtual.ts#L7-L21)

## Dev Server and Hot Reloading
The dev server uses `chokidar` to observe filesystem changes. When a file is modified, it broadcasts a WebSocket event to the connected clients. The client-side `DevClient` receives these events and calls `router.refresh()` to update the page view in real-time.

```mermaid
sequenceDiagram
    participant FS as Filesystem
    participant DS as Dev Server
    participant DC as Dev Client
    FS->>DS: File Changed
    DS->>DC: WebSocket: { type: 'change', absolutePath: '...' }
    DC->>DC: router.refresh()
```
Sources: [packages/local-md/src/dev/node-server.ts:33-163](https://github.com/blade47/fumadocs/blob/main/packages/local-md/src/dev/node-server.ts#L33-L163), [packages/local-md/src/dev/react-client.ts:6-40](https://github.com/blade47/fumadocs/blob/main/packages/local-md/src/dev/react-client.ts#L6-L40)

## Design Trade-offs

| Design Choice | Benefit | Cost |
| :--- | :--- | :--- |
| `ExpressionSync` engine | Portable, works in Workerd/Edge | Limited JS feature support |
| WebSocket-based reloads | Extremely low latency | Requires open port/server-side state |
| `WeakMap` for caching | Automatic garbage collection of AST results | Potentially higher memory footprint per page |

Sources: [packages/local-md/src/eval-estree-expression/index.ts:2-4](https://github.com/blade47/fumadocs/blob/main/packages/local-md/src/eval-estree-expression/index.ts#L2-L4), [packages/local-md/src/index.ts:92](https://github.com/blade47/fumadocs/blob/main/packages/local-md/src/index.ts#L92), [packages/local-md/src/dev/node-server.ts:58-62](https://github.com/blade47/fumadocs/blob/main/packages/local-md/src/dev/node-server.ts#L58-L62)

## Related

- [Preview Environment](https://www.doc0.dev/docs/e8872a72-1909-479c-b585-dc74c6e26726/technical/developer-tools/preview-environment)


## Sitemap

See the full [sitemap](https://www.doc0.dev/docs/e8872a72-1909-479c-b585-dc74c6e26726/llms.txt) for all pages in this wiki.
