# Immediate Mode GUI vs Retained Mode: How Dear ImGui Rebuilds UI Every Frame

> Discover how Dear ImGui's immediate mode GUI differs from retained mode. Learn how widgets are recreated every frame, storing state in your application, not UI controls. Optimize your UI development.

- Repository: [omar/imgui](https://github.com/ocornut/imgui)
- Tags: deep-dive
- Published: 2026-07-24

---

**Dear ImGui implements an immediate mode GUI where widgets are recreated and processed every frame through direct function calls, eliminating persistent widget objects and storing state in application variables rather than UI controls.**

Dear ImGui (ocornut/imgui) revolutionizes interface design by implementing an **immediate mode GUI** paradigm that fundamentally differs from traditional UI frameworks. Instead of maintaining a tree of persistent widget objects, the library reconstructs the entire interface each frame through a sequence of procedural calls. This approach eliminates complex state synchronization between the UI and application logic, making it ideal for game development and real-time tools.

## Core Principles of Immediate Mode GUI

The immediate mode GUI architecture in Dear ImGui operates on three fundamental principles that distinguish it from retained mode alternatives.

### Stateless Widget Rendering

Each call such as `ImGui::Button("OK")` does not create a persistent widget object. Instead, the function queries the current input state, determines whether the widget is hovered or clicked, updates minimal internal state, and immediately returns a boolean result. The widget exists only for the duration of that function call, leaving no residual UI objects in memory after the frame completes.

### Application-Owned State Storage

All **persistent UI data** must be stored by the application in its own variables and passed back to ImGui on the next frame. When calling `ImGui::SliderFloat("Value", &value, 0.0f, 1.0f)`, the library reads from and writes directly to the external `value` variable. This inversion of control ensures that the UI never becomes out of sync with the underlying data model, as there are no hidden widget properties to synchronize.

### Frame-Based Execution Model

The UI hierarchy is implicitly defined by the order of ImGui calls within each frame's execution. In [`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp), the core implementation processes these calls sequentially, building draw lists that persist only until `ImGui::Render()` emits the final command buffers. This contrasts sharply with retained mode systems where a scene graph of objects persists across frames and receives asynchronous events.

## Immediate Mode GUI vs Retained Mode Comparison

Understanding the architectural differences between these paradigms reveals why Dear ImGui achieves its characteristic simplicity and performance.

**Widget Lifecycle**
- **Immediate Mode:** Widgets are created, processed, and destroyed within a single frame iteration. No long-lived objects remain in memory.
- **Retained Mode:** Widgets are instantiated once during initialization and persist until explicitly destroyed, requiring memory management and lifecycle tracking.

**Event Handling**
- **Immediate Mode:** Events are polled directly inside the widget call. Functions like `ImGui::Button()` return interaction flags immediately, allowing conditional logic to execute in-line.
- **Retained Mode:** Events are dispatched to existing widget objects via callbacks, listeners, or signal-slot mechanisms, creating asynchronous complexity.

**State Management**
- **Immediate Mode:** Application variables store all persistent state. ImGui maintains only minimal internal state for navigation and focus in structures managed within [`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp).
- **Retained Mode:** Widget objects own their internal state (text content, selection ranges, scroll positions), requiring explicit data binding to application logic.

**Rendering Architecture**
- **Immediate Mode:** Despite rebuilding the UI each frame, Dear ImGui does **not** issue a draw call per widget. As implemented in [`imgui_draw.cpp`](https://github.com/ocornut/imgui/blob/main/imgui_draw.cpp), the library batches geometry into vertex buffers and emits a small, efficient list of draw commands consumed by backend renderers like [`backends/imgui_impl_opengl3.cpp`](https://github.com/ocornut/imgui/blob/main/backends/imgui_impl_opengl3.cpp).
- **Retained Mode:** Engines typically traverse a persistent scene graph each frame, which may involve cache invalidation and complex batching strategies.

## Implementation in Dear ImGui Source Code

The immediate mode paradigm is realized through specific architectural decisions visible in the repository's source files.

In [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h), the public API exposes functions like `ImGui::Begin()`, `ImGui::End()`, and `ImGui::SliderFloat()` that operate without object instantiation. The core state machine in [`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp) manages frame contexts through `ImGui::NewFrame()` and `ImGui::Render()`, processing input and building draw lists that live only for the current iteration.

The [`imgui_draw.cpp`](https://github.com/ocornut/imgui/blob/main/imgui_draw.cpp) file handles the vertex buffer construction, aggregating geometry from all widget calls into efficient draw lists. This batching mechanism avoids the "hammering the GPU" pitfall that some associate with immediate mode rendering, as clarified in [`docs/README.md`](https://github.com/ocornut/imgui/blob/main/docs/README.md).

## Practical Code Example

The following pattern demonstrates the immediate mode GUI workflow inside a typical application loop:

```cpp
// Application state stored in regular variables
bool show_demo = true;
float value = 0.0f;

while (running) {
    // 1. Start new ImGui frame
    ImGui_ImplXXX_NewFrame();
    ImGui::NewFrame();

    // 2. Build UI (immediate mode pass)
    ImGui::Begin("Demo Window", &show_demo);
    
    if (ImGui::Button("Press Me")) {
        // Handle click immediately
        value = 0.0f;
    }
    
    ImGui::SliderFloat("Value", &value, 0.0f, 1.0f);
    ImGui::End();

    // 3. Render: ImGui builds draw list, backend draws it
    ImGui::Render();
    ImGui_ImplXXX_RenderDrawData(ImGui::GetDrawData());
}

```

In this example, `ImGui::Button()` returns `true` only during the frame where the click occurs, and `ImGui::SliderFloat()` modifies the external `value` variable directly. No window or button objects persist between iterations of the `while` loop.

## Summary

Dear ImGui's immediate mode GUI architecture provides distinct advantages for real-time applications:

- **Zero Widget Objects:** UI elements exist only as function calls, eliminating memory allocation and object lifecycle management overhead.
- **Synchronous Event Handling:** Input processing occurs inline with UI description code, removing the need for callback registration or event queues.
- **Automatic Synchronization:** Application variables serve as the single source of truth, preventing state desynchronization between the UI and business logic.
- **Efficient Rendering:** Geometry batching in [`imgui_draw.cpp`](https://github.com/ocornut/imgui/blob/main/imgui_draw.cpp) ensures optimal GPU utilization despite the per-frame reconstruction paradigm.

## Frequently Asked Questions

### Does immediate mode GUI mean issuing a draw call for every widget every frame?

No. While Dear ImGui reconstructs the UI logic each frame, it does not issue GPU draw calls per widget. Instead, [`imgui_draw.cpp`](https://github.com/ocornut/imgui/blob/main/imgui_draw.cpp) batches all geometry into vertex buffers, and `ImGui::Render()` produces a compact draw list containing only a few commands. Backend implementations like [`imgui_impl_opengl3.cpp`](https://github.com/ocornut/imgui/blob/main/imgui_impl_opengl3.cpp) then render these batches efficiently, making the approach suitable for high-performance applications.

### Where is UI state stored if widgets don't persist between frames?

Persistent state resides entirely in your application's variables. When you call `ImGui::SliderFloat()` or `ImGui::InputText()`, you pass pointers to your own data. ImGui maintains only transient internal state for navigation, focus management, and animation, stored in structures like `ImGuiContext` within [`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp). This design ensures the UI reflects your data model without synchronization code.

### How does immediate mode GUI handle complex layouts without a widget hierarchy?

The UI hierarchy emerges implicitly from the call stack and order of operations. `ImGui::Begin()` and `ImGui::End()` create scoped containers, while functions like `ImGui::SameLine()` or `ImGui::Indent()` modify the current cursor position in the window's layout state. The library tracks this transient hierarchy in frame-specific stacks during `ImGui::NewFrame()`, eliminating the need for persistent parent-child object relationships.

### Is Dear ImGui suitable for applications requiring complex form validation?

Yes, though the pattern differs from retained mode frameworks. Validation logic executes immediately after the widget call returns a value. For example, after `ImGui::InputFloat()` modifies your variable, you can clamp or validate the value before the next frame begins. This immediate feedback loop often results in simpler validation code compared to reactive systems that must propagate changes through observer patterns.