Module Files
When a module grows beyond a few dozen lines, keeping it inline inside src/main.rs or src/lib.rs makes the root file long and harder to navigate. Rust lets you move any module into its own module file by replacing its inline block mod name { ... } with a semicolon declaration mod name; and placing the module's contents in a matching .rs file on disk.
How mod name; Maps to Files on Disk
When rustc encounters mod network; inside the crate root (src/main.rs or src/lib.rs), it searches for the module's source code in two standard locations relative to src/:
| Style | File Path for mod network; |
File Path for Nested mod client; (Inside network) |
Status |
|---|---|---|---|
| Modern Style (Rust 2018–2024) | src/network.rs |
src/network/client.rs |
Recommended (every file has a descriptive name in editor tabs) |
Older mod.rs Style (Rust 2015) |
src/network/mod.rs |
src/network/client.rs |
Supported, but cannot coexist with src/network.rs for the same module |
Recommended Modern File Layout (`src/`):
src/
├── main.rs (Contains `mod config;` and `mod network;`)
├── config.rs (Contents of module `crate::config`)
├── network.rs (Contents of module `crate::network`; contains `pub mod client;`)
└── network/
└── client.rs (Contents of submodule `crate::network::client`)
Important: Inside
src/config.rs, you do not wrap the file's contents inmod config { ... }! The filesrc/config.rsis already the body ofmod config(wrapping its contents in anothermod config { ... }would create a nestedcrate::config::configmodule!).
Complete Multi-File Example
Suppose a project has three files inside src/:
src/math.rs(definescrate::mathand declares submodulepub mod stats;):
// src/math.rs
pub mod stats; // Tells `rustc` to load `src/math/stats.rs`
pub fn square(x: i64) -> i64 {
x * x
}
src/math/stats.rs(definescrate::math::stats):
// src/math/stats.rs
pub fn sum_of_squares(values: &[i64]) -> i64 {
// Call `square` from the parent module `math` using `super::`:
values.iter().map(|&v| super::square(v)).sum()
}
src/main.rs(attachesmod math;to the crate tree and calls both modules):
// src/main.rs
mod math; // Attaches `src/math.rs` to the crate!
fn main() {
let data = [2, 3, 4];
println!("square(5) = {}", math::square(5));
println!("sum_of_squares = {}", math::stats::sum_of_squares(&data));
}
square(5) = 25
sum_of_squares = 29
Crucial Rule: Declare mod name; Exactly Once in the Crate Tree
Unlike #include "math.h" in C or import in Python:
mod math;is a module declaration that compilessrc/math.rsinto the crate. It should appear only once in your entire crate (in the parent module wheremathbelongs, typicallysrc/lib.rsorsrc/main.rs).- Other sibling files do NOT write
mod math;to usemath! Instead, sibling files refer tocrate::math::square(or writeuse crate::math::square;).
src/main.rs: `mod math;` + `mod report;` (Attaches both files to `crate`)
src/report.rs: `use crate::math::square;` (Imports from sibling module `crate::math`)
Common Compiler Errors with Module Files
1. Missing Module File (E0583)
If you write mod missing_module; in src/main.rs when neither src/missing_module.rs nor src/missing_module/mod.rs exists on disk, rustc reports E0583 and shows the exact paths it checked:
// ❌ does not compile (when `src/missing_module.rs` does not exist)
mod missing_module;
fn main() {}
error[E0583]: file not found for module `missing_module`
--> src/main.rs:1:1
|
1 | mod missing_module;
| ^^^^^^^^^^^^^^^^^^^
|
= help: to create the module `missing_module`, create file "src/missing_module.rs" or "src/missing_module/mod.rs"
error: aborting due to 1 previous error
2. Both name.rs and name/mod.rs Present (E0761)
Having both src/network.rs and src/network/mod.rs in the same directory makes it ambiguous which file defines mod network:
error[E0761]: file for module `network` found at both "src/network.rs" and "src/network/mod.rs"
--> src/main.rs:1:1
|
1 | mod network;
| ^^^^^^^^^^^^
|
= help: delete or rename one of them to remove the ambiguity