Streamlit turns Python scripts into interactive data apps with almost no front-end code. Deploying one to production is mostly about configuring the Streamlit server correctly for a container environment — it uses WebSockets and has a few flags that trip people up. Here's the complete setup.
How Streamlit serves
Streamlit runs its own web server (Tornado) and uses a WebSocket connection between the browser and the server to push updates. This matters for deployment: your platform's ingress must support WebSockets, and you must bind the server to all interfaces.
Server configuration for containers
The flags that make Streamlit work in production:
streamlit run app.py \
--server.address=0.0.0.0 \
--server.port=${PORT:-8501} \
--server.headless=true \
--server.enableCORS=false \
--server.enableXsrfProtection=true--server.address=0.0.0.0so the platform can reach it.--server.headless=truestops Streamlit from trying to open a browser and from prompting for an email on first run.- Bind
--server.portto the platform-providedPORT.
You can put these in .streamlit/config.toml instead of the command line:
[server]
address = "0.0.0.0"
headless = true
port = 8501Caching expensive work
Streamlit reruns your whole script on every interaction. Without caching, that means re-loading data and re-running models on every click. Use the cache decorators:
import streamlit as st
@st.cache_data(ttl=600)
def load_dataframe():
return expensive_query()
@st.cache_resource
def get_model():
return load_model()Use cache_data for serializable results (DataFrames, JSON) and cache_resource for non-serializable singletons (ML models, DB connections).
Session state
Streamlit's st.session_state is per-user-session and in-memory. It resets when the app restarts and is not shared across instances. If you scale to multiple replicas, a user could land on different instances between requests — so don't rely on session state for anything that must persist. Put durable data in a database.
Dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8501
CMD ["streamlit", "run", "app.py", "--server.address=0.0.0.0", "--server.port=8501", "--server.headless=true"]Deploying on PandaStack
Streamlit is a container app — it's a stateful server process, not a static site:
- 1Connect your repo as a container app in the [dashboard](https://dashboard.pandastack.io). PandaStack auto-detects Python and installs from
requirements.txt. - 2Set the start command to the
streamlit runline above, bindingPORT. - 3PandaStack's Kong ingress handles the WebSocket upgrade, so live updates work without extra configuration, and you get automatic SSL.
- 4For data, attach a managed PostgreSQL database and read
DATABASE_URL; cache the connection with@st.cache_resource.
Scale-to-zero and Streamlit
Because Streamlit holds per-session WebSocket state, scale-to-zero on the free tier means an idle app cold-starts on the next visit and any open session is lost. For a personal dashboard that's fine. For a shared internal tool people keep open, run it on a tier that stays warm, and keep replica count at 1 unless your data is fully externalized — multi-replica Streamlit needs sticky sessions to avoid breaking the WebSocket.
| Concern | Recommendation |
|---|---|
| WebSocket | Supported via ingress; keep on |
| Replicas | 1 unless state is externalized |
| Heavy compute | Cache with cache_data/cache_resource |
| Persistence | Managed database, not session state |
References
- [Streamlit: Deploy with Docker](https://docs.streamlit.io/deploy/tutorials/docker)
- [Streamlit configuration reference](https://docs.streamlit.io/develop/api-reference/configuration/config.toml)
- [Streamlit caching: cache_data and cache_resource](https://docs.streamlit.io/develop/concepts/architecture/caching)
- [Streamlit session state](https://docs.streamlit.io/develop/concepts/architecture/session-state)
Put your Streamlit dashboard online with WebSockets and a managed database on PandaStack's free tier — start at [dashboard.pandastack.io](https://dashboard.pandastack.io).