Skip to main content

Link Checker

Automated tool for checking broken internal and external links in documentation.

Overview

The link checker scans all Markdown and MDX files in the documentation for broken links. It validates internal links (between documentation pages) and optionally checks external links (URLs to other websites).

Features

  • Internal link validation - Checks /docs/ paths, relative paths (./, ../), and @site/ aliases
  • 🌐 External link checking - Optional HTTP status code checking for external URLs
  • 📊 Detailed reporting - Shows file, line number, link, and error for each broken link
  • 🚀 Fast execution - Parallel checking and smart caching
  • 🔧 CI/CD integration - Can be added to prebuild scripts or GitHub Actions

Usage

npm run check-links
npm run check-links:external
# or
node scripts/check-links.cjs --check-external

Additional options

# Verbose output
node scripts/check-links.cjs --verbose

# Fail on warnings (exit code 2 for warnings)
node scripts/check-links.cjs --fail-on-warning

# All options together
node scripts/check-links.cjs --check-external --fail-on-warning --verbose

Example output

🔍 Docusaurus Link Checker

Options:
Check external links: No
Fail on warnings: No
Verbose: No

Found 165 markdown files to check

============================================================
RESULTS
============================================================

Files checked: 165
Links checked: 306
Unique external links: 65
Errors: 3
Warnings: 0

❌ ERRORS (Broken Links)

docs/architecture.md:45
Link: /docs/tools/nonexistent-tool
Error: Internal link target not found: /docs/tools/nonexistent-tool
Type: internal

✅ No broken links found!
[Link text](./relative-path.md)
[Link text](/docs/absolute-path)
[Link text](https://external.com)

Test Links: Links marked with <!-- test-link --> comment are skipped during validation. Use this for example links in documentation that intentionally don't exist:

<!-- test-link -->
[Example link](./relative-path.md)
<!-- test-link -->
<Link to="/docs/your-page">Link text</Link>

HTML anchor tags

<!-- test-link -->
<a href="/docs/your-page">Link text</a>

Exit codes

  • 0 - No broken links found
  • 1 - Broken links found (errors)
  • 2 - Warnings found (only if --fail-on-warning is set)

Integration with build process

Add to prebuild

To automatically check links before every build, add to package.json:

{
"scripts": {
"prebuild": "node ./scripts/sync-tools.cjs && node ./scripts/validate-mdx.cjs && node ./scripts/check-links.cjs"
}
}

GitHub Actions

Add to .github/workflows/deploy.yml:

- name: Check links
run: npm run check-links

Pre-commit hook

Add to .husky/pre-commit:

#!/bin/sh
cd docusaurus && npm run check-links

What gets checked

Included

  • All .md and .mdx files in docs/ directory
  • All .md files in tools/ source directory
  • Internal links (/docs/, ./, ../, @site/)
  • External links (if --check-external is enabled)

Excluded

  • node_modules/ directory
  • build/ directory
  • .docusaurus/ directory
  • Anchor-only links (#section)
  • mailto:, tel:, and data: URLs
  • Links inside code blocks - Links within fenced code blocks (```) are automatically skipped (they're just syntax examples)
  • Test links - Links marked with <!-- test-link --> HTML comment (for example links in documentation)

Common issues

False positives for generated files

If you get errors for tool documentation links, make sure you've run the sync script first:

npm run prebuild  # Syncs tools and validates MDX
npm run check-links

Issue: Links like tools/cloudflare-access.md may pass validation even if the tool file doesn't exist in the synced Docusaurus structure.

Why it happens: The link checker validates tools/ paths against the source tools/ directory. If a file exists there but hasn't been synced to Docusaurus (or was deleted), the link will appear valid but will be broken in the live site.

Solution: The link checker now validates tools/ paths against both:

  1. Source tools/ directory (for source file validation)
  2. Synced docusaurus/docs/tools/ structure (for Docusaurus site validation)

Best practice: Always run npm run sync-tools before npm run check-links to ensure the synced structure is up to date.

External links timeout after 5 seconds. If you have slow external links, they may be reported as errors. Consider:

  1. Checking external links separately (without --check-external in CI)
  2. Increasing the timeout in scripts/check-links.cjs
  3. Using a link checker service for external links

Relative path issues

Relative paths must be correct from the source file location. Common mistakes:

<!-- ❌ Wrong - missing ./ -->
<!-- test-link -->
[Link](guide.md)

<!-- ✅ Correct -->
[Link](./guide.md)

<!-- ❌ Wrong - wrong directory -->
<!-- test-link -->
[Link](../nonexistent-dir/guide.md)

<!-- ✅ Correct - verify the directory exists -->
<!-- test-link -->
[Link](../existing-dir/guide.md)

Best practices

  1. Run locally before committing - Catch broken links early
  2. Use absolute paths for internal docs - /docs/path is more reliable than ../../path
  3. Check external links periodically - Don't run on every build (too slow)
  4. Fix broken links immediately - Don't let them accumulate
  5. Use @site/ for non-doc files - e.g., @site/src/components/Button

Troubleshooting

Script won't run

Make sure the script is executable:

chmod +x docusaurus/scripts/check-links.cjs

Permission errors

Run with Node directly:

node docusaurus/scripts/check-links.cjs

Out of memory errors

If you have thousands of files, increase Node memory:

NODE_OPTIONS="--max-old-space-size=4096" npm run check-links

Configuration

To customize the link checker, edit scripts/check-links.cjs:

// Timeout for external links (milliseconds)
const EXTERNAL_LINK_TIMEOUT = 5000;

// Directories to exclude
const EXCLUDED_DIRS = ['node_modules', 'build', '.docusaurus'];

// File extensions to check
const FILE_EXTENSIONS = /\.(md|mdx)$/i;

Automatic Skipping

Links inside code blocks are automatically skipped - Any link within a fenced code block (```) is treated as a syntax example and not validated. This means you don't need to mark example links in code blocks.

For links in regular markdown content (not in code blocks) that are intentionally broken examples, mark them with <!-- test-link --> HTML comment:

Syntax:

<!-- test-link -->
[Example link](./non-existent-path.md)

The comment must appear on the line immediately before the link (or on the same line before the link). The link checker will skip validation for these links and not report them as errors.

Use cases:

  • Template placeholders - Links in templates that will be replaced
  • Intentional broken links - Links used to demonstrate error handling
  • Example links outside code blocks - When showing link syntax in regular markdown

Best Practice:

  • Links in code blocks (```) are automatically skipped - no marking needed
  • Use <!-- test-link --> only for links in regular markdown content
  • Use test links sparingly and only for legitimate examples
  • Real broken links should always be fixed, not marked as test links

Future improvements

Planned features for the link checker:

  • Test link support (via <!-- test-link --> comment)
  • Link caching to avoid rechecking unchanged files
  • Parallel external link checking for better performance
  • JSON output format for CI/CD integration
  • Link ignore list (.linkignore file)
  • Automatic link fixing suggestions
  • Integration with Docusaurus build process