Python Streamlit Example¶
Complete example: Deploy a Streamlit application to Airbase
This example shows how to build and deploy a Streamlit data visualization application to Airbase, including handling CSP considerations.
Overview¶
What we're building: - Interactive data dashboard using Streamlit - Data visualization with charts - User input widgets - CSV data upload
Tech stack: - Python 3.13 - Streamlit - Pandas - Plotly (CSP-compatible charting library)
Deployment time: ~5 minutes
Project Structure¶
streamlit-dashboard/
├── app.py # Main Streamlit application
├── requirements.txt # Python dependencies
├── Dockerfile # Container configuration
├── airbase.json # Airbase configuration
├── .env # Environment variables (optional)
└── .gitignore # Git ignore file
Step 1: Create Streamlit Application¶
app.py:
import streamlit as st
import pandas as pd
import plotly.express as px
import os
# Read port from environment (Airbase requirement)
PORT = int(os.environ.get('PORT', 8501))
# Page configuration
st.set_page_config(
page_title="Data Dashboard",
page_icon="📊",
layout="wide"
)
# Title
st.title("📊 Interactive Data Dashboard")
st.markdown("---")
# Sidebar
with st.sidebar:
st.header("Configuration")
# Data source selection
data_source = st.radio(
"Select Data Source:",
["Sample Data", "Upload CSV"]
)
if data_source == "Upload CSV":
uploaded_file = st.file_uploader("Choose a CSV file", type="csv")
# Main content
col1, col2 = st.columns(2)
with col1:
st.subheader("Data Overview")
# Load data based on selection
if data_source == "Sample Data":
# Create sample data
df = pd.DataFrame({
'Category': ['A', 'B', 'C', 'D', 'E'],
'Value': [23, 45, 56, 78, 32],
'Growth': [12, 18, -5, 23, 8]
})
st.success("Using sample data")
else:
if uploaded_file is not None:
df = pd.read_csv(uploaded_file)
st.success(f"Loaded {len(df)} rows")
else:
st.info("Please upload a CSV file")
df = None
# Display data
if df is not None:
st.dataframe(df, use_container_width=True)
# Summary statistics
st.subheader("Summary Statistics")
st.write(df.describe())
with col2:
st.subheader("Visualizations")
if df is not None:
# Chart type selector
chart_type = st.selectbox(
"Select Chart Type:",
["Bar Chart", "Line Chart", "Scatter Plot"]
)
# Create visualization using Plotly (CSP-compatible)
if chart_type == "Bar Chart":
fig = px.bar(
df,
x=df.columns[0],
y=df.columns[1],
title=f"{df.columns[1]} by {df.columns[0]}"
)
elif chart_type == "Line Chart":
fig = px.line(
df,
x=df.columns[0],
y=df.columns[1],
title=f"{df.columns[1]} Trend"
)
else: # Scatter Plot
if len(df.columns) >= 3:
fig = px.scatter(
df,
x=df.columns[1],
y=df.columns[2],
title=f"{df.columns[2]} vs {df.columns[1]}"
)
else:
st.warning("Scatter plot requires at least 3 columns")
fig = None
# Display chart
if fig is not None:
st.plotly_chart(fig, use_container_width=True)
# Interactive widgets section
st.markdown("---")
st.subheader("Interactive Controls")
col3, col4, col5 = st.columns(3)
with col3:
slider_value = st.slider("Select a value:", 0, 100, 50)
st.metric("Selected Value", slider_value)
with col4:
text_input = st.text_input("Enter text:", "Hello Airbase!")
st.write(f"You entered: {text_input}")
with col5:
date_input = st.date_input("Select a date:")
st.write(f"Selected date: {date_input}")
# Footer
st.markdown("---")
st.caption("Deployed on Airbase 🚀 | Built with Streamlit")
Key features: - ✅ Reads PORT from environment variable - ✅ Uses Plotly (CSP-compatible charting) - ✅ Interactive widgets - ✅ File upload capability - ✅ Responsive layout
Step 2: Create Requirements File¶
requirements.txt:
Why these libraries: - Streamlit: Web framework for data apps - Pandas: Data manipulation - Plotly: CSP-compatible interactive charts
Important: Plotly is CSP-compatible. Avoid libraries like matplotlib inline display or altair with default settings, as they may generate inline scripts.
Step 3: Create Dockerfile¶
Dockerfile:
FROM gdssingapore/airbase:python-3.13
# Set environment variables
ENV PYTHONUNBUFFERED=TRUE
# Set working directory
WORKDIR /app
# Copy requirements and install dependencies
COPY --chown=app:app requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
# Copy application code
COPY --chown=app:app app.py ./
# Switch to non-root user
USER app
# Expose port (Streamlit default is 8501, but Airbase uses PORT env var)
EXPOSE 8501
# Run Streamlit
# Note: --server.port uses PORT env var, --server.address binds to all interfaces
CMD ["sh", "-c", "streamlit run app.py --server.port=${PORT:-8501} --server.address=0.0.0.0 --server.headless=true"]
Key configuration: - ✅ Uses Airbase Python 3.13 base image - ✅ Runs as non-root user (app) - ✅ Files owned by app:app - ✅ Binds to 0.0.0.0 (required for container networking) - ✅ Reads $PORT from environment - ✅ Headless mode (no browser auto-open)
Step 4: Create Airbase Configuration¶
airbase.json:
{
"framework": "container",
"handle": "your-team/streamlit-dashboard",
"port": 8501,
"instanceType": "b.small"
}
Configuration notes: - port: 8501 (Streamlit's default) - instanceType: b.small recommended (Streamlit needs more memory than nano) - handle: Replace with your actual project handle
Why b.small? - Streamlit apps are memory-intensive - b.small provides 1GB RAM (vs 500MB for nano) - Better performance for data processing
Step 5: Create Environment Variables (Optional)¶
.env:
Optional settings - Streamlit works fine without these, but you can customize behavior.
Step 6: Create .gitignore¶
.gitignore:
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
venv/
env/
# Environment files
.env
.env.*
# Streamlit
.streamlit/
# IDE
.vscode/
.idea/
# OS
.DS_Store
Deploy to Airbase¶
Build and Deploy to Staging¶
# Navigate to project directory
cd streamlit-dashboard
# Build container
airbase container build
# Deploy to staging for testing
airbase container deploy --yes staging
Expected output:
Building container...
✓ Build complete
✓ Image pushed to registry
Deploying to staging environment...
✓ Deployment successful
✓ Application is live at: https://staging--streamlit-dashboard.app.tc1.airbase.sg
Deployment time: 2-3 minutes
Test in Staging¶
What to test: - [ ] Dashboard loads correctly - [ ] Charts render properly - [ ] Widgets are interactive - [ ] File upload works - [ ] No CSP errors in browser console (F12)
Deploy to Production¶
Production URL: https://streamlit-dashboard.app.tc1.airbase.sg
CSP Compatibility¶
Streamlit and CSP¶
Good news: Core Streamlit is CSP-compatible when used correctly.
What works: - ✅ Streamlit widgets (sliders, inputs, buttons) - ✅ Plotly charts - ✅ Pandas dataframes - ✅ File uploads - ✅ st.columns, st.tabs layouts
What may cause CSP issues: - ❌ Some third-party Streamlit components - ❌ Matplotlib with inline display - ❌ Custom HTML with inline scripts - ❌ Some visualization libraries (Altair default config)
If You Encounter CSP Violations¶
Step 1: Check browser console
Press F12 and look for errors like:
Refused to execute inline script because it violates the following
Content Security Policy directive: "script-src 'self'".
Step 2: Identify the source
- Is it from a third-party Streamlit component?
- Is it from a visualization library?
- Is it from custom HTML?
Step 3: Find alternatives
- Use Plotly instead of Matplotlib inline
- Use built-in Streamlit charts
- Avoid custom HTML with inline scripts
- Check if component has CSP-compatible mode
Step 4: Last resort - Nginx proxy workaround
If you absolutely must use a library with CSP violations (e.g., specific Streamlit components for government data visualization):
See: CSP Nginx Workaround (Note: This weakens security and should only be used when no alternatives exist)
Advanced: Multiple Pages¶
Streamlit supports multi-page apps:
streamlit-dashboard/
├── app.py # Home page
├── pages/
│ ├── 1_📈_Analytics.py # Analytics page
│ ├── 2_📊_Reports.py # Reports page
│ └── 3_⚙️_Settings.py # Settings page
├── requirements.txt
├── Dockerfile
└── airbase.json
No code changes needed - Streamlit automatically detects pages in the pages/ directory.
Update Dockerfile to copy pages:
Performance Optimization¶
Caching¶
Use Streamlit's caching to improve performance:
import streamlit as st
@st.cache_data
def load_data():
# This function result is cached
df = pd.read_csv("large_file.csv")
return df
# Data only loads once, then cached
df = load_data()
Benefits: - Faster page loads - Reduced memory usage - Better user experience
Session State¶
Persist data across reruns:
# Initialize session state
if 'counter' not in st.session_state:
st.session_state.counter = 0
# Button increments counter
if st.button('Increment'):
st.session_state.counter += 1
st.write(f"Counter: {st.session_state.counter}")
Troubleshooting¶
Issue: App not accessible¶
Symptom: Deployment succeeds but URL doesn't load
Causes: 1. Wrong port in airbase.json 2. App not binding to 0.0.0.0 3. App crashed on startup
Solution:
Check Dockerfile CMD:
CMD ["sh", "-c", "streamlit run app.py --server.port=${PORT:-8501} --server.address=0.0.0.0 --server.headless=true"]
Ensure airbase.json port matches:
Issue: Out of memory¶
Symptom: App crashes or becomes unresponsive
Solution: Upgrade instance type in airbase.json:
Ensure you're using b.small instance type:
Then redeploy:
Issue: Slow performance¶
Solutions:
-
Add caching:
-
Optimize data processing:
- Keep datasets small (<100MB)
- Use data sampling for large datasets
- Avoid loading entire datasets into memory
-
Use generators for large data processing
-
Optimize data loading:
- Load less data
- Filter data server-side
- Use data pagination
Issue: CSP violations¶
Symptom: Charts or components not rendering
Solution:
- Check browser console (F12)
- Identify violating library
- Switch to CSP-compatible alternative:
- Use Plotly instead of Matplotlib inline
- Use st.plotly_chart() instead of st.pyplot()
- Avoid custom HTML with inline scripts
Production Checklist¶
Before deploying to production:
- Test all features in staging
- Check browser console for CSP errors
- Verify file uploads work (if using)
- Test with realistic data sizes
- Check performance under load
- Ensure proper instance type (
b.smallrecommended) - Set up monitoring (check application logs)
- Document any custom configuration
Next Steps¶
Enhance your dashboard: - Add authentication (Streamlit supports OAuth) - Connect to databases (PostgreSQL, MongoDB) - Add real-time data updates - Implement user permissions - Create downloadable reports
Resources: - Streamlit Documentation - Plotly Python Documentation - Pandas Documentation
Complete Example Repository¶
You can find the complete working example at:
streamlit-dashboard/
├── app.py # 120 lines
├── requirements.txt # 3 lines
├── Dockerfile # 15 lines
├── airbase.json # 6 lines
└── .gitignore # 10 lines
Total: ~150 lines of code for a complete interactive dashboard.
See Also¶
- Tutorial: Getting Started - First deployment
- How-To: Build and Deploy - Deployment workflow
- Reference: Dockerfile Requirements - Container requirements
- Reference: Base Images - Python base image details
- How-To: CSP Compliance - CSP best practices
- Example: Python Flask - Flask API example