Modules in Rust are like folders in a project. They help you organize related code, such as functions, structs, enums, and constants, together in one place.
Modules also act as namespaces, which means they prevent naming conflicts between items with the same name in different parts of your program.
In short, Rust modules help structure your code and control access to its parts safely.
Benefits of Using Modules In Rust
- Organization: Modules help you split a big program into smaller, logical parts, making the code easier to manage.
- Reusability: You can write code once in a module and use it in different parts of your program without rewriting it.
- Encapsulation: Modules allow us to control which parts of the code are visible outside the module (public) and which stay private, protecting your data and logic.
- Clarity: Well-structured modules make the code cleaner, easier to read, and easier to maintain over time.
How To Create Modules in Rust
We can create a module using the mod keyword followed by the module name. The module’s contents are defined within curly braces { } or in separate files.
Example: Basic Module
mod math {
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
pub fn subtract(a: i32, b: i32) -> i32 {
a - b
}
}
fn main() {
let sum = math::add(5, 3);
let difference = math::subtract(5, 3);
println!("Sum: {}", sum);
println!("Difference: {}", difference);
}
Output:
Sum: 8 // 5 + 3
Difference: 2 // 5 - 3
Module Visibility
In Rust, everything inside a module is private by default. That means functions, structs, or constants cannot be accessed from outside the module.
The pub keyword is used to make functions, structs, or other items accessible from outside the module.
Example: Public and Private Functions
mod tools {
pub fn greet() {
println!("Hello from the public greet function!");
}
fn secret_tool() {
println!("This is a private tool, only visible inside the module.");
}
}
fn main() {
tools::greet(); // Works fine
// tools::secret_tool(); // Error: private function, cannot access
}
Output:
Hello from the public greet function!
Explanation of this code:
- greet() is pub, so it can be accessed in main.
- secret_tool() is private, so trying to call it outside the tools will give an error.
Organizing Modules into Files and Directories
Instead of putting all code in the main.rs file, Rust allow us to split our code into multiple files. Each file can become a module because separating code by functionality makes large programs easier to manage.
Example of Directory-Based Module

For example: File-Based Module
- main.rs
mod operations; // Import the file as a module
fn main() {
let sum = operations::add(10, 15);
let difference = operations::subtract(20, 5);
println!("Sum: {}", sum);
println!("Difference: {}", difference);
}
- operations.rs
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
pub fn subtract(a: i32, b: i32) -> i32 {
a - b
}
Output:
Sum: 25
Difference: 15
Using use Keyword for Importing Modules
The use keyword allows us to bring a module function, struct, or constant directly into scope. After that, we don’t need the full path every time.
Example: Using use
mod utilities {
pub fn greet(name: &str) {
println!("Hello, {}!", name);
}
pub fn farewell(name: &str) {
println!("Goodbye, {}!", name);
}
}
// Bring specific functions into scope
use utilities::greet;
fn main() {
greet("Alice"); // No need to write utilities::greet
// farewell("Alice"); // This would need utilities::farewell
}
Output:
Hello, Alice!
- In this code, we can call the greet() function directly without the module prefix.
- The farewell function is not imported, so you would need to use utilities::farewell() to call it.
How To Use Nested Modules In Rust?
Nested modules allow us to organize code hierarchically, like folders within folders. To access items in inner modules, we write the full path: outer::inner::item().
Example: Nested Modules
mod company {
pub mod employees {
pub fn hire_employee(name: &str) {
println!("Hiring employee: {}", name);
}
pub fn fire_employee(name: &str) {
println!("Firing employee: {}", name);
}
}
pub mod departments {
pub fn list_department(name: &str) {
println!("Department: {}", name);
}
}
}
fn main() {
company::employees::hire_employee("Alice");
company::employees::fire_employee("Bob");
company::departments::list_department("Engineering");
}
Output:

In this code:
- The company is the outer module.
- employees and departments are nested modules inside the company.
Re-exporting with pub use
Re-exporting allows you to bring items from inner modules to a higher-level module, so users don’t have to write the full path every time.
Example: Re-exporting
mod zoo {
pub mod animals {
pub fn lion_sound() {
println!("Lion says: Roar!");
}
pub fn elephant_sound() {
println!("Elephant says: Trumpet!");
}
}
// Re-exporting functions to the top-level zoo module
pub use animals::lion_sound;
pub use animals::elephant_sound;
}
fn main() {
// No need to access zoo::animals::lion_sound
zoo::lion_sound();
zoo::elephant_sound();
}
Output:

Exercise: Build a Mini Calculator Using Modules
Create a Rust program that organizes different arithmetic operations into modules and allows simplified access using re-exporting.
Steps:
- Create a module called calculator.
- Inside the calculator, create two nested modules: basic and advanced.
- The basic module should have:
- add(a, b)
- subtract(a, b)
- The advanced module should have:
- multiply(a, b)
- divide(a, b)
- The basic module should have:
- Use pub use to re-export all functions at the top level of calculator so they can be accessed easily.
- In main, call all four functions and print the results.
Expected Output Example
Add: 10
Subtract: 4
Multiply: 21
Divide: 3