Skip to main content
State management allows your Gradio applications to remember information between user interactions. This is essential for building applications that need to track conversation history, maintain user sessions, or accumulate data over multiple steps.

What is state?

In Gradio, “state” refers to data that persists across multiple function calls within a user session. Without state, each interaction is independent - the application has no memory of previous inputs or outputs. State in Gradio is:
  • Session-specific: Each user has their own isolated state
  • Temporary: State resets when the user refreshes the page or their session expires
  • Invisible: State components don’t appear in the UI
  • Flexible: Can store any Python object (lists, dicts, custom objects)

The State component

The simplest way to manage state is with the State component:
import gradio as gr

def increment(count):
    count = count + 1
    return count, f"Count: {count}"

with gr.Blocks() as demo:
    state = gr.State(value=0)  # Initialize state to 0
    output = gr.Textbox(label="Current Count")
    button = gr.Button("Increment")
    
    button.click(
        fn=increment,
        inputs=state,  # State is an input
        outputs=[state, output]  # State is also an output
    )

demo.launch()
Key points:
  • Initialize state with a default value: gr.State(value=0)
  • Include state in both inputs and outputs to update it
  • Return the updated state from your function

Common state patterns

Accumulating chat history

Maintain conversation context in a chatbot:
import gradio as gr
import random
import time

def respond(message, chat_history):
    bot_message = random.choice(["How are you?", "Nice day!", "Interesting!"])
    chat_history.append({"role": "user", "content": message})
    chat_history.append({"role": "assistant", "content": bot_message})
    time.sleep(1)
    return "", chat_history

with gr.Blocks() as demo:
    chatbot = gr.Chatbot()
    msg = gr.Textbox(placeholder="Type a message...")
    clear = gr.ClearButton([msg, chatbot])
    
    msg.submit(respond, [msg, chatbot], [msg, chatbot])

demo.launch()
The chatbot component itself acts as state, storing the message history.

Multi-step workflows

Collect information across multiple interactions:
import gradio as gr

def collect_name(name, data):
    data = data or {}
    data["name"] = name
    return data, f"Hello {name}! Now enter your age."

def collect_age(age, data):
    data["age"] = age
    return data, f"Thanks! You are {age} years old."

with gr.Blocks() as demo:
    state = gr.State(value={})
    output = gr.Textbox(label="Status")
    
    name_input = gr.Textbox(label="Name")
    name_btn = gr.Button("Submit Name")
    
    age_input = gr.Number(label="Age")
    age_btn = gr.Button("Submit Age")
    
    name_btn.click(collect_name, [name_input, state], [state, output])
    age_btn.click(collect_age, [age_input, state], [state, output])

demo.launch()

Maintaining counters

Track user actions or iterations:
import gradio as gr

def track_clicks(click_count, click_history):
    click_count += 1
    click_history.append(f"Click #{click_count}")
    return click_count, click_history, "\n".join(click_history)

with gr.Blocks() as demo:
    click_count = gr.State(value=0)
    click_history = gr.State(value=[])
    
    output = gr.Textbox(label="Click History", lines=5)
    button = gr.Button("Click Me!")
    
    button.click(
        fn=track_clicks,
        inputs=[click_count, click_history],
        outputs=[click_count, click_history, output]
    )

demo.launch()

State in Interface

When using gr.Interface, you can use the special "state" string shortcut:
import gradio as gr

def process_with_state(text, state):
    state = state or []
    state.append(text)
    history = "\n".join(state)
    return history, state

demo = gr.Interface(
    fn=process_with_state,
    inputs=["textbox", "state"],
    outputs=["textbox", "state"]
)

demo.launch()
When using Interface with state, there must be exactly one state input and one state output.

Complex state objects

State can hold any Python object, including custom classes:
import gradio as gr
from dataclasses import dataclass
from typing import List

@dataclass
class UserSession:
    name: str = ""
    messages: List[str] = None
    preferences: dict = None
    
    def __post_init__(self):
        if self.messages is None:
            self.messages = []
        if self.preferences is None:
            self.preferences = {}

def initialize():
    return UserSession(), "Session initialized"

def add_message(message, session):
    session.messages.append(message)
    count = len(session.messages)
    return session, f"Total messages: {count}"

with gr.Blocks() as demo:
    session = gr.State(value=UserSession())
    status = gr.Textbox(label="Status")
    
    init_btn = gr.Button("Initialize Session")
    init_btn.click(initialize, None, [session, status])
    
    msg_input = gr.Textbox(label="Message")
    msg_btn = gr.Button("Add Message")
    msg_btn.click(add_message, [msg_input, session], [session, status])

demo.launch()

State vs component values

When to use State

Use gr.State when you need to:
  • Store data that shouldn’t be visible to users
  • Maintain large data structures (models, datasets)
  • Track internal application state
  • Keep intermediate computation results
import gradio as gr

# Good use of State: internal counter
with gr.Blocks() as demo:
    counter = gr.State(value=0)  # Not visible
    display = gr.Number(label="Count")  # Visible
    btn = gr.Button("Increment")
    
    btn.click(
        lambda c: (c + 1, c + 1),
        counter,
        [counter, display]
    )

When to use regular components

Use regular components as “state” when:
  • Users need to see the persisted value
  • The state is simple and fits a component type
  • You want users to potentially edit the state
import gradio as gr

# Good use of visible component as state: editable history
with gr.Blocks() as demo:
    history = gr.Textbox(label="History", lines=10)
    new_entry = gr.Textbox(label="Add Entry")
    btn = gr.Button("Add")
    
    btn.click(
        lambda entry, hist: hist + "\n" + entry,
        [new_entry, history],
        history
    )

Initializing state

Default values

Set initial state when creating the component:
import gradio as gr

with gr.Blocks() as demo:
    # Simple types
    counter = gr.State(value=0)
    text_state = gr.State(value="")
    list_state = gr.State(value=[])
    dict_state = gr.State(value={})
    
    # Complex objects
    custom_state = gr.State(value={"user": "Alice", "score": 100})

Dynamic initialization

Initialize state based on computations:
import gradio as gr
import time

def init_with_timestamp():
    return {"started_at": time.time(), "actions": []}

with gr.Blocks() as demo:
    session = gr.State(value=None)
    status = gr.Textbox()
    
    demo.load(
        lambda: (init_with_timestamp(), "Session started"),
        None,
        [session, status]
    )

Clearing state

Reset state to initial values:
import gradio as gr

def reset():
    return 0, "", "State cleared"

with gr.Blocks() as demo:
    counter = gr.State(value=0)
    messages = gr.Textbox(label="Messages")
    status = gr.Textbox(label="Status")
    
    increment_btn = gr.Button("Increment")
    reset_btn = gr.Button("Reset")
    
    increment_btn.click(
        lambda c: (c + 1, f"Count: {c + 1}", ""),
        counter,
        [counter, messages, status]
    )
    
    reset_btn.click(
        reset,
        None,
        [counter, messages, status]
    )
Or use the ClearButton:
import gradio as gr

with gr.Blocks() as demo:
    state = gr.State(value=[])
    textbox = gr.Textbox()
    
    # Clears both state and textbox to their default values
    clear_btn = gr.ClearButton([state, textbox])

State limitations

Session isolation

Each user session has independent state:
import gradio as gr

# This counter is per-user, not global
with gr.Blocks() as demo:
    counter = gr.State(value=0)
    output = gr.Number()
    btn = gr.Button("Increment")
    
    btn.click(
        lambda c: (c + 1, c + 1),
        counter,
        [counter, output]
    )
User A clicking “Increment” doesn’t affect User B’s counter.
If you need to share data across all users, use global Python variables or a database. However, be careful with thread safety!

Not persistent across refreshes

State resets when the page refreshes:
import gradio as gr

# This counter resets to 0 when user refreshes the page
with gr.Blocks() as demo:
    counter = gr.State(value=0)
    # User increments to 10, refreshes page → back to 0
For true persistence, use external storage (databases, files, etc.).

Memory considerations

State is stored in server memory:
import gradio as gr

# Careful! Large state uses server memory
with gr.Blocks() as demo:
    # This could use a lot of memory with many users
    large_data = gr.State(value=[0] * 1000000)
Avoiding storing very large objects in State, especially with many concurrent users. Consider using file storage or databases for large data.

Advanced patterns

Conditional state updates

Update state only under certain conditions:
import gradio as gr

def conditional_update(value, threshold, state):
    if value > threshold:
        state.append(value)
        return state, f"Added {value} to state"
    return state, f"Value {value} too low"

with gr.Blocks() as demo:
    state = gr.State(value=[])
    value_input = gr.Number(label="Value")
    threshold = gr.Number(label="Threshold", value=10)
    status = gr.Textbox(label="Status")
    btn = gr.Button("Check and Add")
    
    btn.click(
        conditional_update,
        [value_input, threshold, state],
        [state, status]
    )

State with multiple functions

Pass state through a chain of operations:
import gradio as gr

def step1(input, state):
    state["step1_result"] = input.upper()
    return state, state["step1_result"]

def step2(state):
    result = state["step1_result"] + "!!!"
    state["step2_result"] = result
    return state, result

with gr.Blocks() as demo:
    state = gr.State(value={})
    inp = gr.Textbox(label="Input")
    mid = gr.Textbox(label="After Step 1")
    out = gr.Textbox(label="After Step 2")
    btn = gr.Button("Process")
    
    btn.click(
        step1, [inp, state], [state, mid]
    ).then(
        step2, state, [state, out]
    )

See also

  • Components - State is a special component
  • Events - How to update state via events
  • Blocks - Using state in custom layouts
  • ChatInterface - Built-in chat history state management