Creating a Rust Project
Cargo provides two commands for creating a new Rust project: cargo new (which creates a brand-new directory and initializes the project inside it) and cargo init (which initializes a Cargo project inside an existing directory).
Creating a Binary Project (cargo new)
By default, cargo new <project_name> creates an executable binary package (an application with a main function):
cargo new greeting_app
cd greeting_app
Creating binary (application) `greeting_app` package
note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
Inspect the generated directory layout (including hidden Git files):
greeting_app/
├── .git/ <-- Initialized Git repository
├── .gitignore <-- Ignores `/target` build directory
├── Cargo.toml <-- Package manifest
└── src/
└── main.rs <-- Application entry point
Generated Files
Cargo.toml:
[package]
name = "greeting_app"
version = "0.1.0"
edition = "2024"
[dependencies]
src/main.rs:
fn main() {
println!("Hello, world!");
}
.gitignore:
/target
Run the freshly created project immediately with cargo run:
cargo run
Compiling greeting_app v0.1.0 (/Users/username/greeting_app)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.20s
Running `target/debug/greeting_app`
Hello, world!
Creating a Library Project (cargo new --lib)
To create a reusable library crate that other programs can depend on (rather than a standalone executable), pass the --lib flag:
cargo new --lib math_utils
Creating library `math_utils` package
Instead of src/main.rs, Cargo generates src/lib.rs containing a sample function and an automated unit test:
math_utils/
├── .git/
├── .gitignore
├── Cargo.toml
└── src/
└── lib.rs <-- Library crate root (no `main` function)
src/lib.rs:
pub fn add(left: u64, right: u64) -> u64 {
left + right
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
}
Because a library has no main function, running cargo run on a library-only package produces an error (a bin target must be available for cargo run). Instead, verify a library with cargo test or cargo check:
cd math_utils
cargo test
Compiling math_utils v0.1.0 (/Users/username/math_utils)
Finished `test` profile [unoptimized + debuginfo] target(s) in 0.22s
Running unittests src/lib.rs (target/debug/deps/math_utils-a1b2c3d4e5f6)
running 1 test
test tests::it_works ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
Initializing an Existing Directory (cargo init)
If you already have an existing folder (for example, a newly cloned empty repository or a directory containing standalone .rs files), run cargo init inside that folder:
mkdir existing_folder
cd existing_folder
cargo init
Creating binary (application) package
| Command | Creates New Directory? | Behavior on Existing src/main.rs |
|---|---|---|
cargo new <path> |
Yes (fails if <path> already exists with Cargo.toml) |
Creates a new src/main.rs |
cargo init |
No (operates on current or specified directory) | Preserves any existing src/main.rs or src/lib.rs without overwriting it |
Command-Line Options for cargo new and cargo init
| Flag | Example | Description |
|---|---|---|
--bin (default) |
cargo new --bin cli |
Creates a binary executable package (src/main.rs) |
--lib |
cargo new --lib core_lib |
Creates a library package (src/lib.rs) |
--name <name> |
cargo new dir_name --name my_pkg |
Sets the package name in Cargo.toml independently of the folder name |
--edition <year> |
cargo new --edition 2024 app |
Sets the Rust edition (2015, 2018, 2021, or 2024) |
--vcs <vcs> |
cargo new --vcs none app |
Controls version control setup: git (default), hg, pijul, fossil, or none |
Note: If you create a new project inside an existing Git repository,
cargo newautomatically detects the parent.gitfolder and skips initializing a nested.gitrepository unless--vcs gitis explicitly passed.
Package Naming Rules
Package names in Cargo.toml must obey strict naming rules:
- Allowed characters: ASCII alphanumeric characters (
a–z,A–Z,0–9), hyphens (-), and underscores (_). (By convention, package names use lowercasesnake_caseorkebab-case.) - Cannot start with a digit (such as
123_app). - Cannot be a Rust reserved keyword (such as
fn,struct,self,super, ortest).
When a package name contains a hyphen (such as my-cool-lib), Cargo automatically converts hyphens to underscores (my_cool_lib) when naming the crate inside Rust source code (use my_cool_lib::*;), because - is the subtraction operator in Rust syntax.