Flag Parsing & Persistent Flags
Cobra gives each command several views over its flags so command-local options, reusable parent options, and inherited options can coexist. These views are backed by pflag flag.FlagSet values and are combined before argument parsing.
This layering exists so a child command can accept its own options while also recognizing flags declared by ancestors, without forcing every command to redefine global behavior. The same merged view also supports help, usage, completion, and flag lookup.
Sources: command.go:1688-1698, command.go:1775-1784, command.go:1716-1740, command.go:1744-1766, command.go:1868-1889
Core concepts
Command-local flags
A command-local flag is an option stored in the command’s ordinary Flags() set; Flags() lazily creates that set with the command display name and a continue-on-error parser.
Sources: command.go:1688-1698
Persistent flags
A persistent flag is an option stored in PersistentFlags() and intended to remain available to descendant commands; that set is also created lazily and uses the command’s shared flag error buffer.
Sources: command.go:1775-1784
Inherited flags
An inherited flag is a parent persistent flag copied into a child’s InheritedFlags() view when it does not collide with a child-local flag.
Sources: command.go:1744-1766
Merged parsing set
The merged parsing set is the command’s Flags() set after Cobra adds the command’s persistent flags and accumulated parent persistent flags.
These views answer different questions:
| View | Source flags | Main purpose |
|---|---|---|
Flags() | The command’s ordinary flag set | The mutable set Cobra parses after merging. |
PersistentFlags() | Flags declared persistent on this command | Flags that descendants may inherit. |
LocalFlags() | The command’s flags plus its own persistent flags, excluding parent flags | Display and inspect options belonging to this command. |
InheritedFlags() | Persistent flags collected from ancestors | Display and inspect options inherited from parents. |
LocalFlags() calls mergePersistentFlags() first, then adds ordinary and own persistent flags unless they are parent flags; InheritedFlags() separately adds parent flags only when they do not collide with local flags.
Sources: command.go:1898-1902, command.go:1716-1740, command.go:1744-1766
How flags are layered across a command tree
A command points to its parent through Parent(), and VisitParents() walks upward by invoking the callback for the immediate parent and then continuing recursively. The command tree is established when AddCommand assigns each child’s parent field.
The parent aggregate is maintained by updateParentsPflags(). It lazily creates parentsPflags, applies the global normalization function when configured, adds the root command’s PersistentFlags() together with flag.CommandLine, and then adds each visited parent’s PersistentFlags().
The resulting relationship is:
Evidence
- root-commandcommand.go:1907
- parent-commandcommand.go:1907
- parent-flagscommand.go:1907
- child-commandcommand.go:1744
- command-linecommand.go:1907
The important boundary is that inherited flags are not simply all parent flags appended blindly: InheritedFlags() checks both its own lookup and LocalFlags() before adding each parent flag, allowing a local flag to take precedence in the child’s view.
Sources: command.go:1892-1894, command.go:884-889, command.go:1342-1368, command.go:1907-1923, command.go:1744-1766
When merging happens before parsing
Cobra merges persistent flags immediately before parsing arguments. ParseFlags() first creates the error buffer if necessary, records its current length, calls mergePersistentFlags(), configures ParseErrorsAllowlist, and finally calls Flags().Parse(args).
mergePersistentFlags() refreshes the parent aggregate, then adds the command’s own PersistentFlags() and parentsPflags into Flags(). This ordering matters because parsing must see the complete flag namespace, including flags declared on ancestors, while still allowing the command’s own set to be the object that receives parsed values.
The execution path reaches this merge during normal command execution: ExecuteC() selects or traverses to a command and then calls execute(flags), while execute() initializes default flags and calls ParseFlags(a).
Evidence
- execute-ccommand.go:1084
- executecommand.go:905
- parse-flagscommand.go:1868
- merge-flagscommand.go:1898
- parse-setcommand.go:1898
The same merge is also required before Cobra creates the local and inherited display views, and before default help and version flags are installed. Therefore help output can distinguish local flags from inherited flags only after the flag layers have been assembled.
Sources: command.go:1868-1889, command.go:1898-1902, command.go:1084-1170, command.go:905-1045, command.go:1716-1740, command.go:1744-1766, command.go:1219-1232, command.go:1238-1258, command.go:1974-2040
How Cobra keeps pflag and command-line flags together
Cobra’s parsing APIs use pflag’s flag.FlagSet abstraction throughout the shown code, including NewFlagSet, AddFlagSet, VisitAll, and Parse. The parent-update path additionally adds flag.CommandLine to the root persistent set before walking parent commands.
This gives the visible fallback boundary: flags already registered in flag.CommandLine are incorporated into the aggregate that later feeds the command’s merged Flags() set. The excerpts do not show registration or conversion details beyond that AddFlagSet hand-off, so the safe interpretation is that Cobra includes that command-line flag set alongside its pflag-managed command sets.
Flag lookup follows the same layering. Flag(name) checks Flags() first and then calls persistentFlag(name); that helper checks the command’s persistent set and, if needed, refreshes and searches parentsPflags.
Sources: command.go:1688-1698, command.go:1868-1889, command.go:1907-1923, command.go:1898-1902, command.go:1844-1852, command.go:1855-1865
How it connects
Command construction supplies the parent links that make inheritance possible: AddCommand assigns parent, and Parent() exposes it. See Command Tree & Registration for the tree-building model.
Execution supplies the timing boundary: ExecuteC() finds the target command, then execute() initializes and parses its flags. See Command Execution Flow for the full execution sequence.
Help and usage consume the separated views: default usage prints LocalFlags() under “Flags” and InheritedFlags() under “Global Flags.” See Help, Usage & Templates for rendering behavior.
Completion and generated documentation also use non-inherited and inherited views separately. See Dynamic Completion Engine and Man Page & Markdown Doc Generation for those consumers.
Sources: command.go:1342-1368, command.go:1892-1894, command.go:1084-1170, command.go:905-1045, command.go:1974-2040, completions.go:462-474, doc/md_docs.go:32-47
Key takeaways
Flags()is the parsing set;PersistentFlags()holds flags intended for descendants.InheritedFlags()is built from ancestor persistent flags and avoids names already present locally.- Cobra refreshes parent flags and merges them before calling
Flags().Parse(args). - The parent aggregate also incorporates flag.CommandLine through
AddFlagSet. - Help, completion, and documentation rely on separate local and inherited flag views.
Sources: command.go:1688-1698, command.go:1775-1784, command.go:1744-1766, command.go:1868-1889, command.go:1898-1902, command.go:1907-1923, command.go:1974-2040, completions.go:462-474, doc/md_docs.go:32-47