curses
The Python curses module provides an interface to the curses library for building text-based user interfaces in Unix terminals. It controls cursor movement, text rendering, colors, and keyboard input through a grid of character cells, enabling interactive applications that run entirely in the terminal. The module is available on Unix-like systems only.
A minimal application wraps a function with curses.wrapper() to handle initialization and cleanup automatically:
hello.py
import curses
def main(stdscr):
stdscr.addstr(0, 0, "Hello, curses!")
stdscr.refresh()
stdscr.getch()
curses.wrapper(main)
Run it in your terminal:
$ python hello.py
The terminal clears, displays “Hello, curses!”, and waits for a keypress before restoring the normal display.
Key Features
- Creates and manages rectangular windows and panels within the terminal
- Supports foreground and background color pairs for styled text output
- Handles keyboard input including function keys, arrow keys, and special characters
- Draws borders, lines, and box characters using the alternate character set
- Provides mouse event support for click and scroll interactions
- Works portably across Unix-like systems by matching the ncurses API, binding to whichever curses library the platform provides
- Ships only on Unix-like desktop systems, not in CPython builds for Windows, Android, iOS, or WebAssembly (WASI)
Frequently Used Classes and Functions
| Object | Type | Description |
|---|---|---|
curses.wrapper() |
Function | Initializes curses, calls a function, and restores the terminal on exit |
curses.initscr() |
Function | Initializes the library and returns a window covering the entire screen |
curses.newwin() |
Function | Creates a new window with specified dimensions and position |
curses.start_color() |
Function | Initializes color support and defines the eight basic colors |
curses.init_pair() |
Function | Defines a foreground and background color pair by number |
curses.color_pair() |
Function | Returns the attribute value for displaying text in a given color pair |
window.addstr() |
Method | Paints a string at the current or specified position in a window |
window.getch() |
Method | Reads a single character or special key code from the user |
window.refresh() |
Method | Updates the physical terminal display to match the window buffer |
window.getmaxyx() |
Method | Returns the height and width of the window as a tuple |
Examples
Drawing a border and rendering colored text centered on the screen:
colored_box.py
import curses
def main(stdscr):
curses.start_color()
curses.init_pair(1, curses.COLOR_YELLOW, curses.COLOR_BLUE)
stdscr.box()
height, width = stdscr.getmaxyx()
label = "Hello, curses!"
stdscr.addstr(
height // 2,
width // 2 - len(label) // 2,
label,
curses.color_pair(1) | curses.A_BOLD,
)
stdscr.refresh()
stdscr.getch()
curses.wrapper(main)
Reading arrow key input to move a label around the screen:
move_text.py
import curses
def main(stdscr):
stdscr.keypad(True)
y, x = 5, 5
label = "Move me!"
while True:
stdscr.clear()
stdscr.addstr(y, x, label)
stdscr.refresh()
key = stdscr.getch()
rows, cols = stdscr.getmaxyx()
if key == curses.KEY_UP:
y = max(0, y - 1)
elif key == curses.KEY_DOWN:
y = min(rows - 1, y + 1)
elif key == curses.KEY_LEFT:
x = max(0, x - 1)
elif key == curses.KEY_RIGHT:
x = min(cols - len(label) - 1, x + 1)
elif key == ord("q"):
break
curses.wrapper(main)
Press the arrow buttons, or click the grid and use your arrow keys, to feed keys to getch() and watch the loop move the label one character cell at a time on a 10-row, 24-column screen:
Positions are always (y, x), row first, with (0, 0) in the top-left corner, so pressing down increases y. The readout shows the branch that ran and the resulting addstr() call. Push the label against an edge and the max() or min() clamp keeps it on screen, stopping it one column short of the right edge.
Common Use Cases
The most common tasks for curses include:
- Building interactive text menus and navigation systems
- Creating real-time monitoring dashboards in the terminal
- Implementing full-screen text editors and file browsers
- Displaying progress indicators that update in place without scrolling
- Handling raw keyboard input for game-like or interactive terminal applications
Real-World Example
A live dashboard uses separate subwindows for a fixed header and a scrolling log area. The header stays pinned while the body accumulates status lines on each tick:
dashboard.py
import curses
import time
def main(stdscr):
curses.start_color()
curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLUE)
curses.init_pair(2, curses.COLOR_GREEN, curses.COLOR_BLACK)
curses.curs_set(0)
height, width = stdscr.getmaxyx()
header = stdscr.subwin(3, width, 0, 0)
body = stdscr.subwin(height - 3, width, 3, 0)
messages = []
for tick in range(10):
header.erase()
header.bkgd(" ", curses.color_pair(1))
title = f"Dashboard | Tick: {tick}"
header.addstr(1, 2, title, curses.color_pair(1) | curses.A_BOLD)
header.refresh()
messages.append(f"[{tick:02d}] System OK")
body.erase()
body.box()
for i, msg in enumerate(messages[-(height - 5):]):
body.addstr(i + 1, 2, msg, curses.color_pair(2))
body.refresh()
time.sleep(1)
stdscr.getch()
curses.wrapper(main)
Run it in your terminal:
$ python dashboard.py
The header updates on each tick while the body accumulates log lines, demonstrating how curses composites independent windows into a single cohesive display.
Related Resources
Tutorial
Python Textual: Build Beautiful UIs in the Terminal
Textual is a Python library for building text-based user interfaces (TUIs) that support rich text, advanced layouts, and event-driven interactivity in the terminal. This tutorial showcases some of the ways you can design an appealing and engaging UI using Textual.
For additional information on related topics, take a look at the following resources:
- The Python Rich Package: Unleash the Power of Console Text (Tutorial)
- How to Read User Input From the Keyboard in Python (Tutorial)
- Building UIs in the Terminal With Python Textual (Course)
- Python Textual: Build Beautiful UIs in the Terminal (Quiz)
- Unleashing the Power of the Console With Rich (Course)
- Reading User Input From the Keyboard With Python (Course)
- How to Read User Input From the Keyboard in Python (Quiz)
Have a question about this? Mentor AI can show you examples, compare related terms, and point you to tutorials.
By Leodanis Pozo Ramos • Updated Oct. 20, 2026