git, docker, and npm.
When to Use Multi-Command Pattern
Use this pattern when your CLI:- Provides multiple related operations
- Needs a clean namespace for different actions
- Benefits from command-specific help
git commit, docker build, npm install
Creating a Router CLI
cli
.command('status', {
description: 'Show repo status',
run() {
return { clean: true }
},
})
.command('install', {
description: 'Install a package',
args: z.object({
package: z.string().optional().describe('Package name'),
}),
options: z.object({
saveDev: z.boolean().optional().describe('Save as dev dependency'),
}),
alias: { saveDev: 'D' },
run(c) {
return { added: 1, packages: 451 }
},
})
.serve()
Command Organization
Each command is self-contained with its own args, options, and handler:Help Text Generation
Help is automatically generated for the router and each command.Router Help
Command-Specific Help
Multiple Arguments Per Command
Each command can have its own argument schema:Complete Multi-Command Example
Here’s a complete package manager CLI:Usage Examples
Type Safety
All arguments and options are fully typed:The
.command() method returns the same CLI instance, so you can chain as many commands as you need. The type system tracks all registered commands for features like CTAs.Router vs Single-Command
| Feature | Router (no run) | Single-Command (with run) |
|---|---|---|
| Subcommands | ✓ Yes | ✗ No |
| Root handler | ✗ No | ✓ Yes |
| Use case | Multi-purpose tool | Single-purpose utility |
| Help format | Lists commands | Shows usage |
| Example | git, docker | grep, curl |

