Skip to main content
Rust Programming
CHAPTER 16 Beginner

Modules and Packages

Updated: May 18, 2026
5 min read

# CHAPTER 16

Modules and Packages

1. Chapter Introduction

Up until now, all our code has been written inside a single file: src/main.rs. In real-world projects, your code will be split across dozens of files and folders (e.g., authentication, database, routing). Rust has a unique and strict module system to manage code organization and visibility. In this chapter, we will learn how to split code into multiple files, use the pub keyword, and install third-party libraries (Crates) using Cargo.

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Understand the difference between a Package, Crate, and Module.
  • Create inline modules.
  • Split code into multiple files and folders.
  • Use the pub keyword to manage privacy (Encapsulation).
  • Install and use third-party crates from crates.io.

3. Packages, Crates, and Modules

Rust has specific terminology for organization:
  1. 1. Package: What you create when you type cargo new. It contains a Cargo.toml file.
  1. 2. Crate: A tree of modules that produces an executable binary or a library. (e.g., main.rs is the "crate root" for a binary crate).
  1. 3. Module: A way to organize code within a Crate into named, nested blocks.

4. Creating Inline Modules and Privacy

By default, everything in Rust (functions, structs, fields) is Private. If you create a module, code outside that module cannot see inside it unless you use the pub (public) keyword.
rust
123456789101112131415161718192021
// Define a module named 'network'
mod network {
    // This is private!
    fn connect_internal() {
        println!("Connecting internally...");
    }

    // This is public!
    pub fn connect() {
        println!("Connecting to the internet...");
        // A public function can call a private function in the same module
        connect_internal(); 
    }
}

fn main() {
    // Call the function using the path
    network::connect();

    // network::connect_internal(); // ERROR: Function is private!
}

5. Splitting Code into Multiple Files

Inline modules get messy. Let's move the network code into its own file!

1. Update src/main.rs: Tell Rust to look for a file or folder named network.

rust
123456
// This tells Rust: "Look for a file named network.rs or a folder named network/mod.rs"
mod network; 

fn main() {
    network::connect();
}

2. Create a new file src/network.rs:

rust
123456
// Notice we DO NOT use 'mod network {}' in this file! 
// The file itself IS the module.

pub fn connect() {
    println!("Connecting from a separate file!");
}

6. The use Keyword

Typing long paths like std::collections::HashMap every time is tedious. The use keyword brings a path into the current scope, so you can call it directly.
rust
12345
use std::collections::HashMap;

fn main() {
    let mut map = HashMap::new(); // Much shorter!
}

7. Third-Party Crates (Cargo.toml)

Rust's standard library is intentionally kept small. For things like Random Number Generation or Web Servers, you download Crates from the official registry: crates.io.

To use an external crate, you add it to your Cargo.toml file under [dependencies]. You can do this manually, or by using the terminal:

bash
12
# Downloads the random number generator crate and adds it to Cargo.toml
cargo add rand

Now, you can use it in your code!

rust
1234567
use rand::Rng; // Bring the Rng trait into scope

fn main() {
    // Generate a random number between 1 and 100
    let secret_number = rand::thread_rng().gen_range(1..=100);
    println!("Random number: {}", secret_number);
}

8. Common Mistakes

  • Forgetting pub on Struct Fields: If you make a struct public (pub struct User), its *fields* are still private by default! You must explicitly mark the fields you want to expose: pub email: String.
  • Using mod in the wrong place: Beginners often put mod network; inside network.rs. You only declare mod in the parent file (usually main.rs or lib.rs) to build the module tree.

9. Best Practices

  • Organize by Domain: Group your files by feature (e.g., mod auth;, mod database;).
  • Use absolute paths for clarity: When bringing things into scope, prefer absolute paths starting with crate:: (e.g., use crate::network::connect;).

10. Exercises

  1. 1. Create a new Cargo project.
  1. 2. Create a new file math.rs containing a pub fn add(a: i32, b: i32) -> i32.
  1. 3. In main.rs, declare mod math; and call the add function. Print the result.

11. MCQs with Answers

Question 1

What is the default visibility of functions and structs in Rust?

Question 2

Which keyword exposes a function or struct to code outside its module?

Question 3

If src/main.rs contains mod utils;, what file is the Rust compiler looking for?

Q4. Do you need to wrap the contents of utils.rs in mod utils {}? a) Yes b) No, the file itself inherently acts as the module body. Answer: b) No.
Question 5

What keyword is used to bring a module path into the current scope to avoid typing long names?

Question 6

What is the central registry for open-source Rust libraries?

Question 7

In which file do you list the third-party crates your project depends on?

Question 8

What terminal command automatically downloads and adds a dependency to your Cargo.toml?

Q9. If you declare pub struct User { name: String }, can another module access the name field? a) Yes b) No, because the fields inside the struct are still private by default. You must declare it as pub name: String. Answer: b) No, fields are private by default.
Question 10

What is a "Crate" in Rust?

12. Interview Questions

  • Q: Explain Rust's module system and how the mod keyword differs from the import or require keywords in other languages. (Answer: mod builds the module tree and tells the compiler what files to include; use merely creates a shortcut path).
  • Q: How does Rust handle Encapsulation (Access Modifiers)?

13. Summary

Organizing code effectively is crucial for building large applications. Rust's module system enforces strict privacy boundaries, requiring you to deliberately expose APIs using pub. With the power of Cargo and crates.io, integrating complex third-party tools into your clean module architecture takes only seconds.

14. Next Chapter Recommendation

We know how to share code between files, but how do we share *behaviors* across different Structs? In Chapter 17: Traits and Generics, we will explore Rust's equivalent to Interfaces, allowing us to write highly reusable, polymorphic code.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·