Rust Development Environment

cargo build

cargo build (aliased as cargo b) compiles your package and all of its dependencies, producing native binary executables and/or library artifacts inside the target/ directory without executing them.

Debug vs Release Builds

By default, running cargo build with no flags compiles using the dev profile (unoptimized, fast compile time, full debug symbols). Passing --release (or -r) compiles using the release profile (full LLVM optimizations, stripped of runtime overflow checks):

# 1. Build in debug mode (`dev` profile) -> outputs to `target/debug/<name>`
cargo build

# 2. Build in release mode (`release` profile) -> outputs to `target/release/<name>`
cargo build --release
   Compiling my_project v0.1.0 (/Users/username/my_project)
    Finished `release` profile [optimized] target(s) in 0.42s

Directory Layout of target/

When cargo build runs, it places all intermediate files, dependency caches, and final executables inside target/ at the root of the package (or workspace):

target/
├── CACHEDIR.TAG                <-- Marks `target/` so backup tools ignore it
├── debug/                      <-- Output of `cargo build` (`dev` profile)
│   ├── <package_name>          <-- Final compiled executable binary!
│   ├── lib<package_name>.rlib  <-- Compiled library (if `src/lib.rs` exists)
│   ├── build/                  <-- Output of custom `build.rs` scripts
│   ├── deps/                   <-- Compiled `.rlib` and `.rmeta` files for dependencies
│   ├── examples/               <-- Compiled binaries from `examples/*.rs`
│   └── incremental/            <-- Query cache for fast incremental recompilation
└── release/                    <-- Output of `cargo build --release` (`release` profile)
    ├── <package_name>          <-- Optimized production executable binary!
    └── deps/

Because target/ can grow to hundreds of megabytes or several gigabytes as dependencies and incremental caches accumulate, it is always listed in .gitignore and can be safely deleted at any time using cargo clean.

Common cargo build Flags

Flag Example Description
--release / -r cargo build --release Builds with optimizations (opt-level = 3) in target/release/
--profile <name> cargo build --profile bench Builds using a specific custom profile defined in Cargo.toml
--bin <name> cargo build --bin server Builds only the specified binary target
--bins cargo build --bins Builds all binary targets (src/main.rs and src/bin/*.rs)
--lib cargo build --lib Builds only the package's library target (src/lib.rs)
--examples cargo build --examples Builds all standalone examples in examples/*.rs
--tests cargo build --tests Compiles unit and integration test binaries without running them
--all-targets cargo build --all-targets Builds libraries, binaries, examples, tests, and benchmarks
--workspace cargo build --workspace Builds all member packages in a Cargo workspace
-p <pkg> / --package cargo build -p core_api Builds a specific package inside a workspace
--features "<list>" cargo build --features "tls,json" Enables optional Cargo feature flags
--all-features cargo build --all-features Enables every optional feature defined in Cargo.toml
--no-default-features cargo build --no-default-features Disables the default = [...] feature set in Cargo.toml
--target <triple> cargo build --target wasm32-unknown-unknown Cross-compiles for <triple> (outputs to target/<triple>/debug/)
-j <N> / --jobs <N> cargo build -j 4 Limits the number of parallel rustc processes (defaults to CPU core count)
--timings cargo build --timings Generates an HTML report (cargo-timing.html) showing per-crate build duration and CPU parallelism
--offline cargo build --offline Builds using only locally cached crates in ~/.cargo/ without touching the network
--locked cargo build --locked Fails if Cargo.lock would need to be updated (recommended in CI and Docker builds)

Cross-Compilation Output Path (--target)

When you pass --target <triple>, Cargo places the build artifacts in a target-specific subdirectory target/<triple>/debug/ (or target/<triple>/release/) so host and cross-compiled artifacts never overwrite each other:

cargo build --target aarch64-apple-darwin --release
target/
└── aarch64-apple-darwin/
    └── release/
        └── my_project

Profiling Build Times (cargo build --timings)

On large projects, passing --timings records when each crate starts compilation, when its .rmeta metadata finishes (unlocking downstream crates to begin type-checking in parallel!), and when LLVM codegen finishes:

cargo clean
cargo build --timings
      Timing report saved to /Users/username/my_project/target/cargo-timings/cargo-timing-20261021T180000Z.html