How to Implement Session State Management in Streamlit Apps: A Complete Guide
Use st.session_state as a persistent dictionary to store variables across script reruns, initializing keys at the top of your app to prevent data loss on every user interaction.
Streamlit's execution model reruns the entire script on every button click or input change, which resets standard Python variables. To build interactive LLM applications that remember chat history, API keys, or loaded documents, you must implement robust session state management in Streamlit apps. The Shubhamsaboo/awesome-llm-apps repository demonstrates production-grade patterns for persisting complex objects and avoiding redundant API calls.
Why Streamlit Session State Management Is Essential
Streamlit apps operate on a stateless request-response cycle. Without st.session_state, every widget interaction wipes your data, forcing users to re-enter API keys or causing duplicate downloads of large transcripts. The session state dictionary survives reruns, acting as a global mutable store that lives outside the script's local scope.
Initializing Session State Keys to Prevent KeyError
Always declare required keys at the top of your script using existence checks. This guarantees the key exists before you read or write it later, preventing KeyError exceptions on the first run.
import streamlit as st
# Declare required keys once
keys = {
"app": None,
"current_video_url": None,
"transcript_loaded": False,
"transcript_text": None,
"word_count": 0,
"chat_history": [],
}
for k, default in keys.items():
if k not in st.session_state:
st.session_state[k] = default
Conditional Resource Loading with Session State
Use session state flags to load heavy resources only when necessary. In advanced_llm_apps/chat_with_X_tutorials/chat_with_youtube_videos/chat_youtube.py, the app fetches YouTube transcripts only when the URL changes or when the transcript_loaded flag is false.
video_url = st.text_input("YouTube URL")
if video_url and (video_url != st.session_state.current_video_url
or not st.session_state.transcript_loaded):
with st.spinner("Fetching transcript…"):
title, transcript = fetch_video_data(video_url)
if "No transcript" not in transcript:
# Reset state for new video
if st.session_state.transcript_loaded:
st.session_state.app = None # new vector store
st.session_state.chat_history = [] # discard old chat
# Store new data
st.session_state.current_video_url = video_url
st.session_state.transcript_text = transcript
st.session_state.word_count = len(transcript.split())
st.session_state.transcript_loaded = True
This pattern eliminates redundant API calls and ensures deterministic updates.
Storing Complex Objects in Streamlit Session State
st.session_state can store any picklable object, including full library instances. The awesome-llm-apps repository stores an Embedchain App instance after creation to avoid rebuilding the vector database on every rerun.
st.session_state.app = embedchain_bot(db_path, openai_access_token)
This approach is essential for maintaining expensive objects like database connections, ML models, or API clients across user interactions.
Building Persistent Chat History with Session State
Append each user question and AI answer to a list stored in session state. This preserves the conversation even after the user sends a new prompt.
prompt = st.text_input("Ask a question")
if prompt and st.session_state.transcript_loaded:
answer = st.session_state.app.chat(prompt)
st.session_state.chat_history.append((prompt, answer))
st.write("**Answer:**", answer)
# Render history
if st.session_state.chat_history:
with st.expander("Chat History"):
for i, (q, a) in enumerate(st.session_state.chat_history, 1):
st.markdown(f"**Q{i}:** {q}")
st.markdown(f"**A{i}:** {a}")
st.divider()
Resetting and Clearing Session State
Provide users with a mechanism to clear data and start fresh. Explicitly wipe relevant entries and call st.rerun() to refresh the UI immediately.
if st.button("🗑️ Clear Video"):
for k in ["current_video_url", "transcript_loaded",
"transcript_text", "word_count", "chat_history", "app"]:
st.session_state[k] = keys[k] # restore defaults
st.rerun() # force UI refresh
This pattern ensures clean state transitions when switching between tasks or users.
Real-World Examples from awesome-llm-apps
The Shubhamsaboo/awesome-llm-apps repository provides several reference implementations demonstrating these patterns:
| File | Role | Implementation Details |
|---|---|---|
advanced_llm_apps/chat_with_X_tutorials/chat_with_youtube_videos/chat_youtube.py |
Full session-state workflow for transcript loading, vector store handling, chat history, and reset logic. | View Source |
advanced_llm_apps/chat_with_X_tutorials/chat_with_youtube_videos/test_session_state.py |
Unit-test that mimics session-state flow without a Streamlit UI, useful for verifying logic. | View Source |
voice_ai_agents/voice_rag_openaisdk/rag_voice.py |
Session-state for storing API keys, selected voice, processed documents, and multi-step pipeline state. | View Source |
starter_ai_agents/opeani_research_agent/research_agent.py |
Session-state managing research workflow state including conversation ID and collected facts. | View Source |
Summary
- Initialize early: Check
if 'key' not in st.session_stateat the top of your script to preventKeyErrorexceptions. - Load conditionally: Compare current inputs against stored session values to avoid redundant API calls and expensive recomputation.
- Store rich objects: Use
st.session_stateto persist picklable instances like database connections, ML models, and API clients. - Persist conversations: Append user queries and responses to a list in session state to maintain chat history across reruns.
- Reset cleanly: Provide explicit clear buttons that restore default values and call
st.rerun()to refresh the UI.
Frequently Asked Questions
How do I prevent Streamlit from resetting my variables on every interaction?
Store variables in st.session_state, which acts as a persistent dictionary that survives script reruns. Initialize keys at the top of your script using if 'key' not in st.session_state to ensure they exist before use.
Can I store complex objects like machine learning models in session state?
Yes, st.session_state can store any picklable Python object, including ML models, database connections, and third-party library instances like Embedchain App objects. This avoids expensive reinitialization on every user interaction.
What is the best way to clear or reset session state in Streamlit?
Iterate over the keys you want to reset and restore them to their default values, then call st.rerun() to immediately refresh the UI. This pattern is useful when switching between videos, resetting chats, or clearing user data.
How do I avoid making duplicate API calls when the user interacts with my app?
Store the last used input value (like a URL) in st.session_state and compare it against the current input before executing the API call. Only fetch new data when the input changes or when a loading flag indicates the resource is not yet cached.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →