Skip to content

Intermediate · Modules, crates, traits and generics · topic 27 of 50 · 30 min

Packages, crates and modules

Explanation

A crate is one compiled unit: a binary (a program with main) or a library. A package is a folder with Cargo.toml that holds one or more crates. Inside a crate, mod splits code into modules, pub makes items visible outside their module, and use brings names into scope. cargo add downloads libraries from crates.io.

Why organise code?

A 50-line program fits in main.rs. A 50,000-line program does not. You need to split code into parts with clear names, hide details that other parts should not touch, and reuse code written by others. Rust gives you three levels for this.

TermWhat it isExample
PackageA folder with a Cargo.toml; built by cargothe shop project
CrateOne unit the compiler builds: a binary or a librarysrc/main.rs (binary), src/lib.rs (library)
ModuleA named section inside a cratemod billing, mod inventory

A binary crate has a main function and becomes a program you can run. A library crate has no main; it provides code for other crates to use. A package can have one library and several binaries. The library's root file is src/lib.rs, and the binary's root is src/main.rs.

Modules and privacy

rust
mod billing {
    pub fn total_with_gst(amount: u32) -> u32 {
        amount + gst(amount)
    }

    fn gst(amount: u32) -> u32 {      // private: only usable inside billing
        amount * 18 / 100
    }
}

fn main() {
    println!("{}", billing::total_with_gst(1000));   // 1180
    // billing::gst(1000);   // error[E0603]: function `gst` is private
}
Everything is private by default. pub opens an item to code outside the module.

Privacy is a design tool. The billing module promises one public function; it can change how gst is calculated inside without breaking anyone. Struct fields are private by default too, even if the struct is pub; mark each field pub that outsiders may use.

Modules in separate files

output
src/
├── main.rs        // mod billing;  mod inventory;
├── billing.rs     // the contents of mod billing
└── inventory/
    ├── mod.rs     // (older style) or use inventory.rs next to the folder
    └── stock.rs   // mod stock; declared inside inventory
mod billing; (with a semicolon) tells the compiler to load the module from billing.rs.

Paths and use

A path names an item: crate::billing::total_with_gst starts at the crate root; super:: means the parent module; self:: the current one. use creates a shortcut so you do not repeat long paths.

rust
use std::collections::HashMap;
use crate::billing::total_with_gst;
use std::io::{self, Write};     // several items at once

fn report() {
    let mut m: HashMap<&str, u32> = HashMap::new();
    m.insert("bill", total_with_gst(500));
}
Common style: import the module or type, then call it, so readers see where things come from.

Using crates from crates.io

crates.io is the public registry of Rust libraries. To use one, add it to Cargo.toml, usually with cargo add, then build. cargo downloads it and its own dependencies.

bash
cargo add rand
cargo add serde --features derive
Adds the latest compatible version to [dependencies].
ini
[dependencies]
rand = "0.9"
serde = { version = "1", features = ["derive"] }
A version like "1" means "1.x.y, any compatible version", following semantic versioning (semver).

Semver means versions look like MAJOR.MINOR.PATCH. A MAJOR change may break your code; MINOR and PATCH should not. "1.2" in Cargo.toml means "at least 1.2.0 and below 2.0.0". Cargo.lock records the exact versions chosen so every build is the same; commit it for applications.

Tip: Before adding a crate, check its downloads, recent updates and documentation on crates.io and docs.rs. Fewer, well-known dependencies mean fewer surprises and a smaller attack surface.

Common mistakes

  • Forgetting pub: "function is private" (E0603). Add pub to the item, and to the module if it is nested.
  • Creating billing.rs but forgetting mod billing; in main.rs or lib.rs. Files are not modules until declared.
  • Making every field pub. Keep fields private and expose methods, so you can change the inside later.
  • Using a crate without adding it to Cargo.toml: "unresolved import". Run cargo add.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Packages, crates and modules · 1/7

Package ⊃ Crate ⊃ Module

As programs grow, you split them. Rust has three levels: packages, crates and modules.

Prefer a video by a teacher? Find free videos on “rust modules crates packages pub use explained” on YouTube ↗

In real life: Structuring a billing app

A small GST billing app for shops grows from one file into a package: src/lib.rs holds modules invoice, tax and customer; src/main.rs is a thin command-line front end; tests import the library. Later the same library is reused by a web front end in another binary, without copying any code.

rust
// src/lib.rs
pub mod tax {
    pub fn gst(amount: u64, rate_percent: u64) -> u64 {
        amount * rate_percent / 100
    }
}

// src/main.rs
use shop::tax;       // "shop" is the package name from Cargo.toml

fn main() {
    println!("GST: {}", tax::gst(2_000, 12));   // GST: 240
}
The binary uses the library crate by the package name.

Practice (0/3 done)

Task 1 · Question

Why does this fail? mod shop { fn open() {} } fn main() { shop::open(); }

Task 2 · Question

In Cargo.toml, serde = "1.0" allows which versions?

Task 3 · Practice

Turn a single-file project into modules: create src/lib.rs with pub mod marks (with pub fn average(&[u32]) -> f64 and a private helper) and pub mod report. Use them from src/main.rs. Then add the rand crate with cargo add and print a random roll number.

Quick quiz

Question 1

1.What is a crate?

Question 2

2.What is the default visibility of items in a module?

Question 3

3.What does super:: refer to in a path?

Question 4

4.Why commit Cargo.lock for an application?

Question 5

5.You wrote src/tax.rs but get "unresolved module". What is missing?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

What is a crate?

Answer: A unit the compiler builds: a binary or a library

Crates are Rust's compilation units.

What is the default visibility of items in a module?

Answer: Private

Items are private unless marked pub.

What does super:: refer to in a path?

Answer: The parent module

super is the parent of the current module.

Why commit Cargo.lock for an application?

Answer: It pins exact dependency versions so builds are repeatable

Cargo.lock records the exact versions used.

You wrote src/tax.rs but get "unresolved module". What is missing?

Answer: mod tax; in main.rs or lib.rs

A file becomes a module only when declared with mod.

What is Cargo.toml?Related

Answer: The project settings: name, version, edition and dependencies

Cargo.toml describes the project and lists the crates it depends on.

From Your first program and cargo

Why might a binary-only crate be hard to integration test?Related

Answer: Integration tests import a library crate; put the logic in lib.rs

Keep main.rs thin and put logic in the library.

From Integration tests and doc tests

Which file marks a folder as a Go module?Related

Answer: go.mod

go.mod holds the module path and Go version and marks the module root.

From Your first program and Go modules

What does cargo-audit check?Related

Answer: Dependencies against a database of known vulnerabilities

It uses the RustSec advisory database.

From Tooling: rustfmt, Clippy, docs and editions

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. 3 more topics in “Modules, crates, traits and generics” before its exam: Traits: shared behaviour, Generics and trait bounds, Trait objects and dynamic dispatch.
  2. Module 7 exam: Modules, crates, traits and generics · 13 questions · 25 min, without help. 4 topics of this module still to finish first.
  3. Then the next module, Closures, iterators and smart pointers. 50 topics left in the course before the final exam.

← Previous: HashMap and HashSet