Arguments
clif’s argument parser is fast, correct, and requires no configuration objects beyond what you need.
Basic parsing
Section titled “Basic parsing”import { parseArgs } from "@arshad-shah/clif";
const result = parseArgs({ name: { type: "string", alias: "n", description: "Your name" }, port: { type: "number", alias: "p", default: 3000 }, verbose: { type: "boolean", alias: "v" },});
result.flags.name; // stringresult.flags.port; // numberresult.flags.verbose; // booleanresult.positional; // string[] — non-flag tokensresult.rest; // string[] — everything after `--`result.unknown; // string[] — flags not defined in your schemaparseArgs defaults to process.argv.slice(2). Pass { args: [...] } only when you want to override — useful for tests, scripted invocations, or parsing a string you’ve already tokenised.
When you pass the defs as as const, the return type of result.flags.* is fully inferred — no casts needed.
Flag formats
Section titled “Flag formats”# Long flags--name alice--name=alice
# Short flags-n alice-p 8080
# Attached values (getopt-style) — value follows the flag in the same token-nalice # same as -n alice-p8080 # same as -p 8080-n=alice # an "=" separator is also accepted
# Stacked booleans-vdf # same as -v -d -f
# Stacked booleans followed by a value-taking flag-vdp8080 # same as -v -d -p 8080
# Negation — sets a known boolean flag to false--no-verbose
# Negative numbers (including scientific notation) are values, not flags--offset -5--scale -1.5e3
# Stop parsing — everything after goes into result.rest-- --not-a-flagType coercion
Section titled “Type coercion”Supported types: "string", "number", "boolean".
number— coerced viaNumber(value). An empty value (--port=) or a non-finite result throwsArgError.boolean—true/1/ empty (--flag=) →true; anything else →false. Bare--flagistrue; bare--no-flagisfalse.string— passed through verbatim. Empty values (--name=) are accepted.
Choices
Section titled “Choices”Constrain values to a set of allowed options:
parseArgs({ env: { type: "string", choices: ["dev", "staging", "prod"], default: "dev", },});Choices are validated against both user input AND any default value — a default that isn’t in choices throws immediately.
Required flags
Section titled “Required flags”parseArgs({ token: { type: "string", required: true } });// → ArgError: Missing required flag: --tokenA default does not satisfy required — the user must still pass the flag explicitly.
Repeated / array flags
Section titled “Repeated / array flags”Set multiple: true to accumulate every occurrence into an array:
const r = parseArgs( { include: { type: "string", multiple: true } }, { args: ["--include", "a", "--include", "b", "--include=c"] },);r.flags.include; // ["a", "b", "c"]Array flags work with number types and choices too. A missing array flag defaults to [].
Positional arguments
Section titled “Positional arguments”Everything that isn’t a flag or its value ends up in result.positional:
mycli build src/index.ts --minify# ^^^^^^^^^^^^^ positionalPass { stopEarly: true } to treat the first non-flag token as a hard stop — useful when delegating to a subprocess that has its own flag parser.
Named positional schema
Section titled “Named positional schema”Describe your positionals with a positionals schema to get named, typed,
validated values on result.values (the raw result.positional array is still
there too):
const r = parseArgs( {}, { args: ["build", "src", "dist"], positionals: [ { name: "command", choices: ["build", "test"] }, { name: "input", required: true }, { name: "outputs", variadic: true }, // collects the rest into an array ], },);
r.values.command; // "build"r.values.input; // "src"r.values.outputs; // ["dist"]Each PositionalDef supports type ("string" | "number"), required,
choices, variadic (collect this and all remaining tokens into an array), and
description (shown in createCLI help). A missing required positional throws
ArgError. On a command, declare positionals directly on the CommandDef and
read them from ctx.args.values — they also appear in the generated --help
usage line and an Arguments: section.
The -- separator
Section titled “The -- separator”Arguments after -- are collected in result.rest and are not parsed:
mycli --verbose -- --some-other-tool-flag# ^^^^^^^^^^^^^^^^^^^^^^^ result.restUnknown flags
Section titled “Unknown flags”By default, unknown flags collect into result.unknown so you can decide what to do:
const r = parseArgs({}, { args: ["--unknown"] });r.unknown; // ["unknown"]Pass { allowUnknown: true } to instead land them in result.flags (boolean true for bare flags, raw string for =value form).
Error handling
Section titled “Error handling”Parse errors throw ArgError with a descriptive message and the offending flag name:
import { parseArgs, ArgError } from "@arshad-shah/clif";
try { parseArgs({ port: { type: "number" } }, { args: ["--port", "abc"] });} catch (err) { if (err instanceof ArgError) { err.message; // Expected number for --port, got "abc" err.flag; // "port" }}When you use createCLI, this is handled for you — ArgErrors render with a friendly ✖ Invalid argument prefix and set process.exitCode = 1.