clap
Build production Rust CLIs with Clap: subcommands, config layering, validation, exit codes, shell completions, and testable command surfaces
What this skill does
# Clap (Rust) - Production CLI Patterns
## Overview
Clap provides declarative command-line parsing with strong help output, validation, and subcommand support. Use it to build CLIs with predictable UX and testable execution paths.
## Quick Start
### Minimal CLI
✅ **Correct: derive Parser**
```rust
use clap::Parser;
#[derive(Parser, Debug)]
#[command(name = "mytool", version, about = "Example CLI")]
struct Args {
/// Enable verbose output
#[arg(long)]
verbose: bool,
/// Input file path
#[arg(value_name = "FILE")]
input: String,
}
fn main() {
let args = Args::parse();
if args.verbose {
eprintln!("verbose enabled");
}
println!("input={}", args.input);
}
```
❌ **Wrong: parse multiple times**
```rust
fn main() {
let _a = Args::parse();
let _b = Args::parse(); // duplicate parsing and inconsistent behavior
}
```
## Subcommands (real tools)
Model multi-mode CLIs with subcommands and shared global flags.
✅ **Correct: global flags + subcommands**
```rust
use clap::{Parser, Subcommand, ValueEnum};
#[derive(Parser, Debug)]
struct Args {
#[arg(long, global = true)]
verbose: bool,
#[arg(long, global = true, env = "MYTOOL_CONFIG")]
config: Option<String>,
#[command(subcommand)]
cmd: Command,
}
#[derive(Subcommand, Debug)]
enum Command {
Serve { #[arg(long, default_value_t = 3000)] port: u16 },
Migrate { #[arg(long, value_enum, default_value_t = Mode::Up)] mode: Mode },
}
#[derive(Copy, Clone, Debug, ValueEnum)]
enum Mode { Up, Down }
fn main() {
let args = Args::parse();
match args.cmd {
Command::Serve { port } => println!("serve on {}", port),
Command::Migrate { mode } => println!("migrate: {:?}", mode),
}
}
```
## Config layering (CLI + env + config file)
Prefer explicit precedence:
1. CLI flags
2. Environment variables
3. Config file
4. Defaults
✅ **Correct: merge config with CLI overrides**
```rust
use clap::Parser;
use serde::Deserialize;
#[derive(Parser, Debug)]
struct Args {
#[arg(long, env = "APP_PORT")]
port: Option<u16>,
}
#[derive(Deserialize)]
struct FileConfig {
port: Option<u16>,
}
fn effective_port(args: &Args, file: &FileConfig) -> u16 {
args.port.or(file.port).unwrap_or(3000)
}
```
## Exit codes and error handling
Map failures to stable exit codes. Return `Result` from command handlers and centralize printing.
✅ **Correct: command returns Result**
```rust
use std::process::ExitCode;
fn main() -> ExitCode {
match run() {
Ok(()) => ExitCode::SUCCESS,
Err(e) => {
eprintln!("{e}");
ExitCode::from(1)
}
}
}
fn run() -> Result<(), String> {
Ok(())
}
```
## Testing (assert_cmd)
Test the binary surface (arguments, output, exit codes) without coupling to internals.
✅ **Correct: integration test**
```rust
use assert_cmd::Command;
#[test]
fn shows_help() {
Command::cargo_bin("mytool")
.unwrap()
.arg("--help")
.assert()
.success();
}
```
## Shell completions (optional)
Generate completions for Bash/Zsh/Fish.
✅ **Correct: emit completions**
```rust
use clap::{CommandFactory, Parser};
use clap_complete::{generate, shells::Zsh};
use std::io;
fn print_zsh_completions() {
let mut cmd = super::Args::command();
generate(Zsh, &mut cmd, "mytool", &mut io::stdout());
}
```
## Anti-Patterns
- Parse arguments in library code; parse once in `main` and pass a typed config down.
- Hide failures behind `unwrap`; return stable exit codes and structured errors.
- Overload one command with flags; use subcommands for distinct modes.
## Resources
- Clap: https://docs.rs/clap
- assert_cmd: https://docs.rs/assert_cmd
- clap_complete: https://docs.rs/clap_complete
Related in toolchain
nextjs-core
IncludedCore Next.js patterns for App Router development including Server Components, Server Actions, route handlers, data fetching, and caching strategies
nextjs-v16
IncludedNext.js 16 migration guide (async request APIs, "use cache", Turbopack)
vitest
IncludedVitest - Modern TypeScript testing framework with Vite-native performance, ESM support, and TypeScript-first design
mcp-protocol-builder
IncludedMCP (Model Context Protocol) - Build AI-native servers with tools, resources, and prompts. TypeScript/Python SDKs for Claude Desktop integration.
golang-database-patterns
IncludedGo database integration patterns using sqlx, pgx, and migration tools like golang-migrate
sveltekit
IncludedSvelteKit - Full-stack Svelte framework with file-based routing, SSR/SSG, form actions, and adapters for deployment