Jesse A. Green / notebook

Live demo: the DocCompiler guide library as a static, read-only snapshot (October 2026). No backend, no accounts, nothing to submit.

Streamlit Admin Guide

Generated June 2026 from streamlit/streamlit at 143d6bb

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

This guide is for the people who run, deploy, secure, extend, and maintain Streamlit applications — operators, platform engineers, architects, and contributors. It documents Streamlit's internal architecture, the complete configuration surface, the security model, deployment strategies, and the code-level internals of the framework.

The companion User Guide covers the st.* authoring API. This document assumes you already understand what a Streamlit app is and focuses on what happens behind the curtain and how to operate it.

Note

This guide documents Streamlit 1.58.0 (streamlit package), built directly from source. Streamlit is an open-source (Apache-2.0) Python framework maintained by Snowflake Inc. A defining fact of this release line: the web server has moved from Tornado to Starlette/Uvicorn (ASGI), which underpins the new st.App embedding model and several operational behaviors below.


1. Executive Summary

Streamlit turns a plain Python script into a reactive web app. Architecturally it is a two-process system bridged by a typed message protocol:

  • A Python backend (the streamlit library + a Starlette/Uvicorn server) executes the user's script and emits UI updates.
  • A React/TypeScript frontend (compiled and bundled, shipped as static assets) renders those updates in the browser.
  • The two communicate over a WebSocket carrying Protocol Buffers messages — ForwardMsg (server → browser) and BackMsg (browser → server).

The central runtime idea is the rerun loop: any user interaction sends a BackMsg rerun request; the backend re-executes the script top to bottom; each st. call produces a delta appended to a ForwardMsg queue; the frontend applies the deltas to a render tree. This makes app code trivially simple at the cost of re-execution, which is mitigated by caching and fragments.

Attribute Value
Language (backend) Python 3.10–3.14
Language (frontend) TypeScript + React + Emotion (CSS-in-JS), built with Vite
Web server Starlette on Uvicorn (ASGI); httptools + websockets
Wire protocol Protocol Buffers over WebSocket
License Apache-2.0
Version 1.58.0
Entry point streamlit = streamlit.web.cli:main
Default port 8501

2. Architecture

2.1 High-level component diagram

                        Browser (React SPA + Emotion + Vite-built assets)
                                  ▲   │
                ForwardMsg (deltas)│   │ BackMsg (rerun / widget / file)
                     protobuf      │   ▼      protobuf
            ┌─────────────────────────────────────────────┐
            │     Starlette / Uvicorn ASGI server          │
            │  /_stcore/stream (WebSocket)                 │
            │  /_stcore/health  /_stcore/host-config       │
            │  /_stcore/upload_file  /media  /static       │
            └─────────────────────────────────────────────┘
                                  │
                                  ▼
            ┌─────────────────────────────────────────────┐
            │                  Runtime                     │
            │   SessionManager → AppSession (per browser)  │
            │        │                                     │
            │        ▼                                     │
            │   ScriptRunner  ── runs your app script ──►  │
            │        │   (top-to-bottom each rerun)        │
            │        ▼                                     │
            │   DeltaGenerator → ForwardMsgQueue           │
            │   MediaFileManager · UploadedFileManager     │
            │   Caching (cache_data / cache_resource)      │
            │   SessionState · Secrets                     │
            └─────────────────────────────────────────────┘

2.2 The request/rerun lifecycle

  1. The browser opens a WebSocket to /_stcore/stream.
  2. The server creates an AppSession for that connection (via the SessionManager).
  3. On connect and on every rerun, the server sends a NewSession ForwardMsg describing the app, config, and theme.
  4. The ScriptRunner executes the user's script in a dedicated thread. Each st. call writes a delta (an Element or Block protobuf) onto the session's ForwardMsgQueue.
  5. The queue is flushed to the browser as ForwardMsg deltas; the frontend applies them to its render tree in order.
  6. A user interaction sends a BackMsg (rerun request, widget state, or page change). The ScriptRunner reruns the script with the new widget values, and the cycle repeats.

Note

Because the script is re-executed wholesale on each interaction, the framework's performance story rests on three mechanisms: the ForwardMsg cache (large messages above global.minCachedMessageSize are cached and referenced by hash), cache_data/cache_resource for app-level memoization, and fragments (@st.fragment) which let a sub-region rerun in isolation.

2.3 Repository / package layout

lib/                          Python backend
  streamlit/                  The installable `streamlit` package
    __init__.py               Public API surface (the st.* namespace)
    delta_generator.py        DeltaGenerator — emits element deltas
    config.py                 Configuration system (all option definitions)
    elements/                 Backend of display elements & charts
      widgets/                Backend of input widgets
      lib/                    Shared element helpers (columns, dialogs, …)
    commands/                 echo, logo, navigation, page_config, execution_control
    runtime/                  Runtime, AppSession, ScriptRunner, caching, state, secrets,
                              fragment, connection_factory, media/uploaded-file managers
    web/                      CLI + server
      cli.py                  The `streamlit` CLI (click)
      server/                 Starlette server, app discovery, routes
    connections/              SQL / Snowflake / Snowpark connection classes
    navigation/               Multipage navigation (Page)
    proto/                    Generated protobuf Python classes
frontend/                     TypeScript/React frontend
  app/                        The Streamlit application shell (the SPA)
  lib/                        Shared component library (elements, widgets, layouts)
  connection/                 WebSocket connection handling
  utils/                      Shared utilities
  component-lib/              Custom components v1 SDK
  component-v2-lib/           Custom components v2 SDK
proto/streamlit/proto/        Protobuf message definitions (source of truth)
e2e_playwright/               End-to-end tests (Playwright via pytest)
specs/                        Internal product/tech specs
wiki/                         Development documentation

2.4 The protobuf protocol

The frontend/backend contract is defined in proto/streamlit/proto/. The key messages:

Message Direction Role
ForwardMsg server → browser Root message carrying deltas, session info, and control signals.
BackMsg browser → server Root message for rerun requests, widget states, page changes, file ops.
NewSession server → browser Sent on every rerun; carries app config, theme, and page metadata.
Block server → browser Layout containers (columns, tabs, expander, popover, form, sidebar).
Element server → browser A single UI element (one per st. display call).

Important

The protobuf layer is the reason api_endpoints static analysis finds "no REST API" — Streamlit's real interface is a binary WebSocket protocol, not HTTP routes. Treat proto/streamlit/proto/*.proto as the authoritative interface spec when reasoning about client/server compatibility. Protobuf changes require recompilation (make protobuf) for both Python and the frontend.

2.5 The st.App ASGI model

st.App (re-exported from streamlit.web.server.starlette.starlette_app) wraps a Streamlit app as a standard ASGI application:

from streamlit import App
app = App("main.py", secrets={"api_key": "..."}, lifespan=my_lifespan,
          routes=extra_routes, middleware=extra_middleware)

This enables three deployment modes (tracked internally as the server mode metric):

  • starlette-managed — the classic streamlit run path (Streamlit owns the server).
  • starlette-app / asgi-server — st.App run under uvicorn/gunicorn/hypercorn.
  • asgi-mounted — st.App mounted inside another ASGI app (FastAPI/Starlette).

Warning

st.App is experimental. A hard constraint: the first App constructed in a process pins the script-level config directory via the process-global config._main_script_path. Running multiple App instances with different script_path values in one process is unsupported and will mis-resolve relative paths.


3. System Requirements

Layer Requirement
Python 3.10, 3.11, 3.12, 3.13, or 3.14
Core dependencies altair, blinker, cachetools, click, gitpython, numpy, packaging, pandas, pillow, pydeck, protobuf (>=3.20,<8), pyarrow (>=7), requests, tenacity, toml, typing-extensions, starlette (>=0.40), uvicorn (>=0.30), httptools, anyio, python-multipart, websockets, itsdangerous, watchdog (non-macOS)
Optional extras snowflake, pdf, auth (Authlib), charts (matplotlib/graphviz/plotly/orjson), sql (SQLAlchemy), performance (orjson/uvloop), all
Browser Any modern evergreen browser (Chrome, Firefox, Safari, Edge).

Note

Streamlit deliberately keeps its dependency list small and version-bounded. pandas is pinned by Python version (2.x on 3.10, 3.x on 3.11+). On macOS, watchdog is omitted and Streamlit falls back to a polling file watcher.


4. Configuration Mastery

4.1 Configuration sources and precedence

Options are resolved in this order, each overriding the previous (from config.get_config_options):

  1. Built-in defaults (defined in lib/streamlit/config.py)
  2. Global ~/.streamlit/config.toml
  3. Per-project $CWD/.streamlit/config.toml
  4. Environment variables (STREAMLIT_<SECTION>_<OPTION>, e.g. STREAMLIT_SERVER_PORT)
  5. Command-line flags to streamlit run (e.g. --server.port 8080)

Inspect the resolved state with streamlit config show. A config value of the form "env:VARNAME" in a TOML file is replaced with that environment variable's value at parse time.

Important

Sensitive options (server.cookieSecret, mapbox.token) cannot be set via CLI flag — attempting it exits with an error. Set them in config.toml or via their environment variable. Changing any [server] option requires a server restart to take effect.

4.2 [server] — the operational core

Option Default Purpose
server.port 8501 Port the server listens on.
server.address unset Bind address. If set, the server is reachable only at this address.
server.baseUrlPath "" Serve the app under a sub-path (e.g. behind a proxy).
server.headless auto* If false, opens a browser on start. *Defaults true on Linux without DISPLAY/WAYLAND_DISPLAY.
server.runOnSave false Auto-rerun when the script file changes.
server.fileWatcherType "auto" auto / watchdog / poll / none.
server.folderWatchList [] Extra absolute directories to watch.
server.folderWatchBlacklist [] Directories to ignore.
server.maxUploadSize 200 Max upload size (MB) for st.file_uploader.
server.maxMessageSize 200 Max WebSocket message size (MB).
server.enableCORS true CORS protection.
server.corsAllowedOrigins [] Allowed origins when CORS is enabled.
server.enableXsrfProtection true CSRF protection via signed cookie.
server.cookieSecret random Sensitive. Symmetric key for signing cookies; set identically across replicas.
server.enableWebsocketCompression false WebSocket compression.
server.websocketPingInterval unset Keep-alive ping interval (s); tune for flaky proxies.
server.enableStaticServing false Serve files from a static/ directory.
server.disconnectedSessionTTL 120 Seconds a disconnected session's state is retained.
server.sslCertFile / server.sslKeyFile unset HTTPS cert/key. Not for production (see Security).
server.showEmailPrompt true First-run email prompt (suppressed when headless).
server.trustedUserHeaders {} (experimental, hidden) Map HTTP headers into st.user.

4.3 [client] — browser-side behavior (runtime-settable)

Option Default Purpose
client.showErrorDetails "full" How much error detail reaches the browser: full / stacktrace / type / none.
client.toolbarMode "auto" Toolbar/menu visibility: auto / developer / viewer / minimal.
client.showSidebarNavigation true Show auto page nav for pages/-based apps.
client.showErrorLinks "auto" Show Google/ChatGPT help links on errors (auto = localhost only).
client.allowedOrigins CC defaults (hidden) Origins allowed to control the app via postMessage when iframed.

Tip

client.* options are the only ones settable at runtime via st.set_option(...) from within a script. Everything else must be set via config file, env var, or CLI flag.

4.4 [runner] — script execution

Option Default Purpose
runner.magicEnabled true Auto-display bare variables/literals.
runner.fastReruns true Handle rerun requests immediately (more responsive; minor race-condition risk for state mutated outside explicit assignment).
runner.postScriptGC true (hidden) Run GC after each script execution.
runner.enforceSerializableSessionState false Raise if non-serializable data is added to session state.
runner.enumCoercion "nameOnly" How Enum members coerce across reruns: off / nameOnly / nameAndValue.
runner.parallelMaxWorkers auto Max parallel fragment worker threads per run.

4.5 [browser], [logger], [magic], [ui], [global]

Option Default Purpose
browser.serverAddress "localhost" Address users point their browser at (CORS/XSRF, terminal URL).
browser.serverPort = server.port Port shown in the URL.
browser.gatherUsageStats true Send anonymous usage stats to Streamlit.
logger.level "info" (debug in dev) Internal log level: error / warning / info / debug.
logger.messageFormat %(asctime)s %(message)s Log format string.
logger.enableRich auto (hidden) Use rich for exception tracebacks if installed.
logger.hideWelcomeMessage false (hidden) Suppress the startup welcome/URL banner.
global.developmentMode auto True only when running from a source checkout.
global.disableWidgetStateDuplicationWarning false Silence the value-vs-session-state warning.
magic.displayRootDocString / magic.displayLastExprIfNoSemicolon false (hidden) Notebook-like magic behaviors.

4.6 [theme] — appearance

The [theme] section controls the visual theme and is inheritable. theme.base can be "light", "dark", or a path/URL to a TOML theme file. You can override per-mode and per-region with [theme.sidebar], [theme.light], [theme.dark], [theme.light.sidebar], and [theme.dark.sidebar] (only these nestings are valid — an invalid nesting raises StreamlitInvalidThemeSectionError).

Group Options (selection)
Colors primaryColor, backgroundColor, secondaryBackgroundColor, textColor, linkColor, borderColor, plus a full named palette (redColor/blueColor/… with matching *BackgroundColor and *TextColor)
Typography font, headingFont, codeFont, baseFontSize, baseFontWeight, headingFontSizes, headingFontWeights, codeFontSize, codeFontWeight, metricValueFontSize, metricValueFontWeight, [[theme.fontFaces]]
Shape baseRadius, buttonRadius (none/small/medium/large/full/px/rem)
Tables dataframeBorderColor, dataframeHeaderBackgroundColor, showWidgetBorder, showSidebarBorder
Charts chartCategoricalColors, chartSequentialColors, chartDivergingColors
Links/code linkUnderline, codeTextColor, codeBackgroundColor
[theme]
base = "light"
primaryColor = "#0068c9"
font = "sans-serif"
baseRadius = "medium"

[[theme.fontFaces]]
family = "MyFont"
url = "app/static/myfont.woff2"
weight = "400"

4.7 [secrets] and [mapbox]

  • secrets.files lists the secrets.toml locations searched (global, project, then script-level; later wins). Access via st.secrets.
  • mapbox.token is deprecated (expired 2026-05-01) — use the MAPBOX_API_KEY environment variable or PyDeck's api_keys argument instead.

Caution

Streamlit warns and auto-corrects a known incompatible combination: server.enableXsrfProtection=true with server.enableCORS=false. When detected, CORS is forced back on, because XSRF protection relies on origin restrictions.


5. Security

Streamlit's security posture centers on protecting the WebSocket channel, the upload path, and (optionally) authenticating users.

5.1 CSRF / XSRF and CORS

  • XSRF protection (server.enableXsrfProtection=true, default on) sends a signed cookie with each request, signed using server.cookieSecret.
  • CORS protection (server.enableCORS=true, default on) restricts cross-origin traffic; pair with server.corsAllowedOrigins.
  • The two are linked: disabling CORS while XSRF is on causes Streamlit to re-enable CORS.

server.cookieSecret defaults to a random per-process value. In any multi-replica deployment you must set the same cookieSecret across all replicas, or signed cookies (and therefore sessions and auth) will break on replica switches. It is a sensitive option — set it via config.toml or the STREAMLIT_SERVER_COOKIE_SECRET environment variable, never on the CLI.

5.3 TLS / HTTPS

server.sslCertFile and server.sslKeyFile enable HTTPS directly.

Caution

The built-in SSL options carry an explicit in-code warning: DO NOT USE in production. They have not been security- or performance-audited. For production, terminate TLS at a load balancer or reverse proxy and run Streamlit behind it over plain HTTP on the internal network.

5.4 Authentication (OIDC)

With the auth extra, st.login / st.logout / st.user provide OpenID Connect login. Credentials live in .streamlit/secrets.toml under [auth] and must include redirect_uri, cookie_secret, and per-provider client_id/client_secret. Missing/malformed config raises descriptive StreamlitAuthErrors. Provider names must not contain underscores. Tokens are validated for provider/exp claims and expiry.

5.5 Upload and message limits

server.maxUploadSize (200 MB) and server.maxMessageSize (200 MB) cap file uploads and WebSocket payloads. Lower these in untrusted environments to limit memory pressure and abuse. Uploads flow through /_stcore/upload_file/{session_id}/{file_id} and are tracked by the UploadedFileManager.

5.6 Embedding and untrusted-app hosting

  • client.allowedOrigins controls which parent-frame origins can drive the app via postMessage when embedded in an iframe. Because app code can modify this at runtime, platforms hosting untrusted app code should override the /_stcore/host-config endpoint at the proxy level rather than relying on this option.
  • server.enableStaticServing exposes a static/ directory — keep it off unless you intend to serve files.
  • client.showErrorDetails="none" (or "type") keeps tracebacks and full error messages out of the browser; they still print to the server console.

Important

Raw-HTML escape hatches (st.html, unsafe_allow_html=True, components.v1.html) are XSS vectors if fed untrusted input. Audit any app that renders user-controlled HTML.


6. Operations

6.1 Running and deploying

Self-hosted (classic):

streamlit run app.py \
  --server.port 8501 \
  --server.address 0.0.0.0 \
  --server.headless true \
  --browser.gatherUsageStats false

Docker (sketch):

FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8501
HEALTHCHECK CMD curl --fail http://localhost:8501/_stcore/health || exit 1
ENTRYPOINT ["streamlit", "run", "app.py", \
            "--server.port=8501", "--server.address=0.0.0.0", "--server.headless=true"]

ASGI via st.App + uvicorn:

# myapp.py
from streamlit import App
app = App("main.py")
uvicorn myapp:app --host 0.0.0.0 --port 8501 --workers 1

Mounted inside FastAPI/Starlette (asgi-mounted mode): construct st.App and mount it on a sub-path of your FastAPI/Starlette application.

Streamlit Community Cloud: push the repo to GitHub, deploy from share.streamlit.io, set secrets in the dashboard. Free for public apps.

6.2 Health checks and internal endpoints

Endpoint Purpose
GET /_stcore/health Liveness/readiness probe (200 = healthy).
WS /_stcore/stream The app WebSocket (ForwardMsg/BackMsg).
POST /_stcore/upload_file/{session_id}/{file_id} File-uploader endpoint.
GET /_stcore/host-config Host configuration (allowed origins, etc.). Override at the proxy for untrusted hosting.
GET /media/{file_id} Media files (images, audio, video).
GET /static/... App static assets / static/ serving.

Tip

Point your load balancer / orchestrator health probe at /_stcore/health. For app-script readiness specifically, the hidden server.scriptHealthCheckEnabled exposes a script-health endpoint that returns 200 on a successful script load and 503 on failure.

6.3 Scaling and session affinity

Streamlit sessions are stateful and in-memory, tied to a single WebSocket on a single replica.

Important

When running multiple replicas behind a load balancer you must enable session stickiness (affinity), or a reconnecting browser will land on a replica with no knowledge of its session and lose state. Also set a shared server.cookieSecret. server.disconnectedSessionTTL (120 s) governs how long a replica keeps a disconnected session's state available for reconnection.

6.4 File watching, logging, restarts

  • File watching uses watchdog when available, polling otherwise (server.fileWatcherType). Enable server.runOnSave for auto-rerun during development.
  • Control logging with logger.level and logger.messageFormat. Install rich for syntax-highlighted tracebacks (logger.enableRich).
  • [server] option changes require a restart — Streamlit logs a warning when it detects a server-option change in a re-parsed config file.

6.5 Cache maintenance

  • streamlit cache clear clears on-disk cache_data/cache_resource caches (not in-memory).
  • Programmatic: my_cached_func.clear() or st.cache_data.clear() / st.cache_resource.clear().
  • cache_data(persist="disk") survives restarts; tune ttl and max_entries to bound memory.

7. Internals (Developer Reference)

This section is for contributors and anyone who needs to reason about Streamlit's behavior at the code level.

7.1 The element pipeline: DeltaGenerator

Every st.<element> call is a method on a DeltaGenerator (DG). The public st.write, st.button, etc. are bound from the singleton _main DG in __init__.py. A DG:

  1. Builds the element's protobuf (Element or Block).
  2. Appends it to the session's delta path (the render-tree coordinate).
  3. Enqueues a ForwardMsg.

Containers (st.columns, st.tabs, st.expander, st.form, st.sidebar, st.container) return child DGs scoped to a Block, which is how nested layouts work. The DG singleton machinery lives in delta_generator_singletons.py to break circular imports between the DG and the elements it dispatches to.

7.2 Runtime, sessions, and the script runner

Component File Responsibility
Runtime runtime/runtime.py Top-level lifecycle; owns sessions and the media manager.
SessionManager / WebsocketSessionManager runtime/session_manager.py, websocket_session_manager.py Create/track AppSessions per WebSocket.
AppSession runtime/app_session.py One browser session: state, script lifecycle, message queue.
ScriptRunner runtime/scriptrunner/ Executes the user script in a thread; handles rerun requests, stop, fragments.
ForwardMsgQueue runtime/forward_msg_queue.py Buffers outgoing deltas; coalesces and flushes to the socket.
ForwardMsgCache runtime/forward_msg_cache.py Caches large messages (≥ global.minCachedMessageSize) by hash.
MediaFileManager / UploadedFileManager runtime/media_file_manager.py, uploaded_file_manager.py Serve media; receive uploads.
SessionState runtime/state/ Backs st.session_state and widget state.
Secrets runtime/secrets.py Loads and merges secrets.toml; backs st.secrets.
Fragment runtime/fragment.py Implements @st.fragment isolated reruns and run_every.

7.3 The web layer

web/cli.py defines the click CLI (run, hello, init, config show, cache clear, skills, docs, version, activate). Each config option is auto-injected as a --section.option flag by the configurator_options decorator. web/server/app_discovery.py inspects the target script to detect whether it's a plain Streamlit script or an ASGI app (st.App/FastAPI/Starlette), routing to bootstrap.run(...) or bootstrap.run_asgi_app(...) accordingly. web/server/starlette/ holds the Starlette routes, WebSocket handler, gzip and path-security middleware, auth routes, and static serving.

7.4 Connections

runtime/connection_factory.py implements st.connection, returning cached connection objects. Built-in BaseConnection subclasses live in connections/: SQLConnection (SQLAlchemy), SnowflakeConnection, SnowparkConnection, plus a callers-rights Snowflake variant. Custom connections subclass BaseConnection.

7.5 Frontend

The frontend is a React SPA (frontend/app/) backed by a shared component library (frontend/lib/), styled with Emotion (CSS-in-JS), and built with Vite. The WebSocket client lives in frontend/connection/. Each backend element has a corresponding React component under frontend/lib/src/components/{elements,widgets,layouts}/. Custom-component SDKs are frontend/component-lib (v1) and frontend/component-v2-lib (v2). Theming and all pixel/rem layout calculations are performed on the frontend — the backend passes only semantic data, never resolved theme values.

7.6 Testing

  • Python unit tests (lib/tests/, pytest) — internal behavior without the frontend; target ≥95% coverage.
  • Frontend unit tests (Vitest + React Testing Library) — co-located *.test.tsx.
  • E2E tests (e2e_playwright/, Playwright via pytest) — full-stack, including visual snapshots.
  • Typing tests (lib/tests/streamlit/typing/) — mypy assert_type checks of the public API; never executed at runtime.
  • The AppTest framework (runtime/testing/) lets you test apps headlessly in Python.

Note

The repository's develop branch is the main branch, and it ships maintainer-written AGENTS.md files at the root and per-subsystem (lib/, frontend/, proto/streamlit/proto/, etc.) describing build commands and conventions. The build orchestrator is make (make protobuf, make check, make frontend-fast); all Python tasks run under uv run.


8. Code Quality and Conventions

  • Linting/formatting: ruff with nearly all rules enabled (select = ["ALL"]), 88-char lines, NumPy docstring convention, relative imports banned. Generated protobuf and vendored code are excluded.
  • Type checking: strict mypy (no implicit re-export, disallow untyped defs, warn-unreachable) plus the ty checker. Public-API typing is asserted in dedicated typing tests.
  • Docstrings: all public st.* methods use NumPy-style docstrings with executable examples and .. output:: directives.
  • Widget API design: heavy use of @overload to give precise return types depending on arguments (e.g. selectbox returns T, T | None, or T | str depending on index/accept_new_options). The single runtime implementation lives at the end of each overload group.
  • Backend/frontend split: the backend never computes layout or theme pixels — that is a frontend responsibility by policy.

9. Potential Improvements & Known Issues

Drawn from the project's own issue tracker and the observable state of the codebase at this commit:

  • Starlette migration fallout. The move from Tornado to Starlette/Uvicorn is recent and surfaces operational edge cases — e.g. #15407 (page breaks for logged-in users after the Tornado→Starlette conversion) and #15421 (Starlette dependency floor). Operators upgrading from a Tornado-era release should retest auth, proxying, and WebSocket stability.
  • st.App is experimental. The single-App-per-process constraint and process-global script-path pinning are sharp edges; expect API changes.
  • Multithreading limits. Several long-standing requests (#7851, #8490) ask for friendlier multi-threading/multi-processing within an app. Today, session state and the script runner assume a single execution thread per session (fragments add bounded parallelism via runner.parallelMaxWorkers).
  • Async caching. st.cache_data/st.cache_resource do not natively cache coroutines (#8308).
  • Widget-state persistence. Persisting keyed widget state when a widget isn't rendered is requested (#6074).
  • Deprecations to track. mapbox.token config (expired 2026-05-01; use MAPBOX_API_KEY/PyDeck api_keys), the deprecated True/False values for client.showErrorDetails, and the deprecated st._bottom (use st.bottom).
  • SSL is dev-only. The built-in SSL options are explicitly not production-grade; production deployments must terminate TLS upstream.

10. Quick Reference

CLI

streamlit run <target> [-- args]   Run an app (file / folder / URL)
streamlit hello                    Built-in demo
streamlit init [dir]               Scaffold a project
streamlit config show              Show all config + sources
streamlit cache clear              Clear on-disk caches
streamlit skills [-g] [-y]         Install AI-agent skills
streamlit docs | version | help
streamlit activate [reset]

Key config defaults

Option Default
server.port 8501
server.maxUploadSize / server.maxMessageSize 200 MB
server.enableCORS / server.enableXsrfProtection true
server.disconnectedSessionTTL 120 s
client.toolbarMode / client.showErrorDetails auto / full
runner.magicEnabled / runner.fastReruns true
browser.gatherUsageStats true

Internal endpoints

GET  /_stcore/health             WS  /_stcore/stream
POST /_stcore/upload_file/...    GET /_stcore/host-config
GET  /media/{file_id}            GET /static/...

Production checklist

  • [ ] Set a shared server.cookieSecret across all replicas.
  • [ ] Enable session stickiness at the load balancer.
  • [ ] Terminate TLS at a proxy (do not use built-in SSL).
  • [ ] Run --server.headless true and --browser.gatherUsageStats false.
  • [ ] Probe /_stcore/health.
  • [ ] Keep secrets.toml out of version control; use platform secret stores.
  • [ ] Set client.toolbarMode="viewer" and client.showErrorDetails="none" for public apps.
  • [ ] Override /_stcore/host-config at the proxy if hosting untrusted app code.