Streamlit re-runs your entire Python script from top to bottom every single time a user interacts with anything — a button click, a slider move, a text input. That is how it works. Most of the time it is fine.
But this creates a real problem: every variable you create in your script gets reset to its starting value on every re-run. So if a user types something in a text box, picks a value from a dropdown, or gets to step 2 of a form — the next interaction wipes it all out.
This is where st.session_state comes in. It is a dictionary that survives every re-run for the whole time the user has the app open. This guide covers everything you need to know to use it well.
The Problem Session State Solves
Before we look at the solution, it helps to see the problem clearly. Here is an app that tries to count button clicks — but it does not work:
Every time the button is clicked, Streamlit re-runs the script. The first line sets count = 0 again. So the count is always either 0 or 1. It never accumulates. Session state is the fix.
What Is Session State
Think of st.session_state like a small notebook that Streamlit keeps open on the desk next to your script. Every time your script re-runs, it can read from and write to that notebook. The notebook stays there the whole time the user has the app open in their browser.
Each entry in the notebook has a name (the key) and a value. You can store anything in it — numbers, strings, lists, DataFrames, even model results.
The notebook is per user, per tab. If two people open your app at the same time, each of them gets their own notebook. If one user opens the app in two browser tabs, each tab gets its own notebook too.
The Basics
Reading and Writing Values
You access session state like a dictionary, or like an object with dot notation. Both work the same way:
Setting Default Values Safely
The most important pattern in session state is always check before writing. If you write a value unconditionally, it will reset every time the script re-runs — which defeats the whole purpose.
Session State with Widgets
Using Widget Keys
Every Streamlit widget — text inputs, sliders, checkboxes, selectboxes — can be given a key parameter. When you do this, Streamlit automatically links that widget's value to session state. You do not have to store it manually.
Callbacks — Run Code When a Widget Changes
Sometimes you want to run some code immediately when a widget value changes, before the rest of the script runs. You do this with the on_change or on_click parameter and a callback function.
Counter Example — The Classic Use Case
Here is the counter we tried to build at the start, now done correctly using session state:
Multi-Step Forms — Keep Users on the Right Step
One of the most powerful uses of session state is building multi-step wizards. Without session state, clicking Next on step 1 would send the user back to step 1 on the next re-run. With session state, you track which step they are on and always show the right one.
Storing Computed Results
One of the best uses of session state is to cache the result of an expensive computation — like running an ML model or querying a database — so you only do it once even if the user changes other things on the page.
Clearing and Resetting State
Sometimes you want to clear specific values or reset the whole app back to its starting state — for example when the user logs out or clicks a Start Over button.
Common Patterns at a Glance
Here is a quick reference of the session state patterns you will use most often in real Streamlit apps:
| Pattern | When to Use | Key Code |
|---|---|---|
| Persist a counter | Any value that increments across clicks | st.session_state.count += 1 |
| Track form step | Multi-step wizards and onboarding flows | st.session_state.step = 2 |
| Widget key binding | Auto-save widget value without manual code | st.text_input('Name', key='name') |
| Store model results | Avoid re-running slow code on every interaction | st.session_state.result = model.predict(...) |
| Toggle a flag | Show and hide parts of the UI conditionally | st.session_state.show_chart = True |
| Shopping cart / list | Accumulate items across multiple interactions | st.session_state.cart.append(item) |
- Streamlit re-runs your whole script on every interaction. Regular Python variables reset every time. Only st.session_state survives between re-runs.
- Always initialise state values using if key not in st.session_state — never unconditionally — or they will reset on every run.
- You can read and write session state using either st.session_state['key'] (dictionary style) or st.session_state.key (dot notation). Both work identically.
- Give widgets a key parameter to automatically link their value to session state. You do not need to copy the value manually.
- Use the on_change parameter with a callback function to run code immediately when a widget value changes.
- Session state is the right tool for multi-step forms — store the current step number and render the right form based on it.
- Store the result of slow operations (ML models, database queries) in session state so they only run when triggered by the user, not on every slider move.
- Use st.session_state.clear() to fully reset, or del st.session_state['key'] to remove a single value.
