In the previous tutorial, we learned why Rust matters. Now let’s install it and write our first program.

By the end of this tutorial, you will have Rust installed, your editor set up, and a working program that you built and ran yourself.

Step 1: Install Rust with rustup

Rust uses a tool called rustup to manage installations. One command installs everything:

macOS / Linux

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

Follow the prompts — choose the default installation (option 1).

After it finishes, restart your terminal or run:

source $HOME/.cargo/env

Windows

Download and run the installer from rustup.rs. Follow the prompts. You may need to install the Visual Studio C++ Build Tools if prompted.

Verify Installation

rustc --version
# rustc 1.87.0 (or newer)

cargo --version
# cargo 1.87.0 (or newer)

If you see version numbers, Rust is installed.

What You Just Installed

rustup installs three tools:

ToolWhat It Does
rustcThe Rust compiler — turns .rs files into executables
cargoThe package manager AND build system — creates projects, manages dependencies, builds, tests
rustupThe version manager — updates Rust, switches between versions

You will almost never call rustc directly. You will use cargo for everything.

Useful rustup Commands

# Update Rust to the latest version
rustup update

# Check which version you have
rustup show

# Add a component (like the formatter)
rustup component add rustfmt
rustup component add clippy

Step 2: Set Up Your Editor

  1. Install VS Code
  2. Install these extensions:
    • rust-analyzer — the main Rust extension (autocomplete, errors, go-to-definition)
    • Even Better TOML — syntax highlighting for Cargo.toml
    • Error Lens — shows errors inline (optional but helpful)

That is the complete setup. rust-analyzer gives you:

  • Autocomplete as you type
  • Error highlighting before you compile
  • Type hints on hover
  • Go to definition (Cmd+Click)
  • Auto-formatting on save

IntelliJ / RustRover

JetBrains makes RustRover — a dedicated Rust IDE. It is free for non-commercial use and has excellent Rust support. If you already use IntelliJ, this is a great choice.

Other Editors

Any editor works with Rust. rust-analyzer supports VS Code, Neovim, Helix, Emacs, and Sublime Text. But VS Code has the smoothest setup for beginners.

Step 3: Create Your First Project

Open your terminal and run:

# Create a new project called "hello"
cargo new hello
cd hello

This creates a folder with this structure:

hello/
├── Cargo.toml     ← Project config (dependencies, version, etc.)
└── src/
    └── main.rs    ← Your code goes here

What is Cargo.toml?

[package]
name = "hello"
version = "0.1.0"
edition = "2024"

[dependencies]
  • name — your project name
  • version — your project version
  • edition — which Rust edition to use (2024 is the latest)
  • [dependencies] — external libraries (empty for now)

Note about editions: Rust has “editions” (2015, 2018, 2021, 2024). Each edition adds new features and syntax. New projects use the latest edition. If you see older tutorials using edition = "2021", the code still works — Rust is backwards compatible.

What is main.rs?

fn main() {
    println!("Hello, world!");
}

This is a complete Rust program:

  • fn main() — the entry point (every Rust program starts here)
  • println!() — prints text to the terminal (the ! means it is a macro, not a function — we will cover macros later)

Step 4: Run Your Program

cargo run

Output:

   Compiling hello v0.1.0 (/path/to/hello)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.5s
     Running `target/debug/hello`
Hello, world!

That’s it. Your first Rust program runs.

What cargo run Does

  1. Compiles your code (turns .rs into a binary executable)
  2. Runs the compiled binary

The compiled binary is at target/debug/hello. You can run it directly:

./target/debug/hello
# Hello, world!

Step 5: Understand the Cargo Commands

CommandWhat It DoesWhen to Use
cargo new nameCreate a new projectStarting a project
cargo runCompile + runDuring development
cargo buildCompile only (don’t run)When you just want to check if it compiles
cargo checkCheck for errors (fastest, no binary)Quick error checking while coding
cargo testRun testsTesting your code
cargo fmtFormat your codeBefore committing
cargo clippyLint your code (suggests improvements)Finding common mistakes
cargo doc --openGenerate and open documentationReading docs for your dependencies

The ones you will use most: cargo run (during development) and cargo check (quick error checking).

cargo check vs cargo build

# Fast — only checks for errors, doesn't produce a binary
cargo check    # Takes ~0.5 seconds

# Slower — compiles everything, produces a binary
cargo build    # Takes ~2-10 seconds

# Even slower — compiles with optimizations for release
cargo build --release    # Takes ~10-60 seconds

Use cargo check while developing — it is much faster because it skips the code generation step. Use cargo build or cargo run when you actually need to run the program.

Step 6: Let’s Write Something More

Let’s make the program interactive:

use std::io;

fn main() {
    println!("What is your name?");

    let mut name = String::new();

    io::stdin()
        .read_line(&mut name)
        .expect("Failed to read input");

    // trim() removes the newline character from the input
    let name = name.trim();

    println!("Hello, {}! Welcome to Rust.", name);
}

Run it:

cargo run
What is your name?
Alex
Hello, Alex! Welcome to Rust.

What is Happening Here?

use std::io;
// Import the io (input/output) module from the standard library

let mut name = String::new();
// Create a mutable variable called "name"
// "mut" means we can change it later
// String::new() creates an empty String

io::stdin().read_line(&mut name).expect("Failed to read input");
// Read a line from the terminal into "name"
// &mut name — pass a mutable reference (we'll cover this in Tutorial #5)
// .expect() — crash with this message if reading fails

let name = name.trim();
// Create a new "name" that shadows the old one
// .trim() removes whitespace and newlines from both ends

Don’t worry if &mut, expect(), and String::new() seem confusing. We will cover every concept in detail in the next tutorials. For now, just know:

  • let creates a variable
  • mut makes it changeable
  • String::new() creates an empty string
  • println!("{}", variable) prints a variable

Step 7: Add a Dependency

Let’s use an external library (called a “crate” in Rust). We will add colored to print colorful text:

cargo add colored

This updates Cargo.toml:

[dependencies]
colored = "3.0.0"

Now use it:

use colored::*;

fn main() {
    println!("{}", "Hello from Rust!".green().bold());
    println!("{}", "This text is red.".red());
    println!("{}", "This text is blue and italic.".blue().italic());
    println!("{}", "Warning!".yellow().on_black());
}

Run it:

cargo run

You will see colorful text in your terminal. That’s how easy it is to use external libraries in Rust — cargo add, import, use.

Finding Crates

  • crates.io — the official crate registry (like npm for JavaScript)
  • lib.rs — a nicer interface for browsing crates
  • Search: cargo search keyword

Bonus: Live Reloading with bacon

When developing, it is annoying to type cargo check or cargo run every time you change a file. bacon watches your files and runs the compiler automatically:

# Install bacon
cargo install --locked bacon

# Run it — it watches your files and shows errors live
bacon

Every time you save a file, bacon re-runs cargo check and shows the results instantly. This makes the edit-compile cycle much faster.

An alternative is cargo-watch:

cargo install cargo-watch
cargo watch -x check

Both tools do the same thing. bacon has a nicer interface. Try both and pick the one you prefer.

Project Structure Deep Dive

After running and building, your project looks like this:

hello/
├── Cargo.toml          ← Project config
├── Cargo.lock          ← Exact dependency versions (auto-generated)
├── src/
│   └── main.rs         ← Your source code
└── target/             ← Build output (compiled binaries, don't commit)
    ├── debug/
    │   └── hello       ← Debug binary (unoptimized, fast compile)
    └── release/
        └── hello       ← Release binary (optimized, slow compile)

.gitignore

Cargo automatically creates a .gitignore that excludes target/:

/target

Never commit the target/ folder — it contains compiled binaries that can be rebuilt.

Debug vs Release

Debug (cargo build)Release (cargo build --release)
Compile speedFast (~2 seconds)Slow (~10-60 seconds)
Binary speedSlower (no optimizations)Fast (fully optimized)
Binary sizeLargerSmaller
Use forDevelopmentProduction / benchmarking

Always develop with debug builds. Only use --release when shipping or benchmarking.

Common Mistakes

Mistake 1: Forgetting to Restart Terminal

After installing Rust, your terminal doesn’t know about cargo yet:

# If you get "command not found: cargo"
source $HOME/.cargo/env
# Or just restart your terminal

Mistake 2: Missing Semicolons

// BAD — missing semicolons
fn main() {
    let x = 5
    println!("{}", x)
}

// GOOD — Rust requires semicolons at the end of statements
fn main() {
    let x = 5;
    println!("{}", x);
}

Rust requires semicolons. If you forget one, the compiler will tell you exactly where.

Mistake 3: Wrong Quotes

// BAD — single quotes are for characters, not strings
let name = 'Alex';  // ERROR: too many characters

// GOOD — double quotes for strings
let name = "Alex";

// Single quotes are for single characters
let letter = 'A';   // OK — one character

Mistake 4: Not Reading Compiler Errors

The Rust compiler has the best error messages of any language. When something goes wrong, read the error carefully — it usually tells you exactly what to fix and often suggests the correction.

error[E0384]: cannot assign twice to immutable variable `x`
 --> src/main.rs:3:5
  |
2 |     let x = 5;
  |         - first assignment
3 |     x = 10;
  |     ^^^^^^ cannot assign twice to immutable variable
  |
help: consider making this binding mutable
  |
2 |     let mut x = 5;
  |         +++

The compiler says: “You need mut to change this variable.” It even shows you where to add it. Trust the compiler.

Quick Reference

ActionCommand
Install Rustcurl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
Update Rustrustup update
New projectcargo new project_name
Runcargo run
Buildcargo build
Quick checkcargo check
Add dependencycargo add crate_name
Format codecargo fmt
Lint codecargo clippy
Run testscargo test

Source Code

The Rust tutorial project is on GitHub:

View source code on GitHub →

What’s Next?

In the next tutorial, we will learn about variables, types, and functions — the building blocks of every Rust program. You will learn about let, mut, type inference, and how functions work differently in Rust.

Next: Rust Tutorial #3: Variables, Types, and Functions