A successful rustc --version is not quite a working Rust project setup. The useful baseline is broader: rustup manages the toolchain, Cargo creates and builds the crate, rustfmt keeps the source formatted, Clippy catches suspicious code, and the test runner proves that at least one behavior works.
This guide takes a new binary crate through that entire loop. The commands target Linux stable Rust 1.98.1. For the rustup installer, Windows installation, rustup component add, and rustup update stable, use the corresponding platform instructions.
1. Tool Roles
The names blur together at first, so keep the boundaries simple:
rustupinstalls and selects Rust toolchains such as stable, beta, and nightly. It also manages optional components.rustccompiles Rust source code.cargocreates projects, resolves dependencies, builds binaries and libraries, runs programs, and executes tests.rustfmtformats Rust source according to a consistent style.clippyadds lints for code that compiles but may be unclear, inefficient, or error-prone.
Rustup is the command-line tool for managing Rust versions and associated tools. Cargo is included when Rust is installed through the official installer. rustfmt and Clippy are rustup components, so they can be added later if a selected installation profile omitted them.
2. Install on Linux or macOS
The rustup installer provides a shell command that downloads and runs the installer. Piping a remote script straight into a shell is convenient, but separating download from execution gives you a chance to inspect what will run.
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs -o rustup-init.sh
less rustup-init.sh
sh rustup-init.sh
Unless your project says otherwise, choose the default stable toolchain. Open a new terminal after installation. If the shell still cannot find cargo, load Cargo's environment file into the current session:
. "$HOME/.cargo/env"
Rust also needs a linker. Most developer machines already have one, but a fresh Linux image may require the distribution's C build tools. Debian and Ubuntu commonly package them as build-essential; Fedora provides C development tool groups. On macOS, Xcode Command Line Tools normally supply the linker. Package names can change, so use your operating system's current documentation if a link step fails.
3. Install on Windows
Download and run rustup-init.exe from the official Rust tools page. A standard MSVC setup also needs the Visual Studio C++ build tools and a Windows SDK. If the installer asks for Visual Studio prerequisites, include those components; rustc cannot produce a Windows executable without the native linker and libraries.
After installation, open a fresh PowerShell or Windows Terminal window before checking the commands. If you develop inside WSL, install the Linux toolchain inside the distribution. Mixing a Windows rustup installation with a WSL project creates avoidable path and linker confusion.
4. Verify the Toolchain
Run four checks:
rustc --version
cargo --version
rustup show active-toolchain
rustup component list --installed
The isolated example for this article used these versions:
rustc 1.98.1 (48a229cea 2026-09-01)
cargo 1.98.1 (797e8a9bc 2026-08-05)
rustfmt 1.9.0-stable (48a229ceae 2026-09-01)
clippy 0.1.98 (48a229ceae 2026-09-01)
Add the formatter and linter if they are missing:
rustup component add rustfmt clippy
Updating stable is one command:
rustup update stable
Do not blindly update a team repository that pins its compiler. A rust-toolchain.toml file in the project root tells rustup which channel and components to use when you work in that directory. This compact configuration is enough for the tutorial project:
[toolchain]
channel = "stable"
profile = "minimal"
components = ["rustfmt", "clippy"]
The minimal profile installs the core compiler and Cargo pieces, while the components list adds the two development checks used here. A production repository can replace stable with an exact version when reproducibility matters more than following every stable release automatically.
5. First Cargo Crate
Cargo packages contain one or more crates. This project needs one executable, so create a binary package. --vcs none keeps the example from initializing a nested Git repository when you try it inside an existing checkout.
cargo new endpoint-check --bin --vcs none
cd endpoint-check
cargo new creates Cargo.toml and src/main.rs. The manifest records package metadata and dependencies. A manifest generated by the current stable Cargo has this shape:
[package]
name = "endpoint-check"
version = "0.1.0"
edition = "2024"
[dependencies]
Replace src/main.rs with the code below. It has a small function worth testing rather than leaving all behavior inside main.
fn status_line(name: &str, url: &str) -> String {
format!("{name}: {url}")
}
fn main() {
println!("{}", status_line("docs", "https://doc.rust-lang.org"));
}
#[cfg(test)]
mod tests {
use super::status_line;
#[test]
fn formats_an_endpoint() {
assert_eq!(
status_line("docs", "https://doc.rust-lang.org"),
"docs: https://doc.rust-lang.org"
);
}
}
This is deliberately small. It will grow into an endpoint-oriented command-line program later in the series, but right now its job is to exercise the toolchain without hiding anything behind a dependency.
6. Command Roles
Start with cargo check while editing. It checks the package and its dependencies without performing the final code-generation step. That usually makes it the quickest compilation feedback loop.
cargo check
cargo build
cargo run --quiet
cargo build produces a development binary under target/debug by default. cargo run builds when necessary and then executes the binary. The --quiet flag suppresses Cargo's own progress messages, not the program's output.
docs: https://doc.rust-lang.org
Use cargo build --release when you need an optimized artifact. Release builds take longer, and they do not improve the ordinary edit-check-test loop, so there is little reason to use them for every beginner exercise.
7. Formatting and Checking with rustfmt
Use cargo fmt as the easiest way to format a Cargo project.
cargo fmt
cargo fmt --check
The first command edits files. The second exits unsuccessfully when formatting would change something, which makes it suitable for CI. A straightforward workflow is to run cargo fmt locally and reserve cargo fmt --check for the pre-commit or CI gate.
Formatting is intentionally mechanical. It settles whitespace and layout so code review can focus on behavior. It does not establish that the program compiles or that its logic is correct.
8. Fail on Clippy Warnings
The usual Clippy entry point is short:
cargo clippy
For a clean new crate, turn warnings into errors:
cargo clippy -- -D warnings
Arguments after -- go to the underlying compiler lint configuration. -D warnings raises every warning to the deny level.
This policy works well for a tutorial or a new codebase because warning-free is the starting state. Enabling it without preparation in an older repository may break unrelated work on existing warnings. Teams usually need to agree on the lint baseline and introduce stricter settings deliberately.
Treat Clippy output as an explanation, not an infallible rewrite order. Read why a lint fired, decide whether it fits the code's intent, and rerun tests after any automatic fix.
9. Run Tests
Functions marked with #[test] are collected by Rust's test harness. cargo test compiles and executes unit, integration, and documentation tests.
cargo test
The example produced this useful part of the output:
running 1 test
test tests::formats_an_endpoint ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
A practical minimum gate for this crate is therefore:
cargo fmt --check
cargo clippy -- -D warnings
cargo test
All three commands should return exit code 0. That means the checked source was formatted, passed the selected lints, and satisfied its current test. It does not mean the program is bug-free; behavior with no test remains unverified. Still, this is a much better starting line than a binary that merely prints Hello, world!.
10. Fix Setup Problems
If the shell reports cargo: command not found, open a new terminal and check whether $HOME/.cargo/bin is on PATH. On Unix shells, . "$HOME/.cargo/env" refreshes the current session.
A missing-linker error usually points to system build tools rather than Rust syntax. Check the C compiler and linker packages on Linux, Xcode Command Line Tools on macOS, or the MSVC C++ Build Tools on Windows.
If Cargo says that fmt or clippy is unavailable, install those rustup components and list the installed components again. There is no need to switch to nightly for this workflow. Stable Rust supports every command used in the project.
11. Next Steps
The crate is now ready for actual Rust syntax. The next installment uses the same project to examine immutable bindings, type inference, explicit annotations, constants, mutation, and shadowing. Before moving on, remember the job of Cargo.toml, src/main.rs, and target, plus the three-command quality gate above.
Full source code
The complete runnable source for this article is available in the Chapter 01 project on GitHub.
Leave a Reply