### Run make all-dev for one-time setup
Source: https://github.com/streamlit/streamlit/blob/develop/CONTRIBUTING.md
One-time setup that creates and manages the virtual environment and dependencies. Run this before starting development.
```bash
make all-dev
```
--------------------------------
### Colored CLI output for skill statuses
Source: https://github.com/streamlit/streamlit/wiki/pull-requests/15116/tech-spec
Example of the expected colored output when reporting skill installation status per target path. Uses Click's secho() and style() with green for installed, blue for up to date, and yellow for skipped due to conflicts. Paths are cyan and arrows match the header color.
```text
✓ Installed: (green, bold)
→ .agents/skills/developing-with-streamlit (green arrow, cyan path)
● Up to date: (blue, bold)
→ .claude/skills/developing-with-streamlit (blue arrow, cyan path)
⚠ Skipped due to conflicts: (yellow, bold)
→ .agents/skills/developing-with-streamlit (yellow arrow)
```
--------------------------------
### Run a Streamlit App Programmatically
Source: https://github.com/streamlit/streamlit/blob/develop/specs/2026-06-14-app-run-method/product-spec.md
Example of initializing an st.App and starting it with the run() method. Positional arguments passed to the script are forwarded to the app via sys.argv.
```python
import sys
import streamlit as st
app = st.App("dashboard.py")
if __name__ == "__main__":
app.run()
# `python app.py --date 2026-06-14 extra` -> dashboard.py sees
# sys.argv == ["app.py", "--date", "2026-06-14", "extra"]
```
--------------------------------
### Usage example for st.grid
Source: https://github.com/streamlit/streamlit/wiki/pull-requests/15185/tech-spec
Example showing how to initialize a grid and add content using a container.
```python
grid = st.grid(4)
with grid.container():
st.metric(...)
st.caption(...)
```
--------------------------------
### GET /_stcore/agent/app manifest response (JSONC)
Source: https://github.com/streamlit/streamlit/wiki/pull-requests/16843/2026-08-28-agent-interface-opus5-product-spec
Example manifest returned by the GET /_stcore/agent/app endpoint, showing the app's name, description, pages, inputs, and other metadata. This is available before any script has run for the caller.
```jsonc
{
"name": "Sales Dashboard",
"description": "Revenue and pipeline metrics by region, refreshed nightly.",
"pages": [{ "title": "Overview", "path": "/" }, { "title": "Reports", "path": "/reports" }],
"inputs": [
{ "name": "country", "type": "selectbox", "label": "Country",
"schema": { "type": "string", "enum": ["Japan", "United States", "Germany"] } },
{ "name": "refresh", "type": "button", "label": "Refresh data",
"schema": { "type": "boolean" }, "destructive": false }
],
"inputs_are_complete": false,
"streamlit_version": "1.63.0",
"document_format_version": 1
}
```
--------------------------------
### Install and verify Streamlit
Source: https://github.com/streamlit/streamlit/blob/develop/README.md
Use pip to install the Streamlit package and run the hello command to verify the installation in your browser.
```bash
$ pip install streamlit
$ streamlit hello
```
--------------------------------
### Install Node.js with nvm
Source: https://github.com/streamlit/streamlit/blob/develop/CONTRIBUTING.md
Install the latest supported Node.js version using nvm, after installing nvm via the linked instructions.
```bash
# Install node
nvm install node
```
--------------------------------
### Start the frontend development server
Source: https://github.com/streamlit/streamlit/blob/develop/frontend/README.md
Commands to start the Streamlit frontend development server. Run either `yarn start` or `make frontend-dev` from the frontend directory.
```bash
yarn start
```
```bash
make frontend-dev
```
--------------------------------
### Testing plan description example
Source: https://github.com/streamlit/streamlit/blob/develop/wiki/pull-requests.md
Example of how to describe testing by listing test files and what they cover. This is used in the PR template checklist.
```markdown
- `lib/tests/streamlit/elements/plotly_chart_test.py` — Tests height parameter
- `e2e_playwright/st_plotly_chart_test.py` — Visual regression tests for height
```
--------------------------------
### Build frontend with make frontend
Source: https://github.com/streamlit/streamlit/blob/develop/CONTRIBUTING.md
Builds the frontend. Run this after the one-time setup.
```bash
make frontend
```
--------------------------------
### Install protoc 26.1 from GitHub release and run make protobuf
Source: https://github.com/streamlit/streamlit/blob/develop/CONTRIBUTING.md
Downloads and installs a specific protoc release from GitHub when Homebrew has no matching formula. Use the asset for your OS and architecture (osx-aarch_64, osx-x86_64, linux-x86_64, or linux-aarch_64). /usr/local/bin must precede Homebrew's protoc on PATH.
```bash
PROTOC_VERSION=26.1 # copy from action.yml
PROTOC_ZIP="protoc-${PROTOC_VERSION}-osx-aarch_64.zip"
curl -fOL "https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/${PROTOC_ZIP}"
sudo unzip -o "$PROTOC_ZIP" -d /usr/local bin/protoc
sudo unzip -o "$PROTOC_ZIP" -d /usr/local 'include/*'
rm "$PROTOC_ZIP"
which protoc # should be /usr/local/bin/protoc
make protobuf
```
--------------------------------
### Option C: Usage examples for combined and single-layer handlers
Source: https://github.com/streamlit/streamlit/blob/develop/specs/2026-04-20-exception-handler/product-spec.md
Usage examples for Option C, showing how to configure both HTTP and script handlers via a tuple, or use a simple callable or mapping for single-layer handling.
```python
# Both layers
app = st.App(
"main.py",
exception_handlers=(
{404: not_found_handler}, # HTTP layer
sentry_sdk.capture_exception, # Script layer
),
)
# Script only (simple callable)
app = st.App("main.py", exception_handlers=sentry_sdk.capture_exception)
# HTTP only (mapping, existing behavior)
app = st.App("main.py", exception_handlers={404: not_found_handler})
```
--------------------------------
### Migration Example to culori
Source: https://github.com/streamlit/streamlit/wiki/pull-requests/15150/tech-spec
Example of using culori for color parsing, mixing, and alpha manipulation.
```typescript
import { parse, formatRgb, interpolate, oklch } from "culori"
// Parse any CSS color
const color = parse("oklch(0.7 0.15 30)")
// Mix in perceptually uniform space
const mixer = interpolate(["red", "blue"], "oklch")
const mixed = mixer(0.5) // Perceptually uniform midpoint
// Set alpha
const withAlpha = { ...color, alpha: 0.5 }
// Output as CSS
formatRgb(withAlpha) // "rgba(237, 118, 101, 0.5)"
```
--------------------------------
### Windows workflow: install and test commands
Source: https://github.com/streamlit/streamlit/wiki/pull-requests/16715/implementation-plan
Run these commands in the Windows workflow after checking out the code and setting up Python. Copies the README into the lib directory, installs pytest and the editable lib package, then runs the meta-skill discovery test with the `-o addopts=` flag to drop the `--cov=streamlit` option from `lib/pyproject.toml`.
```text
Copy-Item README.md lib/README.md
python -m pip install pytest
python -m pip install -e lib
python -m pytest lib/tests/streamlit/web/meta_skill_discover_test.py -o addopts= -q
```
--------------------------------
### Set up base environment on Ubuntu
Source: https://github.com/streamlit/streamlit/blob/develop/CONTRIBUTING.md
Install essential packages, Node.js via nvm, Corepack, uv, and optionally GitHub CLI and ripgrep on Ubuntu.
```bash
# Install some essentials
$ sudo apt-get update
$ sudo apt-get install -y sudo make build-essential curl git rsync unzip protobuf-compiler
# Set frontend dependencies:
$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
$ source ~/.bashrc
$ nvm install node
$ corepack enable
# Install uv for Python
$ curl -LsSf https://astral.sh/uv/install.sh | sh
# (Recommended) Install GitHub CLI - used by AI agents for PR and issue management
# See https://cli.github.com/ for installation instructions
# (Recommended) Install ripgrep - used by AI agents for fast log/code search
$ sudo apt-get install -y ripgrep
```
--------------------------------
### Streamlit Skills CLI Commands
Source: https://github.com/streamlit/streamlit/blob/develop/specs/2026-05-11-streamlit-skills-cli/product-spec.md
The CLI interface for the Streamlit Skills Installer. The default command performs an interactive project install. The --global flag installs the meta skill from GitHub to the user's global agent skills directories instead of project-local bundled skills. The --yes flag skips prompts and confirms installation.
```bash
streamlit skills
```
```bash
streamlit skills --global
```
```bash
streamlit skills --yes
```
```bash
streamlit skills --global --yes
```
--------------------------------
### Install minimum dependencies with uv pip install --no-config
Source: https://github.com/streamlit/streamlit/wiki/pull-requests/15968/tech-spec
Install minimum runtime dependencies with project config disabled so the pandas override cannot replace the minimum. Use --force-reinstall to ensure the minimum versions are installed.
```bash
uv pip install --no-config \
-r scripts/assets/min-constraints-gen.txt \
--force-reinstall
```
--------------------------------
### Example: Call Microsoft Graph with access token
Source: https://github.com/streamlit/streamlit/blob/develop/specs/2025-11-19-auth-oidc-tokens/product-spec.md
Assumes `expose_tokens = "access"` so `st.user.tokens.access` exists. After `st.login()`, if the user is authenticated, it makes an authenticated GET request to an API and displays the JSON response.
```python
import streamlit as st
import requests
st.login()
if st.user:
api_url = "https://api.example.com/me"
resp = requests.get(
api_url, headers={"Authorization": f"Bearer {st.user.tokens.access}"}
)
st.json(resp.json())
```
--------------------------------
### Option B: Usage examples for script and HTTP errors
Source: https://github.com/streamlit/streamlit/blob/develop/specs/2026-04-20-exception-handler/product-spec.md
Usage examples for Option B, showing how to configure script-only or HTTP-only error handling with the unified exception_handlers parameter. Cannot configure both simultaneously.
```python
# Script errors only
app = st.App("main.py", exception_handlers=sentry_sdk.capture_exception)
# HTTP errors only (existing behavior)
app = st.App("main.py", exception_handlers={404: not_found_handler})
```
--------------------------------
### Set up base environment on macOS
Source: https://github.com/streamlit/streamlit/blob/develop/CONTRIBUTING.md
Install required tools on macOS: Apple developer tools, Homebrew, the Protobuf compiler, and optionally GitHub CLI and ripgrep.
```bash
# Some Apple dev tools (developer.apple.com/downloads)
$ xcode-select --install
# Install Homebrew
$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# Install the Protobuf compiler
$ brew install protobuf
# (Recommended) Install GitHub CLI - used by AI agents for PR and issue management
$ brew install gh
# (Recommended) Install ripgrep - used by AI agents for fast log/code search
$ brew install ripgrep
```
--------------------------------
### Install versioned protobuf@33 and run make protobuf
Source: https://github.com/streamlit/streamlit/blob/develop/CONTRIBUTING.md
Installs a versioned Homebrew protobuf formula matching the locked Python protobuf minor version (e.g. protobuf@33 for protobuf 6.33.x) and regenerates protobuf modules. The PATH export is session-scoped; a later `make protobuf` in a new shell will pick Homebrew's unversioned protoc again unless the PATH is persisted.
```bash
brew install protobuf@33
export PATH="$(brew --prefix protobuf@33)/bin:$PATH"
make protobuf
```
--------------------------------
### Install Streamlit skills with streamlit skills
Source: https://github.com/streamlit/streamlit/blob/develop/specs/2026-05-11-streamlit-skills-cli/product-spec.md
Installs Streamlit's AI-agent skills. In project mode (default), it symlinks bundled skills from the active Streamlit environment. In global mode, it fetches the developing-with-streamlit meta skill from the streamlit/agent-skills repository and installs it to ~/.agents/skills/ and ~/.claude/skills/ when Claude Code is detected.
```bash
streamlit skills
```
--------------------------------
### Start dev server with make frontend-dev
Source: https://github.com/streamlit/streamlit/blob/develop/CONTRIBUTING.md
Starts the dev server with hot-reloading. Defaults to port 3000 instead of 8501; can be changed with `VITE_PORT` (or `PORT`). Set `DEV_SERVER_BACKEND_URL` to point at a different backend.
```bash
make frontend-dev
```
--------------------------------
### Install meta skill via npx skills
Source: https://github.com/streamlit/streamlit/blob/develop/specs/2026-05-11-streamlit-skills-cli/product-spec.md
Alternative cross-agent installer using npx skills (vercel/skills). Supports Claude Code, Cursor, Copilot, Gemini CLI, Codex, and others. The -g flag installs globally; -s specifies the skill name. Requires Node.js.
```bash
npx skills add streamlit/agent-skills -s developing-with-streamlit -g
```
--------------------------------
### Basic App.run() usage
Source: https://github.com/streamlit/streamlit/blob/develop/specs/2026-06-14-app-run-method/product-spec.md
A simple example of using the App.run() method to launch a Streamlit dashboard script.
```python
import streamlit as st
app = st.App("dashboard.py")
if __name__ == "__main__":
app.run()
```
--------------------------------
### Example JSON snapshot of a Streamlit app page
Source: https://github.com/streamlit/streamlit/wiki/pull-requests/16843/2026-09-06-agent-app-interface-opus5-2-product-spec
Shows the full snapshot structure with a page, elements, and actions. The example includes a selectbox, button, metric, dataframe, and expander, demonstrating the conventions described above.
```json
{
"schema_version": 1,
"session_id": "s_7f3a",
"status": "ready",
"observed_at": "2026-09-06T10:00:00Z",
"page": {"url_path": "", "title": "Regional revenue", "icon": ":material/payments:"},
"pages": [
{"url_path": "", "title": "Regional revenue", "icon": ":material/payments:"},
{"url_path": "reports", "title": "Reports"}
],
"query_params": {},
"tree": {
"type": "root",
"children": [
{
"type": "main",
"children": [
{"type": "title", "props": {"body": "Regional revenue"}},
{"type": "caption", "props": {
"body": "Net revenue excludes refunds. Periods are UTC. Source: finance ledger."}},
{
"key": "region",
"type": "selectbox",
"props": {
"label": "Region",
"options": ["All", "Europe", "AMER", "APAC"],
"help": "Customer billing region; All includes every region.",
"disabled": false
},
"value": "All"
},
{
"key": "$$ID-8f2c9a1d4b6e7f30-None",
"type": "button",
"props": {"label": "Refresh data", "type": "secondary", "disabled": false}
},
{"type": "metric", "props": {"label": "Net revenue", "value": "€1.2M", "delta": "+8%"}},
{
"type": "dataframe",
"props": {"column_config": {"month": {"label": "Month"}}},
"data": {
"columns": [{"name": "month", "type": "string"},
{"name": "revenue", "type": "number"}],
"row_count": 24,
"column_count": 2,
"preview": {"truncated": true,
"rows": [{"month": "2026-01", "revenue": 120000}]},
"url": "/media/4f1c8ab27d9e5306.arrow"
}
},
{
"type": "expander",
"props": {
"label": "How net revenue is calculated",
"icon": ":material/info:",
"expanded": false
},
"children": [
{"type": "markdown", "props": {
"body": "Gross invoiced amounts minus refunds and credit notes, converted to EUR at the invoice-date rate."}}
}
]
}
]
},
{"type": "sidebar", "children": []},
{"type": "event", "children": []},
{"type": "bottom", "children": []}
]
},
"actions": [
{"key": "region", "kind": "value"},
{"key": "$$ID-8f2c9a1d4b6e7f30-None", "kind": "trigger"}
],
"limitations": []
}
```
--------------------------------
### Search input implementation
Source: https://github.com/streamlit/streamlit/blob/develop/specs/2026-06-29-text-input-types/product-spec.md
Example of using the search input type to capture a user query.
```python
import streamlit as st
query = st.text_input("Search products", type="search")
results = search(query) if query else []
st.write(results)
```
--------------------------------
### RST output directive example
Source: https://github.com/streamlit/streamlit/blob/develop/lib/streamlit/AGENTS.md
Shows the RST directive for the output of a docstring example. Use this to display the app URL and set the iframe height.
```rst
.. output::
https://doc-example.streamlit.app
height: 200px
```
--------------------------------
### SafeSessionState race condition example
Source: https://github.com/streamlit/streamlit/blob/develop/specs/2026-03-05-parallel-fragments/tech-spec.md
An example demonstrating how compound operations like read-modify-write are not atomic in SafeSessionState because the lock is released between operations.
```python
@st.fragment(parallel=True)
def increment():
# Thread A reads counter=5, releases lock
val = st.session_state["counter"]
# Thread B reads counter=5, releases lock
st.session_state["counter"] = val + 1
# Both threads write 6 — lost update
```
--------------------------------
### Global Install Directory Structure
Source: https://github.com/streamlit/streamlit/blob/develop/specs/2026-05-11-streamlit-skills-cli/product-spec.md
The directory structure of the developing-with-streamlit meta skill that is installed globally. It contains a SKILL.md file with meta skill instructions and a scripts/discover.py script that locates the project's bundled skills at runtime.
```text
developing-with-streamlit/
├── SKILL.md # Meta skill instructions
└── scripts/
└── discover.py # Locates project's bundled skills
```
--------------------------------
### App document Markdown example
Source: https://github.com/streamlit/streamlit/wiki/pull-requests/16843/2026-08-28-agent-interface-opus5-product-spec
Example of the app document format. It renders an app's output as Markdown with fenced blocks using st: info strings for inputs, metrics, charts, and dataframes. Charts are summarized with resource URLs, and dataframes show schema, shape, and a head.
```markdown
# Sales Dashboard
page: Overview (of Overview, Reports, Settings) · status: ready
## Filters
```st:inputs
selectbox key=country label="Country" value="Japan" options=["Japan", "United States", "Germany"]
date_input key=range label="Date range" value=["2026-01-01", "2026-06-30"]
button key=refresh label="Refresh data"
```
## Revenue
Revenue grew **12%** year over year, driven by APAC.
```st:metric
label="Revenue" value="¥12.4M" delta="+12%"
```
```st:chart key=revenue-chart type=vega-lite
mark=line x=month (temporal) y=revenue (quantitative) color=region (nominal)
series=["APAC", "EMEA", "AMER"] points=72 x-range=2026-01..2026-06 y-range=0.8M..2.4M
spec=/_stcore/agent/resource/ab12cd
```
```st:dataframe key=top-accounts
columns=[account (str), region (str), revenue (int)] rows=1240 showing=5
| account | region | revenue |
| ------- | ------ | ------- |
| Acme | APAC | 412000 |
| Globex | APAC | 388000 |
data=/_stcore/agent/resource/ef34gh
```
```
--------------------------------
### Run reproduction app with uv
Source: https://github.com/streamlit/streamlit/wiki/issues/12065/investigation
Runs the reproduction app for an installed Streamlit package using uv.
```bash
uv run streamlit run agent-wiki/issues/12065/repro_app.py
```
--------------------------------
### Branch naming examples
Source: https://github.com/streamlit/streamlit/blob/develop/wiki/pull-requests.md
Examples of branch names following the {type}/{brief-description} format in kebab-case. Types include feature, fix, refactor, chore, and docs. Names should be descriptive and specific (3-8 words), avoiding ticket/issue numbers.
```text
feature/add-height-parameter-plotly-charts
fix/dataframe-memory-leak-large-datasets
refactor/element-width-height-logic
chore/update-react-dependencies
```
--------------------------------
### st.App with app metadata
Source: https://github.com/streamlit/streamlit/wiki/pull-requests/16843/2026-09-06-agent-app-interface-gpt-sol-2-product-spec
Python example of creating an st.App with static title and description metadata, used when the companion authoring slice is available.
```python
app = st.App(
"dashboard.py",
app_title="Revenue explorer",
app_description="Explore net revenue by billing region and quarter, in EUR.",
)
```
--------------------------------
### Interactive Flow Prompt
Source: https://github.com/streamlit/streamlit/blob/develop/specs/2026-05-11-streamlit-skills-cli/product-spec.md
The interactive flow of the Streamlit Skills Installer. After running the command, the user is prompted to select an install mode: Project (recommended) or Global. The default choice is Project, indicated by [p].
```text
$ streamlit skills
Streamlit Skills Installer
Install mode:
[p] Project (recommended) - skills available in this project only
[g] Global - discovery skill available in all projects (requires network)
Choice [p]: _
```
--------------------------------
### AI Reasoning Disclosure Example
Source: https://github.com/streamlit/streamlit/blob/develop/specs/2026-02-21-compact-expander-status/product-spec.md
Using a compact expander to show AI reasoning steps.
```python
import streamlit as st
# Compact thinking indicator
with st.expander("Thought for 4 seconds", type="compact", icon=":material/psychology:"):
st.write("Let me think about this problem step by step.")
st.write("First, I need to understand what the user is asking for...")
st.write("Here's my answer: The solution is 42.")
```
--------------------------------
### Empty required selectbox example
Source: https://github.com/streamlit/streamlit/blob/develop/specs/2026-08-18-required-widgets/product-spec.md
Example of a required selectbox that starts empty by passing index=None. With required=True, an empty commit is blocked and an error is shown, but the widget still returns the empty default on initial render.
```python
st.selectbox("Country", countries, index=None, required=True)
```
--------------------------------
### Set up base environment on Rocky Linux / RHEL / Fedora
Source: https://github.com/streamlit/streamlit/blob/develop/CONTRIBUTING.md
Install essential packages, Node.js via nvm, Corepack, uv, and optionally GitHub CLI and ripgrep on Rocky Linux, RHEL, or Fedora.
```bash
# Install some essentials
$ sudo dnf install -y make gcc-c++ curl git rsync unzip protobuf-compiler
# Set frontend dependencies:
$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
$ source ~/.bashrc
$ nvm install node
$ corepack enable
# Install uv for Python
$ curl -LsSf https://astral.sh/uv/install.sh | sh
# (Recommended) Install GitHub CLI - used by AI agents for PR and issue management
# See https://cli.github.com/ for installation instructions
# (Recommended) Install ripgrep - used by AI agents for fast log/code search
$ sudo dnf install -y ripgrep
```
--------------------------------
### st.number_input with value=None and required=True
Source: https://github.com/streamlit/streamlit/wiki/pull-requests/17023/implementation-plan
Example of an empty required number_input field. Starts at min (or 0/0.0) and commits None when empty.
```python
st.number_input("Amount", value=None, required=True)
```
--------------------------------
### TOML configuration for browser.command
Source: https://github.com/streamlit/streamlit/wiki/pull-requests/16761/implementation-plan
Example TOML configuration setting the browser command to 'chrome'.
```toml
[browser]
command = "chrome"
```
--------------------------------
### st.iframe height modes usage examples
Source: https://github.com/streamlit/streamlit/blob/develop/specs/2026-03-13-st-iframe/product-spec.md
Python examples showing how st.iframe auto-sizes to content for HTML strings and uses a fallback height for URLs. The first two calls demonstrate content-based sizing, while the last two show the default 400px fallback and an explicit height override.
```python
# HTML auto-sizes to content
st.iframe("
Short content
") # → small iframe
st.iframe("..." + "x" * 1000 + "
") # → taller iframe
# URLs use sensible fallback
st.iframe("https://example.com") # → 400px default
st.iframe("https://example.com", height=600) # → explicit override
```
--------------------------------
### Example 1: Prefix matching for autocomplete
Source: https://github.com/streamlit/streamlit/blob/develop/specs/2026-03-25-selectbox-filter-mode/product-spec.md
Uses filter_mode="prefix" in st.selectbox to filter countries by prefix, showing only options that start with the typed text. Typing "Aus" displays "Australia" and "Austria".
```python
import streamlit as st
# Countries sorted alphabetically
countries = ["Argentina", "Armenia", "Australia", "Austria", ...]
selected = st.selectbox(
"Select Country",
countries,
filter_mode="prefix",
)
# Typing "Aus" shows "Australia" and "Austria", not "Belarus"
```
--------------------------------
### Windows layout planted on Ubuntu for filesystem tests
Source: https://github.com/streamlit/streamlit/wiki/pull-requests/16715/implementation-plan
Simulate a Windows Python installation on a POSIX system by planting python.exe and Lib/site-packages. Use monkeypatch.setattr(discover_mod.os, "name", "nt") to make the probe treat the OS as Windows.
```text
/python.exe
/Lib/site-packages/streamlit/...
```
--------------------------------
### st.App callable entrypoint example
Source: https://github.com/streamlit/streamlit/wiki/pull-requests/16333/implementation-plan
Shows how to use st.App with a callable entrypoint. The callable must be synchronous and zero-argument. The source file of the callable is used as the app's filesystem anchor for config, secrets, pages, and other paths. The same module works with both `streamlit run app.py` and `uv run app.py`.
```python
import streamlit as st
def main() -> None:
st.title("My app")
app = st.App(main)
if __name__ == "__main__":
app.run()
```
--------------------------------
### Cache Warming API Example
Source: https://github.com/streamlit/streamlit/blob/develop/specs/2026-04-08-cache-background-refresh/product-spec.md
Proposed API to pre-populate cache entries. Not included in the MVP; can be achieved by calling cached functions at startup or with custom initialization logic.
```python
fetch_stock_prices.warm("AAPL", "GOOGL", "MSFT")
```
--------------------------------
### Run load test with default settings
Source: https://github.com/streamlit/streamlit/blob/develop/e2e_playwright/load_testing/README.md
Runs the load test with default settings (5 sessions, all scenarios) using the make command.
```bash
# Run with default settings (5 sessions, all scenarios)
make run-e2e-test e2e_playwright/load_testing/test_load.py
```
--------------------------------
### Prefer Enums Over Booleans: Example of st.text_input type parameter
Source: https://github.com/streamlit/streamlit/blob/develop/specs/AGENTS.md
Shows a bad example using a boolean for password and a good example using string enums for type, allowing easy expansion to email and tel. The exception is disabled=True/False, which is acceptable.
```python
# Bad: Boolean limits expansion
st.text_input("Password", password=True)
# What if we want "email" type later? Another boolean?
# Good: Enum allows expansion
st.text_input("Password", type="password")
st.text_input("Email", type="email") # Easy to add later
st.text_input("Phone", type="tel") # And again
```
--------------------------------
### Basic resizable columns
Source: https://github.com/streamlit/streamlit/wiki/pull-requests/16556/resizable-columns-product-spec
Basic example of resizable columns with three equal-width columns. Users can drag borders to resize adjacent columns.
```python
import streamlit as st
col1, col2, col3 = st.columns(3, resizable=True)
with col1:
st.header("Column 1")
st.write("Drag the border to resize →")
with col2:
st.header("Column 2")
st.write("Content here")
with col3:
st.header("Column 3")
st.write("More content")
```
--------------------------------
### Equivalent launcher modes
Source: https://github.com/streamlit/streamlit/blob/develop/specs/2026-06-14-app-run-method/product-spec.md
Comparison of different ways to launch a Streamlit application, including the new App.run() method.
```bash
python app.py # new: App.run() on the existing `app` object
uv run app.py # new: App.run() (the primary motivating use case)
streamlit run app.py # unchanged: AST discovery finds `app`
uvicorn app:app # unchanged: external ASGI server
```
--------------------------------
### Commit message examples
Source: https://github.com/streamlit/streamlit/blob/develop/wiki/pull-requests.md
Example commit messages following the imperative verb format. Each message is concise and describes the change directly.
```text
Add height parameter to plotly charts
Fix memory leak in dataframe scrolling
Refactor layout config validation logic
```
--------------------------------
### Example Commands for Running Load Tests
Source: https://github.com/streamlit/streamlit/blob/develop/e2e_playwright/load_testing/README.md
Commands to run load tests with different scenarios and session counts. Use PYTEST_ADDOPTS to pass browser and session options. The -k flag filters scenarios by name. High session counts require significant system resources.
```bash
# Run only the simple app scenario with 10 sessions (from repo root)
PYTEST_ADDOPTS='--browser=chromium --num-sessions=10 -k simple_app' \
make run-e2e-test e2e_playwright/load_testing/test_load.py
```
```bash
# Run dataframe and widget scenarios with 25 sessions
PYTEST_ADDOPTS='--browser=chromium --num-sessions=25 -k "dataframe_app or widget_heavy_app"' \
make run-e2e-test e2e_playwright/load_testing/test_load.py
```
```bash
# Run all scenarios with 50 sessions
PYTEST_ADDOPTS='--browser=chromium --num-sessions=50' \
make run-e2e-test e2e_playwright/load_testing/test_load.py
```
--------------------------------
### Fragment referencing an outside container
Source: https://github.com/streamlit/streamlit/blob/develop/specs/2026-06-03-outside-container-writes/tech-spec.md
An example demonstrating a fragment attempting to write to a container defined in the main script scope.
```python
outside = st.container()
@st.fragment
def my_fragment():
outside.button("Click me")
outside.write("Status: ok")
```
--------------------------------
### Usage of st.tabs with key and on_change, and .open property
Source: https://github.com/streamlit/streamlit/blob/develop/specs/2026-01-14-dynamic-tabs-expander/product-spec.md
Shows how to create tabs with key and on_change="rerun", access the .open property on each tab, read the active tab label from session state, and note that non-container elements like st.button return None for .open.
```python
tabs = st.tabs(["A", "B", "C"], key="my_tabs", on_change="rerun")
# Each tab has .open property
tabs[0].open # True if "A" is active, False otherwise
tabs[1].open # True if "B" is active, False otherwise
# Also accessible via session state
st.session_state.my_tabs # Returns "A", "B", or "C" (active tab label)
# Note: Other elements also have .open but it returns None
button = st.button("Click")
button.open # Always None (not a tab/expander/popover)
```
--------------------------------
### Disable Export App-Wide Example
Source: https://github.com/streamlit/streamlit/blob/develop/specs/2025-12-03-dataframe-disable-export/product-spec.md
Example showing how to disable data export for all dataframes in an app by setting the config option and then displaying a dataframe.
```toml
# .streamlit/config.toml
[client]
disableDataExport = true
```
```python
import pandas as pd
import streamlit as st
df = pd.DataFrame({"Name": ["Alice", "Bob"], "Salary": [100000, 120000]})
# Export is disabled for all dataframes
st.dataframe(df)
```
--------------------------------
### App.run() with configuration overrides
Source: https://github.com/streamlit/streamlit/blob/develop/specs/2026-06-14-app-run-method/product-spec.md
Using the config parameter to pin server settings like port and address programmatically.
```python
if __name__ == "__main__":
# Self-contained launcher that pins its own server settings,
# with no config.toml or env vars required.
app.run(config={"server.port": 8502, "server.address": "0.0.0.0"})
```
--------------------------------
### Future DuckDB relation adapter example
Source: https://github.com/streamlit/streamlit/blob/develop/specs/2026-05-07-dataframe-lazy-load/product-spec.md
Example of passing a DuckDB relation to `st.dataframe` for lazy rendering. Marked as a future Phase 3+ adapter.
```python
# Future: DuckDB relation adapter (Phase 3+)
rel = duckdb.sql("SELECT * FROM 'logs/*.parquet'")
st.dataframe(rel)
```
--------------------------------
### st.image with alt parameter examples
Source: https://github.com/streamlit/streamlit/blob/develop/specs/2026-09-14-element-alt-text/product-spec.md
Shows usage of alt for st.image with various argument types: string, list of strings, and list with None. Includes decorative alt="" and caption/alt distinction. Use for images where alt text is required for accessibility.
```python
st.image("sunrise.jpg", alt="Sunrise over a mountain ridge")
st.image("divider.svg", alt="") # decorative — st.image / st.pyplot only
# caption is visible context; alt describes the visual. Never the same string.
st.image(
"chart.png",
caption="Figure 1: Monthly active users, 2024",
alt="Line chart of monthly active users rising from 12k in January to 48k in December",
)
# exactly one alt per image, as with caption; use None to skip one on purpose
st.image(["cat.png", "dog.png"], alt=["Orange tabby on a windowsill", "Black labrador"])
st.image(["logo.png", "chart.png"], alt=[None, "Revenue by quarter, up 12%"])
```
--------------------------------
### Tree structure with multiple fragments and main script
Source: https://github.com/streamlit/streamlit/blob/develop/specs/2026-06-03-outside-container-writes/tech-spec.md
Shows the resulting element tree when two fragments write to an outside container. Each fragment gets a stable wrapper slot between main-script elements, and the wrapper's internal cursor resets on rerun.
```text
outside_container
├── "Header" (main script, index 0)
├── [fragment_a_wrapper] (index 1, stable across reruns)
│ ├── button
│ └── text
├── [fragment_b_wrapper] (index 2, stable across reruns)
│ └── chart
└── "Footer" (main script, index 3)
```
--------------------------------
### Option 1: st.image with alt parameter
Source: https://github.com/streamlit/streamlit/blob/develop/specs/2026-09-14-element-alt-text/product-spec.md
Preferred option. Uses the short, familiar term 'alt' as the parameter name, matching HTML, React, and markdown conventions. The example shows how to provide alternative text for an image.
```python
st.image("chart.png", alt="Line chart of monthly revenue")
```
--------------------------------
### Gallery of cards with badges and link buttons
Source: https://github.com/streamlit/streamlit/wiki/pull-requests/16613/alternative-opus-spec/product-spec
Example showing a model registry gallery: creates three columns, each with a card containing badges, a summary, and a link button. Uses height="stretch" and horizontal container for badges.
```python
import streamlit as st
st.title("Model registry")
for column, model in zip(st.columns(3), models):
with column.card(model.name, model.preview_url, height="stretch"):
with st.container(horizontal=True):
st.badge(model.task, icon=":material/category:")
st.badge(model.license)
st.write(model.summary)
st.link_button("Open", model.url, width="stretch")
```
--------------------------------
### Enable Corepack for yarn
Source: https://github.com/streamlit/streamlit/blob/develop/CONTRIBUTING.md
Enable Corepack, which manages package managers like yarn. May require `brew install corepack` depending on how Node was installed.
```bash
corepack enable
```
--------------------------------
### Bad PR description example
Source: https://github.com/streamlit/streamlit/blob/develop/wiki/pull-requests.md
Example of a bad PR description that lists obvious changes, which should be omitted. Most of these are obvious from the code; only the parameter addition and deprecation are impactful/non-obvious.
```markdown
> - Added `height` parameter to signature
> - Updated layout config dataclass
> - Added validation for height values
> - Added unit tests
> - Updated type hints
```
--------------------------------
### Option 2: st.image with alt_text parameter
Source: https://github.com/streamlit/streamlit/blob/develop/specs/2026-09-14-element-alt-text/product-spec.md
Alternative option using the more explicit 'alt_text' name. This is longer and somewhat redundant, but is more explicit for authors unfamiliar with HTML. The example shows the same image with the alternative text parameter named 'alt_text'.
```python
st.image("chart.png", alt_text="Line chart of monthly revenue")
```
--------------------------------
### RST code-block example for docstring
Source: https://github.com/streamlit/streamlit/blob/develop/lib/streamlit/AGENTS.md
Shows the RST directive for a Python code block in a docstring example. Use this to present executable code with a filename label.
```rst
.. code-block:: python
:filename: streamlit_app.py
import streamlit as st
```
--------------------------------
### Test 1 - App.__init__ assigns config._main_script_path
Source: https://github.com/streamlit/streamlit/wiki/pull-requests/15218/implementation-plan
Two tests verifying that App.__init__ sets config._main_script_path when unset, and does not overwrite it when already set (e.g., by `streamlit run`). The first test creates a script in a temp directory and asserts the path is set to the resolved script path. The second test pre-sets the path to a CLI entry script and ensures it remains unchanged.
```python
def test_init_sets_main_script_path_when_unset(
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
"""App.__init__ should set config._main_script_path so script-level
config.toml is discoverable under direct uvicorn launches."""
from streamlit import config
monkeypatch.setattr(config, "_main_script_path", None)
script = tmp_path / "app.py"
script.write_text("import streamlit as st\n")
monkeypatch.chdir(tmp_path)
App("app.py")
assert config._main_script_path == str(script.resolve())
```
```python
def test_init_does_not_overwrite_main_script_path_when_set(
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
"""App.__init__ must not clobber a value already set by `streamlit run`."""
from streamlit import config
cli_script = tmp_path / "cli_entry.py"
cli_script.touch()
monkeypatch.setattr(config, "_main_script_path", str(cli_script))
App("dashboard/app.py")
assert config._main_script_path == str(cli_script)
```
--------------------------------
### Install uv with curl
Source: https://github.com/streamlit/streamlit/blob/develop/CONTRIBUTING.md
Installs uv, the Python dependency and virtual environment manager used by Streamlit. Requires a uv version allowed by `[tool.uv].required-version` in `pyproject.toml`.
```bash
curl -LsSf https://astral.sh/uv/install.sh | sh
```
--------------------------------
### E2E: Example usage of icon parameter
Source: https://github.com/streamlit/streamlit/wiki/pull-requests/16418/implementation-plan
Example usage of the icon parameter in st_heading.py for E2E tests, covering material icon, emoji, and material icon with divider.
```python
st.title("Title with icon param", icon=":material/star:")
st.header("Header with emoji icon", icon="🚀", divider="blue")
st.subheader("Subheader with icon", icon=":material/bolt:")
```
--------------------------------
### QW-1: Configure primaryForegroundColor, primaryHoverColor, primaryActiveColor
Source: https://github.com/streamlit/streamlit/wiki/references/2026-08-11-theming-gaps-and-recommendations
TOML configuration to fix on-primary foreground contrast issues. Sets text/icon color on primary surfaces and optional explicit hover/active background colors.
```toml
primaryForegroundColor = "#111827" # text/icon color on primary surfaces
primaryHoverColor = "#EAB308" # optional explicit hover bg
primaryActiveColor = "#CA8A04" # optional explicit active bg
```
--------------------------------
### Add parallel worker check to switch_page in execution_control.py
Source: https://github.com/streamlit/streamlit/blob/develop/specs/2026-03-05-parallel-fragments/tech-spec.md
Adds a call to _check_not_parallel_worker("st.switch_page") at the start of switch_page to prevent page navigation during parallel fragment execution, while allowing it during sequential reruns.
```python
def switch_page(page: str | Path | Page, ...) -> NoReturn:
ctx = get_script_run_ctx()
if ctx:
_check_not_parallel_worker("st.switch_page")
# ... existing implementation
```
--------------------------------
### Snowpark DataFrame example
Source: https://github.com/streamlit/streamlit/blob/develop/specs/2026-05-07-dataframe-lazy-load/product-spec.md
Example of passing a Snowpark DataFrame to `st.dataframe` for auto-lazy rendering. Requires a native lazy adapter with known row count and stable range access.
```python
from snowflake.snowpark.functions import col
orders = session.table("orders").filter(col("status") == "OPEN")
st.dataframe(orders)
```
--------------------------------
### Format frontend code with make frontend-format
Source: https://github.com/streamlit/streamlit/blob/develop/CONTRIBUTING.md
Formats JavaScript/TypeScript code using oxfmt.
```bash
make frontend-format
```
--------------------------------
### Run load tests and compare metrics
Source: https://github.com/streamlit/streamlit/wiki/pull-requests/14553/starlette-optimization-plan-opus
Use the existing load test infrastructure to benchmark optimizations. Run either the e2e test or the load test with a specific scenario and session count, then compare the listed key metrics against the Tornado baseline.
```bash
# Run load test for specific scenario:
make run-e2e-test st_command_test.py # or
cd e2e_playwright/load_testing && uv run pytest test_load.py -k simple_app --num-sessions=80
# Compare key metrics:
# - memory_rss_mb_peak
# - memory_rss_mb_avg
# - initial_load_time_ms.p50
# - initial_load_time_ms.p95
# - rerun_time_ms.p50
# - rerun_time_ms.p99
# - thread_count_max
```
--------------------------------
### st.paginator wrapper example
Source: https://github.com/streamlit/streamlit/blob/develop/specs/2026-03-22-st-pagination/product-spec.md
Example usage of the proposed `st.paginator` wrapper that iterates over paginated items. This approach handles slicing automatically but is less flexible and only works with iterable data.
```python
for item in st.paginator(orig_list, group_every=5, start_at_page=3):
st.write(item)
```
--------------------------------
### Polars lazy dataframe example
Source: https://github.com/streamlit/streamlit/blob/develop/specs/2026-05-07-dataframe-lazy-load/product-spec.md
Example of passing a Polars LazyFrame to `st.dataframe` for auto-lazy rendering. Requires a native lazy adapter with known row count and stable range access.
```python
import polars as pl
import streamlit as st
events = pl.scan_parquet("s3://bucket/events/*.parquet")
st.dataframe(events)
```
--------------------------------
### Run autofix and check
Source: https://github.com/streamlit/streamlit/wiki/pull-requests/16662/implementation-plan
Commands to run the autofix and check steps for the project. This is part of the final implementation step.
```bash
make autofix
make check
```
--------------------------------
### Example 3: Contains matching
Source: https://github.com/streamlit/streamlit/blob/develop/specs/2026-03-25-selectbox-filter-mode/product-spec.md
Uses filter_mode="contains" in st.selectbox to perform case-insensitive substring matching. Typing "example" shows all @example.com addresses.
```python
import streamlit as st
# Search anywhere in the string
emails = ["alice@example.com", "bob@company.com", "carol@example.com"]
selected = st.selectbox(
"Select email",
emails,
filter_mode="contains",
)
# Typing "example" shows all @example.com addresses
```
--------------------------------
### Verification Commands from frontend/
Source: https://github.com/streamlit/streamlit/wiki/references/2026-09-03-improving-frontend-linting
Run these commands from the frontend/ directory. The fast gate (yarn oxlint) must stay green in every PR. Full lint includes oxlint and per-workspace eslint with --max-warnings 0. Targeted tests are for files you touched. The optional command prints which testing-library rules are active.
```bash
# Fast gate (must stay green in every PR)
yarn oxlint
# Full lint (oxlint + per-workspace eslint --max-warnings 0)
yarn lint
# Targeted tests for files you touched
yarn test lib/src/components/path/Component.test.tsx
# Optional: print which testing-library rules are actually active
yarn exec eslint --print-config lib/src/components/widgets/Button/Button.test.tsx | less
```
--------------------------------
### Responsive gallery with st.grid("auto")
Source: https://github.com/streamlit/streamlit/wiki/pull-requests/15185/product-spec
Creates a responsive gallery using `st.grid("auto", min_column_width=72, gap="xsmall")`. The grid creates as many columns as fit with no explicit max, useful for galleries.
```python
import streamlit as st
items = ["Apple", "Lemon", "Grape", "Kiwi", "Peach", "Cherry", "Coconut", "Pineapple"]
with st.grid("auto", min_column_width=72, gap="xsmall"):
for item in items:
st.button(item, key=f"item-{item}", width="stretch")
```
--------------------------------
### Run targeted verification tests and documentation command
Source: https://github.com/streamlit/streamlit/wiki/pull-requests/17016/implementation-plan
Use this command sequence to verify the implementation. It runs specific tests for errors, session state, element policies, and metrics, then builds the docs for the session state page, followed by 'make check'.
```bash
uv run pytest \
lib/tests/streamlit/errors_test.py \
lib/tests/streamlit/runtime/state/session_state_test.py \
lib/tests/streamlit/elements/element_policies_test.py \
lib/tests/streamlit/runtime/metrics_util_test.py
uv run streamlit docs st.session_state
make check
```
--------------------------------
### Static data inside function (bad example)
Source: https://github.com/streamlit/streamlit/blob/develop/frontend/AGENTS.md
Avoid recreating static data on every call. This example shows the anti-pattern of defining a map inside a function, which wastes memory and CPU.
```tsx
// ❌ Recreated every call
function getAlignment(config: AlignmentConfig) {
const alignmentMap = {
/* same data */
}
return alignmentMap[config.alignment]
}
```
--------------------------------
### Enable static file serving in config.toml
Source: https://github.com/streamlit/streamlit/blob/develop/specs/2026-03-13-st-iframe/product-spec.md
Configuration to enable static file serving, allowing relative URLs like /app/static/... to serve files from the ./static directory.
```toml
[server]
enableStaticServing = true
```
--------------------------------
### Module-level static data structure (good example)
Source: https://github.com/streamlit/streamlit/blob/develop/frontend/AGENTS.md
Define static lookup maps at module level to avoid recreation on every call. This example shows the recommended approach with a constant ALIGNMENT_MAP.
```tsx
// ✅ Module-level - created once
const ALIGNMENT_MAP: Record = {
[Alignment.LEFT]: "left",
[Alignment.CENTER]: "center",
// ...
} as const
function getAlignment(config: AlignmentConfig) {
return ALIGNMENT_MAP[config.alignment]
}
```
--------------------------------
### Example configurations for auth.logout_params
Source: https://github.com/streamlit/streamlit/wiki/pull-requests/16297/implementation-plan
Examples of configuring logout_params in secrets.toml for AWS Cognito, MS Entra, and custom providers. These configurations demonstrate how to rename parameters, drop defaults, and inject user claims.
```toml
# AWS Cognito (rename post_logout_redirect_uri -> redirect_uri, drop id_token_hint)
[auth]
logout_params = { redirect_uri = "{post_logout_redirect_uri}", post_logout_redirect_uri = "", id_token_hint = "" }
# MS Entra (experimental)
[auth]
logout_params = { logout_hint = "{email}" }
# Custom provider
[auth]
logout_params = { returnTo = "{post_logout_redirect_uri}", post_logout_redirect_uri = "", id_token_hint = "", audience = "{sub}", federated = "true" }
```