Streamlit Expert
Overview
Streamlit Web application development expert skill supporting the latest features from v1.42 to v1.52+ (2025-2026). Provides comprehensive guidance on:
- Authentication: Native OIDC authentication with
st.login(),st.logout(),st.user - Data Visualization: Optimal library selection (Plotly, Altair, native charts) and performance tuning
- Secrets Management: Secure credential handling with
st.secrets - Performance Optimization: Caching strategies, large dataset handling, session state management
- Modern Features: Custom themes, layout containers, multipage apps, Custom Components v2
When to Use This Skill
Use this skill when:
- Building new Streamlit applications from scratch
- Implementing user authentication with OIDC providers (Google, Microsoft, Okta, Auth0)
- Creating data visualization dashboards
- Optimizing Streamlit app performance
- Managing secrets and credentials securely
- Implementing modern Streamlit features (v1.42+)
Workflow Decision Tree
User Request
├── "Add authentication" → Authentication Workflow
├── "Create dashboard/visualization" → Visualization Workflow
├── "App is slow/optimize" → Performance Optimization Workflow
├── "New Streamlit app" → Project Setup Workflow
└── "Deploy app" → Deployment Workflow
1. Project Setup Workflow
Initial Project Structure
my-streamlit-app/
├── .streamlit/
│ ├── config.toml # App configuration
│ └── secrets.toml # Secrets (DO NOT COMMIT)
├── pages/ # Multipage app pages
│ ├── 1_Dashboard.py
│ └── 2_Settings.py
├── app.py # Main entry point
├── requirements.txt
├── .gitignore
└── README.md
Essential .gitignore Entries
# Streamlit secrets - CRITICAL
.streamlit/secrets.toml
# Python
__pycache__/
*.pyc
.venv/
venv/
Recommended Dependencies (2025-2026)
streamlit>=1.52.0
streamlit[auth] # For authentication (includes Authlib>=1.3.2)
plotly>=5.18.0
altair>=5.2.0
pandas>=2.0.0
orjson # Performance optimization for Plotly
2. Authentication Workflow
Prerequisites
Install authentication dependencies:
pip install "streamlit[auth]"Configure identity provider (Google, Microsoft Entra ID, Okta, Auth0)
Obtain from provider:
- Client ID
- Client secret
- Server metadata URL
secrets.toml Configuration
Single Provider Setup
[auth]
redirect_uri = "http://localhost:8501/oauth2callback" # Use https:// in production
cookie_secret = "your-strong-random-secret-here" # Generate with: python -c "import secrets; print(secrets.token_hex(32))"
client_id = "your-client-id"
client_secret = "your-client-secret"
server_metadata_url = "https://accounts.google.com/.well-known/openid-configuration" # Google example
Multiple Providers Setup
[auth]
redirect_uri = "http://localhost:8501/oauth2callback"
cookie_secret = "your-strong-random-secret-here"
[auth.google]
client_id = "google-client-id"
client_secret = "google-client-secret"
server_metadata_url = "https://accounts.google.com/.well-known/openid-configuration"
[auth.microsoft]
client_id = "microsoft-client-id"
client_secret = "microsoft-client-secret"
server_metadata_url = "https://login.microsoftonline.com/{tenant-id}/v2.0/.well-known/openid-configuration"
Authentication Implementation Pattern
import streamlit as st
# Check login status
if not st.user.is_logged_in:
st.title("Welcome to My App")
st.write("Please log in to continue.")
# Single provider
st.login()
# Multiple providers
# col1, col2 = st.columns(2)
# with col1:
# st.login("google")
# with col2:
# st.login("microsoft")
st.stop()
# User is logged in - show main content
st.title(f"Welcome, {st.user.name}!")
st.write(f"Email: {st.user.email}")
# Logout button
if st.button("Logout"):
st.logout()
Accessing User Information
# Available after successful login
st.user.is_logged_in # bool
st.user.name # str
st.user.email # str
# With expose_tokens configured
st.user.tokens.id # ID token (if "id" in expose_tokens)
st.user.tokens.access # Access token (if "access" in expose_tokens)
Security Best Practices
- ALWAYS use HTTPS in production for redirect_uri
- Generate strong cookie_secret:
python -c "import secrets; print(secrets.token_hex(32))" - Never commit secrets.toml - use environment variables or secrets management in deployment
- Identity cookies expire after 30 days - users must re-authenticate
- Authentication not supported for embedded apps
3. Visualization Workflow
Library Selection Guide
| Use Case | Recommended Library | Reason |
|---|---|---|
| Simple charts, KPIs | Native (st.line_chart, st.bar_chart) |
Fastest, zero dependencies |
| Interactive exploration | Plotly | Best interactivity, zoom/pan/hover |
| Statistical visualizations | Altair | Declarative, publication-quality |
| Publication-quality static | Matplotlib/Seaborn | Fine control, PDF export |
| Geospatial mapping | PyDeck | 3D maps, large datasets |
Performance Benchmarks
Rendering Speed (fastest to slowest):
- Native Streamlit charts
- Altair
- Plotly
- Matplotlib
Large Dataset Handling
Altair Limitations and Solutions
import altair as alt
# Altair has a 5,000 row limit by default
# Solution 1: Increase limit (use cautiously)
alt.data_transformers.disable_max_rows()
# Solution 2: Use data URL (recommended for >5000 rows)
# This sends data as a URL reference instead of embedding
alt.data_transformers.enable('vegafusion') # If vegafusion installed
# Solution 3: Downsample data before plotting
def downsample_data(df, max_rows=5000):
if len(df) > max_rows:
return df.sample(n=max_rows, random_state=42)
return df
Plotly Optimization
import plotly.express as px
import streamlit as st
# Install orjson for faster serialization
# pip install orjson
# Use WebGL renderer for large datasets
fig = px.scatter(df, x='x', y='y', render_mode='webgl')
# Reduce data points for smoother interaction
fig.update_traces(marker=dict(size=3))
# Disable expensive animations
fig.update_layout(transition_duration=0)
st.plotly_chart(fig, use_container_width=True, config={'displayModeBar': False})
Chart Configuration Best Practices
import streamlit as st
import plotly.express as px
# Always use container width for responsiveness
st.plotly_chart(fig, use_container_width=True)
# Configure Plotly display options
config = {
'displayModeBar': True,
'displaylogo': False,
'modeBarButtonsToRemove': ['lasso2d', 'select2d'],
'toImageButtonOptions': {
'format': 'png',
'filename': 'chart',
'height': 600,
'width': 800,
'scale': 2
}
}
st.plotly_chart(fig, config=config)
4. Performance Optimization Workflow
Caching Strategy
st.cache_data (for data)
import streamlit as st
import pandas as pd
@st.cache_data(ttl=3600) # Cache for 1 hour
def load_data(file_path: str) -> pd.DataFrame:
"""Load and cache data from file."""
return pd.read_csv(file_path)
@st.cache_data
def expensive_computation(df: pd.DataFrame) -> pd.DataFrame:
"""Cache expensive transformations."""
# Heavy processing here
return processed_df
st.cache_resource (for resources)
import streamlit as st
from sqlalchemy import create_engine
@st.cache_resource
def get_database_connection():
"""Cache database connection (shared across users)."""
return create_engine(st.secrets["database"]["url"])
@st.cache_resource
def load_ml_model():
"""Cache ML model loading."""
import joblib
return joblib.load("model.pkl")
Session State Best Practices
import streamlit as st
# Initialize session state
if "counter" not in st.session_state:
st.session_state.counter = 0
if "data" not in st.session_state:
st.session_state.data = None
# Use session state for user inputs that should persist
def increment():
st.session_state.counter += 1
st.button("Increment",
st.write(f"Count: {st.session_state.counter}")
Fragment-Based Updates (Partial Reruns)
import streamlit as st
@st.fragment
def chart_section():
"""Only this section reruns when its widgets change."""
chart_type = st.selectbox("Chart Type", ["Line", "Bar", "Scatter"])
# Chart rendering here
st.line_chart(data)
@st.fragment
def filter_section():
"""Independent fragment for filters."""
date_range = st.date_input("Date Range")
category = st.multiselect("Categories", options)
return date_range, category
# Main app
st.title("Dashboard")
filter_section()
chart_section()
Memory Optimization for Large Datasets
import streamlit as st
import pandas as pd
# Use appropriate dtypes
@st.cache_data
def load_optimized_data(file_path: str) -> pd.DataFrame:
df = pd.read_csv(
file_path,
dtype={
'id': 'int32',
'category': 'category',
'value': 'float32'
},
parse_dates=['date']
)
return df
# Stream large files
def process_large_file(file):
chunks = pd.read_csv(file, chunksize=10000)
for chunk in chunks:
# Process each chunk
yield process_chunk(chunk)
5. Secrets Management
Local Development
# .streamlit/secrets.toml (NEVER COMMIT)
[database]
host = "localhost"
port = 5432
username = "user"
password = "password"
[api_keys]
openai = "sk-..."
google_maps = "AIza..."
[auth]
redirect_uri = "http://localhost:8501/oauth2callback"
cookie_secret = "dev-secret"
Accessing Secrets
import streamlit as st
# Dictionary-style access
db_host = st.secrets["database"]["host"]
# Attribute-style access
api_key = st.secrets.api_keys.openai
# Pass entire section as kwargs
import psycopg2
conn = psycopg2.connect(**st.secrets.database)
Production Deployment
Streamlit Community Cloud:
- Use the "Secrets" section in app settings
- Paste secrets.toml content directly
Docker/Kubernetes:
- Use environment variables or mounted secret files
- Map to
.streamlit/secrets.tomlpath
Cloud Providers:
- AWS: Use AWS Secrets Manager
- GCP: Use Secret Manager
- Azure: Use Key Vault
6. Modern Features (v1.42-1.52+)
Theming (v1.44+)
# .streamlit/config.toml
[theme]
primaryColor = "#FF4B4B"
backgroundColor = "#FFFFFF"
secondaryBackgroundColor = "#F0F2F6"
textColor = "#262730"
font = "sans serif"
Runtime Theme Detection (v1.46+)
import streamlit as st
# Detect current theme
theme = st.context.theme
if theme == "dark":
chart_template = "plotly_dark"
else:
chart_template = "plotly_white"
Top Navigation (v1.46+)
import streamlit as st
# Create top navigation
pages = st.navigation([
st.Page("home.py", title="Home", icon="🏠"),
st.Page("dashboard.py", title="Dashboard", icon="📊"),
st.Page("settings.py", title="Settings", icon="⚙️"),
], position="top")
pages.run()
Custom Components v2 (v1.51+)
import streamlit as st
from streamlit.components.v1 import components
# Custom component with bidirectional data flow
my_component = components.declare_component(
"my_component",
path="frontend/build"
)
result = my_component(data=my_data, key="unique_key")
New Widgets (v1.52)
import streamlit as st
from datetime import datetime
# Combined date and time input
dt = st.datetime_input("Select date and time", value=datetime.now())
# Download button with callable
def generate_report():
return create_pdf_report()
st.download_button(
"Download Report",
data=generate_report, # Callable - generates on demand
file_name="report.pdf"
)
# Chat input with audio
message = st.chat_input("Type or speak", accept_audio=True)
7. Common Patterns and Best Practices
Application Structure Pattern
import streamlit as st
def main():
# 1. Page configuration (MUST be first)
st.set_page_config(
page_title="My App",
page_icon="🚀",
layout="wide",
initial_sidebar_state="expanded"
)
# 2. Authentication check
if not st.user.is_logged_in:
show_login_page()
st.stop()
# 3. Initialize session state
init_session_state()
# 4. Sidebar navigation
with st.sidebar:
page = st.selectbox("Navigation", ["Dashboard", "Settings"])
# 5. Main content
if page == "Dashboard":
show_dashboard()
elif page == "Settings":
show_settings()
if __name__ == "__main__":
main()
Error Handling Pattern
import streamlit as st
def safe_operation():
try:
result = risky_operation()
st.success("Operation completed!")
return result
except ConnectionError:
st.error("Connection failed. Please check your network.")
except ValueError as e:
st.warning(f"Invalid input: {e}")
except Exception as e:
st.exception(e) # Shows full traceback in dev
# In production, use st.error() with user-friendly message
Form Pattern (Prevent Unnecessary Reruns)
import streamlit as st
with st.form("my_form"):
name = st.text_input("Name")
email = st.text_input("Email")
submitted = st.form_submit_button("Submit")
if submitted:
# Process form data
save_user(name, email)
st.success("Saved!")
Resources
references/
authentication_guide.md- Detailed OIDC setup for major providersperformance_optimization.md- Advanced caching and optimization techniquesvisualization_best_practices.md- Chart library comparison and usage patternsrelease_notes_summary.md- Key features by version
assets/
app_template.py- Production-ready application templateauth_template.py- Authentication implementation templatedashboard_template.py- Data dashboard templatesecrets_template.toml- secrets.toml template with comments
Quick Reference
| Feature | Version | Key API |
|---|---|---|
| Native Auth | 1.42+ | st.login(), st.logout(), st.user |
| Advanced Theming | 1.44+ | config.toml [theme] |
| Top Navigation | 1.46+ | st.navigation(position="top") |
| Theme Detection | 1.46+ | st.context.theme |
| Custom Components v2 | 1.51+ | components.declare_component() |
| Datetime Input | 1.52+ | st.datetime_input() |
| Callable Downloads | 1.52+ | st.download_button(data=callable) |