Expert knowledge for building command-line interfaces in Rust using the clap crate. Use when creating CLI tools, parsing arguments, defining subcommands, or implementing shell completions. Covers Derive API, Builder API, custom validation, and ecosystem crates.
The standard crate for building command-line interfaces in Rust. Provides automatic help generation, shell completions, and robust argument parsing with two API styles.
///) become help text automatically#[arg(short, long)] to create both -n and --name flagsclap = { version = "4", features = ["derive"] } for Derive APIResult from main with clap handling for clean error messages#[command(subcommand)] for git-style nested commandsclap_complete for shell completion scriptsenv feature| Aspect | Derive API | Builder API |
|---|---|---|
| Approach | Declarative with structs/attributes | Imperative with method chaining |
| Ease of Use | High - minimal boilerplate | Moderate - more verbose |
| Flexibility | Covers 90% of use cases | Maximum - dynamic construction |
| Compile Time | Slightly higher (proc macros) | Lower |
| Best For | Most apps, quick prototyping | Dynamic interfaces, complex logic |
use clap::Parser;
/// Simple program to greet a person
#[derive(Parser, Debug)]
#[command(version, about)]
struct Args {
/// Name of the person to greet
#[arg(short, long)]
name: String,
/// Number of times to greet
#[arg(short, long, default_value_t = 1)]
count: u8,
}
fn main() {
let args = Args::parse();
for _ in 0..args.count {
println!("Hello, {}!", args.name);
}
}
use clap::{Arg, Command};
fn main() {
let matches = Command::new("demo")
.version("1.0")
.about("Simple program to greet a person")
.arg(Arg::new("name")
.short('n')
.long("name")
.required(true))
.arg(Arg::new("count")
.short('c')
.long("count")
.default_value("1"))
.get_matches();
let name = matches.get_one::<String>("name").expect("required");
let count: u8 = matches.get_one::<String>("count")
.unwrap().parse().expect("count should be a number");
for _ in 0..count {
println!("Hello, {}!", name);
}
}
#[derive(Parser)]
struct Args {
/// Input file (required positional)
input: String,
/// Output file (optional positional)
output: Option<String>,
/// Multiple files
files: Vec<String>,
}
#[derive(Parser)]
struct Args {
/// Named option: -n NAME or --name NAME
#[arg(short, long)]
name: String,
/// Boolean flag: -v or --verbose
#[arg(short, long)]
verbose: bool,
/// Count occurrences: -v -v -v => 3
#[arg(short, long, action = clap::ArgAction::Count)]
verbosity: u8,
}
use clap::{Parser, Subcommand};
#[derive(Parser)]
#[command(name = "git")]
struct Cli {
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand)]
enum Commands {
/// Clone a repository
Clone {
remote: String,
#[arg(short, long)]
directory: Option<String>,
},
/// Show differences
Diff {
commit1: String,
commit2: String,
},
}
fn main() {
let cli = Cli::parse();
match &cli.command {
Commands::Clone { remote, directory } => { /* ... */ }
Commands::Diff { commit1, commit2 } => { /* ... */ }
}
}
#[arg(value_parser = parse_port)]