Declarative, typed composition for Streamlit. Build UI as Python data (@component functions return element trees); the renderer maps them to st.* on each rerun. No separate frontend build.
Documentation (primary): streamtree.readthedocs.io — getting started, recipes, full example source, guides, API reference, and changelog.
| Without StreamTree | With StreamTree |
|---|---|
| Long imperative scripts | @component + layouts/widgets as a tree |
Ad hoc session_state keys |
state() scoped to the render path |
| Hard to test structure | streamtree.testing.render_to_tree() and summarize_tree_kinds() |
Includes: layouts (Page, VStack, Form, Routes, …), optional [tables] / [charts] / [ui] / [auth], streamtree.asyncio task helpers, multipage discovery in streamtree.helpers.pages, optional [cli] (streamtree run, doctor, init, tree, …). Details, version notes, and extras matrix live in the docs.
Python 3.10+, Streamlit ≥ 1.33, Pydantic v2 (see pyproject.toml).
pip install streamtree
pip install "streamtree[cli]" # Typer + streamtree run / doctor / init / tree
# Optional: [tables] [charts] [ui] [auth] — see Dependency strategy on RTDFrom a clone (contributors):
git clone https://github.com/streamtree-dev/streamtree.git
cd streamtree
uv sync --extra devfrom streamtree import component, render
from streamtree.elements import Button, Card, Page, Text
from streamtree.state import state
@component
def Counter():
count = state(0)
return Card(
Text(f"Count: {count()}"),
Button("Increment", on_click=lambda: count.increment(1)),
Button("Reset", on_click=lambda: count.set(0)),
)
if __name__ == "__main__":
render(Page(Counter()))streamlit run examples/counter.py
# with [cli]: streamtree run examples/counter.pyMore patterns (interop with raw st.*, App / theme, async, routing, multipage, CRUD) are in the recipes and examples sections on Read the Docs.
| Start here | Read the Docs |
|---|---|
| Install & mental model | Getting started |
| How-to cookbook | Recipes |
Every examples/*.py inlined |
Examples (full source) |
Testing & AppTest |
Testing & debugging |
| Plan, roadmap, deps, performance, phases | Guides (use the site nav: Design & roadmap / Operations) |
| Release history | Changelog |
Design files remain in docs/ in the repo; the site above is the supported reading path for stable releases.
uv sync --extra dev
uv run ruff format --check .
uv run ruff check src tests
uv run ty check src
uv run pytest
uv run python -m mkdocs build --strict
uv buildSame checks with pip: pip install -e ".[dev]", then the same ruff, ty, pytest, mkdocs build --strict, and uv build (or python -m build). Coverage is enforced at 100% on src/streamtree (see pyproject.toml). GitHub Actions live under .github/workflows/ (ci.yml, release.yml, and reusable-*.yml); you can re-run CI manually via Actions → CI → Run workflow.
Before tagging v*.*.*: align pyproject.toml version, CHANGELOG.md, and package metadata (see tests/test_package_meta.py). CI and the release workflow run lint, typecheck, tests, MkDocs, and uv build; publishing needs a valid PyPI token or trusted publishing setup (details in workflow comments and PyPI docs).
No stable cross-rerun APIs for arbitrary widget focus or DOM control. Prefer session_state, query params (streamtree.routing, …), st.rerun, and key= discipline. Portal / PortalMount move subtrees within a script; they do not replace Streamlit’s execution model. See Portals & prefetch on RTD.
MIT — LICENSE.