TechLead
Lesson 15 of 28
5 min read
Rust

Modules, Crates & Cargo

Master Rust's module system with mod, pub, use, crate structure, Cargo.toml, workspaces, features, and publishing to crates.io.

The Module System

Rust's module system controls code organization, visibility, and namespacing. It consists of crates (compilation units), modules (namespaces within a crate), paths (how to name items), and use (bringing items into scope).

Module System Concepts

  • Crate: A binary or library — the top-level compilation unit
  • Module: A namespace that controls privacy. Defined with mod
  • Path: crate::module::item — how you refer to items
  • pub: Makes items visible outside their module
// src/lib.rs or src/main.rs

// Inline module
mod math {
    // Private by default
    fn internal_helper() -> f64 { 42.0 }

    // Public — accessible outside the module
    pub fn add(a: f64, b: f64) -> f64 { a + b }
    pub fn multiply(a: f64, b: f64) -> f64 { a * b }

    // Nested module
    pub mod advanced {
        pub fn power(base: f64, exp: u32) -> f64 {
            (0..exp).fold(1.0, |acc, _| acc * base)
        }
    }
}

// Using items from modules
use math::add;
use math::advanced::power;

fn main() {
    println!("{}", add(2.0, 3.0));
    println!("{}", math::multiply(4.0, 5.0)); // Full path
    println!("{}", power(2.0, 10));

    // math::internal_helper(); // ERROR: private function
}

File-Based Modules

// Project structure:
// src/
//   main.rs
//   config.rs          (or config/mod.rs)
//   db/
//     mod.rs
//     connection.rs
//     queries.rs

// --- src/main.rs ---
mod config;          // Loads from src/config.rs
mod db;              // Loads from src/db/mod.rs

use config::AppConfig;
use db::connection::Database;

fn main() {
    let config = AppConfig::from_env();
    let db = Database::connect(&config.database_url);
}

// --- src/config.rs ---
pub struct AppConfig {
    pub database_url: String,
    pub port: u16,
}

impl AppConfig {
    pub fn from_env() -> Self {
        AppConfig {
            database_url: std::env::var("DATABASE_URL")
                .unwrap_or_else(|_| "localhost".into()),
            port: 8080,
        }
    }
}

// --- src/db/mod.rs ---
pub mod connection;
pub mod queries;

// --- src/db/connection.rs ---
pub struct Database {
    url: String,
}

impl Database {
    pub fn connect(url: &str) -> Self {
        println!("Connecting to {url}");
        Database { url: url.to_string() }
    }
}

Cargo.toml and Dependencies

// Cargo.toml
[package]
name = "my-project"
version = "0.1.0"
edition = "2021"
authors = ["Your Name <you@example.com>"]
description = "A great Rust project"
license = "MIT"

[dependencies]
serde = { version = "1", features = ["derive"] }
tokio = { version = "1", features = ["full"] }
reqwest = { version = "0.12", features = ["json"] }
anyhow = "1"
tracing = "0.1"

[dev-dependencies]
criterion = "0.5"       # Benchmarks
mockall = "0.13"        # Mocking

[build-dependencies]
cc = "1"                # For C FFI builds

[features]
default = ["json"]
json = ["serde"]        # Optional feature
full = ["json", "tokio/full"]

[[bin]]
name = "server"
path = "src/bin/server.rs"

Cargo Commands

# Project management
cargo new my-project      # Create binary project
cargo new my-lib --lib    # Create library project
cargo init                # Initialize in current directory

# Building
cargo build               # Debug build
cargo build --release     # Release build (optimized)
cargo check               # Type-check only (fastest)

# Running
cargo run                 # Build and run
cargo run -- arg1 arg2    # Pass arguments
cargo run --bin server    # Run specific binary

# Testing
cargo test                # Run all tests
cargo test test_name      # Run specific test
cargo test -- --nocapture # Show println! output

# Other essentials
cargo doc --open          # Generate and view documentation
cargo bench               # Run benchmarks
cargo clippy              # Run linter
cargo fmt                 # Format code
cargo update              # Update dependencies
cargo tree                # Show dependency tree
cargo add serde           # Add a dependency (cargo-edit)

Workspaces

// Root Cargo.toml for a workspace
[workspace]
members = [
    "core",
    "api",
    "cli",
]
resolver = "2"

// Shared dependencies across workspace
[workspace.dependencies]
serde = { version = "1", features = ["derive"] }
tokio = { version = "1", features = ["full"] }

// In a member's Cargo.toml:
[package]
name = "api"

[dependencies]
core = { path = "../core" }
serde = { workspace = true }      # Use workspace version
tokio = { workspace = true }

Key Takeaways

  • ✅ Modules organize code with mod and control visibility with pub
  • ✅ File-based modules map directory structure to the module tree
  • ✅ Cargo.toml manages dependencies, features, and build configuration
  • ✅ Workspaces share dependencies and enable multi-crate projects
  • cargo check is the fastest way to validate code during development

Continue Learning