Ratatui
A Rust library for terminal user interfaces that redraws the whole screen from your app’s state on every frame, then writes only the cells that changed.
- What it is
- Terminal user interfaces (TUIs)
- Type
- Open source
- Made by
- The Ratatui Developers (forked from tui-rs by Florian Dehau)
- License
- MIT
- Facts checked
- 13 October 2026
What it is
Ratatui draws in immediate mode. Your program owns its state and its loop; each time it wants to update the screen it calls terminal.draw() with a closure, and inside that closure it renders every widget again into a Buffer, a grid of Cells that each hold one symbol and its style. Widgets are plain values that implement a render() method and are thrown away after the frame. When the closure returns, Ratatui compares the new buffer with the previous one and writes only the difference to the terminal, then swaps the two buffers. Layout is computed from constraints such as Length(3) or Fill(1) that split a Rect into smaller areas.
Ratatui only renders. Reading keys and mouse events, raw mode and the alternate screen come from a backend library: Crossterm by default, or Termion, Termwiz or Termina, plus a TestBackend for unit tests. Since version 0.30 (December 2025) the project is a workspace of crates: ratatui-core holds the traits and types and changes slowly, so third-party widget crates can depend on it, while ratatui-widgets and one crate per backend sit on top. With default features off, it compiles for no_std targets; the team reports running it on ESP32 and STM32H7 microcontrollers.
The project is a community fork of tui-rs, which Florian Dehau wrote in 2016 and stopped maintaining. Ratatui’s first release, 0.20.0, came out in March 2023, and tui-rs now points its users to it. It is still released as 0.x and is actively developed: 0.30.2 shipped in June 2026, and commits landed in October 2026. OpenAI’s Codex CLI draws its terminal interface with it.
Why teams pick it
- No widget tree to keep in sync: the UI is a function of your state, which sidesteps most of the lifetime and ownership fights a retained widget tree causes in Rust
- Double buffering with a diff means each frame writes only changed cells to the terminal, however much the app redraws
- Does not take over your program: there is no
app.run()event loop, so it can be added to an existing program, even just to chart its internal state - Pluggable backends (Crossterm, Termion, Termwiz, Termina) and
no_stdsupport reach from desktop terminals to microcontrollers, andTestBackendlets you unit test the UI without a terminal
Watch out for
- Still 0.x: minor releases carry breaking changes (0.30 removed
block::Title, renamedAlignmentand changed theBackendtrait), listed in a separate BREAKING-CHANGES.md - You write the event loop, input handling and app structure yourself; if the loop blocks, the screen stops updating
- Widgets keep nothing between frames, so a selection or scroll offset lives in a separate state value (such as
ListStatefor aStatefulWidget) that your app stores and passes in each time - Needs a recent compiler: the minimum supported Rust version is 1.88 as of 0.30.1
Alternatives
What all terminal user interfaces (tuis) have in common →Compare side by side →
Bubble TeaOpen sourceA Go framework from Charm for terminal apps built on the Elm Architecture: one model holds the state, Update turns messages into a new model, and View describes the screen.How it fits with other technologies
A gauge that grows with the right arrow key (Ratatui 0.30) · rust
use ratatui::crossterm::event::{self, Event, KeyCode};
use ratatui::layout::{Constraint, Layout};
use ratatui::widgets::{Block, Gauge, Paragraph};
use ratatui::Frame;
fn main() -> std::io::Result<()> {
let mut percent: u16 = 0;
// run() enters raw mode and the alternate screen, and restores them on exit
ratatui::run(|terminal| loop {
terminal.draw(|frame| render(frame, percent))?;
if let Event::Key(key) = event::read()? {
match key.code {
KeyCode::Char('q') => break Ok(()),
KeyCode::Right => percent = (percent + 10).min(100),
_ => {}
}
}
})
}
// Called for every frame: describe the whole screen from the current state.
fn render(frame: &mut Frame, percent: u16) {
let [top, rest] = Layout::vertical([Constraint::Length(3), Constraint::Fill(1)])
.areas(frame.area());
let gauge = Gauge::default().block(Block::bordered().title("Upload")).percent(percent);
frame.render_widget(gauge, top);
frame.render_widget(Paragraph::new("Right arrow adds 10%, q quits"), rest);
}See it in a real stack
No architecture uses Ratatui yet. Drop it into the playground and wire it up yourself.Open playground →Worth exploring
Where it came from2016–2026
Florian Dehau started tui-rs in 2016 as a Rust library for terminal dashboards, inspired by the JavaScript library blessed-contrib and the Go library termui. It rendered in immediate mode with intermediate buffers and left input handling to libraries such as Crossterm and Termion, and its popularity kept growing as people used it in more ambitious projects.
In August 2022 Dehau wrote that their work left little energy for the crate and asked for people to take it over, listing its gaps: complex layouts, scrolling and mouse support were hard, and it only suited full-screen apps. Contributors started a community fork in early 2023, moved the open pull requests over and released it as Ratatui 0.20.0 in March 2023, a maintenance release with bug fixes and no big features. In August 2023 tui-rs was marked unmaintained and its README pointed to Ratatui.
The fork kept the immediate-mode design and grew around it: a website with tutorials and templates, convenience functions such as ratatui::init() (0.28.1) and ratatui::run() (0.30), and in December 2025 a split into a workspace of crates with no_std support for embedded targets.
Why it’s built this way
- Immediate mode with intermediate buffers
- Rebuilding widgets from state each frame avoids the lifetime and ownership problems that retained widget trees cause in Rust, which Dehau saw as one reason beginners liked the crate; the buffer diff keeps the terminal output small.
- A library, not a framework
- tui-rs never had an
app.run()that takes over execution, so it could be dropped into any program, even just to visualize a program’s internal state. Ratatui kept that: input comes from the backend, and the loop is yours. - Fork instead of waiting
- The original maintainer had stepped back and changes were waiting unreleased. A community fork under a new name let new maintainers transfer the open pull requests from tui-rs and ship them, starting with a fixes-only release.
- Split into a workspace of crates in 0.30
- A slower-moving
ratatui-coregives widget authors a more stable API, and separate widget and backend crates cut compile times and let apps pick their dependencies.
Timeline
- 2016
Florian Dehau creates tui-rs
- 2022
Dehau asks the community to take over maintenance (August)
- 2023
Community fork released as Ratatui 0.20.0 (March); tui-rs marked unmaintained (August)
- 2025
Ratatui 0.30 splits into crates and adds
no_stdsupport (December) - 2026
Ratatui 0.30.2 (June); development continues on 0.31
- fdehau/tui-rs issue #654: Future of tui-rs (Aug 2022)
- tui-rs README (no longer maintained, see Ratatui; inspirations; immediate rendering)
- Ratatui release notes: v0.20.0, the first release of the fork (Mar 2023)
- Ratatui website: v0.30.0 highlights (modular crates, no_std, run())
- Ratatui crate docs 0.30.2 (forked in 2023; init() in 0.28.1, run() in 0.30.0)
- crates.io: ratatui versions (0.20.0 Mar 2023, 0.30.0 Dec 2025, 0.30.2 Jun 2026)
- Ratatui BREAKING-CHANGES.md (a v0.31.0 section is already in progress)
Sources11 · facts checked 13 October 2026
- Ratatui website: Rendering (immediate mode, render loop management)
- Ratatui website: Rendering under the hood (Buffer, Cell, double buffer diff)
- Ratatui website: Backends (Crossterm, Termion, Termwiz, Termina, TestBackend)
- Ratatui website: v0.30.0 highlights (workspace crates, no_std on ESP32 and STM32H7, run())
- Ratatui crate docs 0.30.2 (run(), crate organization, re-exported crossterm)
- Ratatui BREAKING-CHANGES.md (0.30 and 0.30.1 changes, MSRV 1.88)
- Ratatui docs: StatefulWidget (ListState keeps selection and offset)
- Ratatui README and LICENSE (MIT; forked from tui-rs in 2023)
- Ratatui commits on main (active in October 2026)
- fdehau/tui-rs issue #654: Future of tui-rs (no app.run(), immediate mode and ownership)
- OpenAI Codex: codex-rs/tui/Cargo.toml (depends on ratatui)