web-meta-framework-docusaurus · git:20260328.c755eaf · 2026-03-28 · sha256 3344400235d40031
web-meta-framework-docusaurus git:20260328.c755eafA
Immutable. This exact content is served forever at /api/v1/blob/3344400235d40031.
---
name: web-meta-framework-docusaurus
description: Docusaurus 3.x documentation framework — site configuration, docs/blog plugins, sidebars, versioning, MDX, swizzling, and deployment
---
# Docusaurus
> **Quick Guide:** Docusaurus 3.x is a React-powered static site generator for documentation. Configure everything in `docusaurus.config.js` (ESM). Use `@docusaurus/preset-classic` for docs + blog + pages + sitemap in one preset. Sidebars can be fully autogenerated from filesystem structure using `_category_.json` and front matter `sidebar_position`. Customize theme components via swizzling (prefer `--wrap` over `--eject`). MDX is the default content format — use front matter for metadata, admonitions for callouts, and import React components directly in `.mdx` files. Version docs with `docusaurus docs:version`. Deploy the `build/` output to any static host.
---
<critical_requirements>
## CRITICAL: Before Using This Skill
> **All code must follow project conventions in CLAUDE.md**
**(You MUST use `docusaurus.config.js` (or `.ts`) as the single source of truth for all site configuration — never scatter config across multiple files)**
**(You MUST use `@docusaurus/preset-classic` unless you have a specific reason to configure plugins individually — the preset bundles docs, blog, pages, sitemap, and theme)**
**(You MUST prefer `--wrap` over `--eject` when swizzling — wrapping preserves upstream updates, ejecting creates a maintenance burden)**
**(You MUST use front matter `sidebar_position` and `_category_.json` for sidebar ordering in autogenerated sidebars — do not fight the filesystem-driven convention)**
**(You MUST NOT mix versioned and unversioned docs in the same plugin instance — use separate plugin instances for different doc sets)**
</critical_requirements>
---
**Auto-detection:** Docusaurus, docusaurus.config.js, docusaurus.config.ts, @docusaurus/preset-classic, @docusaurus/core, sidebars.js, docs:version, docusaurus build, docusaurus start, docusaurus deploy, docusaurus swizzle, MDX, _category_.json, sidebar_position, @site, @theme, @theme-original, plugin-content-docs, plugin-content-blog
**When to use:**
- Configuring `docusaurus.config.js` (site metadata, presets, plugins, theme, navbar, footer)
- Setting up or modifying sidebar structure (autogenerated or manual)
- Adding versioned documentation
- Customizing theme components via swizzling
- Writing MDX content with Docusaurus-specific features (admonitions, tabs, code blocks)
- Creating custom pages with React components
- Configuring the blog plugin
- Setting up search (Algolia DocSearch or local)
- Deploying Docusaurus to static hosting
- Configuring i18n / localization
**When NOT to use:**
- General React component patterns (Docusaurus uses React internally but this skill covers Docusaurus APIs, not React fundamentals)
- CSS/styling approaches not specific to Docusaurus theming (general CSS patterns are a separate concern)
- Git hooks, linting, or formatting setup (separate from documentation framework concerns)
- Content that belongs in the docs themselves, not the site framework
- **VitePress** — Vue-based, different config format and plugin system
- **Nextra** — Next.js-based, uses `_meta.json` not `_category_.json`, different routing model
- **Starlight** — Astro-based, uses `astro.config.mjs` and content collections, different architecture entirely
---
## Examples
- [Core Configuration & Sidebars](examples/core.md) — docusaurus.config.js, preset-classic, sidebars, front matter, custom pages
- [MDX & Content](examples/content.md) — MDX features, admonitions, tabs, code blocks, assets, blog plugin
- [Customization & Deployment](examples/customization.md) — Swizzling, CSS variables, versioning, i18n, search, deployment
**Other resources:**
- [Quick Reference](reference.md) — CLI commands, front matter fields, config option tables
---
<philosophy>
## Philosophy
Docusaurus is an **opinionated documentation framework** that trades flexibility for convention. It makes strong decisions about routing (filesystem-based), content format (MDX), and structure (docs + blog + pages) so you can focus on writing content rather than building infrastructure.
**Core principles:**
1. **Convention over configuration** — filesystem structure drives routing and sidebar generation; fight this and you fight the framework
2. **Preset-first** — `preset-classic` bundles the common plugin set; only decompose into individual plugins when you need multiple docs instances or unusual setups
3. **Content as data** — front matter is the metadata layer; `sidebar_position`, `slug`, `tags`, `custom_edit_url` all live in the document, not in external config
4. **Swizzle, don't fork** — customize theme components via the swizzle CLI; wrapping preserves upstream compatibility, ejecting creates a snapshot you must maintain
5. **Static output** — `docusaurus build` produces a static site; there is no server runtime, no SSR in production, no API routes
</philosophy>
---
<patterns>
## Core Patterns
### Pattern 1: docusaurus.config.js Structure
The config file is the single entry point. It uses ESM (`export default`) and configures site metadata, presets (which bundle plugins + theme), and theme-level settings like navbar and footer.
```javascript
// docusaurus.config.js — minimal production setup
export default {
title: "My Docs",
tagline: "Documentation for My Project",
url: "https://docs.example.com",
baseUrl: "/",
onBrokenLinks: "throw",
onBrokenMarkdownLinks: "throw",
favicon: "img/favicon.ico",
presets: [
[
"@docusaurus/preset-classic",
{
docs: {
sidebarPath: "./sidebars.js",
editUrl: "https://github.com/my-org/my-repo/edit/main/docs-site/",
showLastUpdateTime: true,
},
blog: { showReadingTime: true },
theme: { customCss: ["./src/css/custom.css"] },
},
],
],
themeConfig: {
navbar: {
title: "My Docs",
items: [
/* nav items */
],
},
footer: {
style: "dark",
links: [
/* footer columns */
],
},
docs: { sidebar: { hideable: true, autoCollapseCategories: true } },
},
};
```
**Key gotcha:** `onBrokenLinks: 'throw'` is essential for production — it fails the build on broken internal links rather than silently deploying dead links.
> **Full example:** See [examples/core.md](examples/core.md) for complete config with navbar, footer, and multi-instance docs setup.
---
### Pattern 2: Sidebar Configuration
Docusaurus offers two sidebar strategies. **Autogenerated** sidebars derive structure from the filesystem and are the default recommendation. **Manual** sidebars give full control but require maintenance.
```javascript
// sidebars.js — autogenerated (recommended)
export default {
docs: [{ type: "autogenerated", dirName: "." }],
};
```
Control ordering and labels via front matter and `_category_.json`:
```markdown
---
sidebar_position: 3
sidebar_label: Quick Start
---
```
```json
// docs/guides/_category_.json
{
"label": "Guides",
"position": 2,
"collapsible": true,
"collapsed": false,
"link": { "type": "generated-index", "title": "All Guides" }
}
```
**Key gotcha:** Without `sidebar_position`, items sort alphabetically by filename. Use number prefixes (`01-intro.md`) or front matter — but not both, as number prefixes are stripped from the URL slug.
> **Full example:** See [examples/core.md](examples/core.md#sidebar-patterns) for manual sidebars, custom sidebar items generator, and multi-sidebar setups.
---
### Pattern 3: Swizzling Theme Components
Swizzling lets you customize any theme component. **Wrapping** adds behavior around the original; **ejecting** gives you a full copy to modify.
```bash
# List all swizzlable components
npx docusaurus swizzle --list
# Wrap a component (SAFE — preserves upstream updates)
npx docusaurus swizzle @docusaurus/theme-classic Footer -- --wrap
# Eject a component (DANGEROUS — you own the snapshot)
npx docusaurus swizzle @docusaurus/theme-classic Footer -- --eject
```
```jsx
// src/theme/Footer/index.js — wrapping example
import React from "react";
import Footer from "@theme-original/Footer";
export default function FooterWrapper(props) {
return (
<>
<Footer {...props} />
<div className="custom-banner">Custom content below footer</div>
</>
);
}
```
**Key gotcha:** The `@theme-original/` import is critical in wrappers — it references the original component. Using `@theme/` would create an infinite loop since your wrapper IS the `@theme/Footer`.
> **Full example:** See [examples/customization.md](examples/customization.md) for swizzling safety levels, common swizzle targets, and CSS variable theming.
---
### Pattern 4: MDX Content Features
Docusaurus uses MDX v3 — Markdown with embedded JSX. Key Docusaurus-specific features include admonitions, tabs, and code blocks with metadata.
````mdx
---
title: My Document
description: SEO description for this page
sidebar_position: 1
tags: [getting-started, tutorial]
---
import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";
:::tip[Pro Tip]
Admonitions support `note`, `tip`, `info`, `warning`, `danger` types.
The bracket syntax `:::tip[Custom Title]` sets the title.
:::
<Tabs>
<TabItem value="npm" label="npm" default>
```bash npm install my-package ```
</TabItem>
<TabItem value="yarn" label="yarn">
```bash yarn add my-package ```
</TabItem>
</Tabs>
````
**Key gotcha:** MDX v3 is stricter than Markdown — unclosed HTML tags, bare `{` characters, and `<` comparisons in text will cause build errors. Escape them with `\{` and `\<` or use code fences.
> **Full example:** See [examples/content.md](examples/content.md) for code block features, asset handling, and blog plugin configuration.
---
### Pattern 5: Versioning
Docusaurus versions docs by snapshotting the entire `docs/` directory. The current working copy is always `current` (next/unreleased). Cut a release version when shipping.
```bash
# Snapshot current docs as version 1.0.0
npx docusaurus docs:version 1.0.0
```
This creates `versioned_docs/version-1.0.0/` and `versioned_sidebars/version-1.0.0-sidebars.json`. Configure version behavior in the docs plugin:
```javascript
// In preset-classic docs options
docs: {
lastVersion: 'current',
versions: {
current: { label: '2.0.0-beta', path: 'next', banner: 'unreleased' },
'1.0.0': { label: '1.0.0', path: '1.0.0', banner: 'none' },
},
onlyIncludeVersions: ['current', '1.0.0'],
}
```
**Key gotcha:** Versioned docs are full copies, not diffs. Each version doubles the build time and output size. Use `onlyIncludeVersions` in development to speed up builds. Only version when you have actual API/feature differences — not for every release.
> **Full example:** See [examples/customization.md](examples/customization.md#versioning) for version banner configuration and multi-version navigation.
</patterns>
---
<decision_framework>
## Decision Framework
### Sidebar Strategy
```
How should the sidebar be organized?
|-- Small docs site (< 30 pages)?
| +-- Use autogenerated sidebar with sidebar_position front matter
|-- Large docs site with many sections?
| |-- Sections map cleanly to directories? -> Autogenerated + _category_.json
| +-- Need cross-directory grouping? -> Manual sidebar in sidebars.js
|-- Multiple independent doc sets (e.g., API + guides)?
| +-- Use multiple docs plugin instances, each with its own sidebar
+-- Need to mix auto and manual?
+-- Use autogenerated for most, with manual items for special entries
```
### Swizzling Approach
```
Need to customize a theme component?
|-- Adding content around the component? -> Wrap (--wrap)
|-- Need to change the component's internal logic? -> Check safety level first
| |-- Component marked "Safe"? -> Eject is acceptable
| |-- Component marked "Unsafe"? -> Wrap if possible, eject only as last resort
| +-- Component marked "Forbidden"? -> Do not swizzle — find another approach
+-- Just changing colors/spacing? -> Use CSS variables in custom.css (no swizzle needed)
```
### Content Format
```
What kind of page am I creating?
|-- Documentation article? -> .md or .mdx file in docs/
|-- Blog post? -> .md or .mdx file in blog/
|-- Standalone page with custom layout?
| |-- Mostly content? -> .mdx in src/pages/
| +-- Mostly interactive/React? -> .tsx in src/pages/
+-- Need to embed React components in docs? -> Use .mdx with imports
```
</decision_framework>
---
<red_flags>
## RED FLAGS
**High Priority Issues:**
- Using `onBrokenLinks: 'ignore'` or `'log'` in production — broken links should fail the build (`'throw'`)
- Ejecting theme components when wrapping would suffice — ejected components miss upstream bug fixes and feature additions
- Using `@theme/ComponentName` import in a swizzle wrapper instead of `@theme-original/ComponentName` — creates an infinite import loop
- Putting all sidebar config in `sidebars.js` manually when autogenerated would work — creates a maintenance burden that falls out of sync with actual docs
**Medium Priority Issues:**
- Versioning every release instead of only when docs content actually changes — bloats build time and output size
- Not setting `onBrokenMarkdownLinks: 'warn'` at minimum — silent broken links accumulate
- Missing `editUrl` in docs plugin config — blocks "Edit this page" links that drive community contributions
- Not using `showLastUpdateTime: true` — readers cannot tell how current a doc page is
**Common Mistakes:**
- Bare `{` or `<` in MDX content causing build failures — escape with `\{` and `\<` or wrap in code fences
- Forgetting to restart the dev server after changing `docusaurus.config.js` — config changes are not hot-reloaded
- Using `.md` extension with JSX when `format: 'detect'` is configured — in detect mode, only `.mdx` files support JSX (default mode processes both)
- Creating `_category_.json` with wrong field names (`name` instead of `label`, `order` instead of `position`)
- Importing from `@docusaurus/` packages directly in MDX — use `@theme/` or `@site/` aliases instead
**Gotchas & Edge Cases:**
- `baseUrl` must end with `/` — omitting the trailing slash breaks asset resolution
- Static assets in `static/` are served from root, not from `baseUrl` — use `require()` or `useBaseUrl()` for path-safe references
- Blog authors are configured in `blog/authors.yml`, not in `docusaurus.config.js`
- The `slug` front matter field overrides the URL path derived from the filename — useful for keeping clean URLs when renaming files
- `docs-only mode` requires setting `routeBasePath: '/'` in the docs plugin AND `blog: false` in the preset
- Custom pages in `src/pages/` use the file path as the route — `src/pages/support.tsx` becomes `/support`
- Tabs component state is not shared between instances by default — use `groupId` prop to sync tab selection across the page
</red_flags>
---
<critical_reminders>
## CRITICAL REMINDERS
> **All code must follow project conventions in CLAUDE.md**
**(You MUST use `docusaurus.config.js` as the single source of truth for all site configuration)**
**(You MUST use `@docusaurus/preset-classic` unless you have a specific reason to configure plugins individually)**
**(You MUST prefer `--wrap` over `--eject` when swizzling — wrapping preserves upstream updates)**
**(You MUST use front matter `sidebar_position` and `_category_.json` for sidebar ordering — do not fight filesystem-driven conventions)**
**(You MUST NOT mix versioned and unversioned docs in the same plugin instance)**
**Failure to follow these rules will cause broken builds, unmaintainable theme overrides, and sidebar chaos.**
</critical_reminders>