How to Serialize and Deserialize UI State Using Dear ImGui's .ini File System

Dear ImGui persists window positions, sizes, and collapsed states to a human-readable .ini file using LoadIniSettingsFromDisk(), SaveIniSettingsToDisk(), and the extensible ImGuiSettingsHandler system.

Dear ImGui provides a built-in serialization mechanism that captures UI layout state—including window geometry and visibility—into a simple text-based .ini format. Located in the ocornut/imgui repository, this system allows you to serialize and deserialize UI state using either automatic file I/O or manual memory buffers. The architecture relies on registered settings handlers that read and write specific data sections, enabling both default window management and custom application persistence.

Understanding the .ini Serialization Architecture

The serialization pipeline operates through settings handlers registered in the global ImGuiContext. Each handler implements callbacks for reading and writing specific data types—the built-in window handler manages [Window][...] sections, while you can register custom handlers for application-specific data.

When you invoke ImGui::LoadIniSettingsFromDisk() or LoadIniSettingsFromMemory(), Dear ImGui iterates over all registered handlers and executes their ReadAllFn callbacks. Conversely, SaveIniSettingsToDisk() and SaveIniSettingsToMemory() trigger each handler's WriteAllFn to aggregate data into a zero-terminated string or write directly to disk.

According to the source code in imgui.cpp, the implementation follows this flow:

  • LoadIniSettingsFromDisk (line 15759): Opens the specified file, reads its contents into memory, and forwards the buffer to LoadIniSettingsFromMemory.
  • LoadIniSettingsFromMemory (line 15772): Parses the ini text line-by-line, dispatching to each handler's ReadOpenFn and ReadLineFn callbacks.
  • SaveIniSettingsToDisk (line 15848): Generates the complete ini string via SaveIniSettingsToMemory, then writes it to the file system.
  • SaveIniSettingsToMemory (line 15865): Clears the internal text buffer, requests each handler to append its data via WriteAllFn, and returns the resulting string.

Loading UI State from Disk and Memory

You can initialize Dear ImGui with previously saved layout data either by letting the framework handle file I/O automatically or by manually feeding it memory buffers from your own storage system.

Automatic Loading on Startup

By default, Dear ImGui attempts to load settings automatically during the first ImGui::NewFrame() call if io.IniFilename is set. This is the simplest approach for most applications:

ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
io.IniFilename = "my_app_layout.ini";  // Default is "imgui.ini"

// First call to NewFrame() triggers LoadIniSettingsFromDisk()
while (!quit) {
    ImGui::NewFrame();
    // ... UI code ...
    ImGui::Render();
}

Manual Loading from Custom Storage

For applications that manage their own persistence layers (such as user profile databases or encrypted storage), disable automatic file I/O by setting io.IniFilename to nullptr, then manually invoke the memory-based loader:

ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
io.IniFilename = nullptr;  // Disable automatic file operations

// Load from your own storage system
std::string savedState = LoadFromDatabase();
ImGui::LoadIniSettingsFromMemory(savedState.c_str(), savedState.size());

Saving UI State to Disk and Memory

Dear ImGui can persist state changes automatically after a short delay, or you can trigger saves manually to control exactly when and where data gets stored.

Automatic Saving via io.IniFilename

When io.IniFilename is non-NULL, the framework monitors io.WantSaveIniSettings and automatically calls SaveIniSettingsToDisk() a few seconds after any UI change occurs:

ImGuiIO& io = ImGui::GetIO();
io.IniFilename = "app_state.ini";

// Inside your main loop, ImGui handles saving automatically
while (!quit) {
    ImGui::NewFrame();
    // ... UI modifications trigger WantSaveIniSettings ...
    ImGui::Render();
}

Manual Saving to Memory Buffers

To store ini data in custom locations (cloud sync, embedded resources, or databases), check the WantSaveIniSettings flag and retrieve the buffer manually:

if (io.WantSaveIniSettings) {
    size_t dataSize = 0;
    const char* iniData = ImGui::SaveIniSettingsToMemory(&dataSize);
    
    // Persist to your storage backend
    SaveToDatabase(std::string(iniData, dataSize));
    
    io.WantSaveIniSettings = false;  // Reset flag after handling
}

Implementing Custom Settings Handlers

The ImGuiSettingsHandler API allows you to serialize custom application data alongside Dear ImGui's window sections. Register handlers after creating the context but before loading settings.

The handler structure requires three key callbacks: ReadOpenFn allocates storage for your data section, ReadLineFn parses individual key-value pairs, and WriteAllFn serializes your data back to the text buffer:

struct MyAppSettings {
    int magicNumber = 42;
    bool showDemo = true;
};

void RegisterCustomHandler() {
    ImGuiSettingsHandler handler;
    handler.TypeName = "MyApp";
    handler.TypeHash = ImHashStr("MyApp");
    
    handler.ReadOpenFn = [](ImGuiContext*, ImGuiSettingsHandler*, const char*) -> void* {
        static MyAppSettings settings;
        return &settings;
    };
    
    handler.ReadLineFn = [](ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line) {
        MyAppSettings* s = (MyAppSettings*)entry;
        sscanf(line, "MagicNumber=%d", &s->magicNumber);
        sscanf(line, "ShowDemo=%d", (int*)&s->showDemo);
    };
    
    handler.WriteAllFn = [](ImGuiContext*, ImGuiSettingsHandler* h, ImGuiTextBuffer* buf) {
        MyAppSettings* s = (MyAppSettings*)h->UserData;
        buf->appendf("[MyApp][Main]\n");
        buf->appendf("MagicNumber=%d\n", s->magicNumber);
        buf->appendf("ShowDemo=%d\n", s->showDemo);
    };
    
    ImGui::GetCurrentContext()->SettingsHandlers.push_back(handler);
}

Once registered, your [MyApp] sections will automatically appear in the generated .ini output and be parsed during loading.

Summary

  • Dear ImGui uses a text-based .ini format to persist window positions, sizes, and collapsed states between application sessions.
  • Four core functions control the process: LoadIniSettingsFromDisk(), LoadIniSettingsFromMemory(), SaveIniSettingsToDisk(), and SaveIniSettingsToMemory(), implemented in imgui.cpp (lines 15759–15865).
  • Automatic I/O occurs when io.IniFilename points to a valid path, triggering loads on the first frame and saves a few seconds after changes.
  • Manual control requires setting io.IniFilename to nullptr and using the memory-based APIs to integrate with custom storage backends.
  • Custom data persists via the ImGuiSettingsHandler structure, which provides callbacks for reading and writing application-specific sections within the same .ini file.

Frequently Asked Questions

Where does Dear ImGui store window positions by default?

By default, Dear ImGui creates an imgui.ini file in the current working directory. You can inspect or modify this path via ImGuiIO::IniFilename before the first NewFrame() call, as defined in imgui.h (lines 1136–1139).

How do I prevent automatic .ini file creation?

Set io.IniFilename = nullptr immediately after creating the context. This disables both automatic loading and saving, allowing you to manage persistence manually using LoadIniSettingsFromMemory() and SaveIniSettingsToMemory().

Can I store custom application data in the ImGui .ini file?

Yes. Register an ImGuiSettingsHandler with TypeName, ReadOpenFn, ReadLineFn, and WriteAllFn callbacks. Your handler will receive read calls during LoadIniSettingsFromMemory() and write calls during SaveIniSettingsToMemory(), letting you serialize arbitrary data alongside window state.

When should I call LoadIniSettingsFromMemory?

Call it after ImGui::CreateContext() but before the first ImGui::NewFrame(). Loading after the first frame may result in default window positions being applied before your saved state overrides them.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →