Rust Module System: Packages, Crates and Modules
Master Rust module system: Packages, Crates, Modules, path privacy (pub), and use keyword for scalable project organization.
As your Rust projects grow beyond a single file, organizing code becomes essential. Rust provides a structured module system that balances encapsulation, privacy, and reusability.
Explain Like I’m 10: The Toy Factory & Departments#
Think of building a big toy factory:
- Package (
Cargo.toml): The entire factory property, containing tools, supply receipts, and building blueprints. - Crate (Root Library / Binary): A complete shipping container ready to deliver finished toys to customers or other factories.
- Module (
mod): Individual department rooms inside the factory (e.g., Woodworking, Painting, Quality Control). - Privacy (
pub): Locked doors (private) versus public reception counters (pub). By default, all doors in Rust are locked so outsiders cannot tamper with internal machinery.
graph TD
subgraph Package ["Package (Cargo.toml)"]
subgraph BinaryCrate ["Binary Crate (src/main.rs)"]
MainFn["main() entry point"]
end
subgraph LibraryCrate ["Library Crate (src/lib.rs)"]
RootMod["Crate Root (crate::)"]
RootMod --> ModFront["mod front_of_house"]
ModFront --> ModHosting["pub mod hosting"]
ModHosting --> FnAdd["pub fn add_to_waitlist()"]
RootMod --> ModBack["mod back_of_house"]
ModBack --> FnCook["fn fix_incorrect_order()"]
end
end
MainFn -->|use restaurant::front_of_house::hosting| FnAdd
The Hierarchy: Packages, Crates, and Modules#
| Level | Definition | File Convention |
|---|---|---|
| Package | A Cargo bundle with a Cargo.toml file detailing how to build one or more crates. | Root directory containing Cargo.toml |
| Crate | A tree of modules that produces a library or an executable binary. | src/main.rs (binary) or src/lib.rs (library) |
| Module | Organizes code scope and controls item privacy inside a crate. | Inline mod name { ... } or src/name.rs / src/name/mod.rs |
| Path | A way of naming an item (such as a struct, function, or module). | crate::front_of_house::hosting::add_to_waitlist() |
Modules and Privacy Rules#
In Rust, all items (functions, methods, structs, enums, modules) are private to parent modules by default.
graph LR
Parent["Parent Module"] -->|Can see everything inside| Child["Child Module"]
Child -->|Cannot see private siblings/parents unless pub| Sibling["Sibling Item"]
Child -->|Can always see parent items| Parent
Privacy Example: Restaurant Management#
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
fn seat_at_table() {} // private: only accessible inside hosting
}
mod serving {
fn take_order() {}
fn serve_order() {}
fn take_payment() {}
}
}
pub fn eat_at_restaurant() {
// Absolute path starting with crate root
crate::front_of_house::hosting::add_to_waitlist();
// Relative path starting from current module
front_of_house::hosting::add_to_waitlist();
}rust[!NOTE] Making a module
pubonly allows parent modules to refer to it. Its internal functions and fields remain private until explicitly marked withpub.
Struct and Enum Privacy Differences#
Privacy works slightly differently between structs and enums:
- Structs: Marking a struct
pubmakes the struct name public, but its fields remain private by default unless each field is markedpub. - Enums: Marking an enum
pubautomatically makes all of its variants public.
mod back_of_house {
pub struct Breakfast {
pub toast: String, // Public field: customer can choose toast type
seasonal_fruit: String, // Private field: chef decides based on season
}
impl Breakfast {
// Since seasonal_fruit is private, a public constructor is mandatory
pub fn summer(toast: &str) -> Breakfast {
Breakfast {
toast: String::from(toast),
seasonal_fruit: String::from("peaches"),
}
}
}
#[derive(Debug)]
pub enum Appetizer {
Soup, // Automatically public
Salad, // Automatically public
}
}rustBringing Paths into Scope with use#
Writing long paths over and over creates clutter. The use keyword brings paths into local scope like a symbolic link:
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
// Bring module into scope idiomatically for functions
use crate::front_of_house::hosting;
// Bring structs/enums directly into scope
use std::collections::HashMap;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
let mut map = HashMap::new();
map.insert("table_1", "occupied");
}rustsequenceDiagram
participant Code as Caller Code
participant Scope as Local Scope
participant CrateTree as Crate Module Tree
Note over Scope,CrateTree: use crate::front_of_house::hosting;
Scope->>CrateTree: Resolve path to hosting module
CrateTree-->>Scope: Return symbol reference for hosting
Code->>Scope: hosting::add_to_waitlist()
Scope->>CrateTree: Call front_of_house::hosting::add_to_waitlist()
Re-exporting with pub use#
When you bring an item into scope with use, it is private in the new scope. Using pub use makes it available for external callers, allowing you to design clean public APIs:
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
// Re-exporting: External users can call restaurant::hosting::add_to_waitlist() directly
pub use crate::front_of_house::hosting;rustSplitting Modules into Multiple Files#
For real-world projects, keep files small by breaking modules into the filesystem:
my_project/
├── Cargo.toml
└── src/
├── main.rs
├── lib.rs
└── front_of_house/
├── mod.rs (or front_of_house.rs)
└── hosting.rstext// Declares the front_of_house module; Rust loads src/front_of_house.rs
pub mod front_of_house;
pub use crate::front_of_house::hosting;rust// Declares hosting submodule; Rust loads src/front_of_house/hosting.rs
pub mod hosting;rustpub fn add_to_waitlist() {
println!("Added party to waitlist!");
}rustSummary#
- Packages bundle one or more crates defined in
Cargo.toml. - Crates are compilation units producing binary executables or shared libraries.
- Modules (
mod) organize code into hierarchical namespaces and control visibility. - Everything is private by default; use
pubto expose modules, functions, and struct fields. - Use
usefor concise local aliases andpub usefor clean public API re-exports.