How to Link to Other Items in Rust Docs with Intra-Doc Links

Link to other items in Rust docs using relative markdown paths or Rust item paths with the standard link syntax.

When URLs break your docs

You are writing documentation for a library. You mention HashMap and want to link to its docs. You paste a URL. Six months later, the documentation structure changes, or you rename the module, and your link is dead. Or you are writing a tutorial and want to link to a function in the same crate. Hardcoding URLs is fragile. The link breaks the moment the code moves.

Rust solves this with intra-doc links. You write a path relative to the code structure. rustdoc resolves that path at build time and generates a working HTML link. If you rename the item, the link updates automatically. If you delete the item, the build warns you. Your documentation stays in sync with your code without manual maintenance.

What intra-doc links actually do

Intra-doc links bind your documentation to the code itself. They are not static text. They are references that rustdoc validates against the crate's module tree. When you run cargo doc, the tool parses your doc comments, resolves every link, and checks two things:

  1. The target item exists.
  2. The target item is visible from the current scope.

If either check fails, rustdoc emits a warning. This turns documentation maintenance into a compile-time check. You catch broken links before users see them.

Think of intra-doc links like type-safe references. Just as the compiler prevents you from using a variable that doesn't exist, rustdoc prevents you from linking to an item that doesn't exist or isn't accessible.

Syntax and resolution

The syntax uses square brackets. You can provide display text and a path, or just a path.

/// Links to the [new] method and the [Foo] struct.
///
/// You can also use the shorthand form: [Bar].
struct Foo;

impl Foo {
    /// Creates a new instance.
    pub fn new() -> Self {
        Self
    }
}

struct Bar;

The first form [text][path] lets you control the anchor text. The second form [path] uses the path as the text. Both resolve the same way. rustdoc searches for the path starting from the current module, moving up through parent modules, and finally checking external crates.

Use the explicit form when the path is technical but the text should be readable. Use the shorthand when the path is already clear.

Path rules and conventions

Paths in intra-doc links are relative to the current module. This matches how imports work in Rust code. You can use super:: to go up one level, or crate:: to jump to the crate root.

mod utils {
    /// Helper function. See [super::main] for usage.
    pub fn helper() {}
}

/// The entry point. See [utils::helper] for details.
pub fn main() {}

Relative paths can become ambiguous in large crates. A link to foo might resolve to crate::foo or crate::sub::foo depending on the current scope. The community convention is to use crate:: for absolute paths within the crate. This removes ambiguity and makes the link robust against module reorganization.

/// Prefer absolute paths for clarity.
///
/// See [crate::utils::helper] for the implementation.
pub fn api() {}

Treat crate:: as the anchor. It tells readers and tools exactly where the item lives, regardless of where the doc comment appears.

Linking to methods, fields, and traits

You can link to specific members of a struct, enum, or trait using the # fragment syntax. The pattern is Item::member.

/// Configuration for the parser.
///
/// Set [Config::max_depth] to control recursion.
/// Call [Config::new] to create a default instance.
pub struct Config {
    /// The maximum recursion depth.
    pub max_depth: usize,
}

impl Config {
    /// Creates a default configuration.
    pub fn new() -> Self {
        Self { max_depth: 10 }
    }
}

This syntax works for methods, associated functions, fields, associated constants, and associated types. You can also link to trait methods.

/// A trait for serializable data.
///
/// Implement [Serializable::serialize] to provide encoding logic.
pub trait Serializable {
    fn serialize(&self) -> Vec<u8>;
}

If a type implements a trait, you can link to the trait method directly. rustdoc resolves Trait::method to the trait definition, not the implementation. This keeps links stable even if the implementation changes.

Visibility and cross-crate links

Intra-doc links respect visibility rules. You can only link to items that are visible from the current scope. Linking to a private item fails. Linking to a pub(crate) item from outside the crate fails.

mod private {
    /// This function is private.
    fn hidden() {}
}

/// This link fails because `hidden` is not visible.
///
/// See [private::hidden].
pub fn public() {}

rustdoc emits a warning for unresolved links. The warning text looks like warning: unresolved link to 'private::hidden'. Treat this warning as an error. Fix the link or adjust the visibility.

You can link to items in external crates, including std. The path must be resolvable from the current scope.

/// Returns a vector.
///
/// Uses [std::vec::Vec] for storage.
pub fn make_vec() -> Vec<i32> {
    Vec::new()
}

If std is in scope, you can use the shorter Vec path. rustdoc resolves it to std::vec::Vec. Cross-crate links are useful for explaining dependencies or standard library interactions.

Markdown files and fallback behavior

Intra-doc links primarily target Rust code items. However, rustdoc has a fallback behavior. If a path does not resolve to any code item, rustdoc treats it as a relative URL.

This allows you to link to markdown files, images, or other assets.

/// See the [README](../README.md) for installation instructions.
///
/// Check the [design doc](docs/design.md) for architecture details.
pub fn init() {}

The path is relative to the generated HTML file, not the source file. This can be tricky. rustdoc places HTML files in a directory structure that mirrors the module tree. A link to ../README.md works if the HTML file is one level deep.

Use this fallback sparingly. Prefer code links for code. Use relative markdown links only for non-code assets. If the path is ambiguous, use an absolute URL or a standard markdown link with a full path.

Pitfalls and compiler warnings

Intra-doc links are powerful, but they have gotchas.

Typos break links. If you mistype a path, rustdoc warns. The warning includes the unresolved path. Fix the typo. Do not ignore the warning.

Visibility traps. You might link to an item that exists but is not visible. This happens when you move code between modules or change pub modifiers. The link breaks even though the item exists. Check the visibility scope.

Path ambiguity. Relative paths can resolve differently depending on the module. A link to foo might work in one module and fail in another. Use crate:: to avoid this.

Generic parameters. You cannot link to generic parameters directly. [T] does not resolve. Link to the item that uses the parameter instead.

Private fields in public structs. You can link to a struct, but you cannot link to its private fields from outside the module. The link fails. Document private fields internally, or expose them through public methods.

Treat every rustdoc warning as a signal. The tool is checking your documentation for you. Fix the issue to keep your docs reliable.

Decision matrix

Use intra-doc links when you need to reference Rust code items. The link updates automatically when the code changes. Use intra-doc links for structs, functions, traits, methods, fields, and modules. Use the crate:: prefix for absolute paths to ensure stability.

Use standard markdown links when you need to reference external URLs. Intra-doc links cannot point to arbitrary web addresses. Use [text](https://example.com) for external resources.

Use relative markdown links when you need to reference non-code files. Intra-doc links fall back to relative URLs, but the path resolution can be confusing. Use [text](path/to/file.md) for assets, images, or markdown chapters.

Use # fragments when you need to link to specific members. Link to Struct::method or Struct::field to guide readers to the exact detail. Do not link to the parent item if the member is the focus.

Where to go next