Skip to main content

The ImGui Context

Dear ImGui uses a context to store all internal state. The context (ImGuiContext) is an opaque structure that contains:
  • Window data and layout state
  • Input state and event queues
  • Font atlas and rendering data
  • ID stack and widget state
  • Navigation and focus state
  • All temporary frame data
The context is intentionally opaque. You don’t need to understand its internals - just know that it exists and must be properly managed.

Context Creation and Destruction

Basic Setup

Every Dear ImGui application must create a context before using any ImGui functions:

Multiple Contexts

You can create multiple contexts, but only one can be current at a time:
Most applications only need a single context. Multiple contexts are useful for advanced scenarios like multi-threaded rendering or isolated UI instances.

Shared Font Atlas

You can share a font atlas between contexts:

The Frame Lifecycle

Each frame in Dear ImGui follows a strict lifecycle:

NewFrame() - Starting a Frame

ImGui::NewFrame() begins a new Dear ImGui frame. Call this as early as possible in your main loop.

What NewFrame() Does

  1. Validates state - Checks that the previous frame was properly ended
  2. Updates time - Processes io.DeltaTime for animations
  3. Processes inputs - Consumes events from io.AddMouseXXX(), io.AddKeyEvent(), etc.
  4. Updates navigation - Handles keyboard/gamepad navigation
  5. Begins layout - Resets layout state for the new frame
  6. Initializes draw data - Prepares internal buffers
You must call NewFrame() before calling any widget functions. Calling widgets without NewFrame() will trigger an assert.

Submitting UI Commands

Between NewFrame() and Render(), you can call any Dear ImGui functions:

Render() and EndFrame()

ImGui::Render() finalizes the frame and builds the draw data.

What Render() Does

  1. Calls EndFrame() internally (you can also call EndFrame() manually)
  2. Finalizes windows - Completes all Begin/End pairs
  3. Sorts draw data - Optimizes draw call order
  4. Builds draw lists - Finalizes vertex and index buffers
  5. Prepares ImDrawData - Creates the structure for rendering
Render() automatically calls EndFrame(). You only need to call EndFrame() manually if you’re skipping rendering for some reason.

EndFrame() Without Rendering

You can finalize the frame without rendering:
This is useful if you need Dear ImGui to process inputs but don’t want to render the UI.

GetDrawData() - Retrieving Draw Commands

ImGui::GetDrawData() returns the finalized draw data after Render():

ImDrawData Structure

Complete Application Skeleton

Here’s a complete minimal application:

Using Custom Backends

If you’re implementing a custom backend, the core lifecycle remains the same:

Common Lifecycle Errors

Calling End() without Begin():
Always pair Begin() with End().
Calling NewFrame() twice:
Each NewFrame() must be paired with Render() or EndFrame().
Using draw data after NewFrame():
Draw data is only valid between Render() and the next NewFrame().

Performance Considerations

Frame Budget

Dear ImGui is designed to be fast, but you should still be mindful:

Memory Allocations

A well-designed Dear ImGui application should:
  • Never call malloc/free in a typical idle frame
  • Preallocate buffers during initialization
  • Reuse temporary buffers across frames

DLL/Shared Library Considerations

DLL users: Heaps and globals are not shared across DLL boundaries!
If using Dear ImGui across DLL boundaries:
You must call SetCurrentContext() and SetAllocatorFunctions() for each DLL boundary.

Next Steps