citty
A zero-dependency, type-safe CLI framework for Node.js built on native util.parseArgs, with nested subcommands, lifecycle hooks, and a plugin system.
Repository Health
Technical Analysis
citty is a lightweight framework for building command-line interfaces in Node.js. It wraps Node’s built-in util.parseArgs instead of shipping its own argument parser, keeping the package dependency-free while still supporting typed positional, string, boolean, and enum arguments with aliases, defaults, and negation (—no-flag). Commands are defined declaratively via defineCommand, and nested subcommands can be resolved eagerly or lazily (via dynamic import) so large multi-command CLIs only load the code path that’s actually invoked.
Beyond argument parsing, citty provides a small application lifecycle: each command supports setup and cleanup hooks that run around run(), auto-generated —help/—version handling, and a plugin system (defineCittyPlugin) that composes reusable setup/cleanup behavior across commands. It’s maintained by the UnJS team and used as the CLI foundation for projects like Nuxt and Nitro tooling.
What You Get
- Declarative defineCommand API with full TypeScript inference for positional, string, boolean, and enum arguments
- Nested subcommands with eager or lazy (dynamic import) resolution for large CLIs
- Auto-generated —help and —version output, with usage text rendered directly from your argument definitions
- setup/cleanup lifecycle hooks that run around every command, including on error
- A composable plugin system (defineCittyPlugin) for sharing setup/cleanup behavior across commands
- Case-agnostic argument access — kebab-case and camelCase flag spellings both resolve to the same value
Common Use Cases
- Building a multi-command developer CLI (build/dev/lint-style subcommands) with per-command argument definitions
- Wrapping an existing Node script with typed flags, positional arguments, and auto-generated —help output
- Structuring a large CLI where each subcommand is code-split and lazily imported to keep startup fast
- Adding cross-cutting setup/teardown logic (e.g. telemetry, config loading) via a shared citty plugin
Under The Hood
Architecture The library is organized into small single-responsibility modules — command.ts for command resolution/execution, args.ts plus _parser.ts for argument parsing as a thin wrapper over node:util’s parseArgs, usage.ts for help-text rendering, plugin.ts for the plugin system, main.ts for the runMain/createMain entrypoints, and types.ts for the full type-level modeling of ArgsDef-to-ParsedArgs inference. Command execution flows through runCommand, which resolves plugins and the command’s own setup hook, recurses through resolveSubCommand/_findSubCommand to walk nested subCommands (supporting lazy Resolvable values and meta.alias lookups), invokes run(), and always executes cleanup and plugin-cleanup hooks even when run() throws, aggregating multiple cleanup errors into a single Error with a cause array. It’s a clean layered design (parsing to command resolution to execution to usage rendering) with no circular dependencies, though runCommand and resolveSubCommand duplicate similar sub-command-walking logic that could drift if one is changed without the other.
Tech Stack The package has zero runtime dependencies — its only import is Node’s built-in util.parseArgs — and uses scule, a small casing-conversion utility, only for camelCase/kebabCase/snakeCase transforms of argument names. Type-checking runs through TypeScript’s native-preview compiler (tsgo) as a dedicated test:types script, the package is ESM-only with sideEffects: false and a single export pointing at a bundled dist build produced by obuild. Linting and formatting go through oxlint/oxfmt rather than ESLint/Prettier, tests run under Vitest with v8 coverage, and CI runs lint, build, and coverage on every push before uploading to Codecov.
Code Quality Test coverage is broad — dedicated test files exercise the parser, args resolution, main entrypoint, plugin system, and usage rendering separately, mocking process.exit and console methods to assert on —help/—version/error-handling paths with table-driven tests for flag variants. Error handling is explicit and typed via a dedicated CLIError class carrying an error code (unknown command, no command specified, conflicting default/run, argument errors) rather than throwing bare errors, and cleanup-hook failures are collected and re-thrown distinctly from run-time errors instead of being silently swallowed. TypeScript strict mode is enabled with additional safety flags like noUncheckedIndexedAccess, and CI enforces lint plus type-check plus coverage on every push.
API Design citty’s core idea is deferring nearly all argument-parsing behavior to Node’s built-in parseArgs and layering a typed, declarative command/subcommand model on top of it, rather than shipping a bespoke parser the way most CLI libraries in this space do — this keeps the package genuinely dependency-free while Node’s own parser handles low-level tokenization. The declarative defineCommand API, combined with argument types that are fully inferred end-to-end from the args definition, gives strong editor autocomplete with very little boilerplate — a minimal defineCommand with just a run function is already a valid, runnable CLI. Getting started requires almost no ceremony, though the type-level machinery behind that inference is dense enough that debugging a type error in a large argument definition is non-trivial.
Used by 6 apps in this directory
Enclosed
Security
Send end-to-end encrypted notes and files where the server never sees your content — true zero-knowledge sharing.
HyperFrames
AI Development · AI Design Tools
Turn plain HTML and CSS into deterministic, pixel-perfect MP4 videos — authored by humans or AI agents, rendered by headless Chrome and FFmpeg.
likec4
Developer Tools · Devops
Define your software architecture as code and get always up-to-date, interactive C4 diagrams generated automatically from a DSL.
Mastra Code
AI Code Assistants
"A coding agent that never compacts" — a terminal-based AI coding agent built on the Mastra framework, with Observational Memory instead of context compaction, multi-model support, and OAuth login for Claude Max or ChatGPT Plus.
open-pencil
AI Design Tools · Design Tools
An open-source design editor that reads native Figma files, ships a built-in AI assistant with 100+ design tools, and offers real-time serverless collaboration — all without giving up your files.
Papra
Bookmarks Archiving
Self-hosted document archiving with email ingestion, OCR full-text search, and pluggable storage — store once, find anything.