When I first started using Rust, I ran cargo build, saw an executable appear in target/, and moved on. But Cargo creates more than just a binary: it also keeps metadata and intermediate artifacts that help it decide what needs to be rebuilt.
Let's create a tiny project, inspect its build output, and compare a clean build with a repeat build.
1. Create a project
You'll need Rust and Cargo installed. Check with:
rustc --version cargo --version Create a binary project and move into its directory:
cargo new cargo-lab cd cargo-lab Cargo creates a small project structure:
cargo-lab/ ├── Cargo.toml └── src/ └── main.rs Replace the contents of src/main.rs with:
fn main() { let message = "Hello"; println!("{message}, Cargo!"); } 2. Build the project
Run:
cargo build -v The -v (verbose) option shows more detail, including compiler commands when Cargo runs them. The first build may also create a Cargo.lock file and a target/ directory. The exact output depends on your operating system and Rust toolchain, but the project will look roughly like this:
cargo-lab/ ├── Cargo.lock ├── Cargo.toml ├── src/ │ └── main.rs └── target/ └── debug/ └── cargo-lab The executable is at target/debug/cargo-lab (on Windows, it has an .exe extension). You can build and run the program with one command:
cargo run 3. Look inside target/debug
List some of the generated files with:
find target/debug -maxdepth 2 -type f The exact contents vary by platform, toolchain, and project. You may see:
- The executable, such as
target/debug/cargo-lab. -
deps/, which can contain compiled dependencies and other build artifacts. -
.fingerprint/, with metadata Cargo uses to determine whether a package needs rebuilding. -
incremental/, when incremental compilation is enabled for the build. -
build/, when a dependency or package uses a build script.
Not every project has every directory. This example has no third-party dependencies, so its output is relatively small. Rust's standard library is generally supplied by the installed toolchain; Cargo does not rebuild the standard library from source for every ordinary project build.
4. Why is the second build usually faster?
Without changing any files, run the build again:
cargo build -v Cargo will usually report that the package is fresh instead of compiling it again. It tracks the inputs and previous build results so it can skip work when nothing relevant has changed.
Now change the message in src/main.rs and build again:
fn main() { let message = "Hello from Rust"; println!("{message}, Cargo!"); } cargo build -v Cargo needs to recompile the changed program. In a project with dependencies, changing your own source does not necessarily mean that every dependency must be rebuilt.
5. Measure it on your machine
Build times depend on your machine, Rust version, and previous build artifacts. For a simple comparison, run:
cargo clean time cargo build time cargo build cargo clean removes generated build artifacts from target/; it does not delete your source files. The first timing is for a clean build. The second is for a build with no source changes.
Record your own results:
| Run | Time |
|---|---|
| First build | cargo build 0.17s user 0.12s system 49% cpu 0.581 total |
| Build with no changes | cargo build 0.02s user 0.02s system 67% cpu 0.049 total |
Don't compare these numbers directly with someone else's machine. The useful comparison is between the two runs in the same environment.
You can also ask Cargo for a visual report of build timings:
cargo build --timings Cargo writes an HTML report under target/cargo-timings/.
6. What changes with --release?
Try a release build:
cargo build --release Its output goes into target/release/, separate from target/debug/. Cargo uses different build profiles for development and release builds. The release profile applies optimizations, which can make compilation take longer while producing a program intended for distribution.
Takeaways
-
Cargo.tomldescribes the package and its dependencies;Cargo.lockrecords the resolved dependency versions. -
target/contains generated outputs: executables, intermediate artifacts, and metadata. - Cargo checks whether previous outputs can be reused, so a build with no changes usually does much less work.
- Debug and release builds use separate output directories and profiles.
You generally don't need to commit target/ to Git because Cargo can regenerate it. Projects created with cargo new normally include it in .gitignore.
Your turn: How long does a clean build take on your machine, and how long does the second build take? What does cargo build -v report after you change only main.rs?

