Installation and Project Structure

This content was generated with the assistance of AI and should be verified against the official documentation of each tool before being relied on in production.

This section’s bibliography lists the reference material consulted while preparing these pages.

This page was written against Docusaurus 3.10.2 (create-docusaurus 3.10.2) and checked on 2026-10-26. It scaffolds a site for Pocket Units, a tiny units-conversion library for C# and Python, then walks through the generated project: which folder produces which URL, what each file is for, and what the npm scripts and the docusaurus command do. Commands and files below were run with Node.js v24.21.0 and npm 11.19.0, except where a sentence says otherwise.

What you need

A Docusaurus site is a React application that is rendered to static HTML at build time. The installation page of the official documentation lists a single requirement: Node.js 20.0 or above (check it with node -v). Node.js 18 support ended with Docusaurus 3.9. The generated site depends on React 19. npm ships with Node.js; Yarn, pnpm and Bun also work.

Scaffolding a site

The create-docusaurus tool creates a new directory and installs the dependencies. It can be run anywhere, in an empty repository or inside an existing one. The usual form names the site directory and the template:

npx create-docusaurus@latest my-website classic --typescript

The arguments are, in order, the site name, the template and an optional root directory:

  • The name is used as the site path and as the name field of the generated package.json. It may be absolute or relative to the root directory.

  • The template is classic (recommended), facebook (a Meta-specific variant), a Git repository URL starting with https:// or git@, or a local path whose files are copied.

  • The root directory is used to resolve the site path and defaults to the current directory.

The options documented for the tool are listed below. Running npx create-docusaurus@3.10.2 --help prints the same set.

Option Meaning

-t, --typescript

Use the TypeScript variant of a named template. Only classic provides one.

-j, --javascript

Use the JavaScript variant.

-p, --package-manager <manager>

One of npm, yarn, pnpm or bun. When omitted, the tool infers it from an existing lockfile, from the command that started it, or asks.

-s, --skip-install

Create the files but do not install dependencies.

-g, --git-strategy <strategy>

Only for Git repository templates: deep, shallow, copy or custom.

The same site can be created with the package manager’s own initializer: npm init docusaurus, yarn create docusaurus, pnpm create docusaurus or bunx create-docusaurus. The official page also mentions a Fast Track tutorial and an online playground at docusaurus.new for trying the tool without installing anything.

Real output of the command above, reduced to its closing summary:

[INFO] Creating new Docusaurus project...
[INFO] Installing dependencies with npm...
[SUCCESS] Created my-website.
[INFO] Inside that directory, you can run several commands:

  `npm start`
    Starts the development server.

  `npm run build`
    Bundles your website into static files for production.

  `npm run serve`
    Serves the built website locally.

  `npm run deploy`
    Publishes the website to GitHub pages.

We recommend that you begin by typing:

  `cd my-website`
  `npm start`

The scaffolded site pins the Docusaurus packages to the exact release that was current when it was created and uses a caret range for React:

package.json (dependencies, trimmed)
{
  "dependencies": {
    "@docusaurus/core": "3.10.2",
    "@docusaurus/faster": "3.10.2",
    "@docusaurus/preset-classic": "3.10.2",
    "@mdx-js/react": "^3.0.0",
    "clsx": "^2.0.0",
    "prism-react-renderer": "^2.3.0",
    "react": "^19.0.0",
    "react-dom": "^19.0.0"
  },
  "devDependencies": {
    "@docusaurus/module-type-aliases": "3.10.2",
    "@docusaurus/tsconfig": "3.10.2",
    "@docusaurus/types": "3.10.2",
    "@types/react": "^19.0.0",
    "typescript": "~6.0.2"
  },
  "engines": {
    "node": ">=20.0"
  }
}

All packages in the @docusaurus/ namespace must use the same version. The official upgrade instructions are to change the versions in package.json, run the package manager’s install command, and check the result with npx docusaurus --version, which prints 3.10.2 here. The @canary npm dist-tag gives access to unreleased features. At the check date the latest tag was 3.10.2, the last release of the 3.x line, and version 4 existed only as canary builds.

The scaffold already contains two things that older tutorials do not mention: the @docusaurus/faster package, and future: { v4: true } in the configuration. The second is a single switch that turns on a group of flags preparing the site for Docusaurus 4, among them the faster toolchain. The effect is visible in the dev server banner, which reports the Rspack bundler (Rspack 1.7.12 in this run). Both are covered in Docusaurus Faster and v4 readiness.

The generated project

The official page draws the tree of a JavaScript site. The TypeScript variant generated here has the same folders with TypeScript and MDX files, and a few more entries. The listing shows every file, except the images in static/img, the two screenshots in docs/tutorial-extras/img and the banner image of the welcome post:

my-website
├── blog
│   ├── 2019-05-28-first-blog-post.mdx
│   ├── 2019-05-29-long-blog-post.mdx
│   ├── 2021-08-01-mdx-blog-post.mdx
│   ├── 2021-08-26-welcome
│   │   ├── docusaurus-plushie-banner.jpeg
│   │   └── index.mdx
│   ├── authors.yml
│   └── tags.yml
├── docs
│   ├── intro.mdx
│   ├── tutorial-basics
│   │   ├── _category_.json
│   │   ├── congratulations.mdx
│   │   ├── create-a-blog-post.mdx
│   │   ├── create-a-document.mdx
│   │   ├── create-a-page.mdx
│   │   ├── deploy-your-site.mdx
│   │   └── markdown-features.mdx
│   └── tutorial-extras
│       ├── _category_.json
│       ├── img
│       ├── manage-docs-versions.mdx
│       └── translate-your-site.mdx
├── src
│   ├── components
│   │   └── HomepageFeatures
│   │       ├── index.tsx
│   │       └── styles.module.css
│   ├── css
│   │   └── custom.css
│   └── pages
│       ├── index.module.css
│       ├── index.tsx
│       └── markdown-page.mdx
├── static
│   ├── .nojekyll
│   └── img
├── .gitignore
├── README.md
├── docusaurus.config.ts
├── package-lock.json
├── package.json
├── sidebars.ts
└── tsconfig.json

Each entry has a role, summarised here and detailed in the pages named in the last column.

Path Purpose More

blog/

Blog posts, one Markdown or MDX file or one folder with an index.md or index.mdx per post. The date in the file or folder name becomes part of the URL. It also holds authors.yml and tags.yml, the optional global author and tag definitions. The folder can be deleted if the blog plugin is disabled, or renamed with the path option.

Blog and pages

docs/

The documentation. Folders become sidebar categories, files become pages. A _category_.json file configures a folder. The folder can be deleted if the docs plugin is disabled, or renamed with the path option.

Docs and front matter

src/

Everything that is not documentation: React pages, custom components and CSS. The location is a convention, not a requirement.

Styling, theming and swizzling

src/pages/

Any JSX, TSX, Markdown or MDX file here becomes a standalone page. The classic template ships index.tsx (the home page, with its CSS module) and markdown-page.mdx.

Blog and pages

src/components/

React components shared by pages. The template has one, HomepageFeatures, used by the home page.

MDX and React components

src/css/custom.css

Global styles. It is loaded because the preset option theme.customCss points at it, and it is where the Infima variables such as --ifm-color-primary are overridden.

Styling, theming and swizzling

static/

Copied unchanged to the root of the build output. The template adds img/ and an empty .nojekyll file, which stops GitHub Pages from running Jekyll over the output.

SEO and static assets

docusaurus.config.ts

The site configuration: metadata, url and baseUrl, presets, theme configuration and the future flags.

Configuration

sidebars.ts

The order and grouping of documents in the sidebars.

Sidebars

package.json

Dependencies and scripts. A Docusaurus site is an ordinary React application, so any npm package can be added.

This page

tsconfig.json

TypeScript settings that extend @docusaurus/tsconfig. The comment at its top says it is not used by docusaurus start or docusaurus build; it serves editors and the typecheck script.

CLI and TypeScript

.gitignore

Ignores /node_modules, /build and the generated .docusaurus folder, plus cache and log files.

This page

Folders that appear later and are not part of the scaffold are i18n/ (translations, created by write-translations or by hand), versioned_docs/, versioned_sidebars/ and versions.json (created by docs:version), and the generated .docusaurus/ and build/ directories.

From folders to URLs

The plugins of the classic preset turn the folders into routes. The generated site maps as follows:

flowchart LR P["src/pages/index.tsx"] --> R1["/"] M["src/pages/markdown-page.mdx"] --> R2["/markdown-page"] D["docs/intro.mdx"] --> R3["/docs/intro"] C["docs/tutorial-basics/..."] --> R4["/docs/tutorial-basics/..."] B["blog/2021-08-26-welcome/index.mdx"] --> R5["/blog/welcome"] S["static/img/logo.svg"] --> R6["/img/logo.svg"]

Figure: folders of the scaffolded project and the routes they produce.

The documentation page on the docs feature gives the same mapping for a fresh site: docs are served under /docs, and blog posts under /blog with the date in the URL unless a slug is set. The three sample posts of the template set a slug in their front matter (for example slug: first-blog-post), so they are served at /blog/first-blog-post, /blog/long-blog-post, /blog/mdx-blog-post and /blog/welcome. Setting the docs option routeBasePath to / serves the documentation at the site root ("docs-only mode"); the blog can be turned off with blog: false in the preset options. Both are shown in Configuration.

Scripts and the docusaurus command

The scaffold defines these scripts in package.json, each calling the docusaurus binary:

{
  "scripts": {
    "docusaurus": "docusaurus",
    "start": "docusaurus start",
    "build": "docusaurus build",
    "swizzle": "docusaurus swizzle",
    "deploy": "docusaurus deploy",
    "clear": "docusaurus clear",
    "serve": "docusaurus serve",
    "write-translations": "docusaurus write-translations",
    "write-heading-ids": "docusaurus write-heading-ids",
    "typecheck": "tsc"
  }
}

The typecheck script exists only in the TypeScript variant. npx docusaurus --help lists, besides the scripts above, the command docs:version <version>, which tags a new documentation version. Options of each command, as printed by --help in 3.10.2:

Command What it does Options

docusaurus start [siteDir]

Starts the development server with hot reloading. The default address is http://localhost:3000.

-p, --port (3000), -h, --host (localhost), -l, --locale, --hot-only, --config, --no-open, --poll [interval], --no-minify

docusaurus build [siteDir]

Produces the static site in build/.

--dev, --bundle-analyzer, --out-dir, --config, -l, --locale, --no-minify

docusaurus serve [siteDir]

Serves an existing build locally to check it before publishing.

--dir, --config, -p, --port, --build, -h, --host, --no-open

docusaurus deploy [siteDir]

Builds and pushes to the GitHub Pages branch. Deployment is covered in a separate page.

-l, --locale, --out-dir, --config, --skip-build, --target-dir

docusaurus swizzle [theme] [component]

Copies or wraps a theme component for customization.

-w, --wrap, -e, --eject, -l, --list, -t, --typescript, -j, --javascript, --danger, --config

docusaurus clear [siteDir]

Removes generated assets, caches and build artifacts.

none

docusaurus write-translations [siteDir]

Writes the JSON translation files for the default or a given locale.

-l, --locale, --override, --config, --messagePrefix

docusaurus write-heading-ids [siteDir] [files...]

Adds explicit heading IDs to Markdown files.

--syntax, --migrate, --overwrite, --maintain-case

To pass an option through npm, separate it with two dashes, as the official page does for the host option:

npm run start -- --host 0.0.0.0

Not every feature works the same in development: the official page notes that some functionality, anchor links among it, only works in the production build. A development-mode production bundle with full React error messages is available with docusaurus build --dev.

Running, building and checking the site

From the site directory, npm start opens a browser on port 3000. Running it with --no-open and a different port printed the following:

[INFO] Starting the development server...
[SUCCESS] Docusaurus website is running at: http://localhost:3124/
client (Rspack 1.7.12) compiled successfully

The production build and its output:

npm run typecheck
npm run build
> my-website@0.0.0 build
> docusaurus build

[INFO] [en] Creating an optimized production build...
[SUCCESS] Generated static files in "build".
[INFO] Use `npm run serve` command to test your build locally.

The result is a folder of static files that any static hosting service can serve. For the scaffold it contains 404.html, index.html, sitemap.xml, an assets/ folder with hashed JavaScript and CSS, and one folder per route group: docs/, blog/, markdown-page/ and img/. npm run serve -- --no-open -p 3123 served the build, and both the pages and files from static/ answered with status 200.

Adding Pocket Units content

The Pocket Units documentation fits the scaffold without changing any configuration. The commands and files below add a docs category, one blog post, a standalone page and a static download to a copy of the generated site.

docs/pocket-units/category.json
{
  "label": "Pocket Units",
  "position": 3,
  "link": {
    "type": "generated-index",
    "description": "A tiny units-conversion library for C# and Python."
  }
}
docs/pocket-units/overview.md
---
sidebar_position: 1
title: Overview
---

# Pocket Units

Pocket Units converts lengths between metres, feet and inches. It ships as a C# package and a Python package.

```python
from pocket_units import convert

print(convert(1.0, "m", "ft"))
```
docs/pocket-units/installation.md
---
sidebar_position: 2
---

# Installation

Install the Python package with `pip install pocket-units`.
blog/2026-10-26-pocket-units-released/index.md
---
title: Pocket Units is released
authors: [alberto]
tags: [release]
---

The first release of Pocket Units is available.

{/* truncate */}

It converts lengths between metres, feet and inches.
src/pages/about.md
---
title: About Pocket Units
---

# About

Pocket Units is a small demonstration library.

The blog post refers to an author and a tag that must be defined in blog/authors.yml and blog/tags.yml. Because the scaffold sets onInlineAuthors and onInlineTags to warn, an author or tag that is not declared in those files is reported at build time. The two entries appended to the generated files were:

# blog/authors.yml
alberto:
  name: Alberto
  title: Maintainer
  url: https://example.com

# blog/tags.yml
release:
  label: Release
  permalink: /release
  description: Release announcements

Finally, a file at static/files/units.csv (the single line metre,foot,inch) becomes available at /files/units.csv. The next build succeeded and produced these routes among the routes of the site, as listed in build/sitemap.xml:

/about
/blog/2026/10/26/pocket-units-released
/blog/tags/release
/docs/category/pocket-units
/docs/pocket-units/installation
/docs/pocket-units/overview

Note how the blog URL (the post sets no slug) takes its date from the folder name, how the docs URLs follow the folder names while the sidebar order follows sidebar_position and the category position, and how the generated-index link type created the extra page /docs/category/pocket-units.

Pitfalls and version notes

  • Markdown files are compiled as MDX. With the scaffolded configuration, an HTML comment fails the build. The blog post above written with the older truncate marker (an HTML comment) stopped the build with "Client bundle compiled with errors" and the cause "Unexpected character ! (U+0021) before name", followed by a hint to use the JSX comment form. Write the marker as {/* truncate */} in new content. The migration guide lists HTML comments as syntax that is being phased out.

  • Explicit heading IDs. By default npx docusaurus write-heading-ids writes IDs in the classic form {#getting-started}. In the scaffolded site (which has future: { v4: true }) running it over the whole site and then building failed with "Could not parse expression with acorn" in every changed MDX file. The command also accepts --syntax mdx-comment, which writes {/* #getting-started */}; a heading written that way built correctly and produced the expected anchor. The first positional argument of the command is the site directory, so a file list needs npx docusaurus write-heading-ids . docs/intro.mdx --syntax mdx-comment; passing a file as the first argument fails with "No config file found in site dir".

  • Broken Markdown links fail the build. Adding a link to a missing file produced the warning "Markdown link with URL ./nope.md …​ couldn’t be resolved" and then an error "Docusaurus found broken links!", because the scaffold sets onBrokenLinks: 'throw'. Setting that option to warn lets the build pass.

  • Placeholder metadata. The scaffold uses https://your-docusaurus-site.example.com as the site url and facebook/docusaurus as organization and project, and its editUrl values point at the Docusaurus repository. Replace them before publishing. The sitemap in the example above still contains the placeholder address.

  • Clear after upgrades. The documentation recommends npm run clear before reporting a bug, after upgrading versions, or whenever the site misbehaves. In this run it removed .docusaurus, the bundler cache in node_modules/.cache and build.

  • The package manager. The generated lockfile depends on the manager that created the site. The official tree shows a Yarn lockfile; here, with npm, it is package-lock.json.

  • Monorepos. When the documentation lives next to an existing project, run npx create-docusaurus in the monorepo root. On hosts such as Netlify or Vercel set the base directory to the folder that holds the site (for example website/). The official page describes this layout but this page did not build one.

  • Dropped and added versions. Node.js 18 was dropped in 3.9; the minimum is Node.js 20. React 19 is the generated default. Version 4 has not been released; the scaffold’s future.v4 flag is the preparation for it.