Ratatui's template gives you one event loop, one backend, and a manual restore call
A Rust crate for cooking up terminal user interfaces (TUIs) 👨🍳🐀 https://ratatui.rs
At a glance
- What is it?
- Ratatui is a Rust crate for drawing terminal interfaces, but what it ships as a quickstart is a template rather than an install path, and the sample that comes out of it is narrower than it looks: the loop redraws only on keypresses, teardown is a separate call that a panic skips, and the app imports its own terminal backend. Here is what that scaffold does and does not decide for you.
- Who is it for?
- Ratatui suits developers who want to control the terminal frame by frame and are willing to own the event loop, the backend binding, and terminal teardown themselves. Step aside if you want a declarative model.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 2 days ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.
Star history
- ratatui/ratatui23,280 ★ · +593
| Repository | 2026-09-21 | 2026-11-14 |
|---|---|---|
| ratatui/ratatui | 22.7k | 23.3k |
593 Stars in the last 54 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
The sample redraws only after a keypress, and any keypress ends the program
The generated application calls terminal.draw(render)? once per pass and then blocks on event::read()? until something arrives. Nothing in that loop wakes on a timer, and the render function carries no state at all: it writes the same string into frame.area() on every pass. The consequence is concrete. A status line showing elapsed time, a progress indicator that should advance while work runs in the background, or a blinking cursor cannot be produced from this shape, because no draw happens between one keypress and the next. The second limit sits in the same two lines: the guard matches Event::Key(_) against whatever the terminal reports, so the first key of any kind terminates the process. There is no key discrimination, no navigation, and no confirmation on quit. Anyone using the template as a starting point inherits both behaviors and has to add explicit key handling before the program does anything other than exit.
Terminal setup and teardown are two calls that a panic walks straight past
The entry point is four statements: install the error reporter, enter the terminal, run, and come back out. ratatui::init() and ratatui::restore() are separate calls with nothing connecting them, and the restore call sits on the normal path only. An Err returned from run still reaches it, because the Result is captured and returned afterwards. A panic inside run unwinds past the explicit restore call, and the README does not say what ratatui::init() sets up for that case. Ordering matters in the same snippet as well, since color_eyre::install()? runs before the terminal is entered, which keeps error reporting setup outside the alternate screen. If your application later grows threads, macros, or extra entry points, the risk multiplies: every path that can unwind has to hold the same discipline, and a second entry point that forgets restore leaves the same damaged terminal behind when your program exits.
use color_eyre::Result;
use crossterm::event::{self, Event};
use ratatui::{DefaultTerminal, Frame};
fn main() -> Result<()> {
color_eyre::install()?;
let terminal = ratatui::init();
let result = run(terminal);
ratatui::restore();
result
}
fn run(mut terminal: DefaultTerminal) -> Result<()> {
loop {
terminal.draw(render)?;
if matches!(event::read()?, Event::Key(_)) {
break Ok(());
}
}
}
fn render(frame: &mut Frame) {
frame.render_widget("hello world", frame.area());
}The quickstart installs cargo-generate and never names ratatui as a dependency
The quickstart is a template generator rather than a way to install the crate. The block below installs cargo-generate with a locked version and then points it at the templates repository. Nothing in it adds ratatui to a manifest, so your first dependency choices are made by the template instead of by you, and the Hello World sample already imports crossterm and color_eyre. The block carries a second cost. It needs the generator installed from a registry and the template pulled from GitHub, and the README gives no offline layout, and no vendored copy, so a machine behind a restrictive proxy has no documented way in. The Hello World template is also only one of several available, and the README does not enumerate what the others contain, so choosing a starting point means trying them one at a time.
cargo install --locked cargo-generate
cargo generate ratatui/templatesCrossterm sits in your own source, so the backend is not yours to swap
The scaffolded file imports crossterm::event and calls event::read() on crossterm's own Event enum. Input handling is not routed through ratatui at all, so the terminal backend reaches into your source on the second line of the program. The workspace is arranged to keep that boundary somewhere else: there are separate crates for ratatui-core at 0.1.2, ratatui-crossterm at 0.1.2, ratatui-termwiz at 0.1.2, ratatui-termion, and ratatui-termina, and the Hello World template still imports crossterm directly for input. What you cannot do is move to another terminal library by editing one manifest line. An application shaped like this has to rewrite its event loop and its key handling for each alternative backend, and any logic placed inside the loop stays welded to the event type it was written against. This is also the honest answer to the ratatui versus crossterm question: crossterm 0.29 is a pinned workspace dependency rather than a competitor, so the decision in front of you is which terminal library sits underneath the drawing calls, not which of the two names you adopt.
ratatui-termion is left out of default members because it fails to compile on Windows
One backend is deliberately excluded from the default build. In the workspace manifest the ratatui-termion line under default-members is commented out with the note that it does not compile on Windows, while the members glob still claims it as part of the workspace. The crate is therefore versioned and published, yet every default workspace operation skips it, on every platform and not only on Windows. For you this means a project that wants that backend has to edit default-members in the repository or depend on the published crate directly, and the README covers neither step. What you cannot do is read presence in the members list as presence in the build you actually run, which is exactly the assumption that produces a missing backend at the end of a long afternoon. The other backend crates, ratatui-termwiz at 0.1.2 and ratatui-termina, are in the default set, so this is a narrow exclusion rather than a general warning about backends other than crossterm.
Each crate carries its own version line, and the changelog is generated from commit subjects
Every crate here publishes on its own version line. The manifest pins ratatui at 0.30.2 while ratatui-core, ratatui-crossterm, and ratatui-termwiz sit at 0.1.2, and the three most recent releases, all dated 2026-06-19, carry those prefixes in their own names. Nothing in the list has reached 1.0, and a 0.x crate can break compatibility inside a minor increment under the semver rules cargo users already apply. That is why BREAKING-CHANGES.md sits next to CHANGELOG.md as a separate document: an upgrade cannot be judged from the version number alone, and the two files answer different questions about what moved. The changelog itself is produced by git-cliff from Conventional Commits, with .cliffignore deciding what gets filtered, so the wording of your commit subjects is what ends up in the release notes other people read.
The alternatives list has two entries and neither is a Rust crate that draws a frame at a time
The alternatives section offers exactly two things: Cursive, described as an ncurses-based TUI library, and iocraft, described as a declarative TUI library. The README gives only those one-line descriptions, so the Ratatui Forum and the ratatui.rs site are where a deeper comparison has to be taken. What it does state about upkeep is concrete: the project is not archived, the license is MIT, and the last push to the default branch main landed on 2026-11-02, and the three most recent releases are dated 2026-06-19.
Editorial conclusion
Ratatui suits developers who want to control the terminal frame by frame and are willing to own the event loop, the backend binding, and terminal teardown themselves. Step aside if you want a declarative model. Before committing, read BREAKING-CHANGES.md and confirm the crate for your terminal library sits in the workspace default member set, because the ratatui crates move on independent version lines.
Frequently asked questions
how to use ratatui
The quickstart installs cargo-generate and generates a project from the templates repository, and the Hello World template produces a main that calls ratatui::init(), loops on terminal.draw(render), reads events through crossterm, then calls ratatui::restore().
what is ratatui rust
Ratatui is an MIT licensed Rust crate for building terminal user interfaces, forked from the tui-rs crate in 2023, published from the ratatui/ratatui repository with its homepage at ratatui.rs and its docs on docs.rs.
ratatui vs crossterm
Crossterm is not an alternative to ratatui in this repository: the workspace pins crossterm 0.29 as a dependency and the Hello World template imports crossterm::event directly to read keys.
ratatui vs bubble tea
The project does not mention Bubble Tea. Its alternatives are Cursive, an ncurses-based TUI library, and iocraft, a declarative TUI library, while its own workspace depends on crossterm 0.29 for terminal handling.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/ratatui-ratatui)Star history chart for your README
[](https://hysenlabs.com/projects/ratatui-ratatui)Was this useful?