cargo new is the command-line tool for creating new Rust projects. It’s the foundational step for any new Rust development, setting up a basic project structure that adheres to Rust’s conventions.
Let’s see cargo new in action. Imagine you want to start a new binary project called my_awesome_app. You’d open your terminal and type:
cargo new my_awesome_app
This single command creates a new directory named my_awesome_app with the following structure:
my_awesome_app/
├── Cargo.toml
└── src/
└── main.rs
Cargo.toml is the manifest file for your project. It contains metadata about your project, such as its name, version, authors, and dependencies. src/main.rs is the main entry point for your application, containing a simple "Hello, world!" program by default.
If you wanted to create a library instead of a binary, you’d use the --lib flag:
cargo new my_awesome_library --lib
This would result in a similar directory structure, but src/main.rs would be replaced by src/lib.rs, which is the standard entry point for Rust libraries.
my_awesome_library/
├── Cargo.toml
└── src/
└── lib.rs
The beauty of cargo new lies in its opinionated approach. It enforces a standard project layout, which makes it incredibly easy for Rust developers to navigate and understand each other’s projects. When you run cargo build or cargo run within your project directory, Cargo knows exactly where to find your source code and how to compile it.
Cargo.toml is where you declare your project’s dependencies. For example, to add the serde crate for serialization and deserialization, you’d add it under the [dependencies] section:
[package]
name = "my_awesome_app"
version = "0.1.0"
edition = "2021"
[dependencies]
serde = { version = "1.0", features = ["derive"] }
When you first run cargo build, Cargo will download serde and all of its transitive dependencies from crates.io (the official Rust package registry) and compile them for your project.
The default src/main.rs looks like this:
fn main() {
println!("Hello, world!");
}
And src/lib.rs looks like this:
fn add(left: usize, right: usize) -> usize {
left + right
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
}
Notice that the library template includes a basic test. This highlights another convention: tests are colocated with the code they test, either in a tests module within the same file or in a separate tests/ directory for integration tests.
The edition field in Cargo.toml is crucial. It specifies which Rust edition your project uses. Editions are a way for Rust to introduce new language features without breaking existing code. For example, Rust 2015, Rust 2018, and Rust 2021 are different editions. Newer editions typically offer more convenience and safety features. When you create a new project with cargo new, it defaults to the latest stable edition.
When you create a project with cargo new, Cargo also automatically initializes a Git repository for you if you have Git installed. This is a subtle but incredibly useful feature, as version control is an integral part of modern software development. You’ll find a .git/ directory created alongside your project files, ready for you to start committing your changes.
If you’re working on a project that’s part of a larger workspace, you can use cargo new --bin --path <relative_path> or cargo new --lib --path <relative_path> to create a new crate within an existing workspace. This allows you to manage multiple related crates under a single Cargo.toml at the workspace root.
The most surprising thing about cargo new is that it doesn’t just create files; it creates a convention. This convention is so universally adopted that you can often jump into any Rust project and immediately understand its structure, where to find the main logic, where dependencies are declared, and how tests are organized, all without explicit documentation. This shared understanding dramatically speeds up collaboration and onboarding.
After creating a project with cargo new, the next logical step is to add dependencies and start writing your application logic, which will eventually lead to exploring Cargo’s build profiles and optimization flags.