Core Concept: Modules & Crates ​
Updated Mar 2026Overview ​
Rust's module system controls code organization, visibility, and namespacing. A crate is a compilation unit. A module groups related items within a crate.
Module Tree ​
Crate Types ​
rust
// src/main.rs — binary crate entry point
fn main() {
println!("I'm an executable");
}
// src/lib.rs — library crate entry point
pub fn greet(name: &str) -> String {
format!("Hello, {name}!")
}Declaring Modules ​
Inline Modules ​
rust
// src/lib.rs
mod math {
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
fn internal_helper() -> i32 {
42 // Private — only visible within math module
}
}
pub fn use_math() {
let sum = math::add(1, 2); // Access public item
// math::internal_helper(); // ERROR: private
}File-Based Modules ​
src/
├── main.rs # Declares modules
├── auth.rs # mod auth (flat style)
├── api/
│ ├── mod.rs # mod api (directory style)
│ ├── handlers.rs
│ └── middleware.rs
└── models.rsrust
// src/main.rs
mod auth; // Loads from src/auth.rs
mod api; // Loads from src/api/mod.rs (or src/api.rs)
mod models; // Loads from src/models.rs
fn main() {
auth::login("user", "pass");
api::handlers::get_users();
}rust
// src/api/mod.rs
pub mod handlers; // Loads src/api/handlers.rs
pub mod middleware; // Loads src/api/middleware.rsModern File Layout (Rust 2018+) ​
src/
├── main.rs
├── auth.rs # mod auth
├── api.rs # mod api (declares submodules)
├── api/
│ ├── handlers.rs # mod api::handlers
│ └── middleware.rs # mod api::middleware
└── models.rsrust
// src/api.rs (instead of src/api/mod.rs)
pub mod handlers;
pub mod middleware;Visibility ​
rust
mod outer {
pub struct Config {
pub name: String, // Public to everyone
pub(crate) debug: bool, // Public within the crate
pub(super) version: u32, // Public to parent module
secret: String, // Private (default)
}
pub(crate) fn crate_only() {
// Visible within crate, not to external users
}
mod inner {
pub(in crate::outer) fn outer_only() {
// Only visible within outer module
}
}
}use and Paths ​
rust
// Absolute path (from crate root)
use crate::auth::login;
// Relative path
use self::models::User; // Same module
use super::helpers::format; // Parent module
// External crate
use std::collections::HashMap;
use serde::{Serialize, Deserialize};
// Rename to avoid conflicts
use std::fmt::Result as FmtResult;
use std::io::Result as IoResult;
// Glob import (avoid in production — use in tests/preludes)
use std::collections::*;
// Nested paths
use std::io::{self, Read, Write};
use std::collections::{HashMap, HashSet, BTreeMap};Re-exports ​
rust
// src/lib.rs
mod internal {
pub struct Database { ... }
pub fn connect() -> Database { ... }
}
// Re-export for clean public API
pub use internal::Database;
pub use internal::connect;
// Users see: my_crate::Database, my_crate::connect
// NOT: my_crate::internal::DatabasePrelude Pattern ​
rust
// src/prelude.rs
pub use crate::models::{User, Order};
pub use crate::error::AppError;
pub use crate::traits::{Validate, Serialize};
// Usage in other modules:
use crate::prelude::*;Cargo.toml Dependencies ​
toml
[dependencies]
# From crates.io
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1", features = ["full"] }
# From git
my_crate = { git = "https://github.com/user/repo", branch = "main" }
my_crate = { git = "https://github.com/user/repo", rev = "abc123" }
# Local path (workspace or development)
shared = { path = "../shared" }
# Optional (for feature flags)
fancy = { version = "0.5", optional = true }
[dev-dependencies]
pretty_assertions = "1"
[build-dependencies]
cc = "1"Workspaces ​
toml
# Root Cargo.toml
[workspace]
members = [
"crates/core",
"crates/api",
"crates/cli",
]
resolver = "2"
[workspace.dependencies]
serde = { version = "1", features = ["derive"] }Module Best Practices ​
| Practice | Why |
|---|---|
| Keep modules focused (single responsibility) | Easier to navigate and test |
Use pub(crate) over pub when possible | Minimize public API surface |
| Re-export important items from lib.rs | Clean API for consumers |
| Use prelude module for common imports | Reduce boilerplate |
| Prefer flat file layout over deep nesting | Easier to find files |
| One type per file for large types | Better git diffs |