blog.dopana

Back

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:

  1. Package (Cargo.toml): The entire factory property, containing tools, supply receipts, and building blueprints.
  2. Crate (Root Library / Binary): A complete shipping container ready to deliver finished toys to customers or other factories.
  3. Module (mod): Individual department rooms inside the factory (e.g., Woodworking, Painting, Quality Control).
  4. 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#

LevelDefinitionFile Convention
PackageA Cargo bundle with a Cargo.toml file detailing how to build one or more crates.Root directory containing Cargo.toml
CrateA tree of modules that produces a library or an executable binary.src/main.rs (binary) or src/lib.rs (library)
ModuleOrganizes code scope and controls item privacy inside a crate.Inline mod name { ... } or src/name.rs / src/name/mod.rs
PathA 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#

[!NOTE] Making a module pub only allows parent modules to refer to it. Its internal functions and fields remain private until explicitly marked with pub.

Struct and Enum Privacy Differences#

Privacy works slightly differently between structs and enums:

  • Structs: Marking a struct pub makes the struct name public, but its fields remain private by default unless each field is marked pub.
  • Enums: Marking an enum pub automatically makes all of its variants public.

Bringing 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:

sequenceDiagram
    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:

src/lib.rs
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;
rust

Splitting 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.rs
text
src/lib.rs
// 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
src/front_of_house.rs
// Declares hosting submodule; Rust loads src/front_of_house/hosting.rs
pub mod hosting;
rust
src/front_of_house/hosting.rs
pub fn add_to_waitlist() {
    println!("Added party to waitlist!");
}
rust

Summary#

  • 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 pub to expose modules, functions, and struct fields.
  • Use use for concise local aliases and pub use for clean public API re-exports.

References#