Tiny CLI flag utility with superpowers. A has-flag alternative that actually grows with your needs.
flagx is a modern Node.js argv parser — a cli flag parser and has-flag alternative — designed to be the last flag utility you'll ever need. It's tiny, fast, and zero-dependency, but covers everything from simple boolean checks to advanced grouped flags, aliasing, type inference, and validation.
Most tools are either too simple (has-flag — booleans only) or too heavy (minimist, yargs — full parsers with baggage). flagx sits in the middle: a tiny utility that punches way above its weight class.
Simple boolean check? → One line.
Need a port number? → One line.
DB config group? → One line.
Light validation? → One line.
| Feature | has-flag |
minimist |
flagx |
|---|---|---|---|
| Boolean flags | ✅ | ✅ | ✅ |
| Value extraction | ❌ | ✅ | ✅ |
| Type inference | ❌ | ✅ | ✅ |
| Aliases | ❌ | ✅ | ✅ |
| Glob pattern matching | ❌ | ❌ | ✅ |
| Flag grouping | ❌ | ❌ | ✅ |
| Merge env/config | ❌ | ❌ | ✅ |
| Lazy + cached parse | ❌ | ❌ | ✅ |
| Light validation | ❌ | ❌ | ✅ |
| Zero dependencies | ✅ | ✅ | ✅ |
| Bundle size | ~0.1KB | ~3KB | <2KB |
npm install @munesoft/flagximport flagx from "@munesoft/flagx";
// That's it. One line.
if (flagx("debug")) {
console.log("debug mode on");
}Works with all standard flag styles out of the box:
node app.js --debug --port=3000 --no-verbose -f -abcimport flagx from "@munesoft/flagx";
flagx("debug"); // true/false
flagx("verbose"); // true/false
flagx("prod"); // true/falseconst port = flagx.value("port", 3000);
const host = flagx.value("host", "localhost");const port = flagx.value("port", Number); // → always a number
const tags = flagx.value("tag", v => v.split(",")); // → array from stringflagx.alias({ p: "port", v: "verbose", h: "host" });
// Now -p 3000 and --port=3000 both work
const port = flagx.value("port");const { port, host, debug } = flagx.pick(["port", "host", "debug"]);flagx.hasAny(["debug", "verbose"]); // at least one
flagx.hasAll(["port", "host"]); // all required// Flag: --db.host=localhost --db.port=5432 --db.ssl=true
const dbFlags = flagx.match("db.*");
// → { "db.host": "localhost", "db.port": 5432, "db.ssl": true }// Flag: --db.host=localhost --db.port=5432
const db = flagx.group("db");
// → { host: "localhost", port: 5432 }
// Perfect for connecting to a database:
const client = new DB(db);flagx.merge({
env: process.env,
config: { port: 3000, host: "localhost" },
});
// CLI flags always win. Env and config fill in gaps.
const port = flagx.value("port"); // from CLI, env, or configflagx.expect({
port: "number",
debug: "boolean",
name: "string",
});
// Warns on type mismatch, throws in strict modeconst fx = flagx({ strict: true });
fx.expect({ port: "number" }); // throws if wrong type// $ node cli.js build --watch
const cmd = flagx.command(); // → "build"const meta = flagx.meta("port");
// → { exists: true, value: 3000, index: 0, raw: "--port=3000" }flagx.debug();
// [flagx debug] Parsed flags:
// --port 3000 (number)
// --debug true (boolean)console.log(flagx.json());
// { "port": 3000, "debug": true }Check whether a flag is present and truthy. The core has-flag-style API.
flagx("debug"); // true/falseConfigure the instance. Currently supports { strict: boolean }.
flagx({ strict: true });Get a flag's value. Pass a default value or a transform function as the second argument.
flagx.value("port"); // raw value or undefined
flagx.value("port", 3000); // with default
flagx.value("port", Number); // transform: coerce to number
flagx.value("host", v => `http://${v}`); // arbitrary transformExtract multiple flags at once.
flagx.pick(["port", "host", "debug"]);
// → { port: 3000, host: "localhost", debug: true }Return all parsed flags as a plain object.
flagx.all(); // → { port: 3000, debug: true, ... }Returns true if at least one of the keys is present and truthy.
Returns true only if all keys are present and truthy.
Return all flags matching a glob-style pattern (* wildcard).
flagx.match("db.*"); // → all --db.x flags
flagx.match("--no-*"); // → all negated flagsReturn all flags under a prefix, with the prefix stripped from keys.
// --db.host=localhost --db.port=5432
flagx.group("db"); // → { host: "localhost", port: 5432 }Return metadata about a flag.
flagx.meta("port");
// → { exists: true, value: 3000, index: 0, raw: "--port=3000" }Register short-to-long aliases. Chainable.
flagx.alias({ p: "port", v: "verbose" });Merge additional flag sources. CLI args always take precedence.
flagx.merge({ env: process.env, config: loadConfig() });Validate flag types. Warns by default; throws in strict mode.
flagx.expect({ port: "number", debug: "boolean" });Supported types: "boolean", "number", "string", "array"
Returns the first positional argument (typically a subcommand).
Returns all non-flag positional arguments.
Returns the raw argv slice (everything after node script.js).
Prints all parsed flags with types to stdout. Dev-only tool.
Returns all flags as a formatted JSON string.
Override the argv source. Useful for testing.
flagx.from(["--port=3000", "--debug"]);Reset all state including aliases, merges, and cache.
flagx supports every common CLI flag syntax:
| Input | Result |
|---|---|
--flag |
true |
--flag=true |
true (boolean) |
--flag=false |
false (boolean) |
--no-flag |
false |
--key=value |
"value" (string) |
--port=3000 |
3000 (number) |
-f |
true |
-abc |
a=true, b=true, c=true |
-p 3000 |
p=3000 |
--flag --flag |
[true, true] (array) |
-- |
stop parsing (rest → positionals) |
Note on space-separated values: For long flags (--key value), flagx only greedily consumes the next token when it's a typed value (number or boolean). For string values, use --key=value syntax. Short flags (-p value) always consume the next token.
flagx is built around two core principles:
Lazy parsing — argv is never touched until the first API call.
Single parse — the result is cached after the first call. Every subsequent call — flagx("x"), flagx.value("y"), flagx.all() — uses the same cached object.
100 × 1000-flag parses: ~38ms
Cached access: ~0ms
This makes flagx safe to call anywhere — top of a file, in hot paths, conditionally — with no performance penalty.
has-flag does one thing: checks if a flag string exists in process.argv. No values, no types, no aliases. flagx replaces it with a superset that's still a one-liner.
minimist is a capable parser but is heavier (~3KB), older, and doesn't offer grouping, pattern matching, lazy parsing, merge sources, or built-in validation. flagx weighs less and does more.
These are full CLI frameworks: help generation, command routing, middleware. If you're building a complex CLI application, they're worth it. If you just need to read flags in a script, a library, or a build tool, flagx is the right weight.
Does flagx work in CommonJS?
Currently ESM-only (type: "module"). A CJS build can be added if needed.
Does it handle process.argv automatically?
Yes. By default it reads process.argv.slice(2). Use flagx.from([...]) to override.
Can I use it in a library (not a CLI)?
Yes. Use flagx.from(argv) with a passed-in array rather than process.argv.
Is the parse result mutable?
flagx.all() returns a shallow copy. The internal cache is not exposed directly.
What about Windows-style /flag syntax?
Not supported — flagx follows the POSIX/GNU convention used by Node.js ecosystem tools.
cli flag parser · nodejs argv parser · command line flags javascript · has-flag alternative · minimist alternative · argv · cli · flags · parse · args
MIT © Munesoft