8 · Caching, state & layout
The rerun model has a cost: your script re-executes constantly, so anything slow runs over and over. `@st.cache_resource` loads the model ONCE; `@st.cache_data` caches pure computations; `st.session_state` remembers values across reruns; and `st.columns`/`st.sidebar`/`st.tabs` organize the page.
Because the whole script reruns constantly, caching is ESSENTIAL: `@st.cache_resource` loads the model ONCE and shares the same object across reruns (for connections/models — unhashable, long-lived); `@st.cache_data` memoizes PURE computations by their inputs (for data/DataFrames — returns a fresh copy). `st.session_state` persists values across reruns, and `st.columns`/`st.sidebar`/`st.tabs` lay out the page.
Without this:
Without `@st.cache_resource` the model reloads from disk on every single rerun — every slider drag costs a full deserialization — making the app crawl; and without `session_state` you lose any value not derived directly from a widget.
The rerun model is wonderful for simplicity but brutal for performance: because Streamlit reruns your entire script on every interaction, anything slow in that script runs again every single time. Loading a model from disk, querying a database, crunching a big DataFrame — all of it re-executes on every slider drag unless you stop it. The tools to stop it are caching, session state, and layout.
@st.cache_resource — load the model ONCE. Decorate the function that loads your model with @st.cache_resource. The first run executes it (slow: deserialize the .joblib); every rerun after that gets the same model object back instantly from the cache, skipping the load entirely. cache_resource is for global, long-lived, often-unhashable resources you want to share across reruns and users: ML models, database connections, API clients. It returns the same object (not a copy) — which is exactly what you want for a model.
@st.cache_data — cache pure computations. Decorate a function that computes data with @st.cache_data. Streamlit memoizes by the function's inputs: call it again with the same arguments and you get the cached result without recomputing. It's for pure, serializable data — loading a CSV, an expensive aggregation, a transformed DataFrame. Crucially, it returns a fresh copy each call, so mutating the result can't corrupt the cache. (Same idea as functools' memoization, tuned for data.)
The distinction that matters: which one for the model? Use @st.cache_resource for the model object — it's a single shared resource you load once and reuse, not data keyed by inputs. Use @st.cache_data for data the model consumes or produces (a loaded dataset, a batch of scored rows). Picking cache_data for the model is the classic mistake: it tries to hash/copy the model, which is wrong for a shared resource.
st.session_state — remember across reruns. Since every rerun starts the script fresh, ordinary variables reset each time. st.session_state is a per-user dictionary that survives reruns: st.session_state["count"] = st.session_state.get("count", 0) + 1 keeps a running counter, a prediction history, a "has the user logged in?" flag — anything that must persist beyond a single run but isn't tied to one widget's current value.
Layout — organize the page. By default st.* calls stack vertically. To shape the page:
col1, col2 = st.columns(2)— side-by-side columns; write intocol1/col2.st.sidebar— a collapsible left panel, perfect for inputs/filters (st.sidebar.slider(...)).st.tabs(["A", "B"])— tabbed sections to separate, say, "Predict" from "About".
The read-along cell shows a laid-out app: the model loaded via @st.cache_resource, a cached data loader via @st.cache_data, a session_state counter, and a sidebar + columns layout.
A Streamlit app using `@st.cache_resource` to load the model once, `@st.cache_data` to cache a CSV loader, `st.session_state` to count reruns, and a sidebar + columns + tabs layout.
You're loading your trained model into a Streamlit app. Which caching decorator should wrap the `load_model()` function, and why?
- `@st.cache_resource` loads the model ONCE and shares the same object across reruns — use it for models, DB connections, and other long-lived resources.
- `@st.cache_data` memoizes pure computations by their inputs and returns a fresh copy — use it for datasets, DataFrames, and expensive aggregations (NOT the model).
- `st.session_state` persists values across reruns (which otherwise reset), and `st.columns`/`st.sidebar`/`st.tabs` organize an otherwise top-to-bottom page.
Every real Streamlit ML app caches the model with `@st.cache_resource` — without it the rerun model makes the app unusably slow, reloading the artifact on every click.
If you remove it: Skip caching and the model deserializes on every interaction; skip session_state and you lose any running history or flags the dashboard needs between reruns.