skip to content

rich โ€” Beautiful Terminal Output

Make terminal output beautiful with Rich. Covers styled print, Console, tables, progress bars, syntax highlighting, live displays, and the rich-cli command.

5 min read 21 snippets yesterday intermediate

rich โ€” Beautiful Terminal Output#

What it is#

Rich is a Python library for rich text and beautiful formatting in the terminal. It provides:

  • Styled and colored print() with markup
  • Tables, panels, and trees
  • Syntax-highlighted code blocks
  • Progress bars (with ETA and throughput)
  • Live-updating displays (dashboards, spinners)
  • Tracebacks with local variable values

It also ships a standalone CLI tool (rich) for piping colored output from the shell.

[!NOTE] Output blocks below show ANSI-stripped plain text. In your actual terminal, Rich renders in full color with box-drawing characters and smooth animations.

Install#

pip install rich           # Python library
pip install rich-cli       # optional standalone CLI tool

Styled print with markup#

from rich import print

print("[bold green]Success![/bold green] Task completed in [cyan]0.42s[/cyan].")
print("[red]Error:[/red] File not found: [italic yellow]config.yaml[/italic yellow]")
print("[bold]Numbers:[/bold] [blue]42[/blue], [magenta]3.14[/magenta], [white on red] WARNING [/white on red]")

Output:

Success! Task completed in 0.42s.
Error: File not found: config.yaml
Numbers: 42, 3.14,  WARNING 

[!NOTE] In the terminal, โ€œSuccess!โ€ appears bold green, โ€œ0.42sโ€ in cyan, โ€œError:โ€ in red, and โ€ WARNING โ€ as white text on a red background.

Console โ€” control over output stream#

from rich.console import Console

console = Console()
console.print("Hello from Rich!", style="bold magenta")
console.print("Rendered to stderr:", style="dim", end="\n", highlight=False)
console.rule("[bold]Section Break[/bold]")
console.log("This is a log message โ€” includes timestamp and caller")

Output:

Hello from Rich!
Rendered to stderr:
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Section Break โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
[14:30:01] This is a log message โ€” includes timestamp and caller      rich_demo.py:7

Tables#

from rich.console import Console
from rich.table import Table

console = Console()

table = Table(title="Python Package Summary", show_lines=True)
table.add_column("Package", style="cyan", no_wrap=True)
table.add_column("Purpose", style="white")
table.add_column("Install", style="green")

table.add_row("requests", "HTTP client",       "pip install requests")
table.add_row("pandas",   "DataFrames",         "pip install pandas")
table.add_row("fastapi",  "ASGI web framework", "pip install fastapi")
table.add_row("pytest",   "Testing framework",  "pip install pytest")
table.add_row("ruff",     "Linter + formatter", "pip install ruff")

console.print(table)

Output:

              Python Package Summary               
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Package  โ”‚ Purpose           โ”‚ Install              โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ requests โ”‚ HTTP client       โ”‚ pip install requests โ”‚
โ”‚ pandas   โ”‚ DataFrames        โ”‚ pip install pandas   โ”‚
โ”‚ fastapi  โ”‚ ASGI web frameworkโ”‚ pip install fastapi  โ”‚
โ”‚ pytest   โ”‚ Testing framework โ”‚ pip install pytest   โ”‚
โ”‚ ruff     โ”‚ Linter + formatterโ”‚ pip install ruff     โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Progress bar#

import time
from rich.progress import Progress, SpinnerColumn, TimeElapsedColumn

items = list(range(20))

with Progress(
    SpinnerColumn(),
    "[progress.description]{task.description}",
    "[progress.percentage]{task.percentage:>3.0f}%",
    TimeElapsedColumn(),
) as progress:
    task = progress.add_task("Processing items...", total=len(items))
    for item in items:
        time.sleep(0.05)  # simulate work
        progress.advance(task)

print("Done!")

Output:

โ ธ Processing items... 100%  0:00:01
Done!

[!NOTE] During execution the progress bar animates with a spinner, live percentage, and elapsed time. The final state shows 100%.

Track (simple progress)#

For simple iterables, rich.progress.track is the quickest way:

import time
from rich.progress import track

results = []
for i in track(range(10), description="Computing..."):
    time.sleep(0.1)
    results.append(i * i)

print(results)

Output:

Computing... โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ” 100% 0:00:01
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Syntax highlighting#

from rich.console import Console
from rich.syntax import Syntax

console = Console()

code = '''
def fibonacci(n: int) -> int:
    if n < 2:
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)

print(fibonacci(10))
'''

syntax = Syntax(code.strip(), "python", theme="monokai", line_numbers=True)
console.print(syntax)

Output:

  1 def fibonacci(n: int) -> int:
  2     if n < 2:
  3         return n
  4     return fibonacci(n - 1) + fibonacci(n - 2)
  5 
  6 print(fibonacci(10))

[!NOTE] In the terminal, keywords appear in purple, strings in yellow, and line numbers are dimmed โ€” Monokai theme colors.

Live updating display#

import time
from rich.console import Console
from rich.live import Live
from rich.table import Table

console = Console()

def make_table(step: int) -> Table:
    table = Table(title=f"Live Update โ€” step {step}")
    table.add_column("Metric")
    table.add_column("Value", style="cyan")
    table.add_row("Step",     str(step))
    table.add_row("Progress", f"{step * 10}%")
    table.add_row("Rate",     f"{step * 1.7:.1f} items/s")
    return table

with Live(make_table(0), refresh_per_second=4) as live:
    for i in range(1, 11):
        time.sleep(0.3)
        live.update(make_table(i))

console.print("[bold green]Finished![/bold green]")

Output (final frame):

     Live Update โ€” step 10     
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Metric   โ”‚ Value          โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Step     โ”‚ 10             โ”‚
โ”‚ Progress โ”‚ 100%           โ”‚
โ”‚ Rate     โ”‚ 17.0 items/s   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
Finished!

Pretty-print data structures#

from rich import inspect, pretty
from rich.console import Console

console = Console()

data = {
    "users": [
        {"id": 1, "name": "Alice", "roles": ["admin", "user"]},
        {"id": 2, "name": "Bob",   "roles": ["user"]},
    ],
    "total": 2,
}
console.print(data)

Output:

{
    'users': [
        {'id': 1, 'name': 'Alice', 'roles': ['admin', 'user']},
        {'id': 2, 'name': 'Bob', 'roles': ['user']}
    ],
    'total': 2
}

Rich tracebacks#

from rich.traceback import install
install(show_locals=True)  # call once at app startup

# Now all unhandled exceptions produce rich tracebacks
# with syntax-highlighted frames and local variable values
raise ValueError("something went wrong")

Output:

โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Traceback (most recent call last) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ demo.py:5 in <module>                                                    โ”‚
โ”‚                                                                          โ”‚
โ”‚   3 install(show_locals=True)                                            โ”‚
โ”‚   4                                                                      โ”‚
โ”‚ โฑ 5 raise ValueError("something went wrong")                            โ”‚
โ”‚                                                                          โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
ValueError: something went wrong

rich-cli โ€” shell command#

The rich CLI tool lets you pipe and render content from the shell:

# Render markdown in the terminal
rich README.md

# Syntax-highlight a Python file
rich main.py --syntax python

# Pretty-print JSON
cat data.json | rich - --json

# Render a CSV as a table
rich data.csv

Output (markdown rendering):

                       My Project                        
                                                         
  A short description of the project.                   
                                                         
  Usage                                                  
  โ”โ”โ”โ”โ”                                                  
                                                         
  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  
  โ”‚ $ python main.py --help                          โ”‚  
  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  

Markup reference#

MarkupEffect
[bold]text[/bold]Bold
[italic]text[/italic]Italic
[underline]text[/underline]Underline
[red]text[/red]Red foreground
[on blue]text[/on blue]Blue background
[bold cyan]text[/bold cyan]Bold cyan
[link=https://example.com]click[/link]Hyperlink (terminals that support OSC 8)
[/]Reset all styles