{"id":17187,"library":"citty","title":"Citty CLI Builder","description":"citty is a modern, elegant, and highly performant CLI builder for Node.js, currently stable at version `0.2.2`. It distinguishes itself by being entirely zero-dependency since `v0.2.0`, leveraging Node.js's native `util.parseArgs` for its core argument parsing. This design choice results in a significantly reduced install size (from 267kB to 22.8kB as of `v0.2.0`) and fast execution, making it an excellent choice for lightweight command-line tools. `citty` provides a flexible and composable API that supports nested sub-commands, complete with options for lazy and asynchronous loading, which is crucial for building large-scale CLIs without incurring heavy startup costs. Recent enhancements in `v0.2.2` introduced a robust plugin system, allowing developers to extend command functionality with reusable `setup` and `cleanup` hooks. It also offers smart value parsing, type casting, boolean shortcuts, and automatically generates comprehensive usage information. The project maintains an active release cadence, frequently adding new features and addressing issues, demonstrating its ongoing development and commitment to a stable and feature-rich experience.","status":"active","version":"0.2.2","language":"javascript","source_language":"en","source_url":"https://github.com/unjs/citty","tags":["javascript","typescript"],"install":[{"cmd":"npm install citty","lang":"bash","label":"npm"},{"cmd":"yarn add citty","lang":"bash","label":"yarn"},{"cmd":"pnpm add citty","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"While CommonJS `require` might work in some setups, ESM `import` is the primary and recommended usage, especially in modern Node.js CLI projects.","wrong":"const { defineCommand } = require('citty')","symbol":"defineCommand","correct":"import { defineCommand } from 'citty'"},{"note":"This function is the entry point for executing your Citty CLI application. Ensure your main script is configured as an ESM module.","wrong":"const { runMain } = require('citty')","symbol":"runMain","correct":"import { runMain } from 'citty'"},{"note":"Introduced in `v0.2.2`, `defineCittyPlugin` is used for creating reusable command plugins. Requires `v0.2.2` or newer.","wrong":"const { defineCittyPlugin } = require('citty')","symbol":"defineCittyPlugin","correct":"import { defineCittyPlugin } from 'citty'"}],"quickstart":{"code":"import { defineCommand, runMain } from 'citty';\n\n// Define a simple command with a positional argument and an optional boolean flag\nconst mainCommand = defineCommand({\n  meta: {\n    name: 'greeter-app',\n    version: '1.0.0',\n    description: 'A simple CLI application to greet users based on arguments.'\n  },\n  args: {\n    name: {\n      type: 'positional',\n      description: 'The name of the person to greet. This argument is required.',\n      required: true,\n      valueHint: '<your-name>'\n    },\n    friendly: {\n      type: 'boolean',\n      description: 'Use a friendly greeting like \\'Hi\\' instead of \\'Greetings\\'.',\n      default: false\n    },\n    repeat: {\n      type: 'string',\n      description: 'Specify how many times to repeat the greeting.',\n      default: '1'\n    }\n  },\n  setup({ args }) {\n    console.log(`[SETUP] Initializing greeter for command: ${this.meta.name}`);\n    if (isNaN(Number(args.repeat))) {\n        console.error(\"Warning: 'repeat' argument must be a number. Defaulting to 1.\");\n        args.repeat = \"1\"; // Ensure it's a number for run()\n    }\n  },\n  async run({ args }) {\n    const greeting = args.friendly ? 'Hi' : 'Greetings';\n    const repeatCount = Number(args.repeat);\n    for (let i = 0; i < repeatCount; i++) {\n        console.log(`${greeting} ${args.name}!`);\n    }\n  },\n  cleanup({ args }) {\n    console.log(`[CLEANUP] Finished greeting ${args.name} ${args.repeat} time(s).`);\n  }\n});\n\n// Run the main command. This should be the entry point of your CLI.\n// Example usage: node cli.mjs John --friendly --repeat 3\nrunMain(mainCommand);","lang":"typescript","description":"This example demonstrates how to define a main command with positional and optional arguments, including `setup`, `run`, and `cleanup` hooks. It shows basic argument parsing and execution flow."},"warnings":[{"fix":"Review your CLI argument parsing logic, especially for edge cases or complex argument structures, if upgrading from versions prior to `v0.2.0`. This change generally simplifies the dependency graph.","message":"Starting with `v0.2.0`, citty transitioned to a zero-dependency architecture by leveraging Node.js's native `util.parseArgs`. While this significantly reduces bundle size and improves performance, it might subtly alter argument parsing behavior compared to previous versions that relied on third-party dependencies.","severity":"gotcha","affected_versions":">=0.2.0"},{"fix":"Upgrade to `v0.2.2` or higher. This version includes a fix that properly allows users to define and override these arguments within their command's `args` configuration, ensuring consistent behavior.","message":"Prior to `v0.2.2`, handling user-defined arguments for common flags like `-h`, `--help`, `-v`, and `--version` could be unreliable or lead to unexpected behavior, as citty might implicitly handle these. User-defined arguments for these specific flags were not consistently respected.","severity":"gotcha","affected_versions":"<0.2.2"},{"fix":"For full support and expected behavior of subcommand aliases, default subcommands, and the plugin system, ensure you are using `citty@0.2.2` or newer. Refactor any custom logic to utilize the new official APIs.","message":"Features such as subcommand aliases, default subcommands, and the plugin system were introduced or significantly enhanced in `v0.2.2`. Codebases relying on custom workarounds for these functionalities or attempting to use them in earlier versions might encounter errors or unexpected behavior.","severity":"gotcha","affected_versions":"<0.2.2"}],"env_vars":null,"last_verified":"2026-04-22T00:00:00.000Z","next_check":"2026-07-21T00:00:00.000Z","problems":[{"fix":"Run `npm install citty` or `yarn add citty`. Ensure your package.json `type` is set to `module` or your file uses the `.mjs` extension for ESM imports.","cause":"The `citty` package is not installed in your project, or your Node.js environment cannot resolve ESM imports correctly.","error":"Cannot find module 'citty'"},{"fix":"Ensure all required positional or named arguments are supplied on the command line. For example, if 'name' is required, run `your-cli <value_for_name>`.","cause":"A command was executed without providing a value for an argument explicitly marked as `required: true` in its definition.","error":"Error: Missing required argument: <arg_name>"},{"fix":"Either define the argument in your command's `args` object with the correct type, or remove the unknown argument from the CLI call.","cause":"The CLI received an argument or option that was not explicitly defined in the `args` configuration for the executed command or any of its subcommands.","error":"Unknown argument: --invalid-option"},{"fix":"Verify that lazy-loaded subcommands correctly return the default export of a `defineCommand` result. Ensure promises for `Resolvable<T>` types are awaited or handled correctly, particularly in `subCommands` configurations.","cause":"This often occurs when a subcommand is expected to be a `Command` object but is instead `undefined` or a `Promise` that hasn't resolved, especially with lazy loading or incorrect dynamic imports.","error":"TypeError: Cannot read properties of undefined (reading 'meta') or (reading 'run')"}],"ecosystem":"npm","meta_description":null}