Backend / Web frameworks / Streamlit / 02_session_state.md

Streamlit Session State - Interview Questions

Updated 3 interview angles 5 min read source
On this page11
  1. 1. What is st.session_state and why do you need it?
  2. 2. How do you read and write session state?
  3. 3. How do widgets interact with session state?
  4. 4. What are on_change callbacks?
  5. 5. How do you reset state or “clear the form”?
  6. 6. What is st.rerun() and when do you call it?
  7. 7. What’s the difference between widget value, widget key, and session_state?
  8. 8. How do you share state across pages in a multipage app?
  9. 9. Common session_state pitfalls
  10. 10. Cross-links
  11. Interview angle

Streamlit Session State - Interview Questions

1. What is st.session_state and why do you need it?

Streamlit re-runs the script top-to-bottom on every interaction. Local variables are reset each run. st.session_state is a dict-like object that persists across reruns within the same browser session.

python
import streamlit as st

if "count" not in st.session_state:
    st.session_state["count"] = 0

if st.button("Increment"):
    st.session_state["count"] += 1

st.write("Count:", st.session_state["count"])

Without session state, the counter would reset to 0 on every rerun.

Scope: per browser tab. Two tabs = two separate sessions. Closing the tab clears it. There is no cross-user or persistent storage — for that, use a database.

2. How do you read and write session state?

Two equivalent syntaxes:

python
# Dict-style
st.session_state["user_id"] = 42
uid = st.session_state["user_id"]

# Attribute-style (only for valid Python identifiers)
st.session_state.user_id = 42
uid = st.session_state.user_id

# Safe read with default
n = st.session_state.get("count", 0)

# Init pattern
st.session_state.setdefault("history", [])

Standard dict operations work: in, .get(), .pop(), iteration.

3. How do widgets interact with session state?

Every widget with a key parameter automatically writes its value to st.session_state[key]:

python
name = st.text_input("Name", key="user_name")
# After render, st.session_state["user_name"] holds the current value.
# `name` and `st.session_state["user_name"]` are the same value.

You can also seed a widget by setting state before the widget is created:

python
if "user_name" not in st.session_state:
    st.session_state["user_name"] = "Alice"
st.text_input("Name", key="user_name")

You cannot assign to st.session_state[key] after the widget with that same key has rendered in the same run — Streamlit raises an error. Either set it before the widget, or use a callback.

4. What are on_change callbacks?

Widgets accept an on_change callback that fires before the rerun, useful for side effects or for syncing state across widgets:

python
def on_select():
    st.session_state["selection_changed"] = True
    log.info(f"Selected: {st.session_state['kind']}")

st.selectbox("Kind", ["A", "B", "C"], key="kind", on_change=on_select)

Callbacks run in the order: on_change fires → script reruns. Pass arguments via args=(...) or kwargs={...}.

on_click is the same idea for buttons.

5. How do you reset state or “clear the form”?

python
# Reset specific keys
for key in ["name", "age", "email"]:
    if key in st.session_state:
        del st.session_state[key]
st.rerun()

# Reset everything
st.session_state.clear()
st.rerun()

Note: deleting a widget’s key resets that widget on the next render only if the widget is re-created. If you want a “Clear” button that resets a form, the standard pattern is:

python
if st.button("Clear"):
    st.session_state.pop("name", None)
    st.session_state.pop("age", None)
    st.rerun()

6. What is st.rerun() and when do you call it?

st.rerun() (formerly st.experimental_rerun) immediately stops the current run and starts a new one from the top.

Use cases:

  • Inside a callback that mutated state and wants the UI to reflect it on the next render.
  • After a form submit when the next render needs different layout.
  • After login: store the token, rerun, render the authenticated app.

Most of the time you don’t need it — Streamlit reruns automatically on widget changes. Reach for st.rerun() only when you’ve changed state programmatically (not via a widget) and want an immediate refresh.

python
if st.button("Login"):
    token = authenticate(...)
    st.session_state["token"] = token
    st.rerun()  # next run sees the token, shows the app

7. What’s the difference between widget value, widget key, and session_state?

python
value = st.text_input("Name", key="user_name", value="default")
  • Return value (value) — the current widget value, available immediately in this run.
  • key="user_name" — the slot in st.session_state where Streamlit writes/reads it. With a key, the widget is bound to that slot.
  • value="default" — the initial value used the first time, before the user touches it. Ignored if a value already exists in session state for that key.

After the widget renders, value == st.session_state["user_name"]. They’re the same data, accessed two ways.

8. How do you share state across pages in a multipage app?

st.session_state is shared across pages of the same Streamlit app — you don’t need any extra plumbing.

python
# page_1.py
st.session_state["user_id"] = login()

# page_2.py
uid = st.session_state.get("user_id")
if uid is None:
    st.warning("Please log in.")
    st.stop()

State persists as long as the browser tab stays open. Closing the tab or hitting “Rerun” cold (Ctrl-Shift-R) clears it.

For cross-session persistence (user closes tab, comes back), write to a DB or set cookies via a component like streamlit-cookies-controller.

9. Common session_state pitfalls

Pitfall Fix
Setting state for a widget after the widget renders → error Set state before the widget, or use on_change callback
Expecting state to persist after browser refresh It doesn’t. Use a DB or cookies
Two tabs of the same app share state They don’t. Each tab is its own session
Mutating a list/dict in state and not seeing the change The reference is the same; mutation works. If it doesn’t, you’re probably reassigning a local variable that shadows the state entry
Callback not firing on_change fires only when the widget value actually changes, not on every rerun
st.button value not surviving Buttons are momentary; persist the click into session state
Race conditions between callback writes and widget writes Callbacks run before the rerun completes — set non-widget state in callbacks; let widgets manage their own keys

Interview angle 3

  • “What is st.session_state?” - a per-session dict surviving reruns. It’s the only way to keep state, since local variables are recreated on every run.
  • “How long does it live?” - for the browser session. It’s not persistent storage and it’s not shared between users, so anything that must outlive a refresh belongs in a database.
  • “What’s the widget-key interaction?” - a widget with key="x" reads and writes st.session_state["x"], so you can set a widget’s value programmatically by assigning to it before the widget renders.