Register composable before/after hooks with cli.use(). Middleware executes in registration order, onion-style—each calls await next() to proceed to the next middleware or the command handler.
Basic Middleware
Use middleware for cross-cutting concerns like timing, logging, or auth:
Output
Middleware Context
Middleware receives a context object with metadata:
Output
Context Properties
| Property | Type | Description |
|---|
c.name | string | The CLI name |
c.command | string | The resolved command path |
c.version | string | undefined | CLI version |
c.agent | boolean | Whether stdout is not a TTY |
c.env | object | Parsed environment variables |
c.var | object | Variables set by upstream middleware |
c.set(key, value) | function | Set a typed variable |
c.error(opts) | function | Return an error result |
Authentication Middleware
Short-circuit the chain by returning early:
Output
Dependency Injection with Variables
Declare a vars schema to enable typed variables. Middleware sets them with c.set(), and both middleware and command handlers read them via c.var:
Output
Default Values
Use .default() for variables that don’t need middleware:
Per-Command Middleware
Run middleware only for specific commands:
Output
Per-command middleware runs after root and group middleware.
Error Handling
Middleware can handle errors from downstream middleware or commands:
Structured Errors
Return structured errors with error codes:
Output
Structured errors show up in the output envelope with code and retryable flag.
Throwing Errors
Throwing also works and produces an UNKNOWN error code:
Typed Middleware
Use the middleware() helper for full type safety:
Environment Variables
Access parsed environment variables in middleware:
Environment variables are validated once at startup before any middleware runs.
Middleware Order
Middleware executes in an onion pattern:
Output
Execution Order
- Root CLI middleware (in registration order)
- Group CLI middleware (if mounted)
- Per-command middleware (if defined)
- Command
run handler
Source Code
The middleware implementation is in src/middleware.ts:
Use middleware for cross-cutting concerns like auth, logging, and timing. Use variables (c.var and c.set()) for type-safe dependency injection.