# cargo-modules: Rust Crate Structure Visualization and Orphan Detection

> cargo-modules is a Cargo plugin that visualizes a Rust crate's module hierarchy as a tree, its internal dependencies as a Graphviz dot graph, and detects unlinked source files, helping developers understand and audit large codebases without reading every source file manually.

**regexident/cargo-modules** — Visualize/analyze a Rust crate's internal structure

- Repository: https://github.com/regexident/cargo-modules
- Stars: 1,269 · Forks: 60
- Language: Rust
- License: MPL-2.0
- Published: 2026-09-10 · Updated: 2026-09-10 · Language: en
- Canonical page: https://hysenlabs.com/projects/regexident-cargo-modules

## Understanding Crate Structure at a Glance

As a Rust codebase grows, the module hierarchy becomes harder to hold in memory. Modules can be nested multiple levels deep, each with its own visibility rules, and the relationship between a module's pub interface and its internal structure is not obvious from reading source files one at a time. Finding orphaned files that were never included in the module tree requires checking each file against the mod declarations manually.

cargo-modules addresses this by reading a Rust crate through rust-analyzer's internal APIs and producing three outputs: a text tree of the module hierarchy with visibility annotations, a Graphviz dot graph of internal dependencies, and a report of source files that exist in the crate's directory but are not connected to the module tree. The tool is implemented as a Cargo subcommand, so it integrates directly into the standard Rust toolchain workflow.

## Three Commands and What Each Produces

The tool exposes three subcommands. The structure command prints the crate's module hierarchy as an indented tree. Each node shows its visibility level, the keyword (mod, fn, trait, enum, etc.), and any test attributes. Running the command with --cfg-test includes test modules and test functions in the output:

```bash
cargo modules structure --cfg-test
```

The dependencies command generates a Graphviz dot representation of internal module dependencies. Flags filter which node types to include in the graph. To produce a graph showing only module-level dependencies without functions, types, traits, or external crates:

```bash
cargo modules dependencies --no-externs --no-fns --no-sysroot --no-traits --no-types --no-uses > mods.dot
```

The orphans command detects source files within the crate's directory that are not reachable through the module tree:

```bash
cargo modules orphans
```

The README notes that the --dependencies command is equivalent to cargo-modules generate graph from version 0.12.0 or earlier, which matters when following older documentation.

## Installing and Running cargo-modules

cargo-modules installs through the standard Cargo package manager:

```bash
cargo install cargo-modules
```

Once installed, the subcommand runs inside any Rust project directory. The README includes a walkthrough using the bundled test project:

```bash
cd ./tests/projects/readme_tree_example
cargo-modules structure --cfg-test
```

The output of the structure command on that example project shows the tree indented with box-drawing characters, with each node labeled by visibility, keyword, name, and test attributes. The --lib and --bin flags restrict processing to a specific target when a workspace contains multiple crates.

The Cargo.toml sets the minimum supported Rust version at 1.95.0. The dependencies include petgraph for graph operations, clap for argument parsing, and the ra_ap_ family of crates from rust-analyzer, all pinned to version 0.0.345. The tight rust-analyzer pinning means cargo-modules may require a specific toolchain version.

## Visibility Color Coding in Terminal and Graph Output

When running in a terminal with color support and without NO_COLOR defined, the structure command colors each node's visibility label. Green marks items visible to all (pub). Yellow marks items visible to the current crate (pub(crate)). Orange marks items visible to a specific parent module (pub(in path)). Red marks items visible only to the current module (pub(self), or items with no pub modifier). The keyword is highlighted in blue, and test-guarded items display their cfg(test) or #[test] attributes in gray and cyan.

The dependencies graph uses the same color scheme for nodes, with blue added for crate roots. This lets a developer scan the graph and immediately see which modules have a narrow visibility scope versus which ones are fully public, without reading individual visibility declarations in the source.

## Cycle Detection and Where the Tool Is Not Enough

The dependencies command accepts a --acyclic flag. When this flag is set, cargo-modules searches for cycles in the dependency graph and returns an error if any are found. This makes the command suitable as a CI gate to prevent circular module dependencies from entering the codebase.

The tool operates on the crate's static structure as understood by rust-analyzer, not on runtime behavior. It cannot detect which code paths are exercised at runtime, which modules are performance-critical, or how external dependencies interact with internal module boundaries. For dependency analysis across crate boundaries, cargo-depgraph is the relevant alternative: it produces a graph of crate-level Cargo dependencies rather than intra-crate module dependencies.

cargo-modules is specifically useful for auditing internal module architecture. Teams doing a refactor that changes module boundaries will find the structure and dependencies outputs useful for understanding the before-state and checking the after-state. Teams looking for unused external dependencies should use cargo-machete or cargo-udeps instead.

## License, Rust-Analyzer Dependency, and Maintenance

cargo-modules is licensed under the Mozilla Public License 2.0 (MPL-2.0), a file-level copyleft license. Modifications to cargo-modules source files must be shared back, but it can be used alongside files under other licenses in the same project. This is more permissive than LGPL and less permissive than MIT for the specific files covered.

The tool's dependency on the ra_ap_ crates from rust-analyzer is pinned tightly: all nine ra_ap_ dependencies are pinned to exactly version 0.0.345. rust-analyzer does not maintain API stability across minor versions, and the tight pinning prevents silent breakage but also means upgrades require explicit version bumping. The current version in Cargo.toml is 0.27.0. The last push to the repository was on 2026-09-24. The repository does not have formal GitHub releases.

The Cargo.toml also sets a minimum supported Rust version (MSRV) of 1.95.0 and declares a 2024 edition. The dev-opt profile sets opt-level=2 with debug enabled, and several ra_ap_ crates inherit this profile, which means debug builds of cargo-modules compile the rust-analyzer dependencies with moderate optimization to keep analysis performance reasonable during development. For contributors running cargo test, the test suite uses assert_cmd for integration-style tests that run the compiled binary against the projects in tests/projects/, and insta for snapshot testing of the output.

## Conclusion

cargo-modules is the right tool for Rust developers who need to understand the module layout of a large or unfamiliar crate, audit visibility boundaries before a refactor, or detect orphaned source files that the compiler never processes. The --acyclic flag on the dependencies command makes it useful in CI as a guard against circular module dependencies. Teams that need visual dependency diagrams for external documentation should pipe the dot output through Graphviz. MPL-2.0 is a file-level copyleft license, which permits use in projects with different licenses as long as modifications to cargo-modules files themselves are shared back.

## FAQ

### What is the difference between cargo-modules structure and cargo-modules dependencies?

The structure command prints the crate's module hierarchy as an indented text tree with visibility labels. The dependencies command generates a Graphviz dot graph showing which modules depend on which others, suitable for piping through dot to produce a visual diagram.

### Can cargo-modules detect circular module dependencies?

Yes. The dependencies command accepts a --acyclic flag that searches for cycles in the module dependency graph and returns an error if any are found, making it suitable for use as a CI check.

### Does cargo-modules work with Cargo workspaces that contain multiple crates?

Yes. The --package flag selects a specific crate by package ID, and --lib or --bin flags restrict processing to a library or named binary target within that crate.

## Sources

- [Issues](https://github.com/regexident/cargo-modules/issues)
- [License: MPL-2.0](https://github.com/regexident/cargo-modules/blob/main/LICENSE)
- [README](https://github.com/regexident/cargo-modules/blob/main/README.md)
- [regexident/cargo-modules on GitHub](https://github.com/regexident/cargo-modules)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/regexident-cargo-modules
