Rust Development Environment

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 new automatically detects the parent .git folder and skips initializing a nested .git repository unless --vcs git is 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 lowercase snake_case or kebab-case.)
  • Cannot start with a digit (such as 123_app).
  • Cannot be a Rust reserved keyword (such as fn, struct, self, super, or test).

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.