DEV Community

Hermosilla
Hermosilla

Posted on Edited on

What Cargo Generates When You Build a Small Rust Project

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
Enter fullscreen mode Exit fullscreen mode

Create a binary project and move into its directory:

cargo new cargo-lab
cd cargo-lab
Enter fullscreen mode Exit fullscreen mode

Cargo creates a small project structure:

cargo-lab/
├── Cargo.toml
└── src/
    └── main.rs
Enter fullscreen mode Exit fullscreen mode

Replace the contents of src/main.rs with:

fn main() {
    let message = "Hello";
    println!("{message}, Cargo!");
}
Enter fullscreen mode Exit fullscreen mode

2. Build the project

Run:

cargo build -v
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

3. Look inside target/debug

List some of the generated files with:

find target/debug -maxdepth 2 -type f
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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!");
}
Enter fullscreen mode Exit fullscreen mode
cargo build -v
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Cargo writes an HTML report under target/cargo-timings/.

6. What changes with --release?

Try a release build:

cargo build --release
Enter fullscreen mode Exit fullscreen mode

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.toml describes the package and its dependencies; Cargo.lock records 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?

Top comments (0)