urfave/cli v3: a declarative Go CLI package with no dependencies outside the standard library
A declarative, simple, fast, and fun package for building command line tools in Go
At a glance
- What is it?
- urfave/cli builds commands, subcommands and flags from a declarative Go struct, and its v3 module ships without third-party runtime dependencies. Here is what it does well, what the documentation leaves open, and when a different framework fits better.
- Who is it for?
- Adopt urfave/cli when you want a Go CLI defined in one place, with commands, aliases, typed flags, shell completion and no third-party runtime dependencies; the MIT licence keeps reuse simple, and the last push on 2026-09-14 means the tree is current. Skip it if you need generated code, a plugin system, or config parsing built into the core rather than in urfave/cli-altsrc and urfave/cli-docs.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem urfave/cli solves for Go command line tools
Go's flag package covers a single flat set of options. Real tools grow subcommands, aliases, environment variable fallbacks and shell completion, and that plumbing is repetitive in every project. urfave/cli exists to make that structure declarative: you describe commands, subcommands and flags as Go values rather than wiring parsing by hand. The README lists the intended scope: commands and subcommands with alias and prefix match support, a permissive help system, dynamic completion for bash, zsh, fish and powershell, and input flags for simple types, slices, time and duration. It is aimed at Go developers who want a conventional CLI shape without adopting a code generator or a heavier runtime. The project is run by unpaid volunteers, and the README points questions to GitHub Discussions rather than a commercial support channel. That matters when you are deciding how much of your release process to hang on it.
How the declarative model maps onto parsing and execution
The repository layout shows the mechanism. cli.go, command.go, command_parse.go, command_run.go and command_setup.go split the lifecycle into distinct files, so parsing, setup and execution are separate stages rather than one monolith. Flag types have their own files: flag_string.go, flag_int.go, flag_duration.go, flag_timestamp.go, flag_string_slice.go, flag_float_slice.go, flag_string_map.go and others, which is why the README can promise slices of simple types, maps and time values without extra packages. flag_ext.go and flag_impl.go suggest a shared implementation layer behind the concrete types. Completion is not bolted on: completion.go, autocomplete/, fish.go and fish_test.go are top-level entries, matching the README's claim of dynamic completion for four shells. The go.mod file declares module github.com/urfave/cli/v3, go 1.22, and a single require for github.com/stretchr/testify, which is a test dependency; the README states there are no dependencies except the Go standard library, and the module graph is consistent with that for consumers. The trade-off is that the core stays focused: documentation generation and structured config files live in separate modules, urfave/cli-docs and urfave/cli-altsrc, so a project that wants YAML or TOML input adds a second dependency.
Installing urfave/cli v3 and running a first command
The README points to the hosted documentation at cli.urfave.org, built from the ./docs directory, and the module path in go.mod is github.com/urfave/cli/v3. Add it with go get, then define a command in main.go.
Installing urfave/cli v3 and running a first command (continued)
A minimal program declares a cli.Command with a Name and a slice of cli.Flag values, then hands it to the run entry point. The README gives examples/example-hello-world/ as a starting point in the repository, so the smallest useful program has this shape.
Installing urfave/cli v3 and running a first command (continued 2)
Run it with go run . --name world and the action prints the greeting. Flags can also be read from environment variables and files, but the README places structured formats behind the urfave/cli-altsrc module, so a YAML or TOML config file means adding that module rather than relying on the core. To check the repository itself, the Makefile exposes a single entry point: make test runs the build script, and the catch-all rule forwards arguments through GFLAGS and FLAGS, for example make test GFLAGS='--packages cli'. Documentation is built with mkdocs through make docs.
Where urfave/cli stops short
The core does not parse structured config files. The README is explicit that environment variables and plain text files are built in, while structured formats are supported via the urfave/cli-altsrc module. If your tool must read a YAML file with no extra dependency, this package alone will not do it. Documentation generation has the same shape: man pages and Markdown come through urfave/cli-docs, not the main module. Completion is generated rather than inferred, so the four supported shells are a fixed set; a shell outside bash, zsh, fish and powershell is not covered by the README. The project is maintained by volunteers, and the README says so plainly, which means response time on issues is not a contractual guarantee. Finally, the module is at v3 and requires go 1.22 in go.mod, so projects pinned to older toolchains cannot import it without an upgrade. None of these are defects, but each one changes the dependency count or the toolchain floor of the program you are building.
urfave/cli against cobra and kong
The most common comparison is urfave/cli versus cobra, and the difference is in how much is generated for you. Cobra pairs with a generator and a scaffolding CLI, so a new project starts from generated files and a directory convention; urfave/cli has no generator in the repository layout, and you write the command tree as Go values in your own files. That keeps the source of truth in one place and makes the diff for a new subcommand small, at the cost of typing the structure yourself. Kong takes a different route again: it derives the command surface from struct tags and function signatures, so the parsing rules live in the type definitions rather than in explicitly constructed flag values. urfave/cli sits between the two, closer to hand-written configuration than to reflection over your types. The practical test is whether you want the argument surface to be greppable as Go code (urfave/cli), generated as files (cobra), or inferred from struct tags (kong).
Maintenance, licensing and the cost of upgrading
The repository is not archived, and the last push was on 2026-09-14, the same day as the v3.12.0 release. The two releases before it, v3.11.0 and v3.10.1, landed on 2026-08-16 and 2026-06-29, so the cadence across that window is roughly monthly. That is a reasonable signal for a volunteer project, but it is a cadence, not a support contract. The licence is MIT, which permits commercial and closed-source use with the usual requirement to keep the copyright notice and permission text; that is a summary of the licence family, not legal advice, and your own counsel should confirm how it applies to your distribution. Upgrading across major versions is the real cost centre here. The module path carries the version, github.com/urfave/cli/v3, so v2 and v3 can coexist in a dependency graph but not in the same import path. Because the command and flag types are constructed in your code rather than generated, a major version bump shows up as compile errors in the files where you build commands, which is easier to audit than a silent behaviour change but still means touching every command file. The Makefile's make test target is the check the maintainers use on the repository itself.
Editorial conclusion
Adopt urfave/cli when you want a Go CLI defined in one place, with commands, aliases, typed flags, shell completion and no third-party runtime dependencies; the MIT licence keeps reuse simple, and the last push on 2026-09-14 means the tree is current. Skip it if you need generated code, a plugin system, or config parsing built into the core rather than in urfave/cli-altsrc and urfave/cli-docs. Before committing, check the v3 migration notes for the APIs you use, and confirm that your Go toolchain meets the go 1.22 directive in go.mod.
Frequently asked questions
What is urfave/cli used for?
It is a Go package for building command line tools, with commands and subcommands, aliases and prefix matching, typed input flags, and dynamic shell completion for bash, zsh, fish and powershell. The README describes it as declarative, and the repository splits parsing, setup and execution across separate files.
How does urfave/cli compare with cobra for a Go CLI?
urfave/cli has no generator in its repository layout, so the command tree is written as Go values; cobra is commonly used with a generator and a scaffolding CLI. The README also states that urfave/cli has no dependencies except the Go standard library.
Does urfave/cli read configuration files?
Environment variables and plain text files are built in, while structured file formats such as YAML and TOML are supported through the separate urfave/cli-altsrc module. The core module in go.mod does not include a config parser.
Which Go version does urfave/cli v3 require?
The go.mod file for the v3 module declares go 1.22, and the module path is github.com/urfave/cli/v3. Projects on older toolchains cannot import it without upgrading Go.
Is urfave/cli still maintained?
The repository is not archived and the last push was on 2026-09-14, matching the v3.12.0 release date. The README notes the project is run by unpaid volunteers, so issue response time is not guaranteed.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/urfave-cli)