Opinionated Node CLI Toolkit
A composable, type-safe toolkit for building Node command-line apps. Define flags, args and commands separately, compose them, and get fully typed input in every command. Help pages, errors and exit codes are handled for you.
npm install jinjuRequires Node >=22.12. ESM-only; CommonJS projects can require('jinju').
import { arg, flag, jinju, scope } from 'jinju';
// Flags shared by every command created from the scope.
const base = scope({
flags: { verbose: flag.count({ alias: 'v', description: 'Increase verbosity' }) },
});
const sync = base.command({
description: 'Sync files',
args: [arg.directory({ name: 'files', description: 'Path to the files' }).required()],
flags: {
mode: flag.string({ description: 'Mode', choices: ['fast', 'safe'] }).default('safe'),
},
run: ({ args: [path], flags }) => {
// path: string, flags: { verbose: number; mode: 'fast' | 'safe' }
},
});
const app = jinju({ version: '1.0.0', commands: { sync } });
await app.run(); // reads process.argv.slice(2)$ app sync ./photos -vv --mode fast
$ app sync --help- Typed from your definitions:
runreceives exact types, such as'fast' | 'safe'orURL[] | undefined - Composable and immutable: derive
.required(),.multiple()and.default()variants, and share flags and args with scopes - Command trees: nested subcommands, aliases, variadic args and dynamic segments (
app my-site deploy), checked at compile time - Validation: numbers, URLs, emails, paths, choices, environment variables, custom parsers and any Standard Schema
- Help and errors: generated
--helppages and collected errors, both customisable - Testable: inject argv, env, stdout, stderr and the exit code
See the guide and the API reference.
© 2026 Mike Simmonds