Streamlit is an open-source (Apache 2.0) Python library for creating interactive web applications and dashboards with focus on data apps and internal tools.
- Backend (Server): Python, Starlette/Uvicorn server, pytest
- Frontend (Web UI): TypeScript, React, Emotion (CSS-in-JS), Vite, Vitest
- Communication: Protocol Buffers (protobuf) over WebSocket.
lib/: All backend code and assets.streamlit/: The main Streamlit library package.streamlit/elements/: Backend code of elements and widgets.streamlit/runtime/: App runtime and execution logic.streamlit/web/: Web server and CLI implementationtests: Python unit tests (pytest).
frontend/: All frontend code and assets.app/: Streamlit application UI.lib/: Shared TypeScript library that contains elements, widgets, and layouts.connection/: WebSocket connection handling logic.utils/: Shared utilities.component-lib/: Library for building Streamlit custom components v1.component-v2-lib/: Library for building Streamlit custom components v2.
proto/streamlit/proto/: Protobuf definitions for client-server communication.e2e_playwright/: E2E tests using playwright (via pytest).scripts/: Utility scripts for development and CI/CD.specs/: Product and tech specs for Streamlit features..github/workflows/: GitHub Actions workflows used for CI/CD.wiki/: Documentation relevant for development of Streamlit.
- Prefer
maketargets for all dev tasks (tests, lint, format, builds). - Always use
uv runto run any Python command (e.g.uv run streamlit,uv run pytest,uv run ruff,uv run mypy, etc.). - Always use
uv runfor git commands that trigger hooks (e.g.uv run git commit,uv run git push). Pre-commit hooks require the uv environment to run linters and formatters. - The committed root
uv.lockis the source of truth for normal development and CI. Do not hand-edit it. - For Python dependency changes, edit the relevant
pyproject.toml, runuv lock, and commit both files. Also runuv lockafter changing the package name or version. Useuv lock --upgrade-package <package>for a targeted upgrade,uv lock --upgradefor a full compatible upgrade, anduv lock --checkto verify consistency. - The dev/CI
[dependency-groups]in the rootpyproject.tomluse bare package names becauseuv.lockowns the versions: do not add lower-bound floors, reserve exact==pins for tools we deliberately hold back, and add upper caps (<) only for versions known to break us (mirrored byignoreentries in.github/dependabot.yml); a!=exclusion of a single known-broken release needs noignoreentry. This does NOT apply tolib/pyproject.toml, whose version ranges are the published package's contract with users. See the comment above[dependency-groups]in the rootpyproject.tomlfor details. - If
uv.lockconflicts during a merge, restore it withgit checkout origin/develop -- uv.lock, then runuv lock; never hand-merge it. - For Python unit tests:
uv run pytestcommands are allowed and encouraged for running specific tests during development. - For E2E tests:
uv run pytestcommands targetinge2e_playwright/files are blocked by policy. Usemake run-e2e-test <filename>instead.
Selection of make commands for development (run in the repo root):
help: Show all available make commands. [~1s]check: Run all checks (format, lint, types, unit tests) on changed files only. AddE2E_CHECK=trueto include E2E tests. [varies by changes]protobuf: Recompile Protobufs for Python and the frontend. [~5s]autofix: Autofix linting and formatting errors. [~30s]
Backend Development (Python):
python-init: Install the locked Python environment selected byPYTHON_DEPENDENCY_GROUP(devby default).python-lint: Lint and check formatting of Python files (ruff). [~1s]python-tests: Run all Python unit tests (pytest). [~3min]python-types: Run the Python type checker (mypy & ty). [~30s]python-format: Format Python files (ruff). [~1s]
Frontend Development (TypeScript):
frontend-fast: Build the frontend (vite). [~40s]frontend-dev: Start the frontend development server (hot-reload). [until stopped]frontend-lint: Lint and check formatting of all frontend files (oxlint + eslint). [~45s]frontend-knip: Run Knip unused-export and unused-dependency analysis. [~5s]frontend-types: Run the TypeScript type checker on all files (tsc). [~15s]frontend-format: Format all frontend files (oxfmt). [~2s]frontend-tests: Run all frontend unit tests (vitest). [~5min]
E2E Testing (Playwright):
run-e2e-test: Run e2e test, via:make run-e2e-test st_command_test.py. [varies by test]
Debugging backend & frontend:
debug: Start Streamlit backend and Vite dev server together, via:make debug my_app.py. [until stopped]- Frontend hot-reload: Changes to frontend code (
frontend/) are applied within seconds. - Backend hot-reload: Only changes to the app script trigger a rerun. Changes to the Streamlit library itself (
lib/streamlit/) require restartingmake debug. - Logs are written to a per-session directory under
work-tmp/debug/(e.g.work-tmp/debug/<session>/backend.logandwork-tmp/debug/<session>/frontend.log). work-tmp/debug/latest/is a symlink to the most recent debug session (e.g.work-tmp/debug/latest/backend.log). If multiple sessions are running simultaneously, this symlink can move—prefer using the session directory printed bymake debug.- Log files are cleared at the start of each session and persist after exit for post-mortem analysis.
- Browser
console.log()output appears in the session’sfrontend.log. - See .claude/skills/debugging-streamlit/SKILL.md for the full debugging guide.
- Frontend hot-reload: Changes to frontend code (
- Follow existing patterns: Check neighboring files for conventions.
- Keep fixes proportionate: Before handling an edge case, weigh how likely real apps are to hit it and how bad the failure would be against the complexity the fix adds. Rare or theoretical cases seldom justify new state, abstractions, parameters, or long special-case branches. Often the better trade-off is a clear error, a short doc note, or leaving the code as is. Security issues and data loss still need a real fix. This applies to review feedback too: a reviewer, human or bot, flagging an edge case does not by itself justify a complex fix.
- Comments must describe current behavior or why the code exists. Do not describe a previous state of the code or rely on change history.
- Subagent model: When launching subagents, use the same model as the parent session (
model: inherit/ omit any model override). Do not switch to a different or faster model unless the user explicitly requests it. Prefer the named custom agents in.claude/agents/when available. - You can use the
work-tmpdirectory to store temporary files, specs, and scripts. - Use
agent-wiki/(gitignored, cloned on first use) to share intermediate files (specs, plans, learnings) relevant for the current PR. This is a local checkout of streamlit.wiki. Files are stored inpull-requests/<pr-number>/and accessible athttps://issues.streamlit.app/agent_wiki_explorer?file=<relative-path>. Seesharing-pr-agent-artifactsskill. - If you fail to run a
makecommand, remember to run it from the root / top-level directory. - Use
make debug <script.py>to start both backend and frontend with hot-reload for debugging. The app URL will be printed on startup (defaulthttp://localhost:3001;3000is reserved for manualmake frontend-dev; it may use3002+if you have other sessions running). Avoid pinningVITE_PORTunless you have a specific hard requirement (last resort). - Run
make checkafter completing changes to run formatting, linting, type checking, and unit tests on all uncommitted files. - The main branch of this repository is
develop. - For adding new elements, widgets, or features that span backend, frontend, and protobufs, see
wiki/new-feature-guide.md.
- Most new user-facing features should be covered by both unit tests and E2E tests.
- Python Unit Tests: Test internal behavior without frontend. Located at
lib/tests/streamlit/<package>/<module>_test.pymirroringlib/streamlit/<package>/<module>.py(legacy tests may vary). - Frontend Unit Tests: Test React components, hooks, and related functionality with Vitest and React Testing Library. Co-located as
<Component>.test.tsxnext to<Component>.tsx. - E2E Tests: Test the entire app logic end-to-end with Playwright. Located at
e2e_playwright/<name>_test.pywith app code ine2e_playwright/<name>.py. User-facing features should be covered by E2E tests (e.g., parameters and commands in the publicst.API). - (Python) Type Tests: Verify public API typing with
assert_typeunder both mypy and ty. Located atlib/tests/streamlit/typing/<command>_types.py. Update these for newst.*commands and for new or changed parameters. - AppTest: When a command can be represented as an element or block, support new
st.*commands and new or changed parameters in AppTest (lib/streamlit/testing/v1/). Seelib/streamlit/AGENTS.md. - Prefer running specific tests / test scripts for newly added tests instead the entire test suite.