Typer
Typer generates CLIs from Python type hints. Built on Click, it reduces boilerplate while keeping Click's ecosystem.
Search across all documentation pages
Typer generates CLIs from Python type hints. Built on Click, it reduces boilerplate while keeping Click's ecosystem.
import typer
app = typer.Typer()
@app.command()
def greet(name: str, loud: bool = False):
msg = f"Hello, {name}"
typer.echo(msg.upper() if loud else msg)
if __name__ == "__main__":
app()When to reach for this:
import typer
from pathlib import Path
from typing import Optional
from enum import Enum
app = typer.Typer(help="Invoice management CLI")
class OutputFormat(str, Enum):
json = "json"
csv = "csv"
@app.command()
def export(
invoice_id: int = typer.Argument(..., help="Invoice ID"),
output: Path = typer.Option("out.json", help="Output file"),
format: OutputFormat = OutputFormat.json,
verbose: bool = typer.Option(False, "--verbose", "-v"),
):
if verbose:
typer.echo(f"Exporting invoice {invoice_id} as {format.value}", err=True)
# export logic
typer.echo(f"Written to {output}")
@app.command()
def list(limit: int = typer.Option(10, min=1, max=100)):
typer.echo(f"Listing {limit} invoices")
if __name__ == "__main__":
app()What this demonstrates:
Enum becomes Choice automaticallyPath validates file pathstyper.Option and typer.Argument for metadata| Type hint | CLI behavior |
|---|---|
str | String argument |
int | Integer with validation |
bool | Flag (default False) |
Optional[str] | Optional option |
Enum | Choice from enum values |
Path | File/directory path |
bool as positional is tricky. Fix: use typer.Option for flags.uv add "typer[all]" for dev.| Alternative | Use When | Don't Use When |
|---|---|---|
| Click | More control over parsing | Type hints cover your needs |
| argparse | Zero dependencies | Type-driven CLI wanted |
| cyclopts | Dataclass-heavy config | Simple function commands |
Typer for type-hint projects. Click for fine-grained control.
from typer.testing import CliRunner (same pattern as Click).
app = typer.Typer() + sub = typer.Typer() + app.add_typer(sub, name="db").
Use Pydantic models as types for structured config (Typer 0.12+).
typer.Argument(help="...") or docstrings on commands.
typer[all] includes completion. Install via --install-completion.
Use async def with typer 0.9+ async support or wrap with asyncio.run.
Multiple @app.command() decorated functions.
Load config separately; Typer handles CLI args. Consider pydantic-settings.
Yes. Powers FastAPI CLI. Built on stable Click foundation.
Stack versions: This page was written for Python 3.14.0, FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, and uv 0.6+.
Reviewed by Chris St. John·Last updated Jul 19, 2026