Session state — giving your app memory
Here’s the mistake every Streamlit beginner makes:
import streamlit as st
count = 0
if st.button("Add one"):
count = count + 1
st.write(f"Count: {count}")
Click the button. The count shows 1. Click again… still 1. Forever 1. Why?
Why variables vanish
Remember the rerun model: every click re-runs the whole script from the top. So count = 0 runs again, wiping your increment before it ever displays. Plain variables have the memory of a goldfish.
The fix: st.session_state
st.session_state is a dictionary that survives reruns. It’s your app’s memory:
import streamlit as st
if "count" not in st.session_state:
st.session_state.count = 0
if st.button("Add one"):
st.session_state.count += 1
st.write(f"Count: {st.session_state.count}")
Click away now — it climbs: 1, 2, 3… The value lives in session state, so reruns no longer erase it.
The pattern to memorize
if "my_key" not in st.session_state:
st.session_state.my_key = initial_value
Initialize before you read. This one pattern prevents the most common Streamlit crash (KeyError) — check the key exists first, set a default if not.
Where you’ll use it (real examples from this course)
- Quiz app — which question number the user is on
- Countdown timer — the deadline they’re counting toward
- To-do list — the list of tasks between actions
- Typing test — when the timer started
If an app needs to remember anything longer than one rerun, it goes in session state.
Clearing memory (restarts)
if st.button("Restart"):
for key in ["count", "history"]:
st.session_state.pop(key, None)
st.rerun()
pop(key, None) removes a key safely (no crash if it’s missing) — that’s how apps “start over”.
Common Errors & Fixes
- KeyError: ‘count’ — you read st.session_state.count before initializing it. Use the initialize-first pattern.
- Value updates but display lags one click behind — you’re displaying before updating. Update the state first, then display (or call st.rerun() after changing state).
- State resets when I restart the app — session state lives per browser session; closing the tab or restarting the server clears it. That’s expected.
What to try next
Build a click-counter with a Reset button and a “highest count ever” that survives resets (hint: store two keys, only reset one).
Key takeaways
- • Why plain variables reset on every interaction
- • st.session_state as your app's memory
- • The initialize-before-read pattern