1. Architecture Overview
Docusaurus is a modular, plugin-driven static site generator that transforms Markdown/MDX content into a React-based single-page application. Built as a Yarn workspaces monorepo, it separates concerns across ~40 packages: a core engine, content plugins, themes, utilities, and a bundler abstraction layer.
The architecture follows a three-tier model:
┌─────────────────────────────────────────────────────┐
│ docusaurus.config.js │
│ (User Configuration) │
└──────────────┬───────────────────────┬──────────────┘
│ │
┌──────────▼──────────┐ ┌────────▼────────────┐
│ Preset Classic │ │ Standalone Plugins │
│ ┌────────────────┐ │ │ (PWA, Redirects, │
│ │ plugin-docs │ │ │ Ideal Image, etc.) │
│ │ plugin-blog │ │ └──────────────────────┘
│ │ plugin-pages │ │
│ │ plugin-sitemap │ │
│ │ theme-classic │ │
│ │ gtag / GTM │ │
│ └────────────────┘ │
└──────────┬──────────┘
│
┌──────────▼──────────────────────────────────────┐
│ @docusaurus/core │
│ CLI → LoadContext → Plugin Init → Lifecycle │
│ → Content Load → Route Gen → Bundler → SSG │
└──────────┬──────────────────────────────────────┘
│
┌──────────▼──────────────────────────────────────┐
│ @docusaurus/bundler │
│ Webpack (default) ──or── Rspack (future flag) │
│ SWC / Terser / Lightning CSS minifiers │
└─────────────────────────────────────────────────┘
Component Inventory
| Component | Package | Role |
|---|---|---|
| Core Engine | @docusaurus/core |
CLI, plugin orchestration, SSG, dev server |
| Bundler | @docusaurus/bundler |
Webpack/Rspack abstraction, minification |
| Docs Plugin | @docusaurus/plugin-content-docs |
Documentation with versioning, sidebars |
| Blog Plugin | @docusaurus/plugin-content-blog |
Blog posts, authors, feeds |
| Pages Plugin | @docusaurus/plugin-content-pages |
Static/MDX pages |
| Classic Theme | @docusaurus/theme-classic |
UI components, navbar, footer, sidebar |
| Theme Common | @docusaurus/theme-common |
Shared React hooks, utilities, contexts |
| Preset Classic | @docusaurus/preset-classic |
Bundle of docs + blog + pages + theme |
| MDX Loader | @docusaurus/mdx-loader |
Webpack loader for MDX/Markdown |
| Utils | @docusaurus/utils |
Path normalization, constants, data files |
| Utils Validation | @docusaurus/utils-validation |
Joi-based schema validation |
| Types | @docusaurus/types |
TypeScript type definitions |
| Logger | @docusaurus/logger |
Structured logging with performance tracking |
| Faster | @docusaurus/faster |
SWC/Rspack/Lightning CSS optimizations |
| Create Docusaurus | create-docusaurus |
Project scaffolding CLI |
| Client Redirects | @docusaurus/plugin-client-redirects |
HTML-based URL redirects |
| PWA | @docusaurus/plugin-pwa |
Service worker, offline access |
| Sitemap | @docusaurus/plugin-sitemap |
XML sitemap generation |
| Google Analytics | @docusaurus/plugin-google-analytics |
Legacy GA integration |
| Google Gtag | @docusaurus/plugin-google-gtag |
GA4 via gtag.js |
| Google Tag Manager | @docusaurus/plugin-google-tag-manager |
GTM container injection |
| Vercel Analytics | @docusaurus/plugin-vercel-analytics |
Vercel analytics integration |
| Rsdoctor | @docusaurus/plugin-rsdoctor |
Build analysis and diagnostics |
| Search Algolia | @docusaurus/theme-search-algolia |
DocSearch integration |
| Live Codeblock | @docusaurus/theme-live-codeblock |
Interactive React code editor |
| Mermaid | @docusaurus/theme-mermaid |
Mermaid diagram rendering |
| Translations | @docusaurus/theme-translations |
Locale translation files |
| Ideal Image | @docusaurus/plugin-ideal-image |
Responsive image optimization |
| SVGR | @docusaurus/plugin-svgr |
Import SVGs as React components |
| CSS Cascade Layers | @docusaurus/plugin-css-cascade-layers |
CSS @layer wrapping |
| Babel | @docusaurus/babel |
Babel presets and configuration |
| CSSNano Preset | @docusaurus/cssnano-preset |
CSS minification configuration |
| ESLint Plugin | @docusaurus/eslint-plugin |
Coding convention enforcement |
| Stylelint Copyright | @docusaurus/stylelint-copyright |
Copyright header check for CSS |
| LQIP Loader | @docusaurus/lqip-loader |
Low-quality image placeholder |
| Remark npm2yarn | @docusaurus/remark-plugin-npm2yarn |
Package manager tab generation |
| Module Aliases | @docusaurus/module-type-aliases |
TypeScript path aliases |
| TSConfig | @docusaurus/tsconfig |
Shared TypeScript configuration |
Technology Stack
| Layer | Technology |
|---|---|
| Language | TypeScript (strict), compiled to ES modules |
| Runtime | Node.js >= 24.14 |
| UI Framework | React >= 19.2.0 |
| Content Format | MDX 3.x (via @mdx-js/react) |
| Bundler (default) | Webpack 5 with persistent caching |
| Bundler (opt-in) | Rspack via @docusaurus/faster |
| CSS Processing | PostCSS, CSSNano, Lightning CSS (opt-in) |
| JS Compilation | Babel (default) or SWC (opt-in via Faster) |
| Monorepo | Yarn workspaces + Lerna |
| Testing | Jest 30 with SWC transform |
| Linting | ESLint, Stylelint, CSpell, Syncpack |
| Visual Testing | Argos (Playwright screenshots) |
Plugin Lifecycle
Plugins follow a standardized async lifecycle:
validateOptions() → constructor(context, options) → loadContent()
→ contentLoaded({content, actions}) → configureWebpack()
→ injectHtmlTags() → postBuild() → extendCli()
Key lifecycle methods:
| Method | Purpose |
|---|---|
validateOptions |
Joi schema validation of plugin config |
loadContent |
Read and process source files |
contentLoaded |
Generate routes and data files via actions |
configureWebpack |
Merge custom webpack/rspack config |
configurePostCss |
Modify PostCSS options |
injectHtmlTags |
Add tags to <head> or <body> |
postBuild |
Post-build hooks (sitemap, feed generation) |
extendCli |
Register custom CLI commands |
getThemePath |
Return path to theme components |
getClientModules |
Return client-side module paths |
Note
A plugin constructor can return
nullto self-disable, allowing conditional activation based on environment or config. This is used by analytics plugins that only activate in production.
Data Flow
1. CLI invoked (start/build)
2. LoadContext: read docusaurus.config, resolve presets → plugins
3. Plugin init: validateOptions → construct → ensure unique IDs
4. Content loading: each plugin reads its source files
5. Route generation: plugins emit routes + data files to @generated/
6. Bundler: Webpack/Rspack compiles client + server bundles
7. SSG: AppRenderer executes React server-side for each route
8. Output: static HTML + JS/CSS bundles in build/ directory
Plugins output data to @generated/{pluginName}/{pluginId}/, which is aliased for import in React components. The AppRenderer must call shutdown() after SSG to clear Node.js require caches and prevent memory leaks.
2. System Requirements
| Requirement | Minimum | Recommended |
|---|---|---|
| Node.js | >= 24.14 | Latest LTS |
| npm/Yarn/pnpm/Bun | Any supported version | Yarn 1.22+ |
| Git | Required for deploy, VCS metadata | Latest |
| OS | Windows, macOS, Linux | Linux for CI |
| Memory | 2 GB | 4+ GB for large sites |
| Disk | Depends on site size | SSD recommended |
Build-Time Dependencies (devDependencies from monorepo root)
| Package | Version | Purpose |
|---|---|---|
react / react-dom |
^19.2.0 | UI framework |
@mdx-js/react |
^3.0.0 | MDX integration |
typescript |
~6.0.2 | Type checking |
jest |
^30.2.0 | Testing |
@swc/core |
^1.7.39 | SWC compilation |
lerna |
^7.4.2 | Monorepo management |
eslint |
^8.45.0 | Code linting |
prettier |
^2.8.8 | Code formatting |
husky |
^8.0.3 | Git hooks |
User Site Dependencies (classic template)
| Package | Version | Purpose |
|---|---|---|
@docusaurus/core |
3.9.2 | Core engine |
@docusaurus/preset-classic |
3.9.2 | Standard plugin bundle |
@docusaurus/faster |
3.9.2 | Build optimization (optional) |
@mdx-js/react |
^3.0.0 | MDX support |
clsx |
^2.0.0 | Conditional CSS classes |
prism-react-renderer |
^2.3.0 | Code syntax highlighting |
react / react-dom |
^19.2.0 | UI framework |
3. Configuration Reference
Site Configuration (docusaurus.config.js)
The configuration file exports a Config object (or async factory function).
Core Settings
| Key | Type | Default | Required | Description |
|---|---|---|---|---|
title |
string |
— | Yes | Site title |
tagline |
string |
'' |
No | Site tagline |
url |
string |
— | Yes | Production URL |
baseUrl |
string |
'/' |
Yes | Base URL path |
favicon |
string |
— | No | Favicon path |
trailingSlash |
boolean | undefined |
undefined |
No | Trailing slash policy |
organizationName |
string |
— | No | GitHub org/user (for deploy) |
projectName |
string |
— | No | GitHub repo name (for deploy) |
deploymentBranch |
string |
'gh-pages' |
No | Branch for GitHub Pages deploy |
onBrokenLinks |
'ignore' | 'log' | 'warn' | 'throw' |
'throw' |
No | Broken link behavior |
onBrokenAnchors |
'ignore' | 'log' | 'warn' | 'throw' |
'warn' |
No | Broken anchor behavior |
onBrokenMarkdownLinks |
'ignore' | 'log' | 'warn' | 'throw' |
'warn' |
No | Broken Markdown link behavior |
onDuplicateRoutes |
'ignore' | 'log' | 'warn' | 'throw' |
'warn' |
No | Duplicate route behavior |
staticDirectories |
string[] |
['static'] |
No | Static asset directories |
noIndex |
boolean |
false |
No | Add noindex meta to all pages |
headTags |
HtmlTagObject[] |
[] |
No | Additional <head> tags |
scripts |
(string | HtmlTagObject)[] |
[] |
No | Additional <script> tags |
stylesheets |
(string | HtmlTagObject)[] |
[] |
No | Additional <link> stylesheets |
clientModules |
string[] |
[] |
No | Client-side modules to load |
i18n Configuration
| Key | Type | Default | Description |
|---|---|---|---|
i18n.defaultLocale |
string |
'en' |
Default locale |
i18n.locales |
string[] |
['en'] |
All supported locales |
i18n.path |
string |
'i18n' |
Root i18n directory |
i18n.localeConfigs |
Record<string, LocaleConfig> |
{} |
Per-locale overrides |
future Flags
| Key | Type | Default | Description |
|---|---|---|---|
future.faster.swcJsLoader |
boolean |
false |
Use SWC instead of Babel for JS/TS |
future.faster.swcJsMinimizer |
boolean |
false |
Use SWC for JS minification |
future.faster.swcHtmlMinimizer |
boolean |
false |
Use SWC for HTML minification |
future.faster.lightningCssMinimizer |
boolean |
false |
Use Lightning CSS for CSS minification |
future.faster.rspackBundler |
boolean |
false |
Use Rspack instead of Webpack |
future.faster.mdxCrossCompilerCache |
boolean |
false |
Cache MDX across client/server builds |
future.v4.removeLegacyPostBuildHeadAttribute |
boolean |
false |
Remove legacy post-build API |
future.v4.useCssCascadeLayers |
boolean |
false |
Wrap styles in CSS @layer |
Important
The
futureflags are opt-in previews of breaking changes planned for Docusaurus v4. Enable them incrementally to prepare for the next major version.
Markdown Configuration
| Key | Type | Default | Description |
|---|---|---|---|
markdown.format |
'mdx' | 'md' | 'detect' |
'mdx' |
Default Markdown processor |
markdown.mermaid |
boolean |
false |
Enable Mermaid code blocks |
markdown.remarkPlugins |
RemarkPlugin[] |
[] |
Remark plugins |
markdown.rehypePlugins |
RehypePlugin[] |
[] |
Rehype plugins |
markdown.parseFrontMatter |
function |
— | Custom frontmatter parser |
Environment Variables (Complete Reference)
User-Facing
| Variable | Default | Description |
|---|---|---|
PORT |
3000 |
Dev server / serve port |
DOCUSAURUS_CLI_SITE_DIR |
. |
Override site directory |
DOCUSAURUS_CLI_CONFIG |
undefined |
Override config file path |
BASE_URL |
— | Override baseUrl at build time |
Deployment
| Variable | Default | Description |
|---|---|---|
GIT_USER |
— | GitHub username for HTTPS deploy |
GIT_PASS |
— | GitHub token (obfuscated in logs) |
USE_SSH |
— | Use SSH for deploy (true/false) |
ORGANIZATION_NAME |
— | Override organizationName config |
PROJECT_NAME |
— | Override projectName config |
DEPLOYMENT_BRANCH |
'gh-pages' |
Target branch for deploy |
CURRENT_BRANCH |
— | Override source branch detection |
GITHUB_HOST |
— | Custom GitHub host |
GITHUB_PORT |
— | Custom GitHub port |
GIT_USER_NAME |
— | Git commit author name |
GIT_USER_EMAIL |
— | Git commit author email |
CUSTOM_COMMIT_MESSAGE |
— | Custom deploy commit message |
CI_PULL_REQUEST / CIRCLE_PULL_REQUEST |
— | Skip deploy on PR builds |
CIRCLE_PROJECT_USERNAME |
— | Fallback for organizationName |
CIRCLE_PROJECT_REPONAME |
— | Fallback for projectName |
Build Optimization
| Variable | Default | Description |
|---|---|---|
DOCUSAURUS_PERF_LOGGER |
— | Enable performance logging |
DOCUSAURUS_RSPACK_TRACE |
— | Enable Rspack trace output |
TERSER_PARALLEL |
— | Override Terser parallelism |
USE_SIMPLE_CSS_MINIFIER |
— | Use simpler CSS minification |
SKIP_HTML_MINIFICATION |
— | Skip HTML minification entirely |
WEBPACK_URL_LOADER_LIMIT |
— | URL loader inline size limit |
DOCUSAURUS_SERVER_NODE_TARGET |
— | Override Node target for server bundle |
Development / Testing
| Variable | Default | Description |
|---|---|---|
NODE_ENV |
— | Environment (production/development) |
SIMULATE_PRODUCTION_VISIBILITY |
— | Show draft/unlisted state in dev |
DOCUSAURUS_BABEL_CONFIG_FILE_NAME |
— | Override Babel config filename |
DOCUSAURUS_GENERATED_FILES_DIR_NAME |
— | Override .docusaurus directory name |
DOCUSAURUS_DEPLOY_DEBUG |
— | Enable verbose deploy logging |
DOCUSAURUS_CRASH_TEST |
— | Force crash (testing only) |
DOCUSAURUS_SLOWER |
— | Add artificial delays (testing) |
DOCUSAURUS_SITE_VCS |
— | Override VCS provider |
PWA
| Variable | Default | Description |
|---|---|---|
PWA_SERVICE_WORKER_URL |
— | Custom service worker URL |
PWA_DEBUG |
— | Enable PWA debug logging |
PWA_SW_CUSTOM |
— | Custom service worker code path |
Warning
GIT_PASSis obfuscated in deploy command logs, but always use environment secrets (CI variables) rather than hardcoding credentials.
Plugin Option Schemas
Docs Plugin (@docusaurus/plugin-content-docs)
| Option | Type | Default | Description |
|---|---|---|---|
path |
string |
'docs' |
Docs source directory |
id |
string |
'default' |
Plugin instance ID |
sidebarPath |
string | false |
'sidebars.js' |
Sidebar config file |
include |
string[] |
['**/*.{md,mdx}'] |
File inclusion globs |
exclude |
string[] |
Various test patterns | File exclusion globs |
editUrl |
string | function |
— | Edit link base URL or function |
editLocalizedFiles |
boolean |
false |
Route edits to localized files |
editCurrentVersion |
boolean |
true |
Edit links point to current version |
showLastUpdateAuthor |
boolean |
false |
Show last Git author |
showLastUpdateTime |
boolean |
false |
Show last Git update time |
routeBasePath |
string |
'docs' |
URL base path |
versions |
object |
— | Per-version configuration |
onlyIncludeVersions |
string[] |
— | Limit which versions to build |
breadcrumbs |
boolean |
true |
Show breadcrumbs |
Blog Plugin (@docusaurus/plugin-content-blog)
| Option | Type | Default | Description |
|---|---|---|---|
path |
string |
'blog' |
Blog source directory |
include |
string[] |
['**/*.{md,mdx}'] |
File inclusion globs |
exclude |
string[] |
Various patterns | File exclusion globs |
editUrl |
string | function |
— | Edit link base |
showReadingTime |
boolean |
true |
Display reading time |
authorsMapPath |
string |
'authors.yml' |
Authors definition file |
authorsBaseRoutePath |
string |
'/authors' |
Author pages URL base |
onInlineAuthors |
string |
— | Inline author handling strategy |
feedOptions |
object |
— | RSS/Atom feed configuration |
blogTitle |
string |
'Blog' |
Blog page title |
blogSidebarCount |
number | 'ALL' |
5 |
Sidebar recent posts count |
Sitemap Plugin (@docusaurus/plugin-sitemap)
| Option | Type | Default | Description |
|---|---|---|---|
ignorePatterns |
string[] |
[] |
Route patterns to exclude |
lastmod |
'date' | 'datetime' | null |
null |
Lastmod format |
priority |
number |
0.5 |
Default page priority |
changefreq |
string |
— | Default change frequency |
createSitemapItems |
function |
— | Custom sitemap item generator |
Client Redirects Plugin (@docusaurus/plugin-client-redirects)
| Option | Type | Default | Description |
|---|---|---|---|
redirects |
{from, to}[] |
[] |
Static redirect definitions |
fromExtensions |
string[] |
[] |
Auto-redirect from extensions |
toExtensions |
string[] |
[] |
Auto-redirect to extensions |
createRedirects |
function |
— | Dynamic redirect generator |
PWA Plugin (@docusaurus/plugin-pwa)
| Option | Type | Default | Description |
|---|---|---|---|
debug |
boolean |
false |
Enable debug logging |
offlineModeActivationStrategies |
string[] |
[] |
Offline activation strategies |
injectManifestConfig |
object |
— | Workbox manifest config |
pwaHead |
{tagName, ...}[] |
[] |
Head tag injection |
swCustom |
string |
— | Custom service worker module |
swRegister |
string | false |
— | SW registration module |
Module Resolution (Plugin Shorthand)
Docusaurus resolves plugin names using these patterns:
| Input | Resolved |
|---|---|
'content-docs' |
@docusaurus/plugin-content-docs |
'my-plugin' |
docusaurus-plugin-my-plugin |
'@scope/my-plugin' |
@scope/docusaurus-plugin-my-plugin |
'./local-plugin' |
./local-plugin (relative path) |
Same pattern applies to themes (docusaurus-theme-*) and presets (docusaurus-preset-*).
4. Deployment & Scaling
GitHub Pages Deployment
The built-in deploy command handles the full workflow:
- Builds the site (unless
--skip-build) - Creates a temporary directory
- Clones the deployment branch
- Copies build output
- Commits and pushes
Required configuration:
// docusaurus.config.js
module.exports = {
url: 'https://my-org.github.io',
baseUrl: '/my-repo/',
organizationName: 'my-org',
projectName: 'my-repo',
trailingSlash: false,
};
CI deployment example:
GIT_USER=git CURRENT_BRANCH=main \
GIT_PASS=$GITHUB_TOKEN \
npx docusaurus deploy
For organization pages (<org>.github.io without a subpath), set deploymentBranch: 'main' and baseUrl: '/'.
Static Hosting (Netlify, Vercel, Cloudflare)
The build output is a self-contained static site in build/:
npx docusaurus build
# Deploy build/ to any static host
For Netlify detection, Docusaurus checks NETLIFY and CONTEXT environment variables to adjust build behavior (e.g., deploy preview settings).
Scaling Considerations
| Concern | Solution |
|---|---|
| Large sites (1000+ pages) | Enable @docusaurus/faster for Rspack + SWC |
| Many versions | Use onlyIncludeVersions to build a subset |
| i18n with many locales | Build locales in parallel CI jobs with --locale |
| Memory pressure | NODE_OPTIONS=--max-old-space-size=4096 |
| Build speed | Enable mdxCrossCompilerCache for large MDX sites |
| CI caching | Cache node_modules/.cache and .yarn/.cache between builds |
Tip
The
clearcommand removesnode_modules/.cacheand.yarn/.cachebundler caches. In CI, preserve these directories between runs for faster incremental builds.
5. Operations
Build Monitoring
Enable performance logging to track build phases:
DOCUSAURUS_PERF_LOGGER=true npx docusaurus build
The logger tracks start/end marks for each build phase. If a mark is missing, it throws: No performance start mark for label=${label}.
For deep build analysis, use Rsdoctor:
plugins: ['@docusaurus/plugin-rsdoctor'],
RSDOCTOR=true npx docusaurus build
Health Checks
Use the debug plugin (included in classic preset) during development:
http://localhost:3000/__docusaurus/debug— site config, routes, plugin datahttp://localhost:3000/__docusaurus/debug/config— resolved configurationhttp://localhost:3000/__docusaurus/debug/routes— all registered routes
Cache Management
| Cache | Location | Purpose | Clear With |
|---|---|---|---|
| Generated files | .docusaurus/ |
Plugin data, aliases | npx docusaurus clear |
| Build output | build/ |
Production bundle | npx docusaurus clear |
| Webpack cache | node_modules/.cache |
Persistent build cache | npx docusaurus clear |
| Yarn PnP cache | .yarn/.cache |
PnP build cache | npx docusaurus clear |
Note
The
clearcommand removes all four cache locations. In development, a full clear forces regeneration of all data files and full rebundle on next start.
Version Management
Docusaurus versions are snapshots of the docs/ directory:
docs/ → "current" (unreleased next version)
versioned_docs/
version-3.10.0/ → v3.10.0 snapshot
version-3.9.2/ → v3.9.2 snapshot
...
versioned_sidebars/
version-3.10.0-sidebars.json
version-3.9.2-sidebars.json
Version creation copies docs + sidebars + i18n translations. The Docusaurus website itself maintains 10+ versioned snapshots (v2.x through v3.10.0).
Translation Workflow
- Extract messages:
npx docusaurus write-translations --locale fr - Translate JSON files in
i18n/fr/ - Translate content by placing localized Markdown in
i18n/fr/docusaurus-plugin-content-docs/current/ - Build:
npx docusaurus build --locale fr
Crowdin integration is available via the @crowdin/cli package (used by the Docusaurus website itself).
Tip
Use
--messagePrefixwithwrite-translationsto mark untranslated strings (e.g.,--messagePrefix "🚧 ") so they stand out in the UI during development.
6. Performance
Bundler Selection
| Bundler | Flag | Characteristics |
|---|---|---|
| Webpack (default) | — | Mature ecosystem, persistent caching, widest plugin compatibility |
| Rspack (opt-in) | future.faster.rspackBundler |
Significantly faster builds, Rust-based, Webpack API compatible |
Minification Options
| Minifier | Type | Flag | Notes |
|---|---|---|---|
| Terser | JS | default | Configurable parallelism via TERSER_PARALLEL |
| SWC | JS | swcJsMinimizer |
ES2020 target, tree-shaking, faster |
| CSSNano | CSS | default | Custom preset in @docusaurus/cssnano-preset |
| Lightning CSS | CSS | lightningCssMinimizer |
Browserslist-aware, Rust-based |
| Terser (HTML) | HTML | default | Can fail; errors logged as HTML minification failed (Terser) |
| SWC (HTML) | HTML | swcHtmlMinimizer |
Fallback errors: HTML minification failed (SWC) |
Skip HTML minification entirely with SKIP_HTML_MINIFICATION=true.
MDX Cross-Compiler Cache
When mdxCrossCompilerCache is enabled, MDX files compiled for the client bundle are cached and reused for the server bundle (and vice versa). This is production-only and avoids double-compiling large MDX sites.
Browserslist Targets
The @docusaurus/faster package computes targets from browserslist:
- Client: From
browserslistconfig inpackage.json(production/development contexts) - Server: From the current Node.js version, overridable with
DOCUSAURUS_SERVER_NODE_TARGET
7. Security
Content Security
| Concern | Mitigation |
|---|---|
| XSS in user content | MDX sanitizes by default; React escapes JSX |
| Script injection | scripts and headTags config only; no runtime injection |
| Deploy credentials | GIT_PASS obfuscated in logs; use CI secrets |
| API keys in config | Algolia search key is public (search-only); no server-side secrets |
Dependency Security
The monorepo uses:
lockfile-lint— validates lockfile integritysyncpack— ensures dependency version consistency across packagespatch-package— applies security patches without waiting for upstream- Yarn deduplication via
yarn-deduplicatein postinstall
PWA Security
The PWA service worker is compiled separately by Webpack with its own Babel configuration. Custom service worker code (swCustom) is inlined — audit any custom SW modules for fetch interception or cache poisoning.
Caution
The PWA plugin's service worker has full control over network requests and cached responses. Only enable it in trusted deployment environments and audit any custom service worker code.
CSP Considerations
Docusaurus injects inline scripts for:
- Color mode initialization
- Service worker registration (PWA)
- Analytics scripts (gtag, GTM)
If deploying with strict Content-Security-Policy headers, add appropriate nonce or sha256 hashes for these inline scripts.
8. Developer Internals
Repository Structure
facebook/docusaurus/
├── packages/
│ ├── docusaurus/ Core engine
│ │ └── src/
│ │ ├── commands/ CLI commands (start, build, deploy, etc.)
│ │ ├── server/ Server-side: config loading, plugins, codegen
│ │ ├── webpack/ Webpack configuration and utilities
│ │ └── client/ Client-side exports and theme fallbacks
│ ├── docusaurus-bundler/ Webpack/Rspack abstraction
│ ├── docusaurus-faster/ SWC/Rspack/Lightning CSS optimizations
│ ├── docusaurus-logger/ Structured logging with perf tracking
│ ├── docusaurus-types/ TypeScript type definitions
│ ├── docusaurus-utils/ Path, URL, data file utilities
│ ├── docusaurus-utils-common/ Shared utilities (client + server)
│ ├── docusaurus-utils-validation/ Joi schema helpers
│ ├── docusaurus-babel/ Babel presets and configuration
│ ├── docusaurus-mdx-loader/ Webpack MDX loader + remark plugins
│ ├── docusaurus-preset-classic/ Plugin bundle (docs+blog+pages+theme)
│ ├── docusaurus-plugin-content-docs/ Versioned documentation
│ ├── docusaurus-plugin-content-blog/ Blog with authors + feeds
│ ├── docusaurus-plugin-content-pages/ Static/MDX pages
│ ├── docusaurus-plugin-sitemap/ XML sitemap
│ ├── docusaurus-plugin-client-redirects/ Client-side redirects
│ ├── docusaurus-plugin-pwa/ Progressive Web App
│ ├── docusaurus-plugin-google-analytics/ Legacy GA
│ ├── docusaurus-plugin-google-gtag/ GA4
│ ├── docusaurus-plugin-google-tag-manager/ GTM
│ ├── docusaurus-plugin-vercel-analytics/ Vercel analytics
│ ├── docusaurus-plugin-rsdoctor/ Build diagnostics
│ ├── docusaurus-plugin-ideal-image/ Responsive images
│ ├── docusaurus-plugin-svgr/ SVG as React components
│ ├── docusaurus-plugin-css-cascade-layers/ CSS @layer support
│ ├── docusaurus-theme-classic/ Standard UI components
│ ├── docusaurus-theme-common/ Shared React hooks + utils
│ ├── docusaurus-theme-search-algolia/ DocSearch integration
│ ├── docusaurus-theme-live-codeblock/ Interactive code editor
│ ├── docusaurus-theme-mermaid/ Diagram rendering
│ ├── docusaurus-theme-translations/ Locale message files
│ ├── docusaurus-module-type-aliases/ TS path aliases
│ ├── docusaurus-tsconfig/ Shared tsconfig base
│ ├── docusaurus-remark-plugin-npm2yarn/ Package manager tabs
│ ├── docusaurus-cssnano-preset/ CSS minifier config
│ ├── create-docusaurus/ Project scaffolding CLI
│ ├── eslint-plugin/ ESLint rules
│ ├── stylelint-copyright/ CSS copyright checker
│ └── lqip-loader/ Low-quality image placeholders
├── website/ Docusaurus.io website (dogfood)
│ ├── docs/ Current documentation
│ ├── versioned_docs/ Version snapshots (2.x through 3.10.0)
│ ├── versioned_sidebars/ Version sidebar configs
│ ├── blog/ Blog posts
│ ├── src/ Custom pages and components
│ ├── _dogfooding/ Internal test content
│ └── docusaurus.config.ts Website config
├── examples/ Template examples (classic, classic-ts)
├── admin/ Admin scripts and new.docusaurus.io
├── argos/ Visual regression testing
├── jest/ Jest configuration
└── package.json Root workspace config
Module Deep Dive: Core Engine (@docusaurus/core)
CLI (src/commands/cli.ts): Commander-based CLI registration. 8 built-in commands plus external command passthrough via externalCommand() which loads plugins to check for custom commands.
Build (src/commands/build/): Orchestrates the full build pipeline — loads context, initializes plugins, generates routes, runs bundler, performs SSG. The --bundle-analyzer flag activates webpack-bundle-analyzer for treemap visualization.
Start (src/commands/start/): Dev server with HMR. Polls filesystem when --poll is set (useful for network drives or Docker volumes). Auto-opens browser unless --no-open.
Deploy (src/commands/deploy.ts): GitHub Pages deployment via Git operations. Builds SSH or HTTPS URLs based on USE_SSH, clones the deploy branch into a temp directory, copies build output, commits, and pushes. All execa.commandSync calls are logged (obfuscating GIT_PASS).
Server (src/server/): Config loading, plugin initialization, site metadata, route generation, i18n setup, code generation. The LoadContext object provides site config, paths, and environment to all plugins.
Plugins (src/server/plugins/): Plugin lifecycle management — config normalization, module resolution (shorthand names), option validation, unique ID enforcement, initialization.
Module Deep Dive: Docs Plugin
The docs plugin is the most complex content plugin (~93K chars of source):
- Version management: Reads
versioned_docs/,versioned_sidebars/, andversions.jsonto construct a multi-version content tree - Document processing: Parses frontmatter, generates slugs/permalinks, resolves edit URLs, fetches VCS metadata (last author/time)
- Sidebar pipeline: Load → Normalize shorthands → Validate → Generate (unwrap autogenerated) → Post-process (defaults, category links, flatten empty)
- Navigation: Links docs with previous/next based on sidebar order
- CLI extension: Adds
docs:version <version>command for creating version snapshots
Module Deep Dive: Blog Plugin
The blog plugin (~104K chars) manages:
- Author system: Global
authors.ymlwith schema validation (unique permalinks, normalized images, social links). Supports both key-based references and inline author definitions. - Feed generation: RSS, Atom, JSON feeds with post content. Feed generation errors are caught per-post with descriptive messages.
- Post processing: Date parsing, reading time calculation, truncation marker detection, tag normalization.
Module Deep Dive: MDX Loader
The MDX loader (@docusaurus/mdx-loader) provides:
- Format detection:
.md→ CommonMark mode,.mdx→ MDX mode, configurable default - Remark plugins: Admonitions (NOTE/TIP/WARNING/etc.), heading IDs, TOC extraction, image transforms, link transforms, npm2yarn, unused directive warnings
- Cross-compiler caching: Production-only cache sharing between client and server MDX compilation
- Frontmatter handling: Custom Joi extension (
JoiFrontMatter) that converts YAML-auto-typed numbers/dates back to strings
Module Deep Dive: Bundler Abstraction
The bundler package (@docusaurus/bundler) abstracts Webpack and Rspack:
CurrentBundlertype: Runtime selection between Webpack and Rspack- Persistent caching: Both bundlers support filesystem caching for incremental builds
- CSS extraction:
MiniCssExtractPlugin(Webpack) orCssExtractRspackPlugin(Rspack) - Custom Rspack progress plugin:
CustomRspackProgressPluginextends Rspack's progress plugin
Module Deep Dive: Logger
The logger (@docusaurus/logger) provides:
- Structured logging: Template literal tag API —
logger.info\text path=${val}`` - Performance tracking: Start/end marks with duration measurement. Enabled via
DOCUSAURUS_PERF_LOGGER - Error formatting: Interpolated error messages with
code,path,nameformatters
Code Patterns and Conventions
| Pattern | Convention |
|---|---|
| Module system | ES Modules (.ts compiled, .mjs for config) |
| Error handling | Typed errors with {cause: err} chaining |
| Plugin self-disable | Return null from constructor |
| Unique IDs | DEFAULT_PLUGIN_ID = 'default'; uniqueness enforced at init |
| Path handling | Forward slashes everywhere; @docusaurus/utils normalizers |
| Config validation | Joi schemas via @docusaurus/utils-validation |
| Trailing slash | Centralized normalization in utils; configurable per-site |
| VCS integration | Optional Git-based last-update metadata (author, time) |
| Content visibility | isDraft() / isUnlisted() — production-only filtering |
| Data file loading | YAML/JSON support; localized paths take priority |
| Async-first | Plugin lifecycle is fully async; build commands await all phases |
Constants (@docusaurus/utils/src/constants.ts)
| Constant | Value | Description |
|---|---|---|
DEFAULT_BUILD_DIR_NAME |
'build' |
Output directory name |
GENERATED_FILES_DIR_NAME |
'.docusaurus' |
Generated files directory |
SRC_DIR_NAME |
'src' |
Source directory name |
DEFAULT_STATIC_DIR_NAME |
'static' |
Static assets directory |
DEFAULT_PORT |
3000 |
Default server port |
DEFAULT_PLUGIN_ID |
'default' |
Default plugin instance ID |
Testing Strategy
| Layer | Tool | Configuration |
|---|---|---|
| Unit tests | Jest 30 | @swc/jest transform, jest.config.ts at root |
| DOM tests | @testing-library/react |
jsdom environment |
| Snapshot tests | Jest + custom serializers | jest-serializer-ansi-escapes, jest-serializer-react-helmet-async |
| Visual regression | Argos + Playwright | Screenshots compared against baselines |
| Type checking | TypeScript 6.0 | tsc (not run during build) |
Test fixtures live alongside source: src/__tests__/__fixtures__/. The monorepo uses @swc/jest for fast test compilation.
ESLint Rules (@docusaurus/eslint-plugin)
The custom ESLint plugin enforces:
- No synchronous filesystem operations — prevents blocking the event loop in plugin code
- No direct lodash imports — enforces specific sub-module imports for tree-shaking
- Coupling restrictions — prevents improper cross-references between content plugins
Stylelint Rule (@docusaurus/stylelint-copyright)
Enforces copyright header comments at the top of CSS files.
Potential Improvements
Based on source analysis:
- TypeScript 6.0 migration: The
@docusaurus/tsconfigbase needs updates for thebaseUrldeprecation (issue #11893) - CommonMark mode expansion: Feature request #9092 tracks making more features work without MDX (head tags, live code blocks, tabs)
- Rspack stability: The Rspack bundler path is opt-in; some edge cases with i18n on Cloudflare Pages remain (issue #11961)
execamigration: Deploy command usesexeca.commandSyncwith manual argument escaping; a TODO in source notes migration toexeca(file, [...args])with async/await- PWA hash router incompatibility: The PWA plugin explicitly detects and warns about
hashRouterusage text{pattern in LaTeX: MDX/Acorn error triggered by certain LaTeX syntax (issue #11235)
Contributing
The monorepo uses:
- Yarn workspaces for package management
- Lerna for versioning and publishing
- Husky for pre-commit hooks
- lint-staged for staged-file linting
- Prettier for code formatting
- CSpell for spell checking with a
project-words.txtdictionary - Syncpack for dependency version consistency
Development workflow:
yarn install # Install all dependencies + build packages (postinstall)
yarn start # Build packages then start website
yarn test # Run Jest tests
yarn lint # ESLint + Stylelint + CSpell + Syncpack
yarn format # Prettier formatting
Package build: lerna run build --no-private compiles all public packages. The postinstall hook runs patch-package, yarn-deduplicate, and package builds.
Canary releases: Automated via yarn canary which bumps to a canary version tag (<version>-canary-<count>+<sha>) and publishes to the canary dist-tag.
9. Integration Points
Algolia DocSearch
The search theme detects DocSearch version (v3 vs v4) and configures webpack aliases for backward compatibility. It generates:
- OpenSearch XML (
opensearch.xml) for browser search integration - A search page route at the configured
searchPagePath - Translation messages for localized search UI
Analytics Providers
| Provider | Plugin | Injection |
|---|---|---|
| Google Analytics 4 | plugin-google-gtag |
gtag.js script in <head> |
| Google Tag Manager | plugin-google-tag-manager |
GTM script + noscript iframe |
| Google Analytics (legacy) | plugin-google-analytics |
analytics.js script |
| Vercel Analytics | plugin-vercel-analytics |
Vercel script injection |
All analytics plugins check NODE_ENV === 'production' before injecting scripts.
Crowdin (Translation Management)
The Docusaurus website uses Crowdin for translation management:
yarn crowdin:upload:website # Upload source strings
yarn crowdin:download:website # Download translations (fr, ko, pt-BR, zh-CN, ja)
Configuration lives in crowdin-v2.yaml at the repo root.
CI/CD Integration
Netlify detection: Checks NETLIFY and CONTEXT env vars. Deploy previews may adjust build behavior.
CircleCI integration: Deploy command falls back to CIRCLE_PROJECT_USERNAME / CIRCLE_PROJECT_REPONAME for organization/project names, and checks CI_PULL_REQUEST / CIRCLE_PULL_REQUEST to skip deploy on PR builds.
Generic CI: CI env var is checked by serve command to default --no-open (don't try to open a browser in CI).