Skip to content

Using no_std

Ratatui is no_std-compatible, which allows it to run in embedded and other resource-constrained environments. This means you can run TUIs on a wider range of targets and have widget usable in both desktop and embedded environments.

  1. Disable default features so the crate does not pull in std-only dependencies:
ratatui = { version = "0.30", default-features = false }
  1. Choose a backend that works on your platform.

The built-in backends rely on std, so no_std targets need a custom backend that implements ratatui::backend::Backend or a third-party option like mousefood 🧀

  1. When checking a no_std build, compile with a no_std target.

For example, on ESP32:

Terminal window
cargo check --target riscv32imc-unknown-none-elf

If you already have a Ratatui widget, you can make it no_std-compatible with a few small changes. Even if you haven’t built for embedded before!

  1. Opt into no_std and add alloc crate:

    lib.rs
    #![no_std]
    extern crate alloc;
  2. Depend on ratatui-core instead of the full ratatui crate to avoid backend dependencies:

    ratatui-core = { version = "0.30", default-features = false }
  3. Swap std types for their core/alloc equivalents, for example core::fmt, alloc::string::String, alloc::vec::Vec, and alloc::boxed::Box.

  4. Keep a std feature (off by default) for conveniences like tests or examples, but write your core widget logic so it also works without it.

  5. Avoid std-only APIs in widget code paths. Examples: use core::time::Duration instead of std::time::Duration, pass in data rather than reading files, and keep logging behind a feature so it can be disabled on targets without I/O.

Here is a minimal no_std widget implementation:

#![no_std]
extern crate alloc;
use alloc::string::String;
use ratatui_core::buffer::Buffer;
use ratatui_core::layout::Rect;
use ratatui_core::text::Line;
use ratatui_core::widgets::Widget;
struct Greeting {
message: String,
}
impl Widget for &Greeting {
fn render(self, area: Rect, buf: &mut Buffer) {
Line::raw(&self.message).render(area, buf);
}
}