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.