Rust Modules
Every example so far has lived in one main.rs file. That’s fine for small programs, but real projects split code into logical pieces. Rust’s tool for that is the module system — mod, pub, and use.
Defining a module
Section titled “Defining a module”A module is a named block that groups related code together:
mod math { pub fn add(a: i32, b: i32) -> i32 { a + b }}
fn main() { let sum = math::add(2, 3); println!("{sum}");}Output:
5Two things to notice: the function is called with math::add(...), using the module name as a path. And it’s marked pub — without that, it wouldn’t be reachable from outside the module.
Everything is private by default
Section titled “Everything is private by default”This is worth calling out because it surprises people: unlike most things in Rust, module contents are private by default. If you remove pub from the example above, it won’t compile:
mod math { fn add(a: i32, b: i32) -> i32 { // no `pub` a + b }}
fn main() { let sum = math::add(2, 3); // ❌ error: function `add` is private println!("{sum}");}You have to explicitly mark anything you want callers outside the module to use with pub. This is intentional — it lets a module hide its internal helper functions and only expose the parts meant to be a public API.
Nested modules
Section titled “Nested modules”Modules can contain other modules, which is how larger projects build up a tree-like structure:
mod shapes { pub mod circle { pub fn area(radius: f64) -> f64 { 3.14159 * radius * radius } }}
fn main() { let area = shapes::circle::area(2.0); println!("{area}");}use — shortening long paths
Section titled “use — shortening long paths”Writing shapes::circle::area(...) every time gets tedious. use brings a path into scope so you can refer to it directly:
mod shapes { pub mod circle { pub fn area(radius: f64) -> f64 { 3.14159 * radius * radius } }}
use shapes::circle;
fn main() { let area = circle::area(2.0); // shorter than shapes::circle::area println!("{area}");}You’ve actually already used use — it’s the same keyword from the HashMap page (use std::collections::HashMap;).
Splitting modules across files
Section titled “Splitting modules across files”The examples above put everything in one file, which the Rust Playground requires. In a real project on your own machine, each module usually gets its own file. If you had a project with a math module, it would typically look like this:
src/├── main.rs└── math.rsmod math; // tells Rust: look for this module's code in math.rs
fn main() { let sum = math::add(2, 3); println!("{sum}");}pub fn add(a: i32, b: i32) -> i32 { a + b}mod math; (with a semicolon, no body) tells Rust to load the module’s contents from math.rs in the same directory. This is the pattern you’ll use as soon as a project grows beyond a single file.
Practice
Section titled “Practice”1. A temperature module
Section titled “1. A temperature module”Make a module called convert with two public functions: c_to_f (Celsius to Fahrenheit) and f_to_c (the other way). From main, print 100°C is 212°F and 212°F is 100°C.
Hint: the formulas are c * 9.0 / 5.0 + 32.0 and (f - 32.0) * 5.0 / 9.0. Don’t forget pub, and call the functions with the module name, like convert::c_to_f(100.0).
Show solution
mod convert { pub fn c_to_f(c: f64) -> f64 { c * 9.0 / 5.0 + 32.0 }
pub fn f_to_c(f: f64) -> f64 { (f - 32.0) * 5.0 / 9.0 }}
fn main() { println!("100°C is {}°F", convert::c_to_f(100.0)); println!("212°F is {}°C", convert::f_to_c(212.0));}Output:
100°C is 212°F212°F is 100°CBoth functions are pub, so main (which lives outside the module) can call them. Remove one pub and the compiler tells you that function is private.
2. A private helper
Section titled “2. A private helper”Make a nested module school::grades with a public function letter(score: u32) -> char that returns 'A' for 90 and up, 'B' for 80 and up, and 'C' otherwise. Inside grades, also write a private helper is_at_least(score: u32, min: u32) -> bool that letter uses. Bring school::grades into scope with use, then print the letter for 95, 85 and 70.
Hint: both school’s inner mod grades and fn letter need pub, but is_at_least should not have it. Code inside the same module can always call private functions.
Show solution
mod school { pub mod grades { pub fn letter(score: u32) -> char { if is_at_least(score, 90) { 'A' } else if is_at_least(score, 80) { 'B' } else { 'C' } }
// private: only code inside `grades` can call this fn is_at_least(score: u32, min: u32) -> bool { score >= min } }}
use school::grades;
fn main() { for score in [95, 85, 70] { println!("{score} -> {}", grades::letter(score)); }}Output:
95 -> A85 -> B70 -> Cletter can call is_at_least because they live in the same module. From main, grades::is_at_least(95, 90) would fail with “function is_at_least is private”. That’s the point: the module shows a small public API and keeps its helpers to itself.
mod name { ... }groups related code into a named module.- Everything inside a module is private by default — add
pubto expose it outside the module. usebrings a path into scope so you don’t have to write it out in full every time.- In a multi-file project,
mod name;(no body) loads that module’s code from a matching file. - Code inside a module can always use that module’s private items, so keep helpers private and expose only what callers need.
Quick check
Section titled “Quick check”Quick check
1. By default, are items inside a mod public or private?
2. How do you tell Rust to load a module's code from math.rs instead of writing it inline?
Score: 0 / 2
Read more
Section titled “Read more”- Managing Growing Projects with Packages, Crates, and Modules — The Rust Book: the official chapter on packages, crates and modules, and how they fit together.
- Defining Modules to Control Scope and Privacy — The Rust Book: a worked example of a module tree, with a handy cheat sheet of the rules.
- Separating Modules into Different Files — The Rust Book: the multi-file layout in more detail, including folders for nested modules.
- Modules — Rust by Example: runnable examples of visibility,
use,superandself. - Visibility and privacy — The Rust Reference: the precise rules, including
pub(crate)for “public inside my crate only”.