Skip to content

Fix: Docusaurus Not Working — Build Failing, Sidebar Not Showing, or Plugin Errors

FixDevs ·

Quick Answer

How to fix Docusaurus issues — docs and blog configuration, sidebar generation, custom theme components, plugin setup, MDX compatibility, search integration, and deployment.

The Problem

The Docusaurus build fails with a cryptic error:

npm run build
# Error: [ERROR] Docusaurus found broken links!
# Or: Error: Module not found: Can't resolve '@docusaurus/theme-common'

Or the sidebar doesn’t show your docs:

Sidebar appears but is empty — docs exist in the docs/ folder

Or MDX content renders as plain text:

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

<Tabs>
  <TabItem value="npm">npm install</TabItem>
</Tabs>
<!-- Renders as plain text instead of tabbed interface -->

Or a custom page component doesn’t render:

404 — page not found for a page in src/pages/

Why This Happens

Docusaurus is a React-based static site generator optimized for documentation. Its plugin-driven architecture requires specific configuration:

  • Broken links are treated as build errors — Docusaurus checks all internal links during build. A typo in a markdown link or a reference to a deleted page fails the build. This is intentional to catch dead links early.
  • Sidebar is auto-generated from the file structure or configured manually — by default, Docusaurus scans the docs/ directory and creates a sidebar. If sidebars.js has a manual config that doesn’t match the actual files, pages are missing from navigation.
  • MDX components must be from @theme/ — Docusaurus provides built-in components via @theme/ imports. Using raw HTML or components from other libraries without wrapping them in MDX causes rendering issues.
  • docusaurus.config.js is the central configuration — presets, plugins, themes, and site metadata are all configured here. Missing presets (like @docusaurus/preset-classic) remove core features.

Fix 1: Set Up Docusaurus

npx create-docusaurus@latest my-docs classic --typescript
cd my-docs
npm start
// docusaurus.config.ts
import type { Config } from '@docusaurus/types';
import type * as Preset from '@docusaurus/preset-classic';

const config: Config = {
  title: 'My Project',
  tagline: 'Docs for My Project',
  favicon: 'img/favicon.ico',
  url: 'https://docs.myproject.com',
  baseUrl: '/',

  organizationName: 'my-org',
  projectName: 'my-project',

  // Broken link handling
  onBrokenLinks: 'throw',       // 'throw' | 'warn' | 'ignore'
  onBrokenMarkdownLinks: 'warn',

  i18n: {
    defaultLocale: 'en',
    locales: ['en'],
  },

  presets: [
    [
      'classic',
      {
        docs: {
          sidebarPath: './sidebars.ts',
          editUrl: 'https://github.com/my-org/my-project/tree/main/',
          showLastUpdateTime: true,
          showLastUpdateAuthor: true,
        },
        blog: {
          showReadingTime: true,
          editUrl: 'https://github.com/my-org/my-project/tree/main/',
          blogSidebarCount: 'ALL',
        },
        theme: {
          customCss: './src/css/custom.css',
        },
      } satisfies Preset.Options,
    ],
  ],

  themeConfig: {
    navbar: {
      title: 'My Project',
      logo: { alt: 'Logo', src: 'img/logo.svg' },
      items: [
        { type: 'docSidebar', sidebarId: 'docs', position: 'left', label: 'Docs' },
        { to: '/blog', label: 'Blog', position: 'left' },
        { href: 'https://github.com/my-org/my-project', label: 'GitHub', position: 'right' },
      ],
    },
    footer: {
      style: 'dark',
      copyright: `Copyright © ${new Date().getFullYear()} My Project.`,
    },
    prism: {
      theme: require('prism-react-renderer').themes.github,
      darkTheme: require('prism-react-renderer').themes.dracula,
      additionalLanguages: ['bash', 'typescript', 'json', 'yaml'],
    },
    colorMode: {
      defaultMode: 'light',
      respectPrefersColorScheme: true,
    },
  } satisfies Preset.ThemeConfig,
};

export default config;

Fix 2: Sidebar Configuration

// sidebars.ts
import type { SidebarsConfig } from '@docusaurus/plugin-content-docs';

const sidebars: SidebarsConfig = {
  docs: [
    // Simple link
    'intro',

    // Category with items
    {
      type: 'category',
      label: 'Getting Started',
      collapsed: false,  // Expanded by default
      items: [
        'getting-started/installation',
        'getting-started/configuration',
        'getting-started/quick-start',
      ],
    },

    // Auto-generated from directory
    {
      type: 'category',
      label: 'Guides',
      items: [
        { type: 'autogenerated', dirName: 'guides' },
      ],
    },

    // Category with link
    {
      type: 'category',
      label: 'API Reference',
      link: {
        type: 'generated-index',
        title: 'API Reference',
        description: 'All API endpoints and types.',
      },
      items: [
        'api/authentication',
        'api/users',
        'api/posts',
      ],
    },

    // External link
    {
      type: 'link',
      label: 'GitHub',
      href: 'https://github.com/my-org/my-project',
    },
  ],
};

export default sidebars;
# Docs directory structure
docs/
├── intro.md                      # /docs/intro
├── getting-started/
│   ├── installation.md           # /docs/getting-started/installation
│   ├── configuration.md
│   └── quick-start.md
├── guides/
│   ├── _category_.json           # Auto-generated category config
│   ├── basic-usage.md
│   └── advanced.md
└── api/
    ├── authentication.md
    ├── users.md
    └── posts.md
// docs/guides/_category_.json — category metadata
{
  "label": "Guides",
  "position": 3,
  "collapsed": false,
  "collapsible": true
}

Fix 3: MDX Components

---
title: Installation Guide
sidebar_position: 1
tags: [getting-started, setup]
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import Admonition from '@theme/Admonition';
import CodeBlock from '@theme/CodeBlock';

# Installation

## System Requirements

:::info
Node.js 18 or higher is required.
:::

:::warning
**Breaking change:** Version 3.0 requires a new configuration format.
:::

:::danger
Never expose your API keys in client-side code.
:::

:::tip
Use `npx` to always run the latest version.
:::

## Install the Package

<Tabs groupId="package-manager">
  <TabItem value="npm" label="npm" default>

```bash
npm install my-package
yarn add my-package
pnpm add my-package

Code Example

{`import { defineConfig } from 'my-package';

export default defineConfig({ // Options here });`}


## Fix 4: Custom Pages and Components

```typescript
// src/pages/index.tsx — custom homepage
import Layout from '@theme/Layout';
import Link from '@docusaurus/Link';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';

export default function Home() {
  const { siteConfig } = useDocusaurusContext();

  return (
    <Layout title="Home" description={siteConfig.tagline}>
      <header style={{ textAlign: 'center', padding: '4rem 0' }}>
        <h1>{siteConfig.title}</h1>
        <p>{siteConfig.tagline}</p>
        <Link
          className="button button--primary button--lg"
          to="/docs/intro"
        >
          Get Started
        </Link>
      </header>
    </Layout>
  );
}
// src/components/FeatureCard.tsx — reusable component
export function FeatureCard({ title, description, icon }: {
  title: string;
  description: string;
  icon: string;
}) {
  return (
    <div className="col col--4" style={{ padding: '1rem' }}>
      <div style={{ textAlign: 'center' }}>
        <span style={{ fontSize: '3rem' }}>{icon}</span>
        <h3>{title}</h3>
        <p>{description}</p>
      </div>
    </div>
  );
}

// Use in MDX
import { FeatureCard } from '@site/src/components/FeatureCard';

<div className="row">
  <FeatureCard icon="⚡" title="Fast" description="Blazing fast builds" />
  <FeatureCard icon="🔧" title="Flexible" description="Highly customizable" />
  <FeatureCard icon="📱" title="Responsive" description="Mobile-first design" />
</div>

Fix 5: Search Integration

# Option 1: Algolia DocSearch (free for open-source)
# Apply at: https://docsearch.algolia.com/
// docusaurus.config.ts — Algolia search
themeConfig: {
  algolia: {
    appId: 'YOUR_APP_ID',
    apiKey: 'YOUR_SEARCH_API_KEY',  // Public search-only key
    indexName: 'my-project',
    contextualSearch: true,
  },
},
# Option 2: Local search (no external service)
npm install @easyops-cn/docusaurus-search-local
// docusaurus.config.ts — local search plugin
themes: [
  [
    '@easyops-cn/docusaurus-search-local',
    {
      hashed: true,
      language: ['en'],
      highlightSearchTermsOnTargetPage: true,
      docsRouteBasePath: '/docs',
    },
  ],
],

Fix 6: Deployment

# Build static site
npm run build

# Test the build locally
npm run serve
# GitHub Pages — built-in command
GIT_USER=your-username npm run deploy

# Or via GitHub Actions
# .github/workflows/deploy.yml
name: Deploy Docusaurus
on:
  push:
    branches: [main]
permissions:
  contents: read
  pages: write
  id-token: write
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 20, cache: npm }
      - run: npm ci
      - run: npm run build
      - uses: actions/upload-pages-artifact@v3
        with: { path: build }
  deploy:
    needs: build
    runs-on: ubuntu-latest
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    steps:
      - id: deployment
        uses: actions/deploy-pages@v4

Still Not Working?

“Docusaurus found broken links” — this is a build error, not a warning. Fix the links or temporarily set onBrokenLinks: 'warn' in docusaurus.config.ts. Common causes: typos in markdown links, linking to deleted pages, or missing trailing slashes. Run npm run build to see all broken links at once.

Sidebar shows “undefined” for a category — the _category_.json file has invalid JSON or the label field is missing. Also check that sidebars.ts entries match actual file paths. 'getting-started/installation' expects docs/getting-started/installation.md to exist.

MDX compilation error — Docusaurus uses MDX v3. Some MDX v1/v2 syntax doesn’t work. Common issues: JSX expressions must be on their own line (not inline with markdown), { and } must be escaped in markdown text (use \{), and < in text must use &lt;.

Custom CSS not applying — verify the CSS file path in docusaurus.config.ts matches: theme: { customCss: './src/css/custom.css' }. Use CSS custom properties to override theme values: --ifm-color-primary, --ifm-font-family-base, etc.

For related documentation issues, see Fix: Nextra Not Working and Fix: MDX Not Working.

F

FixDevs

Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.

Was this article helpful?

Related Articles