Benchmark

Feature comparison between Click Extra and competing CLI frameworks across ecosystems. The tables below track where Click Extra leads, where it matches, and where it can still improve.

Every cell links to its evidence. A ✅ marks support built in, on by default or behind one documented switch, and links its documentation or source line. A 🟡 marks partial or opt-in support, or support from an official companion package, and links the proof. A ❌ links a statement that rules the feature out: a maintainer’s refusal, a feature request left open, a documented limit. A blank cell means no citable source was found either way, and N/A marks a row that does not apply to the framework. A row label links to click-extra’s documentation of the feature.

Developer experience

click-extra reads TOML, YAML, JSON, INI, and XML config files, including [tool.*] sections from pyproject.toml and remote URLs. Config-file precedence is layered through Click’s default_map, so command-line flags and environment variables always win. The strict-check pipeline ships an extension mechanism so apps can validate data-keyed sub-tables alongside click-extra’s own CLI-flag checks. cobra achieves similar coverage through Viper (YAML, TOML, JSON, HCL, INI, env vars). Cyclopts supports TOML, YAML, JSON, and env vars. Cement uses INI by default with YAML and JSON via extensions. clap requires a companion crate for config file support.

End-user experience

click-extra’s colored help uses a theme system with semantic highlighting for options, choices, metavars, defaults, env vars, and subcommand names. Seven built-in themes ship out of the box (dark, light, dracula, monokai, nord, solarized-dark, plus a monochrome manpage); users can override any slot of an existing palette or define brand-new themes directly in the CLI’s --config file ([tool.<cli>.themes.<name>]), with overrides scoped per-invocation so concurrent runs in the same process don’t bleed into each other. A machine-wide CLICK_EXTRA_THEME variable, or the per-CLI <CLI>_THEME Click derives, picks a palette without touching either. cobra’s help is plain text. Cyclopts uses Rich for formatted help output and ships a single style. rich-click also renders through Rich and ships over a hundred themes, which end users select with the RICH_CLICK_THEME variable or its wrapper’s own flag, but a custom palette is declared in Python rather than in the wrapped CLI’s configuration file, and it has no background-detection equivalent of --theme=auto. Shell completion in Click and click-extra covers command names, option names and values in bash, zsh and fish, with no installer. click-extra also offers --params, --time, --table-format and git-aware --version out of the box, and an opt-in --telemetry/--no-telemetry.

Parser flag scoping

Behavior when placing global flags before vs. after a subcommand:

Framework

Global flags before subcommand

click-extra

✅

Click[1]

✅

Cloup[2]

✅

cobra[3]

✅

Fire[4]

🟡

Typer[5]

✅

clap[6]

✅

Cement[7]

✅

Cyclopts[8]

✅

Tyro[9]

✅

rich-click[10]

✅

bpaf[11]

✅

Every framework accepts a parent command’s flags before the subcommand. Fire gets 🟡 because a bare boolean flag there takes the subcommand name as its value. The clig.dev table covers the other position: Click, and the frameworks built on it, reject a parent’s flags after the subcommand.

clig.dev guidelines

The Command Line Interface Guidelines are an open-source guide to command-line design. The table grades each framework against the 50 guidelines a framework can implement, out of the guide’s 96. The other 46 are advice on what an app prints and how it behaves, listed below the table.

Graded in October 2026 from source code and probes of minimal apps, against click-extra 9.4.1, Click 8.5.0, Cloup 4.0.0, cobra 1.10.2, Fire 0.7.1, Typer 0.27.2, clap 4.6.7, Cement 3.0.16, Cyclopts 5.1.1, Tyro 1.0.16, rich-click 1.9.9 and bpaf 0.9.28.

Guideline ↴ \ Framework →

click-extra

Click[1]

Cloup[2]

cobra[3]

Fire[4]

Typer[5]

clap[6]

Cement[7]

Cyclopts[8]

Tyro[9]

rich-click[10]

bpaf[11]

The basics

Non-zero exit code on failure

✅

✅

✅

🟡

✅

✅

✅

✅

✅

✅

✅

✅

Help and version on stdout

✅

✅

✅

✅

❌

✅

✅

✅

✅

✅

✅

✅

Errors on stderr

✅

✅

✅

✅

✅

✅

✅

✅

✅

✅

✅

✅

Help

--help on every subcommand

✅

✅

✅

✅

✅

✅

✅

✅

✅

✅

✅

✅

Concise help when arguments are missing

✅

✅

✅

✅

✅

✅

✅

✅

✅

✅

✅

✅

Both -h and --help

✅

🟡

🟡

✅

🟡

🟡

✅

✅

✅

✅

🟡

✅

Support link in help

🟡

🟡

🟡

🟡

🟡

🟡

🟡

🟡

🟡

🟡

🟡

🟡

Docs link in help

🟡

🟡

🟡

🟡

🟡

🟡

🟡

🟡

🟡

🟡

🟡

🟡

Examples section

✅

🟡

🟡

✅

🟡

🟡

🟡

🟡

🟡

🟡

🟡

🟡

Grouped or ordered help entries

✅

🟡

✅

✅

🟡

✅

✅

🟡

✅

✅

✅

✅

Formatted help

✅

❌

🟡

❌

✅

✅

✅

🟡

✅

✅

✅

🟡

Typo suggestions

✅

✅

✅

🟡

✅

✅

✅

🟡

✅

✅

Help instead of waiting on a TTY stdin

Documentation

Web docs generation

✅

❌

✅

❌

✅

❌

❌

✅

🟡

✅

help subcommand

✅

✅

✅

❌

🟡

❌

Man page generation

✅

❌

✅

🟡

❌

✅

Output

Machine-readable output

✅

🟡

🟡

🟡

🟡

❌

❌

🟡

🟡

🟡

--plain tabular output

✅

🟡

❌

--json output

✅

🟡

❌

Color off: no TTY, NO_COLOR, --no-color

✅

🟡

🟡

N/A

🟡

🟡

🟡

🟡

🟡

🟡

🟡

🟡

No animation without a TTY

✅

✅

✅

N/A

N/A

✅

N/A

N/A

N/A

N/A

✅

N/A

Pager

✅

✅

✅

❌

✅

❌

❌

✅

Errors

Readable usage errors

✅

✅

✅

✅

🟡

✅

✅

✅

✅

✅

✅

✅

Traceback behind a debug switch

🟡

Bug report helper

✅

❌

🟡

Arguments and flags

Long flag names

✅

✅

✅

✅

✅

✅

✅

✅

✅

✅

✅

✅

No auto-generated short flags

✅

✅

✅

✅

❌

✅

✅

✅

✅

✅

✅

✅

Variadic arguments

✅

✅

✅

✅

✅

✅

✅

✅

✅

✅

✅

✅

Standard flags beyond --help

✅

🟡

🟡

🟡

🟡

🟡

🟡

🟡

🟡

🟡

🟡

✅

Prompt for missing values

✅

✅

✅

❌

✅

❌

🟡

❌

❌

✅

Prompts bypassable by flags

✅

✅

✅

N/A

N/A

✅

N/A

N/A

N/A

✅

N/A

Confirmation with a --yes bypass

✅

✅

✅

❌

🟡

❌

🟡

❌

✅

- for stdin and stdout

✅

✅

✅

❌

✅

❌

✅

✅

✅

Parent flags after the subcommand

❌

❌

❌

✅

✅

❌

✅

❌

✅

✅

✅

Interactivity

No prompt when stdin is not a TTY

N/A

N/A

N/A

N/A

N/A

N/A

--no-input

N/A

N/A

N/A

N/A

N/A

N/A

Hidden password input

✅

✅

✅

N/A

N/A

✅

N/A

✅

N/A

N/A

✅

N/A

Robustness

Input validation

✅

✅

✅

🟡

🟡

✅

✅

✅

✅

✅

✅

🟡

Hello world --help under 100 ms

🟡

✅

✅

✅

✅

✅

✅

✅

🟡

✅

✅

✅

Progress bar or spinner

✅

✅

✅

✅

❌

✅

Future-proofing

Deprecation warnings

✅

✅

✅

✅

🟡

❌

🟡

🟡

✅

❌

Explicit aliases, no prefix matching

✅

🟡

✅

✅

🟡

🟡

✅

✅

✅

✅

✅

✅

Signals

Clean Ctrl-C exit

✅

✅

✅

✅

✅

✅

🟡

✅

✅

✅

Configuration

XDG config location

🟡

🟡

🟡

❌

🟡

❌

🟡

❌

🟡

Flags, then env vars, then config files

✅

🟡

🟡

🟡

❌

🟡

🟡

🟡

✅

🟡

🟡

🟡

Environment variables

Auto-named env vars

✅

✅

✅

🟡

❌

✅

🟡

🟡

🟡

❌

✅

🟡

General-purpose env vars

✅

🟡

🟡

🟡

🟡

🟡

🟡

✅

✅

🟡

🟡

🟡

.env loading

🟡

Distribution

Single binary

🟡

🟡

🟡

✅

✅

❌

🟡

✅

Analytics

Telemetry consent switch

✅

Total ✅ / 🟡

39 / 5

23 / 13

25 / 12

20 / 11

10 / 12

23 / 13

20 / 9

16 / 18

21 / 9

16 / 9

26 / 12

20 / 9

click-extra prints JSON and plain tables through the json and plain values of its --table-format option.

No framework skips prompts when stdin is not a TTY, accepts --no-input, or shows help instead of waiting on a terminal stdin. No framework puts a support or documentation link in the help on its own either: all of them leave it to free-form epilog text.

The 46 guidelines left out
  • The basics: use an argument-parsing library, which every framework is.

  • Help: move a long list of examples out of the help.

  • Output: put humans first, keep success output brief, report state changes, make the state easy to see, suggest the next command, make actions outside the program explicit, add density with ASCII art, use color with intention, use symbols and emoji where they help, hide output only the developers understand, and do not treat stderr as a log file.

  • Errors: keep the signal-to-noise ratio high, and put the most important information where the user looks first.

  • Arguments and flags: prefer flags to arguments, avoid two arguments for different things, make the default right for most users, accept a word like none for an optional value, and never read secrets from flags.

  • Interactivity: let the user escape.

  • Subcommands: stay consistent across subcommands, name each level consistently, and avoid ambiguous names.

  • Robustness: work in parallel with care, time out, recover from failures, design for crashes, and expect misuse.

  • Future-proofing: keep changes additive, feel free to change human output, avoid a catch-all subcommand, and avoid time bombs.

  • Signals: skip slow clean-up on a second Ctrl-C.

  • Configuration: ask before changing the configuration of another program.

  • Environment variables: use them for context-dependent behavior, keep values on one line, do not take over common names, do not use .env as a configuration file, and never read secrets from them.

  • Naming: pick a simple, memorable word that is not too generic, use only lowercase letters and dashes, keep it short, and make it easy to type.

  • Distribution: make it easy to uninstall.

  • Analytics: consider alternatives to analytics.

Startup time

The “under 100 ms” row times a hello-world --help on an Apple Silicon Mac with Python 3.14, as the median of 15 runs: Click 36 ms, Cloup 55 ms, Fire 57 ms, Tyro 59 ms, Cement 66 ms, rich-click 73 ms, Typer 90 ms, Cyclopts 113 ms (on 5.0.0) and click-extra 141 ms. 🟡 marks a time between 100 and 200 ms. cobra, clap and bpaf compile to native executables, with no interpreter to start.

Unique strengths

Features unique to click-extra or significantly stronger than all competitors:

  • Multi-format config with pyproject.toml: no other framework reads [tool.*] from pyproject.toml natively. Cobra/Viper comes closest but targets Go projects.

  • Help colorization with theme system: click-extra highlights options, choices, metavars, defaults, env vars, and subcommand names with configurable themes. Seven built-in themes (six color palettes dark, light, dracula, monokai, nord, solarized-dark and a monochrome manpage) plus user-defined and partial-override themes declared directly in the CLI’s --config file ([tool.<cli>.themes.<name>]). Theme overrides are scoped per invocation via ctx.meta, so back-to-back runs in the same process don’t cross-contaminate, and a machine-wide CLICK_EXTRA_THEME sets the palette of every Click Extra CLI at once. rich-click is the only other framework shipping a theme catalog an end user can pick from, and it reads no palette from the wrapped CLI’s configuration file; the rest offer basic ANSI colors without semantic highlighting.

  • Table and data serialization: print_table() and serialize_data() with fifty output formats. Cement offers table output but with fewer format options and no serialization pipeline.

  • Parameter introspection: --params exposes every parameter’s value, source, default, and environment variable. Click, cobra, Typer, clap and Cyclopts expose parameter sources to code only: no other framework gives the end user an option for it.

  • Version with git metadata: template variables for branch, hash, date, tag, with pre-baking for compiled binaries (Nuitka, PyInstaller).

  • Configuration validation extension hook: ConfigValidator lets apps declare extension paths ([tool.<cli>.managers.<id>], [tool.<cli>.plugins], …) that click-extra’s strict check skips and the app validates with rooted ValidationErrors. --validate-config collects every error in one pass. No other framework exposes the strict-check pipeline this way.

  • wrap subcommand: applies click-extra’s help colorization, themes, and config loading to any installed Click CLI without touching its source code. The wrapped CLI inherits the --config theme loader, so users can theme a third-party tool from their own pyproject.toml.

  • Man page generation: render_manpages() and write_manpages() emit one roff man page per command. They work on a command object (no console_scripts entry point) and discover subcommands dynamically, superseding the unmaintained click-man (last released 0.4.2 in 2021). The long-standing click-man limitations are fixed by construction: Click’s \b markers (click-man#9), modern Python (#72), dynamic subcommands (#14, #56), plus the ENVIRONMENT, FILES and EXIT STATUS sections it never grew. cobra and bpaf are the only compared frameworks with comparable native man page output; Click itself closed the topic in 2018 (pallets/click#434).

Gaps and opportunities

Todo

Close the click-extra-side gaps the sections below identify:

  • a @persistent_option decorator (or a persistent=True kwarg on @option) registering an option on a group and injecting it into every subcommand at decoration time, covering the inherited-flags family Click has consistently declined;

  • populate ctx.params during shell completion, so a completion callback can depend on parameter values already typed on the command line;

  • native NushellComplete and PowerShellComplete classes, for users without the carapace binary the Carapace spec needs;

  • a @completion_option bundling multi-shell detection and auto-install, matching Typer’s --install-completion.

Persistent / inherited flags

cobra’s persistent flags propagate from a parent command to all subcommands automatically. Click’s maintainers have consistently stated that options belong to the command they modify, and positional dependence (cli --opt subcmd vs cli subcmd --opt) is intentional (pallets/click#66, pallets/click#1034). The official workaround is custom decorators that apply the same options to multiple commands.

This is one of Click’s most requested features. The highest-demand closed issues all center on the same family of problems: parent group options are invisible to subcommands (pallets/click#108, 9 thumbs-up), required group options block --help on child commands (pallets/click#814, 14 thumbs-up; pallets/click#295, 15 thumbs-up), and group options are lost in CommandCollection (pallets/click#347, 13 thumbs-up: closed as not_planned in September 2025, formalizing the rejection).

The ongoing parser rewrite (pallets/click#2205) and related PR for dynamic context parameters (pallets/click#2784) could eventually unblock this upstream, but both have been in progress since 2022 with no merge date in sight. click-extra could add a @persistent_option decorator (or a persistent=True kwarg on @option) that registers the option on the group and injects it into all subcommands at decoration time. The config file support already handles cross-command defaults; persistent flags would complete the story for the CLI layer.

Enhanced shell completion

Click’s built-in completion covers command names, option names and values, but has several known gaps. clap, cobra, bpaf, Cyclopts, and Typer all provide richer completion out of the box. The upstream issues below represent the main areas where click-extra could close the gap:

Context-dependent completions (pallets/click#2303, pallets/click#2184, pallets/click#928): the Context object during shell completion is missing already-parsed parameter values, so completions cannot depend on previous arguments (like completing tags based on a previously typed project name). This is the highest-demand open completion issue (14+ thumbs-up). click-extra could override the completion resolution to populate ctx.params properly.

Broken --option=value completion (pallets/click#2847): completing --option=val<TAB> is broken in both bash and zsh. The = separator parsing in _resolve_context needs fixing.

Default callbacks evaluated during completion (pallets/click#2614): since Click 8.0, default value callbacks run during tab-completion even when resilient_parsing should suppress them. Makes completion slow for apps with expensive defaults.

Fish multiline help (pallets/click#3043): help text containing newlines used to break fish completion. Fixed upstream in pallets/click#3126 (merged 2026-04-29), which also closes the bug report. click-extra’s >=8.4.1 floor ships the fix, so fish completion handles multi-line help text out of the box and no click-extra workaround is needed.

Enum Choice mismatch (pallets/click#3015): click.Choice(MyEnum) completed MyEnum.foo instead of foo because completion skipped the normalization the Choice type applies at parse time. Fixed upstream in pallets/click#3471 (merged 2026-05-19, first released in Click 8.4.1), which routes completion through Choice.normalize_choice() so suggestions match what the parser accepts. click-extra’s >=8.4.1 floor closes the gap for every supported Click version. click-extra’s own EnumChoice was never affected: it stores choice strings rather than Enum members, so its completions never carried the Enum.member form.

Additional shells rejected upstream (pallets/click#2888, pallets/click#3188, pallets/click#2672): Click explicitly rejected adding nushell, Carapace, and PowerShell completion to core: all three issues are closed as not_planned, so the door is closed upstream and remains a click-extra opportunity. click-extra already answers pallets/click#3188 with the Carapace spec generator, which drives nushell and PowerShell completion through the carapace binary. Native NushellComplete and PowerShellComplete classes would close the remaining gap for users who do not install it.

Multi-shell auto-install: Typer’s --install-completion detects the current shell and installs the completion script automatically. click-extra could bundle a similar @completion_option.

Activity

Metrics ↴ \ Framework →

click-extra

Click[1]

Cloup[2]

cobra[3]

Fire[4]

Typer[5]

clap[6]

Cement[7]

Cyclopts[8]

Tyro[9]

rich-click[10]

bpaf[11]

Watchers

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

Contributors

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

Commit activity

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

Commits since latest release

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

Last release date

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

Last commit

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

Open issues

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

Open PRs

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

Forks

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

Dependencies freshness

Libraries.io

Libraries.io

Libraries.io

-

Libraries.io

Libraries.io

Libraries.io

Libraries.io

Libraries.io

Libraries.io

Libraries.io

Libraries.io

Popularity

GitHub star history of click-extra and its alternatives

The vertical axis counts by powers of ten: Click, Typer, cobra and clap each outweigh click-extra by at least an order of magnitude, and a linear axis would draw click-extra and most of the smaller frameworks flat along the bottom edge.

GitHub restricted its stargazer endpoints to a repository’s own admins in June 2026, which left every third-party star chart on the web, this page’s star-history.com embed included, rendering an error card. repomatic sample-metrics reads every project on this page weekly into metrics.csv instead, so the history accrues here and cannot be revoked.

A line only bends where that store holds readings to bend it. click-extra is reconstructed exactly from the timestamp of every star it still holds, so its curve runs back to its first star. The alternatives are instead mined from archived copies of their GitHub pages, one capture at a time and only as far back as the archive was crawling them: a project not yet reached shows one straight line from its creation date to its first sampled reading. Read those straight segments as how far the mining has got, not as how the project grew. The star counts below are live in every case.

Metrics ↴ \ Framework →

click-extra

Click[1]

Cloup[2]

cobra[3]

Fire[4]

Typer[5]

clap[6]

Cement[7]

Cyclopts[8]

Tyro[9]

rich-click[10]

bpaf[11]

Stars

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

SourceRank

Libraries.io SourceRank

Libraries.io SourceRank

Libraries.io SourceRank

-

Libraries.io SourceRank

Libraries.io SourceRank

Libraries.io SourceRank

Libraries.io SourceRank

Libraries.io SourceRank

Libraries.io SourceRank

Libraries.io SourceRank

Libraries.io SourceRank

Dependent repos

Dependent repos (via libraries.io)

Dependent repos (via libraries.io)

Dependent repos (via libraries.io)

-

Dependent repos (via libraries.io)

Dependent repos (via libraries.io)

Dependent repos (via libraries.io)

Dependent repos (via libraries.io)

Dependent repos (via libraries.io)

Dependent repos (via libraries.io)

Dependent repos (via libraries.io)

Dependent repos (via libraries.io)

Distribution

Registry ↴ \ Framework →

click-extra

Click[1]

Cloup[2]

cobra[3]

Fire[4]

Typer[5]

clap[6]

Cement[7]

Cyclopts[8]

Tyro[9]

rich-click[10]

bpaf[11]

PyPI

PyPI

PyPI

PyPI

-

PyPI

PyPI

-

PyPI

PyPI

PyPI

PyPI

-

Crates.io

-

-

-

-

-

-

Crates.io

-

-

-

-

Crates.io

Metadata

Metadata ↴ \ Framework →

click-extra

Click[1]

Cloup[2]

cobra[3]

Fire[4]

Typer[5]

clap[6]

Cement[7]

Cyclopts[8]

Tyro[9]

rich-click[10]

bpaf[11]

License

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

Main language

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

GitHub

Latest version

GitHub release (latest SemVer)

GitHub release (latest SemVer)

GitHub release (latest SemVer)

GitHub release (latest SemVer)

GitHub release (latest SemVer)

GitHub release (latest SemVer)

GitHub release (latest SemVer)

GitHub release (latest SemVer)

GitHub release (latest SemVer)

GitHub release (latest SemVer)

GitHub release (latest SemVer)

GitHub release (latest SemVer)

Benchmark date

2026-10

2026-10

2026-10

2026-10

2026-10

2026-10

2026-10

2026-10

2026-10

2026-10

2026-10

2026-10

Excluded frameworks

Sorted by last commit, most recent first:

  • docopt-ng (~200 stars), last commit July 2026: the maintained fork of docopt has not released since 0.9.0 in May 2023. Jazzband, the organization hosting it, is winding down and moves its projects to new homes by the end of 2026.

  • Cleo (~1,400 stars), last commit March 2026: only automated pre-commit updates since 2.1.0 in October 2023, and the 3.0 rewrite has stalled. Cleo is maintained as a part of Poetry, not on its own.

  • docopt (~8,000 stars), last commit June 2025: no release since 0.6.2 in 2014. Its docstring-driven way to declare a CLI was influential, and lives on in docopt-ng above.

  • argh (~400 stars), last commit July 2024: no commit or release since 0.31.3.

Project URLs