Progress Display

Rich can display continuously updated information regarding the progress of long running tasks / file copies etc. The information displayed is configurable, the default will display a description of the ‘task’, a progress bar, percentage complete, and estimated time remaining.

Rich progress display supports multiple tasks, each with a bar and progress information. You can use this to track concurrent tasks where the work is happening in threads or processes.

To see how the progress display looks, try this from the command line:

python -m rich.progress


Progress works with Jupyter notebooks, with the caveat that auto-refresh is disabled. You will need to explicitly call refresh() or set refresh=True when calling update(). Or use the track() function which does a refresh automatically on each loop.

Basic Usage

For basic usage call the track() function, which accepts a sequence (such as a list or range object) and an optional description of the job you are working on. The track function will yield values from the sequence and update the progress information on each iteration. Here’s an example:

import time
from rich.progress import track

for i in track(range(20), description="Processing..."):
    time.sleep(1)  # Simulate work being done

Advanced usage

If you require multiple tasks in the display, or wish to configure the columns in the progress display, you can work directly with the Progress class. Once you have constructed a Progress object, add task(s) with (add_task()) and update progress with update().

The Progress class is designed to be used as a context manager which will start and stop the progress display automatically.

Here’s a simple example:

import time

from rich.progress import Progress

with Progress() as progress:

    task1 = progress.add_task("[red]Downloading...", total=1000)
    task2 = progress.add_task("[green]Processing...", total=1000)
    task3 = progress.add_task("[cyan]Cooking...", total=1000)

    while not progress.finished:
        progress.update(task1, advance=0.5)
        progress.update(task2, advance=0.3)
        progress.update(task3, advance=0.9)

The total value associated with a task is the number of steps that must be completed for the progress to reach 100%. A step in this context is whatever makes sense for your application; it could be number of bytes of a file read, or number of images processed, etc.

Updating tasks

When you call add_task() you get back a Task ID. Use this ID to call update() whenever you have completed some work, or any information has changed. Typically you will need to update completed every time you have completed a step. You can do this by updated completed directly or by setting advance which will add to the current completed value.

The update() method collects keyword arguments which are also associated with the task. Use this to supply any additional information you would like to render in the progress display. The additional arguments are stored in task.fields and may be referenced in Column classes.

Hiding tasks

You can show or hide tasks by updating the tasks visible value. Tasks are visible by default, but you can also add an invisible task by calling add_task() with visible=False.

Transient progress

Normally when you exit the progress context manager (or call stop()) the last refreshed display remains in the terminal with the cursor on the following line. You can also make the progress display disappear on exit by setting transient=True on the Progress constructor. Here’s an example:

with Progress(transient=True) as progress:
    task = progress.add_task("Working", total=100)

Transient progress displays are useful if you want more minimal output in the terminal when tasks are complete.

Indeterminate progress

When you add a task it is automatically started, which means it will show a progress bar at 0% and the time remaining will be calculated from the current time. This may not work well if there is a long delay before you can start updating progress; you may need to wait for a response from a server or count files in a directory (for example). In these cases you can call add_task() with start=False or total=None which will display a pulsing animation that lets the user know something is working. This is known as an indeterminate progress bar. When you have the number of steps you can call start_task() which will display the progress bar at 0%, then update() as normal.

Auto refresh

By default, the progress information will refresh 10 times a second. You can set the refresh rate with the refresh_per_second argument on the Progress constructor. You should set this to something lower than 10 if you know your updates will not be that frequent.

You might want to disable auto-refresh entirely if your updates are not very frequent, which you can do by setting auto_refresh=False on the constructor. If you disable auto-refresh you will need to call refresh() manually after updating your task(s).


The progress bar(s) will use only as much of the width of the terminal as required to show the task information. If you set the expand argument on the Progress constructor, then Rich will stretch the progress display to the full available width.


You may customize the columns in the progress display with the positional arguments to the Progress constructor. The columns are specified as either a format string or a ProgressColumn object.

Format strings will be rendered with a single value “task” which will be a Task instance. For example "{task.description}" would display the task description in the column, and "{task.completed} of {}" would display how many of the total steps have been completed. Additional fields passed via keyword arguments to ~rich.progress.Progress.update are store in task.fields. You can add them to a format string with the following syntax: "extra info: {task.fields[extra]}".

The default columns are equivalent to the following:

progress = Progress(

To create a Progress with your own columns in addition to the defaults, use get_default_columns():

progress = Progress(

The following column objects are available:

To implement your own columns, extend the ProgressColumn class and use it as you would the other columns.

Table Columns

Rich builds a Table for the tasks in the Progress instance. You can customize how the columns of this tasks table are created by specifying the table_column argument in the Column constructor, which should be a Column instance.

The following example demonstrates a progress bar where the description takes one third of the width of the terminal, and the bar takes up the remaining two thirds:

from time import sleep

from rich.table import Column
from rich.progress import Progress, BarColumn, TextColumn

text_column = TextColumn("{task.description}", table_column=Column(ratio=1))
bar_column = BarColumn(bar_width=None, table_column=Column(ratio=2))
progress = Progress(text_column, bar_column, expand=True)

with progress:
    for n in progress.track(range(100)):

Redirecting stdout / stderr

To avoid breaking the progress display visuals, Rich will redirect stdout and stderr so that you can use the built-in print statement. This feature is enabled by default, but you can disable by setting redirect_stdout or redirect_stderr to False


If the Progress class doesn’t offer exactly what you need in terms of a progress display, you can override the get_renderables method. For example, the following class will render a Panel around the progress display:

from rich.panel import Panel
from rich.progress import Progress

class MyProgress(Progress):
    def get_renderables(self):
        yield Panel(self.make_tasks_table(self.tasks))

Reading from a file

Rich provides an easy way to generate a progress bar while reading a file. If you call open() it will return a context manager which displays a progress bar while you read. This is particularly useful when you can’t easily modify the code that does the reading.

The following example demonstrates how we might show progress when reading a JSON file:

import json
import rich.progress

with"data.json", "rb") as file:
    data = json.load(file)

If you already have a file object, you can call wrap_file() which returns a context manager that wraps your file so that it displays a progress bar. If you use this function you will need to set the number of bytes or characters you expect to read.

Here’s an example that reads a url from the internet:

from time import sleep
from urllib.request import urlopen

from rich.progress import wrap_file

response = urlopen("")
size = int(response.headers["Content-Length"])

with wrap_file(response, size) as file:
    for line in file:
        print(line.decode("utf-8"), end="")

If you expect to be reading from multiple files, you can use open() or wrap_file() to add a file progress to an existing Progress instance.

See <> for a minimal clone of the cp command which shows a progress bar as the file is copied.

Multiple Progress

You can’t have different columns per task with a single Progress instance. However, you can have as many Progress instances as you like in a Live Display. See and for examples of using multiple Progress instances.


See for a realistic application of a progress display. This script can download multiple concurrent files with a progress bar, transfer speed and file size.