CodeWorlds
Back to collections
Guide19 min readCodeWorlds Team

Docusaurus, Meta's documentation generator

Docusaurus 3.10.2 under MIT. Configuration, search through Algolia DocSearch, the real cost of versioning, and how it compares to Starlight, Nextra and Mintlify.

Docusaurus, Meta's documentation generator

Docusaurus builds a static documentation site from Markdown and MDX files, using React as the templating layer. The current @docusaurus/core release is 3.10.2 from 10 July 2026, licensed MIT. There is no search engine in the box, and that is the first decision you have to make before rolling it out, not after.

What Docusaurus is and is not

Docusaurus takes a directory of Markdown and MDX files, adds a navbar, a sidebar, a theme switch and a blog section, and generates static HTML from all of it. You drop the output on any static host, Netlify or GitHub Pages for instance. No application server is required.

The templating layer is React. That is not an implementation detail but a consequence you will carry. The published 3.10.2 package declares peerDependencies on react at ^18.0.0 || ^19.0.0 and react-dom at the same range, and engines.node requires Node 20.0 or newer. Every page you want to write outside Markdown is a React component in src/pages. Every visual change that goes beyond CSS variables means swizzling, that is, replacing a theme component with your own copy.

What Docusaurus does not do matters just as much. There is no server-side search, because there is no server. It does not generate API documentation from source code, for which you need a separate plugin or a generator that emits Markdown files. It does not manage permissions, so documentation behind a login is a hosting problem, not a generator problem. It is also not a component library you show to designers, which is what Storybook is for.

What it does include are three things the competition often lacks in core: documentation versioning, translations and a blog. Those three items decide when Docusaurus wins.

Version, licence and release cadence

The licence is a textbook case and checking it takes three minutes. The facebook/docusaurus repository has a LICENSE file on the main branch with the MIT text and the header "Copyright (c) Facebook, Inc. and its affiliates". There is no LICENSE.md, so there is nothing to guess about which one applies. The license field in the npm registry for @docusaurus/core reads MIT. The unpacked core-3.10.2.tgz contains package/LICENSE with the same MIT text, next to 122 .js files and roughly 1.2 MB of actual code. Three sources, one answer, no dummies. The companion packages behave the same way: @docusaurus/preset-classic, @docusaurus/theme-search-algolia, @docusaurus/faster and create-docusaurus are all at 3.10.2 under MIT.

The question about Docusaurus 4 needs a precise answer, because whether you start a project now depends on it. The npm registry has no version beginning with 4. at all, on any channel. The dist-tags look like this: latest is 3.10.2, next is 3.0.0-rc.1, alpha is 3.9.2-alpha.4, canary is 3.10.1-canary-6655 from 4 June 2026. The next tag was left at a release candidate for version 3 and nobody has moved it since, so npm install @docusaurus/core@next gives you an old version rather than a v4 preview.

Version 4 does exist in another form, and already inside the released 3.10.2. The published package's lib/server/configValidation.js carries future.v4 flags with four entries: useCssCascadeLayers, siteStorageNamespacing, fasterByDefault and mdx1CompatDisabledByDefault. All default to false. This is a mechanism for preparing a site for the next major release without waiting for it. The practical conclusion: you can start on version 3, but turn these flags on straight away, because otherwise the migration will mean fixing four things at once instead of one at a time.

The release cadence has to be checked, not assumed. Stable releases went like this: 3.9.2 landed on 17 October 2025, 3.10.0 only on 7 April 2026, that is after almost six months of silence, 3.10.1 twenty-three days later on 30 April 2026, and 3.10.2 on 10 July 2026. Today, 22 August 2026, six weeks have therefore passed since the last release, and on this schedule that is well within the norm, since six-month gaps have already happened. The main branch is alive: the latest commits on main are from 21 August 2026, one day ago. Separately, it stands out that the canary channel stopped at a package from 4 June 2026, so automatic publishing of development builds is not running as regularly as repository activity would suggest.

Starting a project and the shape of the config

Getting into a project is short and needs no global installs.

Code
Bash
npx create-docusaurus@latest my-website classic --typescript
cd my-website
npm run start
npm run build
npm run serve

The classic template contains @docusaurus/preset-classic, that is the docs plugin, the blog plugin, the pages plugin and a theme with dark mode support. The --typescript flag switches the template to the TypeScript variant. The scripts in the generated package.json are start, build, swizzle, deploy, clear, serve, write-translations and write-heading-ids, all thin wrappers around the docusaurus command.

The whole configuration lives in a single docusaurus.config.js. The section worth knowing from day one is future, because that is where the build-speed flags and the version 4 preparation flags sit.

JSdocusaurus.config.js
JavaScript
// docusaurus.config.js
export default {
  future: {
    v4: {
      useCssCascadeLayers: true,
      siteStorageNamespacing: true,
      fasterByDefault: true,
      mdx1CompatDisabledByDefault: true,
    },
    faster: {
      swcJsLoader: true,
      swcJsMinimizer: true,
      swcHtmlMinimizer: true,
      lightningCssMinimizer: true,
      rspackBundler: true,
      rspackPersistentCache: true,
      mdxCrossCompilerCache: true,
      ssgWorkerThreads: true,
      gitEagerVcs: true,
    },
  },
};

Each of these flags has a concrete meaning: swcJsLoader replaces Babel with SWC, lightningCssMinimizer replaces cssnano and clean-css, rspackBundler replaces webpack with Rspack, rspackPersistentCache adds a persistent cache and requires keeping the ./node_modules/.cache directory between builds, ssgWorkerThreads spreads static site generation across a thread pool, and gitEagerVcs reads the whole Git repository at once instead of file by file, which matters on large repositories. The faster section requires adding the @docusaurus/faster package to your dependencies. In release 3.10.2 all these flags are off by default, unless you enable future.v4.fasterByDefault.

The documentation also carries a warning that is easy to miss: features prefixed with experimental_ or unstable_, such as experimental_router and experimental_vcs, may change in minor releases and are not treated as breaking changes under semantic versioning.

Search, the most common surprise

Docusaurus has no built-in search. The official documentation lists four routes and openly marks which one is supported: Algolia DocSearch has first-class support from the Docusaurus team, while Typesense DocSearch, local search and your own SearchBar component are community-maintained, with a request to report bugs to their respective repositories. That distinction has practical consequences the moment something breaks after an upgrade.

The official route works like this. Algolia runs a free DocSearch programme, but it is aimed at public technical documentation and technical blogs. The eligibility page says applications are usually turned down when the site is not production ready or contains non-technical content. You apply through the Algolia dashboard, where you submit a domain for validation against the programme requirements, and after approval you have to verify domain ownership within seven days or the crawler stops working. By default the crawler visits the site once a week, and the schedule can be changed in the interface.

For commercial product documentation that means something concrete: the free programme is not for you and you pay Algolia list prices. On the pricing page, as of 22 August 2026, the Grow plan includes 10,000 search requests per month and costs 0.50 dollars per additional thousand requests beyond that, plus 100,000 records with 0.40 dollars per additional thousand records. The Grow Plus plan has the same free thresholds, but the overage rate for search requests is 1.75 dollars per thousand. The crawler is billed separately: the questions section on the same page says Grow and Grow Plus include 10,000 crawls per month, while the product table row shows "10,000/mo then 0.80 dollars per additional 1K crawls/mo". In that same row, the raw page source also carries a "5,000 per month" value in a column whose plan name cannot be read without running the page scripts. Two different numbers on one line are a reason to check the limit in the dashboard before signing anything, not in an article.

Configuration on the Docusaurus side is short, and every field below genuinely exists.

JSdocusaurus.config.js
JavaScript
// docusaurus.config.js
export default {
  themeConfig: {
    algolia: {
      appId: 'YOUR_APP_ID',
      apiKey: 'YOUR_SEARCH_API_KEY',
      indexName: 'YOUR_INDEX_NAME',
      contextualSearch: true,
      externalUrlRegex: 'external\\.com|domain\\.com',
      replaceSearchResultPathname: {
        from: '/docs/',
        to: '/',
      },
      searchParameters: {},
      searchPagePath: 'search',
      insights: false,
    },
  },
};

The apiKey field is the public search key and the documentation states plainly that it is safe to commit. contextualSearch is on by default and keeps results scoped to the current docs version and current language, so browsing version 2 does not hand you duplicates from version 1. Contextual filters are merged with whatever you pass in searchParameters.facetFilters. There is also a newer askAi field, taking an assistant id or an object with assistantId, indexName, apiKey, appId and suggestedQuestions.

One version detail is worth checking before an upgrade. @docusaurus/theme-search-algolia at 3.10.2 declares a @docsearch/react dependency in the range ^3.9.0 || ^4.3.2, while the DocSearch site already announces 5.0.0 as stable. Docusaurus does not support that fifth version today.

If your documentation sits behind a firewall or does not qualify for the free programme, the Docusaurus documentation points to the "run your own" page on the DocSearch site. You should know what you are walking into: that page is marked as a legacy version, covers DocSearch 1.x and 2.x, and its last-updated date is 1 December 2021. It describes running the algolia/docsearch-scraper Docker image, with a ChromeDriver for pages that need JavaScript. It works, but it is not a maintained path.

The local alternative people actually use today is a community package.

JSdocusaurus.config.js
JavaScript
// docusaurus.config.js
export default {
  themes: [
    [
      require.resolve('@easyops-cn/docusaurus-search-local'),
      {
        hashed: true,
        language: ['en', 'pl'],
        indexDocs: true,
        indexBlog: true,
        indexPages: false,
        docsRouteBasePath: '/docs',
        highlightSearchTermsOnTargetPage: true,
        explicitSearchResultPath: true,
        fuzzyMatchingDistance: 1,
      },
    ],
  ],
};

@easyops-cn/docusaurus-search-local is at 0.55.3 from 29 July 2026 under MIT. The index is produced at build time and downloaded by the browser, so it grows along with the documentation, which on a large page set means a sizeable file to fetch. The hashed option appends a content hash so the index can be cached long-term. There is one recurring configuration trap: in docs-only mode, when you set routeBasePath in the preset to /, you must set docsRouteBasePath to the same value or the index will come out empty. The older docusaurus-lunr-search package is at 3.6.0 published on 10 January 2025, that is over a year and a half without a release, and I would not pick it for a new project.

Documentation versioning and what it costs

Versioning is the strongest argument for Docusaurus and at the same time the most expensive feature in the set. The docusaurus docs:version 1.1.0 command does three things: it copies the entire contents of the docs/ directory into a new versioned_docs/version-1.1.0/ directory, creates versioned_sidebars/version-1.1.0-sidebars.json from the current sidebar configuration, and appends the version number to versions.json.

It copies, it does not link. After freezing three versions you have four sets of the same files in the repository, and every typo fix in a paragraph present in all of them is four separate edits or a deliberate decision that old versions do not get fixed.

Code
TEXT
website
├── docs                         # the "current" version
│   └── hello.md                 # /docs/next/hello
├── versions.json                # ["1.1.0", "1.0.0"]
├── versioned_docs
│   ├── version-1.1.0
│   │   └── hello.md             # /docs/hello
│   └── version-1.0.0
│       └── hello.md             # /docs/1.0.0/hello
├── versioned_sidebars
│   ├── version-1.1.0-sidebars.json
│   └── version-1.0.0-sidebars.json
└── docusaurus.config.js

What the documentation says about build time is worth reporting without embellishment. The versioning page opens with a warning to think it through before starting, because versioning can make it hard for contributors to help. It goes on to say that most of the time you do not need versioning, since it will just increase your build time and introduce complexity to your codebase, and that it suits sites with high traffic and rapid documentation changes between versions. Under the onlyIncludeVersions option there is a tip to limit yourself to two or three versions in development and deploy previews, precisely to improve startup and build time.

What the documentation does not give is numbers. There is no multiplier, no chart, no measurement showing what percentage the build time grows per version. The relationship is qualitative: more versions means more pages to generate, more files to process and a longer run. If you need a hard number for your own repository, the only honest route is measuring a build with onlyIncludeVersions set to one version and comparing it against the full set.

The remaining docs plugin options that govern this behaviour are disableVersioning, includeCurrentVersion, lastVersion and the versions dictionary, where each version takes label, path, a banner of none, unreleased or unmaintained, badge and className. There is also a trick for projects that shipped version 1 and are not planning version 2: instead of freezing, you set lastVersion: 'current' and give the current version a label and a path, which keeps a single docs/ directory while the reader still sees a version number.

Translations and building multiple languages

Translations work on files, not through an external service. In the configuration you declare i18n.defaultLocale and the i18n.locales list, and then translate three kinds of assets. Markdown and MDX files are translated as a whole, without splitting into sentences, so the context is preserved. Labels from React code and from themeConfig go into JSON files in the Chrome i18n format, where each key has message and description fields. The third kind is plugin data, such as sidebar category labels.

Code
Bash
npm run write-translations -- --locale fr
npm run start -- --locale fr
npx docusaurus build --locale fr
npx docusaurus build

The write-translations command performs static analysis of your code only, it does not run the site, so messages built dynamically from expressions will not be extracted. The build command without a --locale flag builds all known locales, and with the flag only the ones you name, which is a practical escape hatch once a full build in the continuous integration pipeline starts taking too long.

The documentation also spells out what the translation system does not do: it does not detect the user's locale automatically, since that belongs to the host, it does not back any particular translation service as a vendor, and it does not translate slugs, calling that technically complicated and of little search value. The default classic theme labels already ship translated into many languages in the @docusaurus/theme-translations package.

Docusaurus against the alternatives

FeatureDocusaurus 3.10.2Astro Starlight 0.41.7Nextra 4.6.1Mintlify
LicenceMITMITMITengine not public
Latest release2026-07-102026-08-052025-12-04outside the npm registry
Templating layerReactAstroNext.jsclosed
Search in corenonePagefind, no configurationPagefind in the themevendor service
Docs versioningbuilt incommunity pluginnot in coreservice feature
Translationsbuilt inbuilt independs on Next.js routingservice feature
Blogbuilt innot in corevia the themeservice feature

Several rows in that table need a comment. Starlight has full-text search based on Pagefind enabled by default with no configuration at all, and a single page is excluded from the index with pagefind: false in the file's frontmatter. Versioning is not in core, it is handled by the community plugin starlight-versions from the plugin directory. Nextra also reaches for Pagefind, visible in the published 4.6.1 package where the search component loads the pagefind/pagefind.js module, but release 4.6.1 itself dates from 4 December 2025, so it is over eight months old. We covered Mintlify separately in the article on Mintlify, and there the key difference is different in kind: the engine repository is not public, so licence and version comparisons have no counterpart here.

When Docusaurus wins. A large open source project with several maintained major versions, documentation in several languages and a release blog gets all three features out of the box, free, with no vendor in the middle. On top of that comes free search from the DocSearch programme, provided the application is accepted.

When it loses. For a thirty-page documentation set the whole machinery is excessive and Starlight or a plain Markdown directory in the repository will do. A team that does not know React will get stuck on swizzling at the first unusual visual change. And if the documentation is meant to be part of an existing Next.js application, on one domain and sharing the logged-in state, then Docusaurus is a separate application with a separate build, so Nextra or your own routes in Next.js will be simpler.

Three drawbacks are worth naming outright, because none of them disappears after installation. First, the entire build is React, so the documentation site drags the React ecosystem along with its upgrades and version conflicts. Second, migrations between major versions required rewriting configuration, and the trace of that is still in the code: the markdown.mdx1Compat option with its comments, admonitions and headingIds defaults exists precisely to ease the move to version 3, and the future.v4.mdx1CompatDisabledByDefault flag prepares its removal. Third, search is an external dependency, and in the official variant also an external service with its own price list and its own admission rules.

Common mistakes

Assuming search will simply be there. This is the most frequent mistake and it surfaces the day before launch. The decision between DocSearch and local search has to be made at the start, because an application to the Algolia programme is not instant and can be rejected.

Hiding the apiKey in environment variables. The key in the algolia configuration is the public search key and the documentation says outright that it can be committed to the repository. Building a secret-handling procedure around it wastes time and makes deploy previews harder along the way.

Versioning from day one. Freezing a version before the documentation stabilises gives you two directories to maintain and zero benefit. The documentation advises the opposite, and the lastVersion: 'current' trick lets you display a version number without copying files.

Turning on future.faster flags without the package. The faster section requires @docusaurus/faster in your dependencies, as does future.v4.fasterByDefault. Without that package the build fails.

A docsRouteBasePath mismatch with local search. In docs-only mode, when the preset's routeBasePath is set to /, the same value has to reach the search plugin's options. The symptom is misleading, because the site builds fine and search simply finds nothing.

Updating initialIndexSettings in the crawler configuration. Those settings initialise the index only if it does not exist yet. After a change, the recommended move is deleting the index and starting a fresh crawl, rather than expecting the new configuration to apply on its own.

FAQ

Is Docusaurus 4 out yet?

Not in the npm registry. As of 22 August 2026 there is no @docusaurus/core package at 4.x there, on any channel. The next tag points at 3.0.0-rc.1, that is a release candidate for version 3, so installing from that channel takes you backwards. Version 4 is being prepared through the future.v4 flags already available in 3.10.2, and that is the right way to get ready for it.

What does search actually cost on a commercial project?

The free DocSearch programme covers public technical documentation and technical blogs, so commercial product documentation will not benefit from it. You pay Algolia list prices: the Grow plan includes 10,000 search requests per month and 0.50 dollars per additional thousand, plus 100,000 records and 0.40 dollars per additional thousand. Grow Plus has the same thresholds but 1.75 dollars per thousand overage requests. On top of that comes crawler billing, where the price list shows two different numbers, so check the limit in the dashboard.

Can a team use Docusaurus without knowing React?

For writing and publishing documentation, yes, because the content is Markdown and MDX files and the classic theme works without writing components. The boundary sits where CSS variables end. A custom home page, an unusual doc page layout or a change to sidebar behaviour all mean swizzling a theme component, that is, working in React and maintaining that copy across upgrades.

Can versioning be switched off after the fact?

Yes. The disableVersioning option turns versioning off despite existing versions, and the site then contains only the current version. A version can also be removed for good: delete its number from versions.json, delete the versioned_docs/version-X directory and the versioned_sidebars/version-X-sidebars.json file. If you only want faster preview builds, onlyIncludeVersions with two or three versions is enough.

Does Docusaurus fit documentation inside a Next.js application?

Not in the sense of embedding. Docusaurus is a standalone application with its own build and its own router, not a set of components to plug into existing routes. You can serve it under a /docs path at the reverse proxy level, but that is still two separate deployments. When documentation has to share layout and session with the application, Nextra or your own MDX pages in the Next.js project are closer to the goal.

What do the Docusaurus Faster flags give and are they worth enabling?

They swap slower tools for faster ones: SWC instead of Babel for transpilation and minification, Lightning CSS instead of cssnano and clean-css, Rspack instead of webpack, a thread pool for static site generation and faster reads of Git metadata. In 3.10.2 they are off by default, they require the @docusaurus/faster package, and rspackPersistentCache additionally requires keeping ./node_modules/.cache between builds. They are worth enabling, but measure on your own repository, because the gain depends on the number of pages and versions.

Read next

We use cookies to enhance your experience on the site