All packages
CLI 161/mo
@munesoft/

flagx

Tiny CLI flag utility with superpowers. A has-flag alternative for Node.js with zero dependencies.

Installation

$ npm install @munesoft/flagx

Documentation

@munesoft/flagx

Tiny CLI flag utility with superpowers. A has-flag alternative that actually grows with your needs.

npm version zero dependencies size license


What is flagx?

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.

Why flagx?

| 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 |


Quick Start

bash
npm install @munesoft/flagx
js
import 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:

bash
node app.js --debug --port=3000 --no-verbose -f -abc

Examples

Boolean check (the has-flag replacement)

js
import flagx from "@munesoft/flagx";

flagx("debug");     // true/false
flagx("verbose");   // true/false
flagx("prod");      // true/false

Get a value with default

js
const port = flagx.value("port", 3000);
const host = flagx.value("host", "localhost");

Transform on read

js
const port = flagx.value("port", Number);         // → always a number
const tags = flagx.value("tag", v => v.split(",")); // → array from string

Aliases

js
flagx.alias({ p: "port", v: "verbose", h: "host" });

// Now -p 3000 and --port=3000 both work
const port = flagx.value("port");

Pick multiple flags at once

js
const { port, host, debug } = flagx.pick(["port", "host", "debug"]);

Multi-flag logic

js
flagx.hasAny(["debug", "verbose"]);    // at least one
flagx.hasAll(["port", "host"]);        // all required

Glob pattern matching

js
// Flag: --db.host=localhost --db.port=5432 --db.ssl=true
const dbFlags = flagx.match("db.*");
// → { "db.host": "localhost", "db.port": 5432, "db.ssl": true }

Grouping

js
// 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);

Merge env vars or config

js
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 config

Light validation

js
flagx.expect({
  port: "number",
  debug: "boolean",
  name: "string",
});
// Warns on type mismatch, throws in strict mode

Strict mode

js
const fx = flagx({ strict: true });
fx.expect({ port: "number" }); // throws if wrong type

Command detection

js
// $ node cli.js build --watch
const cmd = flagx.command(); // → "build"

Flag metadata

js
const meta = flagx.meta("port");
// → { exists: true, value: 3000, index: 0, raw: "--port=3000" }

Debug output (dev tool)

js
flagx.debug();
// [flagx debug] Parsed flags:
//   --port                 3000                 (number)
//   --debug                true                 (boolean)

JSON output (AI-friendly)

js
console.log(flagx.json());
// { "port": 3000, "debug": true }

API Reference

flagx(name): boolean

Check whether a flag is present and truthy. The core has-flag-style API.

js
flagx("debug"); // true/false

flagx(options): api

Configure the instance. Currently supports { strict: boolean }.

js
flagx({ strict: true });

flagx.value(name, defaultOrTransform?): any

Get a flag's value. Pass a default value or a transform function as the second argument.

js
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 transform

flagx.pick(keys[]): object

Extract multiple flags at once.

js
flagx.pick(["port", "host", "debug"]);
// → { port: 3000, host: "localhost", debug: true }

flagx.all(): object

Return all parsed flags as a plain object.

js
flagx.all(); // → { port: 3000, debug: true, ... }

flagx.hasAny(keys[]): boolean

Returns true if at least one of the keys is present and truthy.


flagx.hasAll(keys[]): boolean

Returns true only if all keys are present and truthy.


flagx.match(pattern): object

Return all flags matching a glob-style pattern (* wildcard).

js
flagx.match("db.*");     // → all --db.x flags
flagx.match("--no-*");   // → all negated flags

flagx.group(prefix): object

Return all flags under a prefix, with the prefix stripped from keys.

js
// --db.host=localhost --db.port=5432
flagx.group("db"); // → { host: "localhost", port: 5432 }

flagx.meta(name): object

Return metadata about a flag.

js
flagx.meta("port");
// → { exists: true, value: 3000, index: 0, raw: "--port=3000" }

flagx.alias(map): api

Register short-to-long aliases. Chainable.

js
flagx.alias({ p: "port", v: "verbose" });

flagx.merge(sources): api

Merge additional flag sources. CLI args always take precedence.

js
flagx.merge({ env: process.env, config: loadConfig() });

flagx.expect(schema): boolean

Validate flag types. Warns by default; throws in strict mode.

js
flagx.expect({ port: "number", debug: "boolean" });

Supported types: "boolean", "number", "string", "array"


flagx.command(): string | undefined

Returns the first positional argument (typically a subcommand).


flagx.positionals(): string[]

Returns all non-flag positional arguments.


flagx.raw(): string[]

Returns the raw argv slice (everything after node script.js).


flagx.debug(): api

Prints all parsed flags with types to stdout. Dev-only tool.


flagx.json(): string

Returns all flags as a formatted JSON string.


flagx.from(argv[]): api

Override the argv source. Useful for testing.

js
flagx.from(["--port=3000", "--debug"]);

flagx.reset(): api

Reset all state including aliases, merges, and cache.


Parsing Rules

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.


Performance

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.


Comparison

vs has-flag

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.

vs minimist

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.

vs yargs/commander

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.


FAQ

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.


Keywords

cli flag parser · nodejs argv parser · command line flags javascript · has-flag alternative · minimist alternative · argv · cli · flags · parse · args


License

MIT © Munesoft