In Rust communities, “crate” is often discussed like a package unit. You can think of a package as a project/software package wrapper.
Rust projects commonly involve two crate types:
- library crates
- binary crates
cargo new creates a new project. By default it creates an executable binary package (--bin is default and can be omitted).
cargo run compiles in debug mode and then runs. With --release, Rust applies heavy optimization for performance.
mod keyword: declares a module and tells the compiler to include module files.
use keyword: imports types/functions from a module into current scope.
Difference between mod and creating lib.rs
- Using
modinmain.rs: modules are visible only inside the current binary crate.main.rsacts as root of this module tree. - Creating
lib.rs: defines a library crate. Module hierarchy starts fromlib.rs, making code reusable by other crates.
Why does lib.rs reduce many mod declarations in main.rs?
Once modules are declared in lib.rs, main.rs can directly use them without repeating top-level mod declarations. This keeps main.rs focused on entry logic.
Basics
cargo new {project} --bin --vcs none: create binary/lib project without auto git init.cargo build: compile in debug mode by default.cargo run: compile in debug mode and run.cargo build --release: compile in release mode;rustcperforms optimization.
After pulling a remote Rust project, cargo build will automatically resolve dependencies and build.
Cargo manages dependencies and versions via Cargo.toml (similar role to pyproject.toml in Python). During build, it also generates Cargo.lock (similar idea to uv.lock), containing more specific resolved dependency metadata.
To update dependency versions, run cargo update; otherwise Cargo uses the versions declared/resolved from current configuration.
Cargo Project Layout Conventions
.
├── Cargo.lock
├── Cargo.toml
├── src/
│ ├── lib.rs
│ ├── main.rs
│ └── bin/
│ ├── named-executable.rs
│ ├── another-executable.rs
│ └── multi-file-executable/
│ ├── main.rs
│ └── some_module.rs
├── benches/
│ ├── large-input.rs
│ └── multi-file-bench/
│ ├── main.rs
│ └── bench_module.rs
├── examples/
│ ├── simple.rs
│ └── multi-file-example/
│ ├── main.rs
│ └── ex_module.rs
└── tests/
├── some-integration-tests.rs
└── multi-file-test/
├── main.rs
└── test_module.rs
Cargo.tomlandCargo.lockare at package root.- Source files live in
src. - Default library entry:
src/lib.rs. - Default binary entry:
src/main.rs.- Additional binaries go in
src/bin/.
- Additional binaries go in
- Benchmarks go in
benches/. - Examples go in
examples/. - Integration tests go in
tests/.
If a binary/example/bench/integration-test has multiple source files, place them in a subdirectory with a main.rs. The executable name follows the folder name.