The src Directory
In a Cargo package, the src/ directory holds all Rust source files (.rs) that make up the package's library and binary crates. Cargo uses a set of conventional file paths inside src/ to automatically discover compilation targets without requiring you to list every source file in Cargo.toml.
Standard src/ Directory Layout
A full-featured Cargo package can contain a library root, a default binary root, additional binaries, and module subdirectories inside src/:
my_package/
├── Cargo.toml
└── src/
├── lib.rs <-- Library crate root (at most 1 per package)
├── main.rs <-- Default binary crate root (compiled to `target/debug/my_package`)
├── config.rs <-- Module file (`mod config;` declared in `lib.rs` or `main.rs`)
├── network/ <-- Submodule directory (`mod network;`)
│ ├── mod.rs <-- (Or `src/network.rs` alongside `src/network/`)
│ └── client.rs <-- Submodule `network::client` (`mod client;`)
└── bin/ <-- Additional binary executables (`cargo run --bin <name>`)
├── migrate.rs <-- Single-file binary target (`migrate`)
└── server/ <-- Multi-file binary target (`server`)
├── main.rs
└── routes.rs
Conventional Targets Discovered in src/
Cargo inspects src/ and automatically registers the following compilation targets:
File Path in src/ |
Target Type | Resulting Crate / Binary Name | How to Run or Build |
|---|---|---|---|
src/lib.rs |
Library crate (--lib) |
Package name (with - replaced by _) |
cargo build --lib / cargo test --lib |
src/main.rs |
Default binary crate (--bin) |
Package name | cargo run (or cargo run --bin <pkg_name>) |
src/bin/<name>.rs |
Additional single-file binary | <name> |
cargo run --bin <name> |
src/bin/<name>/main.rs |
Additional multi-file binary | <name> |
cargo run --bin <name> |
How rustc Discovers Other Files in src/
Unlike Go or Java—which automatically compile every source file placed in a directory—rustc starts ONLY at the crate root file (src/main.rs or src/lib.rs) and compiles other .rs files in src/ only if they are explicitly declared with mod <name>; in the module tree!
If you create src/helper.rs but never write mod helper; inside src/main.rs (or src/lib.rs), src/helper.rs is completely ignored during compilation.
src/main.rs (Crate Root)
|
+-- `mod config;` ---> Compiler loads and compiles `src/config.rs`
|
+-- `mod network;` ---> Compiler loads and compiles `src/network.rs` (or `src/network/mod.rs`)
|
+-- `pub mod client;` ---> Compiler loads `src/network/client.rs`
Example: Connecting a Module File in src/
Suppose your src/ directory contains two files: src/main.rs and src/math.rs.
src/math.rs:
pub fn double(n: i32) -> i32 {
n * 2
}
src/main.rs:
mod math; // Tells `rustc` to load `src/math.rs` as the `math` module
fn main() {
println!("21 doubled is {}", math::double(21));
}
21 doubled is 42
Modern Module Subdirectories (src/network.rs vs src/network/mod.rs)
When a module like network has its own child submodules (network::client), Rust supports two directory layouts inside src/:
| Style | Parent Module File | Child Module File (network::client) |
Status |
|---|---|---|---|
| Modern (2018+ Edition) | src/network.rs |
src/network/client.rs |
Recommended (avoids having dozens of tabs all named mod.rs in your editor) |
| Older (2015 Edition) | src/network/mod.rs |
src/network/client.rs |
Supported, but do not create both src/network.rs and src/network/mod.rs at the same time (E0761) |
Multiple Binaries in src/bin/
When a project needs helper CLI utilities alongside its main application (such as a database migration tool migrate or a data seeding script seed), place each utility inside src/bin/:
// src/bin/seed.rs
fn main() {
println!("Seeding database with initial records...");
}
Run a specific binary in src/bin/ using --bin:
cargo run --bin seed
Compiling my_package v0.1.0 (/Users/username/my_package)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.19s
Running `target/debug/seed`
Seeding database with initial records...
When both src/main.rs and src/bin/*.rs exist in the same package, running bare cargo run without --bin becomes ambiguous unless you set default-run in Cargo.toml:
[package]
name = "my_package"
version = "0.1.0"
edition = "2024"
default-run = "my_package"
Directories Outside src/ Recognized by Cargo
While application and library production code lives inside src/, Cargo also recognizes three sibling directories at the package root for tests, examples, and benchmarks:
| Sibling Directory | Purpose | Invoked Via |
|---|---|---|
tests/*.rs |
Integration tests (each file is compiled as a separate crate testing your library's public API) | cargo test |
examples/*.rs |
Standalone runnable example programs demonstrating how to use your library | cargo run --example <name> |
benches/*.rs |
Performance benchmarks | cargo bench |