web-meta-framework-docusaurus
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-classicfor docs + blog + pages + sitemap in one preset. Sidebars can be fully autogenerated from filesystem structure using_category_.jsonand front mattersidebar_position. Customize theme components via swizzling (prefer--wrapover--eject). MDX is the default content format — use front matter for metadata, admonitions for callouts, and import React components directly in.mdxfiles. Version docs withdocusaurus docs:version. Deploy thebuild/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.jsonnot_category_.json, different routing model - Starlight — Astro-based, uses
astro.config.mjsand content collections, different architecture entirely
Examples
- Core Configuration & Sidebars — docusaurus.config.js, preset-classic, sidebars, front matter, custom pages
- MDX & Content — MDX features, admonitions, tabs, code blocks, assets, blog plugin
- Customization & Deployment — Swizzling, CSS variables, versioning, i18n, search, deployment
Other resources:
- Quick Reference — CLI commands, front matter fields, config option tables
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:
- Convention over configuration — filesystem structure drives routing and sidebar generation; fight this and you fight the framework
- Preset-first —
preset-classicbundles the common plugin set; only decompose into individual plugins when you need multiple docs instances or unusual setups - Content as data — front matter is the metadata layer;
sidebar_position,slug,tags,custom_edit_urlall live in the document, not in external config - Swizzle, don't fork — customize theme components via the swizzle CLI; wrapping preserves upstream compatibility, ejecting creates a snapshot you must maintain
- Static output —
docusaurus buildproduces a static site; there is no server runtime, no SSR in production, no API routes
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.
// 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 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.
// sidebars.js — autogenerated (recommended)
export default {
docs: [{ type: "autogenerated", dirName: "." }],
};
Control ordering and labels via front matter and _category_.json:
---
sidebar_position: 3
sidebar_label: Quick Start
---
// 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 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.
# 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
// 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 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.
---
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 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.
# 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:
// 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 for version banner configuration and multi-version navigation.
<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/ComponentNameimport in a swizzle wrapper instead of@theme-original/ComponentName— creates an infinite import loop - Putting all sidebar config in
sidebars.jsmanually 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
editUrlin 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
.mdextension with JSX whenformat: 'detect'is configured — in detect mode, only.mdxfiles support JSX (default mode processes both) - Creating
_category_.jsonwith wrong field names (nameinstead oflabel,orderinstead ofposition) - Importing from
@docusaurus/packages directly in MDX — use@theme/or@site/aliases instead
Gotchas & Edge Cases:
baseUrlmust end with/— omitting the trailing slash breaks asset resolution- Static assets in
static/are served from root, not frombaseUrl— userequire()oruseBaseUrl()for path-safe references - Blog authors are configured in
blog/authors.yml, not indocusaurus.config.js - The
slugfront matter field overrides the URL path derived from the filename — useful for keeping clean URLs when renaming files docs-only moderequires settingrouteBasePath: '/'in the docs plugin ANDblog: falsein the preset- Custom pages in
src/pages/use the file path as the route —src/pages/support.tsxbecomes/support - Tabs component state is not shared between instances by default — use
groupIdprop 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>
More from agents-inc/skills
web-animation-css-animations
CSS Animation patterns - transitions, keyframes, scroll-driven animations, @property, GPU-accelerated properties, accessibility with prefers-reduced-motion
20web-testing-playwright-e2e
Playwright E2E testing patterns - test structure, Page Object Model, locator strategies, assertions, network mocking, visual regression, parallel execution, fixtures, and configuration
18web-animation-view-transitions
View Transitions API patterns - same-document transitions, cross-document MPA transitions, shared element animations, pseudo-element styling, accessibility
17web-animation-framer-motion
Motion (formerly Framer Motion) animation patterns - motion components, variants, gestures, layout animations, scroll-linked animations, accessibility
17web-styling-cva
Class Variance Authority - type-safe component variant styling with cva(), compound variants, and VariantProps
16web-i18n-next-intl
Type-safe i18n for Next.js App Router
16