Baike.dev
All toolsOnline toolsAI codingTrendingOpen sourceNewsSubmit
Log in
< Back to tools
C

citty

> 编程语言
Open source

Elegant CLI Builder

1.3K stars0 likes0 views
WebsiteGitHub

About

Elegant CLI Builder

citty

Elegant CLI Builder

  • Zero dependency, fast and lightweight (based on native util.parseArgs)
  • Smart value parsing with typecast and boolean shortcuts
  • Nested sub-commands with lazy and async loading
  • Pluggable and composable API with auto generated usage

Usage

bash
npx nypm add -D citty
…
bash
node index.mjs john
# Greetings john!

Sub Commands

Sub commands can be nested recursively. Use lazy imports for large CLIs to avoid loading all commands at once.

javascript
import { defineCommand, runMain } from "citty";

const sub = defineCommand({
  meta: { name: "sub", description: "Sub command" },
  args: {
    name: { type: "positional", description: "Your name", required: true },
  },
  run({ args }) {
    console.log(`Hello ${args.name}!`);
  },
});

const main = defineCommand({
  meta: { name: "hello", version: "1.0.0", description: "My Awesome CLI App" },
  subCommands: { sub },
});

runMain(main);

Subcommands support meta.alias (e.g., ["i", "add"]) and meta.hidden: true to hide from help output.

Lazy Commands

For large CLIs, lazy load sub commands so only the executed command is imported:

javascript
const main = defineCommand({
  meta: { name: "hello", version: "1.0.0", description: "My Awesome CLI App" },
  subCommands: {
    sub: () => import("./sub.mjs").then((m) => m.default),
  },
});

meta, args, and subCommands all accept Resolvable values — a value, Promise, function, or async function — enabling lazy and dynamic resolution.

Hooks

Commands support setup and cleanup functions called before and after run(). Only the executed command's hooks run. cleanup always runs, even if run() throws.

javascript
const main = defineCommand({
  meta: { name: "hello", version: "1.0.0", description: "My Awesome CLI App" },
  setup() {
    console.log("Setting up...");
  },
  cleanup() {
    console.log("Cleaning up...");
  },
  run() {
    console.log("Hello World!");
  },
});

Plugins

Plugins extend commands with reusable setup and cleanup hooks:

javascript
import { defineCommand, defineCittyPlugin, runMain } from "citty";

const logger = defineCittyPlugin({
  name: "logger",
  setup({ args }) {
    console.log("Logger setup, args:", args);
  },
  cleanup() {
    console.log("Logger cleanup");
  },
});

const main = defineCommand({
  meta: { name: "hello", description: "My CLI App" },
  plugins: [logger],
  run() {
    console.log("Hello!");
  },
});

runMain(main);

Plugin setup hooks run before the command's setup (in order), cleanup hooks run after (in reverse). Plugins can be async or factory functions.

Arguments

Argument Types

Type Description Example
positional Unnamed positional args cli
string Named string options --name value
boolean Boolean flags, supports --no- negation --verbose
enum Constrained to options array --level=info|warn|error

Common Options

Option Description
description Help text shown in usage output
required Whether the argument is required
default Default value when not provided
alias Short aliases (e.g., ["f"]). Not for positional
valueHint Display hint in help (e.g., "host" renders --name=)

Example

javascript
const main = defineCommand({
  args: {
    name: { type: "positional", description: "Your name", required: true },
    friendly: { type: "boolean", description: "Use friendly greeting", alias: ["f"] },
    greeting: { type: "string", description: "Custom greeting", default: "Hello" },
    level: {
      type: "enum",
      description: "Log level",
      options: ["debug", "info", "warn", "error"],
      default: "info",
    },
  },
  run({ args }) {
    console.log(`${args.greeting} ${args.name}! (level: ${args.level})`);
  },
});

Boolean Negation

Boolean args support --no- prefix. The negative variant appears in help when default: true or negativeDescription is set.

Case-Agnostic Access

Kebab-case args can be accessed as camelCase: args["output-dir"] and args.outputDir both work.

Built-in Flags

--help / -h and --version / -v are handled automatically. Disabled if your command defines args with the same names or aliases.

API

Function Description
defineCommand(def) Type helper for defining commands
runMain(cmd, opts?) Run a command with usage support and graceful error handling
createMain(cmd) Create a wrapper that calls runMain when invoked
runCommand(cmd, opts) Parse args and run command/sub-commands; access result from return value
parseArgs(rawArgs, argsDef) Parse input arguments and apply defaults
renderUsage(cmd, parent?) Render command usage to a string
showUsage(cmd, parent?) Render usage and print to console
defineCittyPlugin(def) Type helper for defining plugins

Development

  • Clone this repository
  • Install latest LTS version of Node.js
  • Enable Corepack using corepack enable
  • Install dependencies using pnpm install
  • Run interactive tests using pnpm dev

License

Made with Published under MIT License.

Issues· 0 open

View all issuesOpen on GitHub

No open issues yet, or sync has not completed.

> Tags

TypeScript

No comments yet. Be the first to share.

> Details

PublishedAug 1, 2026
UpdatedSep 17, 2026
Category编程语言
PricingOpen source

> Related tools

T
TypeScript
JavaScript 的超集,为前端与全栈提供静态类型
P
Python
通用编程语言,广泛用于 Web、数据与 AI
G
Go
Google 推出的简洁高效系统语言