How to use build scripts

Use mdbook commands to build, test, and serve the Rust book documentation locally or in CI.

When standard cargo commands fall short

You clone the official Rust book repository, run cargo test out of habit, and watch it fail. The repository is not a standard crate. It is a documentation project powered by mdbook. The README hands you three commands: mdbook build, mdbook test, and mdbook serve. They look simple, but they hide a specific workflow that bridges markdown files, Rust code examples, and a static site generator.

How mdbook actually works

mdbook is a command-line tool that turns a directory of markdown files into a complete, navigable website. Standard cargo doc generates API reference documentation from code comments. mdbook does the opposite. It starts with prose and weaves code examples into it. Think of cargo doc as a dictionary generated from your source files. mdbook is a textbook authoring system. It handles table of contents generation, syntax highlighting, search indexing, and responsive layouts out of the box.

The tool reads a book.toml configuration file at the root of your project. That file maps your markdown chapters, sets the title, and points to custom CSS or JavaScript. When you run a build command, mdbook parses the markdown, extracts fenced code blocks, runs them through rustdoc for testing if configured, and stitches everything into static HTML files.

# book.toml
[book]
# Authors appear in the HTML metadata and sidebar
authors = ["You"]
language = "en"
multilingual = false
# Points to the directory containing SUMMARY.md and chapters
src = "src"
title = "My First Book"

[output.html]
# Enables the built-in search index for the generated site
git-repository-url = "https://github.com/example/book"

Run mdbook init to generate this skeleton automatically. The command creates the directory structure, writes a default book.toml, and gives you a working SUMMARY.md. Once the skeleton exists, mdbook build compiles the markdown into a book/ directory. mdbook serve starts a local HTTP server that watches for file changes and reloads the page automatically.

Building and testing locally

When you execute mdbook build, the tool walks through SUMMARY.md and processes each linked file. It extracts code blocks marked with rust and passes them to rustdoc for syntax checking. If a block contains compile_fail, mdbook expects the compiler to reject it. If it contains ignore, the tool skips compilation entirely. This keeps your documentation examples verified without cluttering your test suite.

// Example of how mdbook handles code block attributes
// The tool runs this block normally and expects success
fn basic_example() {
    println!("Hello from the book");
}

// This block is marked to fail compilation
// mdbook verifies the error matches expectations
fn compile_fail_example() {
    let x: i32 = "not a number";
}

// This block is skipped during testing
// Useful for examples that require external dependencies
fn ignored_example() {
    println!("Skipped during mdbook test");
}

The output lands in book/html/. Every markdown file becomes an HTML page. Cross-links between chapters resolve automatically. The tool injects a search index, a sidebar, and a theme stylesheet. You can override the default theme by placing a theme/ directory next to src/. Drop a css/ folder inside it, and mdbook appends your styles after the defaults.

Treat your markdown as the source of truth. Let the compiler verify the examples. Do not manually update HTML files.

The trpl crate and library paths

The official Rust book uses a more complex setup. It contains a separate crate called trpl (The Rust Programming Language) that holds helper functions for code examples. The book's markdown files reference these helpers with extern crate trpl;. Standard rustdoc does not know where to find that crate during documentation builds. You have to point it to the compiled dependencies.

# Build the helper crate first to generate .rlib files
cargo build -p trpl

# Run the book tests with the dependency path
# The flag tells rustdoc where to find external crates
mdbook test --library-path packages/trpl/target/debug/deps

The --library-path flag tells rustdoc where to look for compiled .rlib files. Without it, every example that imports trpl fails with a missing crate error. The same flag applies when you run mdbook build if you want the compiler to verify those examples during the site generation.

For continuous integration, you automate this exact sequence. GitHub Actions needs to install mdbook, build the helper crate, and run the tests.

# .github/workflows/main.yml
name: Book CI
on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install mdbook
        # Downloads a precompiled binary to skip compilation time
        run: |
          curl -sSL https://github.com/rust-lang/mdBook/releases/download/v0.4.40/mdbook-v0.4.40-x86_64-unknown-linux-gnu.tar.gz | tar -xzf -
          sudo mv mdbook /usr/local/bin/
      - name: Build helper crate
        # Compiles trpl so the .rlib files exist for the next step
        run: cargo build -p trpl
      - name: Test book examples
        # Points rustdoc to the compiled dependencies
        run: mdbook test --library-path packages/trpl/target/debug/deps

The workflow downloads a precompiled binary of mdbook to avoid compiling it from source. It builds trpl in debug mode, then runs the book tests pointing to the dependency directory. This keeps CI fast and deterministic.

Keep the library path explicit. Hardcoding relative paths breaks when runners change directory structures.

Common traps and how to avoid them

Missing the --library-path flag is the most common stumbling block. The compiler error reads error[E0463]: can't find crate for 'trpl'. The fix is always the same. Build the helper crate first, then pass the path to its deps folder.

Another trap is caching. mdbook caches search indexes and compiled assets in a .mdbook/ directory. If you change SUMMARY.md or add new chapters, the cache might serve stale links. Run mdbook clean to wipe it. The command deletes the output directory and the cache, forcing a full rebuild.

Theme overrides can also break unexpectedly. mdbook uses a specific CSS variable naming convention. If you override a variable with the wrong prefix, the default theme silently ignores it. Check the official theme source code to match the exact variable names.

Cross-compilation quirks appear when you run mdbook test on a machine with a different architecture than the target. The rustdoc binary runs examples natively. If your CI runner is ARM but your examples assume x86, the tests fail. Pin your runner architecture to match your development environment, or use mdbook test only for syntax verification and run full integration tests separately.

Treat mdbook clean as your reset button. When the site looks wrong, wipe the cache before rewriting your markdown.

Choosing the right documentation tool

Use mdbook when you are writing a tutorial, a reference guide, or any prose-heavy documentation that needs a navigable website. Use cargo doc when you need API reference documentation generated directly from code comments and doc tests. Use a static site generator like Hugo or Jekyll when your documentation requires complex templating, blog functionality, or multi-language routing that mdbook does not support. Reach for mdbook plugins when you need custom preprocessors, like generating diagrams from mermaid syntax or extracting code from external files.

The community treats mdbook as the standard for Rust learning materials. The official language book, the Rust by Example repository, and most RFCs use it. Keep your SUMMARY.md as the single source of truth for navigation. Do not hardcode links between chapters. Let mdbook resolve them through relative paths. It saves hours of broken links when you restructure the table of contents.

Verify every code block. Point the library path correctly. Let the tool handle the HTML.

Where to go next