Skip to main content

Nesting Sub-Applications

To build complex, modular CLI tools in Typer, you can combine multiple Typer instances using the add_typer() method. This allows you to define commands in separate modules and organize them into either a flat structure or a nested hierarchy of command groups.

Merge Sub-Apps into a Flat Structure

If you want to organize your code into multiple files but keep all commands at the top level of your CLI, call add_typer() without providing a name.

import typer

# Assume these are imported from other modules
users_app = typer.Typer()
@users_app.command()
def create():
print("Creating user")

items_app = typer.Typer()
@items_app.command()
def sell():
print("Selling item")

app = typer.Typer()

# Commands from users_app and items_app will appear directly under 'app'
app.add_typer(users_app)
app.add_typer(items_app)

if __name__ == "__main__":
app()

In this configuration, running python main.py --help will show both create and sell as available commands.

Create Nested Command Groups

To create a hierarchy (e.g., main-app users create), provide a name when calling add_typer(). This treats the sub-application as a subcommand group.

import typer

users_app = typer.Typer()

@users_app.command()
def create():
print("Creating user")

@users_app.command()
def delete():
print("Deleting user")

app = typer.Typer()

# This creates a 'users' group
app.add_typer(users_app, name="users")

if __name__ == "__main__":
app()

The resulting CLI structure will be:

  • python main.py users create
  • python main.py users delete

Override Sub-App Configuration

You can customize how a sub-application appears in the parent app by passing arguments to add_typer(). These values take precedence over any configuration defined within the sub-app itself.

import typer

sub_app = typer.Typer(help="Original help text")

@sub_app.command()
def info():
print("Sub-app info")

app = typer.Typer()

# Override the name and help text for this specific inclusion
app.add_typer(
sub_app,
name="management",
help="Customized management commands",
short_help="Manage system"
)

The add_typer method in typer/main.py supports several parameters for overriding, including:

  • name: The name of the subcommand group.
  • help: The long help text shown in the group's help page.
  • short_help: The text shown in the parent app's command list.
  • rich_help_panel: The panel name when using Rich formatting.

Troubleshooting: Ignored Callbacks

A common issue occurs when merging sub-applications without a name: the sub-app's callback is ignored.

The "No-Name" Callback Warning

When you use app.add_typer(sub_app) (without a name), Typer merges the commands directly. Because there is no intermediate group created, there is no place to execute a group-level callback.

import typer

app = typer.Typer()
sub_app = typer.Typer()

@sub_app.callback()
def sub_callback():
"""This callback will NOT run because sub_app is added without a name."""
print("Running sub callback")

# This will trigger a warning in Typer
app.add_typer(sub_app)

Solution: If you need the logic in sub_callback to run, you must either:

  1. Provide a name to add_typer(sub_app, name="sub") to create a group.
  2. Move the logic to the main app's callback or into the individual commands.

Precedence of Metadata

If you define help text in multiple places, Typer resolves it in this order of priority:

  1. Arguments passed directly to app.add_typer(..., help="...").
  2. The @sub_app.callback(help="...") decorator in the sub-application.
  3. The typer.Typer(help="...") constructor of the sub-application.
  4. The docstring of the sub-application's callback function.