Streamlit Core Knowledge

SkillCloud & infra

Streamlit Python web application framework. Covers session state, caching, layouts, widgets, multipage apps, and deployment. Use when building interactive Python data apps or dashboards.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Streamlit Core Knowledge skill

What this skill tells your AI

The instructions your AI receives, as published by claude-dev-suite/claude-dev-suite in skills/backend-frameworks/streamlit/SKILL.md and read by ahel’s review.

Installation & Run

pip install streamlit
streamlit run app.py
streamlit run app.py --server.port 8080

Core Concepts

App Execution Model

Streamlit re-runs the entire script top-to-bottom on every user interaction. Use caching and session_state to avoid redundant work.

Session State

import streamlit as st

# Initialize (always check first)
if "data" not in st.session_state:
    st.session_state.data = []

# Read and write
st.session_state.data.append(item)
st.write(st.session_state.data)

# Callback pattern (preferred for widget interactions)
def on_submit():
    st.session_state.result = process(st.session_state.input_val)

st.text_input("Input", key="input_val")
st.button("Submit", on_click=on_submit)

Caching

# @st.cache_data — serializable return values (DataFrames, dicts, lists)
@st.cache_data(ttl=600)  # cache expires in 10 min
def load_dataset(path: str) -> pd.DataFrame:
    return pd.read_csv(path)

# @st.cache_resource — non-serializable (DB connections, ML models)
@st.cache_resource
def get_model():
    return load_ml_model("model.pkl")

# Clear cache programmatically
load_dataset.clear()

Layout & Components

Columns

col1, col2 = st.columns(2)          # equal width
col1, col2, col3 = st.columns([3, 1, 1])  # weighted

with col1:
    st.metric("Revenue", "$12,345", delta="+5%")
with col2:
    st.image("logo.png")

Tabs

tab1, tab2, tab3 = st.tabs(["Overview", "Details", "Export"])
with tab1:
    show_overview()
with tab2:
    show_details()

Sidebar

with st.sidebar:
    selected = st.selectbox("Area", options=["11301", "11090", "27301"])
    date_range = st.date_input("Date range", value=(start, end))

Expander

with st.expander("Advanced Options", expanded=False):
    threshold = st.slider("Threshold", 0.0, 1.0, 0.5)

Input Widgets

# Text
name = st.text_input("Name", placeholder="Enter tag name")
text = st.text_area("Description", height=100)

# Numbers
n = st.number_input("Count", min_value=0, max_value=1000, value=10, step=1)
ratio = st.slider("Ratio", 0.0, 1.0, 0.5)

# Selection
choice = st.selectbox("Type", ["Motor", "Valve", "Analog"])
choices = st.multiselect("Areas", ["11301", "11090"])
flag = st.checkbox("Include alarms", value=True)
option = st.radio("Export format", ["CSV", "Excel", "JSON"])

# File upload
uploaded = st.file_uploader("Upload Excel", type=["xlsx", "xls"])
if uploaded:
    df = pd.read_excel(uploaded)

Data Display

# DataFrame with config
st.dataframe(
    df,
    column_config={
        "tag": st.column_config.TextColumn("Tag", width="medium"),
        "value": st.column_config.NumberColumn("Value", format="%.2f"),
    },
    hide_index=True,
    use_container_width=True,
)

# Metrics
st.metric(label="Total Tags", value=len(df), delta=f"+{new_count} new")

# Charts
st.line_chart(df.set_index("timestamp")[["value"]])
st.bar_chart(df.groupby("area")["count"].sum())

# Download button
csv = df.to_csv(index=False).encode("utf-8")
st.download_button("Download CSV", csv, "export.csv", "text/csv")

Forms (batch input — single rerun on submit)

with st.form("generate_form"):
    area = st.text_input("Area code")
    count = st.number_input("Instance count", min_value=1, value=1)
    submitted = st.form_submit_button("Generate")

if submitted:
    if not area:
        st.error("Area code is required")
    else:
        with st.spinner("Generating..."):
            result = generate_files(area, count)
        st.success(f"Generated {result.count} files")

Progress & Status

# Spinner
with st.spinner("Loading data..."):
    data = fetch_data()

# Progress bar
progress = st.progress(0, text="Starting...")
for i, item in enumerate(items):
    process(item)
    progress.progress((i + 1) / len(items), text=f"Processing {i+1}/{len(items)}")
progress.empty()

# Status messages
st.success("Operation completed")
st.error("Something went wrong")
st.warning("Check your input")
st.info("Processing in background")

Multipage Apps

# app.py (Streamlit 1.36+)
import streamlit as st

pg = st.navigation([
    st.Page("pages/overview.py", title="Overview", icon="📊"),
    st.Page("pages/generator.py", title="Generator", icon="⚙️"),
    st.Page("pages/export.py", title="Export", icon="📁"),
])
pg.run()

Configuration

# .streamlit/config.toml
[server]
port = 8501
headless = true
maxUploadSize = 200  # MB

[theme]
primaryColor = "#1f77b4"
backgroundColor = "#ffffff"
secondaryBackgroundColor = "#f0f2f6"
textColor = "#31333f"
font = "sans serif"

[client]
toolbarMode = "viewer"

Secrets

# .streamlit/secrets.toml (gitignored)
[api]
key = "..."
key = st.secrets["api"]["key"]
# Or flat access
key = st.secrets.api.key

Deployment (Docker)

FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
EXPOSE 8501
CMD ["streamlit", "run", "app.py", "--server.headless=true", "--server.port=8501"]

Testing Streamlit Apps

# Use streamlit.testing.v1 (Streamlit >= 1.18)
from streamlit.testing.v1 import AppTest

def test_app():
    at = AppTest.from_file("app.py").run()
    assert not at.exception
    assert at.title[0].value == "My App"

def test_form_submission():
    at = AppTest.from_file("app.py").run()
    at.text_input[0].set_value("11301").run()
    at.button[0].click().run()
    assert at.success[0].value == "Generated 1 files"

Anti-Patterns

Anti-PatternFix
Heavy I/O on every rerun@st.cache_data
Global mutable statest.session_state
Business logic in UI scriptSeparate services/ module
No key= on dynamic widgetsAlways set key=
st.rerun() in loopUse fragments or callbacks

Signals

GitHub stars
33
Forks
6
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
streamlit
Source
github.com/claude-dev-suite/claude-dev-suite