Deploying ML Models to Streamlit
Not every audience wants a raw JSON API — a product manager or a stakeholder
usually wants to type in some numbers and click a button. Streamlit lets you turn
the same saved pipeline into a small interactive web page, using nothing but plain
Python, so you can hand someone a link instead of a curlcurl command.
What Streamlit is
Streamlit turns Python scripts into web apps.
It’s great for:
- demos
- internal tools
- quick validation with stakeholders
Where Streamlit fits in the deployment flow
flowchart LR M["Trained pipeline model.joblib"] --> A["Streamlit app.py"] A --> W["Widgets collect input
number_input, selectbox..."] W --> B{"User clicks Predict"} B --> P["pipeline.predict"] P --> D["st.write shows prediction"]
Minimal Streamlit inference app
# Requires: streamlit, joblib
import streamlit as st
import joblib
model = joblib.load("model.joblib")
st.title("ML Prediction Demo")
age = st.number_input("Age", min_value=0, max_value=120, value=30)
income = st.number_input("Income", min_value=0.0, value=50000.0)
city = st.text_input("City", value="Pune")
plan = st.selectbox("Plan", ["Free", "Pro", "Enterprise"])
if st.button("Predict"):
X = [{"age": age, "income": income, "city": city, "plan": plan}]
pred = model.predict(X)[0]
st.write("Prediction:", pred)# Requires: streamlit, joblib
import streamlit as st
import joblib
model = joblib.load("model.joblib")
st.title("ML Prediction Demo")
age = st.number_input("Age", min_value=0, max_value=120, value=30)
income = st.number_input("Income", min_value=0.0, value=50000.0)
city = st.text_input("City", value="Pune")
plan = st.selectbox("Plan", ["Free", "Pro", "Enterprise"])
if st.button("Predict"):
X = [{"age": age, "income": income, "city": city, "plan": plan}]
pred = model.predict(X)[0]
st.write("Prediction:", pred)Running it locally
pip install streamlit joblib
streamlit run app.py
# -> opens http://localhost:8501 in your browserpip install streamlit joblib
streamlit run app.py
# -> opens http://localhost:8501 in your browserDon’t reload the model on every click
Streamlit re-runs your entire script from top to bottom every time a
widget changes — every number you type, every button you click. Without
caching, joblib.load("model.joblib")joblib.load("model.joblib") on line 4 would re-read the file from
disk on every single interaction, which gets slow (or expensive) fast for a
large model. @st.cache_resource@st.cache_resource tells Streamlit to run that function once
and reuse the same object across reruns:
import streamlit as st
import joblib
@st.cache_resource
def load_model():
return joblib.load("model.joblib")
model = load_model() # only actually loads from disk the first timeimport streamlit as st
import joblib
@st.cache_resource
def load_model():
return joblib.load("model.joblib")
model = load_model() # only actually loads from disk the first timeUse @st.cache_resource@st.cache_resource for things you don’t want copied (models, database
connections). Use the related @st.cache_data@st.cache_data for cacheable data (like a
CSV you read into a DataFrame) — Streamlit copies that result on each cache
hit so callers can’t accidentally mutate the cached object.
Batch predictions from an uploaded file
A single-row form is fine for a demo, but stakeholders often want to drop in
a whole spreadsheet and get predictions for every row back. st.file_uploaderst.file_uploader
plus pandaspandas makes that a few lines:
import streamlit as st
import pandas as pd
st.header("Batch predictions")
uploaded = st.file_uploader("Upload a CSV of rows to score", type="csv")
if uploaded is not None:
df = pd.read_csv(uploaded)
df["prediction"] = model.predict(df)
st.dataframe(df)
st.download_button(
"Download results",
df.to_csv(index=False),
file_name="predictions.csv",
)import streamlit as st
import pandas as pd
st.header("Batch predictions")
uploaded = st.file_uploader("Upload a CSV of rows to score", type="csv")
if uploaded is not None:
df = pd.read_csv(uploaded)
df["prediction"] = model.predict(df)
st.dataframe(df)
st.download_button(
"Download results",
df.to_csv(index=False),
file_name="predictions.csv",
)Deployment options
- Streamlit Community Cloud
- Docker + any cloud VM
- internal server
Keeping secrets out of the app
If your app needs an API key or database password, never hard-code it into
app.pyapp.py. Streamlit reads a local .streamlit/secrets.toml.streamlit/secrets.toml file (and, on
Streamlit Community Cloud, a “Secrets” panel in the app settings) and exposes
it as st.secretsst.secrets:
db_password = "correct-horse-battery-staple"db_password = "correct-horse-battery-staple"password = st.secrets["db_password"]password = st.secrets["db_password"]Add .streamlit/secrets.toml.streamlit/secrets.toml to .gitignore.gitignore so it never ends up in version
control.
Mini-checkpoint
When would you prefer Streamlit over an API?
- when you need a user-facing demo UI quickly.
🧪 Try It Yourself
Exercise 1 – Build an Input Widget
Exercise 2 – Assemble the Feature Row for Prediction
Exercise 3 – Guard the Predict Button
Next
Continue to Dockerizing an ML Application — package the Streamlit app (or the Flask/FastAPI service) with its dependencies so it runs the same way on any machine.
If this helped you, consider buying me a coffee ☕
Buy me a coffeeWas this page helpful?
Let us know how we did
