FAQ
Why do I need a coerce function?
Terminal input is always a string. coerce converts it to whatever your schema expects.
You can skip it when the schema expects a string. Using one that produces the wrong type is a TypeScript error. You cannot get it silently wrong.
See Coerce helpers.
Which validation library can I use?
Any library that implements Standard Schema and lets primitive types be optional or carry a default value. Zod, Valibot, Sury, and Decoders all qualify.
See Using schemas.
How do I see the raw input?
Every handler receives a context with an entry per option and argument: where the value came from, and the exact strings the user typed.
cli.onExecute(({ context }) => { const option = context.options.someOption;
if (option.source === "terminal") { console.log(option.flag, option.stringValues); }});See Context.
What is the difference between typed arguments and positionals?
Typed arguments are declared, ordered, and validated. Positionals are whatever is left over, always plain strings.
| Typed arguments | Positionals | |
|---|---|---|
| Validation | Against the schema | None |
| Type | Whatever the schema produces | Always string |
| Order | Filled left to right | Everything that is left |
| Optional / default | Controlled by the schema | Never optional, never has defaults |
See Positionals.
Can an option hold a nested object?
Yes, with coerce.object. Users can pass a full JSON string or set fields one at a time with dotted flags.
example --db.host=prod-db --db.port=3306example --db '{"host":"prod-db","port":3306}'See Object options.
Can an option be passed more than once?
Yes, when its coerce produces an array or a set. Each occurrence is coerced on its own, and the results are merged before validation. Separators and repetition mix freely.
example --tags a,b # ["a", "b"]example --tags a --tags b # ["a", "b"]example --tags a,b --tags c # ["a", "b", "c"]Repeating anything else fails with ValidationErrorCode.OptionNotRepeatable.
See Repeatable options.
How does --no-flag work?
A boolean flag is true when it appears. The --no- prefix inverts the final value, including one that you assigned yourself.
--verbose true--no-verbose false--no-verbose=true falseSee Boolean flags.
Is there a built-in --help?
No. Define a help option and print the message yourself. That way you decide when it appears.
See Help messages.
Why is my error not in result.error?
result.error only carries parsing and validation errors. Anything your handler throws propagates to the caller. With an async handler, use runAsync so the rejection is awaited.
See Errors.
Does it work in the browser?
Yes. Load it from a CDN and pass run a string instead of an argv array.
See Loading from a CDN.