Streamlit: a specific supported feature or practical engineering decision
Learn how @st.fragment limits reruns to UI-only changes while preserving @st.cache_data and @st.cache_resource, with a practical example and notes on limits.
15 Nov 2025, 16:05 UTC

Problem: UI widgets cause full reruns and waste cached work
When a slider or select box sits at the top of a Streamlit script, every interaction triggers a full rerun from the top. If the script loads a large dataset or builds a model, that work repeats even though the data itself hasn’t changed. This wastes CPU, adds latency, and can hit rate limits on external services.
How @st.fragment interacts with caching
Streamlit’s @st.fragment decorator marks a function so that only that function is re‑executed when its widgets change. The rest of the script, including any @st.cache_data or @st.cache_resource calls, is not re‑run. The cached functions still use their normal cache keys (function source, arguments, closure variables) and respect TTL and max_entries. In other words, a fragment gives you UI‑only updates while leaving expensive cached work untouched.
Worked example: filtering a cached DataFrame with a slider inside a fragment
import streamlit as st
import pandas as pd
@st.cache_data
def load_data():
# Simulate expensive load
return pd.read_csv("large_dataset.csv")
def chart_fragment():
# This block runs only when the slider changes
selected = st.slider("Threshold", 0, 100, 50)
df = load_data() # cache hit if data unchanged
filtered = df[df["value"] > selected]
st.line_chart(filtered)
def main():
st.title("Demo: fragment with cached data")
# Load data once (cached)
data = load_data()
st.write(f"Rows loaded: {len(data)}")
# Call the fragment
chart_fragment()
if __name__ == "__main__":
main()
Explanation: load_data executes once and its result is reused across all reruns. Moving the slider only invokes chart_fragment; the cached data load is a hit, so no CSV parsing occurs again. You can verify by adding a print("loading") inside load_data and watching the console — the message appears only on the first run or when the CSV changes.
Trade‑offs and limits
- Fragment cannot return a value directly to the main script; use
st.session_stateif you need to pass data out. - Each fragment gets its own widget state; keys must be unique or prefixed to avoid collisions.
- Although the fragment UI reruns, the cached function still respects its TTL and
max_entries; data is not duplicated. - On Streamlit Cloud, the filesystem is ephemeral, but caching remains in memory;
persist='disk'is not needed for this pattern.
Actionable closing
When a widget drives frequent UI updates but the underlying data is expensive, wrap the widget‑dependent code in @st.fragment and keep data‑loading functions decorated with @st.cache_data or @st.cache_resource. Verify by adding a print inside the cached function and confirming it appears only on the first run or when the data source changes.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.