streamlit-development
Streamlit Development
Build interactive data applications using Streamlit, test them locally, and deploy to Snowflake's native Streamlit environment.
Quick Start
Execution Modes:
- Local Development - PyPI packages, full environment
- Snowflake Deployment - Snowflake Anaconda packages, managed environment
Connection Pattern
Critical: Support both local development and Snowflake deployment:
import streamlit as st
from snowflake.snowpark.context import get_active_session
from snowflake.snowpark import Session
@st.cache_resource
def get_snowpark_session():
try:
return get_active_session() # Snowflake
except:
return Session.builder.config('connection_name', 'default').create() # Local
For connection setup, see the snowflake-connections skill for:
- Creating
~/.snowflake/connections.toml - Authentication methods (SSO, key pair, username/password)
- Multiple environment configurations
- Environment variable overrides
Local Development
Setup
# Install dependencies (pin Streamlit version to match Snowflake)
uv pip install --system -r requirements.txt
# Example requirements.txt
streamlit==1.46.0 # Must match Snowflake version
snowflake-snowpark-python
pandas
Run Locally
streamlit run app.py
# Or with environment overrides (see snowflake-connections skill)
SNOWFLAKE_DATABASE=MY_DB streamlit run app.py
Testing
Unit/Integration Tests
pytest streamlit_app/tests/ -v
Browser Testing
Use Playwright MCP for interactive testing:
- Verify pages load without errors
- Test forms and navigation
- Check responsive design
See TESTING_GUIDE.md for patterns.
Deployment
Option 1: Snowflake CLI (Recommended)
snow streamlit deploy --replace -c default
Option 2: Schemachange
Include Streamlit deployment in migration scripts.
Key Patterns
- Separate data access from UI logic
- Cache Snowpark sessions
- Use forms for multi-field input
- Handle errors gracefully
- Limit column nesting (max 2 levels)
See TROUBLESHOOTING.md for common issues.
Related Skills
Complementary Testing:
playwright-mcpskill - Automate browser testing for Streamlit apps
Use playwright-mcp for visual testing, form validation, responsive design testing, and accessibility checks of your Streamlit applications.
Code Organization Best Practices
1. Separate Data Access from UI
✅ DO: Modular data access
# utils/data_loader.py
class DataQueries:
def __init__(self, session):
self.session = session
def get_sales(self, start_date, end_date):
return self.session.sql(f"""
SELECT * FROM sales
WHERE date BETWEEN '{start_date}' AND '{end_date}'
""").to_pandas()
# app.py
from utils.data_loader import DataQueries
session = get_snowpark_session()
queries = DataQueries(session)
df = queries.get_sales('2024-01-01', '2024-12-31')
st.dataframe(df)
❌ DON'T: Mix SQL with UI code
2. Cache Snowpark Session
Always cache your session to avoid reconnection overhead:
@st.cache_resource
def get_snowpark_session():
"""Get or create Snowpark session (cached)"""
try:
return get_active_session() # When running in Snowflake
except:
from snowflake.snowpark import Session
return Session.builder.config('connection_name', 'default').create()
3. Use Forms for Multi-Field Input
✅ DO: Group inputs in forms
with st.form("customer_form"):
name = st.text_input("Name")
email = st.text_input("Email")
phone = st.text_input("Phone")
if st.form_submit_button("Save"):
save_customer(name, email, phone)
st.success("Customer saved!")
❌ DON'T: Trigger rerun on every input (causes rerun on every keystroke)
4. Handle Errors Gracefully
Provide helpful feedback:
try:
save_customer(name, email)
st.success("✅ Customer saved successfully!")
except ValueError as e:
st.error(f"❌ Invalid input: {e}")
st.info("💡 Tip: Check that email format is correct")
except Exception as e:
st.error(f"❌ Unexpected error: {e}")
st.info("💡 Please contact support if this persists")
5. Limit Column Nesting (Max 2 Levels)
✅ DO: 2 levels maximum
col1, col2 = st.columns(2)
with col1:
label_col, input_col = st.columns([1, 3])
with label_col:
st.markdown("**Name:**")
with input_col:
name = st.text_input("Name", label_visibility="collapsed")
❌ DON'T: 3+ levels of nested columns (causes Streamlit errors)
Performance Optimization
Cache Data Queries
@st.cache_data(ttl=600) # Cache for 10 minutes
def load_sales_data(start_date, end_date):
return session.sql(f"""
SELECT * FROM sales
WHERE date BETWEEN '{start_date}' AND '{end_date}'
""").to_pandas()
Use Session State
# Initialize state
if 'data' not in st.session_state:
st.session_state.data = load_data()
# Access throughout app
df = st.session_state.data
Lazy Load Heavy Computations
if st.button("Run Analysis"):
with st.spinner("Analyzing..."):
result = expensive_computation()
st.session_state.result = result
if 'result' in st.session_state:
st.write(st.session_state.result)
Snowflake-Specific Considerations
API Limitations
Some Streamlit features don't work in Snowflake:
| Feature | Status | Alternative |
|---|---|---|
st.dialog() |
❌ Not supported | Use st.expander() or modals |
st.toggle() |
❌ Not supported | Use st.checkbox() |
st.rerun() |
⚠️ Older versions only | Use st.experimental_rerun() |
st.connection() |
❌ Not supported | Use get_active_session() |
Package Availability
Only Snowflake Anaconda packages available:
# environment.yml
name: streamlit_env
channels:
- snowflake
dependencies:
- pandas
- plotly
# ❌ DON'T include:
# - streamlit (already provided)
# - snowflake-snowpark-python (already provided)
Check package availability: https://repo.anaconda.com/pkgs/snowflake/
Python Version Support
Don't specify Python version - Snowflake controls this:
# ❌ DON'T DO THIS
dependencies:
- python=3.11 # Wrong!
# ✅ DO THIS
dependencies:
- pandas
- plotly
Common Pitfalls
DuplicateWidgetID Error
Problem: Two widgets with same implicit key
Solution: Add explicit keys
st.text_input("Name", key="customer_name")
st.text_input("Name", key="product_name")
IndentationError
Check before deploying:
python -c "import ast; ast.parse(open('streamlit_app/app.py').read())"
Session Not Found (Local Development)
Ensure proper fallback:
def get_snowpark_session():
try:
return get_active_session() # Snowflake
except:
from snowflake.snowpark import Session
return Session.builder.config('connection_name', 'default').create()
Form Parameter Errors
Some parameters not supported in Snowflake:
- ❌
border=Falseinst.form() - ❌
border=Trueinst.container() - ❌
hide_index=Trueinst.dataframe()(older versions)
Pre-Deployment Checklist
Before Deploying
- ✅ Fix all indentation errors
- ✅ Run unit tests:
pytest streamlit_app/tests/ -v - ✅ Test locally:
streamlit run streamlit_app/app.py - ✅ Verify forms and navigation with browser testing
- ✅ Check
environment.ymlonly has non-default packages - ✅ Remove development dependencies
- ✅ Test with different user roles/permissions
- ✅ Verify data access controls
Deployment Commands
# Method 1: Snowflake CLI (Recommended)
snow streamlit deploy --replace --connection default
# Method 2: Schemachange
schemachange deploy --config-folder . --connection-name default
Post-Deployment
- ✅ Verify app appears in Snowflake: Data → Databases → Schema → Streamlit
- ✅ Test all features in Snowflake UI
- ✅ Check permissions for different roles
- ✅ Monitor for errors in Streamlit logs
Security Best Practices
1. Never Hardcode Credentials
✅ DO:
session = get_active_session() # Uses Snowflake auth
❌ DON'T:
password = "secret123" # Never do this!
2. Use Role-Based Access Control
# Check user role
current_role = session.sql("SELECT CURRENT_ROLE()").collect()[0][0]
if current_role == "ADMIN":
st.write("Admin features visible")
else:
st.info("Admin access required")
3. Validate User Inputs
def save_customer(name, email):
if not name or len(name) < 2:
raise ValueError("Name must be at least 2 characters")
if "@" not in email:
raise ValueError("Invalid email format")
# Proceed with save
...
Resources
connections.py- Required session pattern for local/Snowflake compatibilitysnowflake-connectionsskill - Connection setup, authentication, and multi-environment configurationplaywright-mcpskill - Browser testing automation for Streamlit apps
Goal: Transform AI agents into expert Streamlit developers who build production-ready data applications with proper code organization, performance optimization, and Snowflake-specific best practices.