Agent skill
building-streamlit-multipage-apps
Building multi-page Streamlit apps. Use when creating apps with multiple pages, setting up navigation, or managing state across pages.
Install this agent skill to your Project
npx add-skill https://github.com/streamlit/agent-skills/tree/main/developing-with-streamlit/skills/building-streamlit-multipage-apps
SKILL.md
Streamlit multi-page apps
Structure and navigation for apps with multiple pages.
Directory structure
streamlit_app.py # Main entry point
app_pages/
home.py
analytics.py
settings.py
Important: Name your pages directory app_pages/ (not pages/). Using pages/ conflicts with Streamlit's old auto-discovery API and can cause unexpected behavior.
Main module
# streamlit_app.py
import streamlit as st
# Initialize global state (shared across pages)
if "api_client" not in st.session_state:
st.session_state.api_client = init_api_client()
# Define navigation
page = st.navigation([
st.Page("app_pages/home.py", title="Home", icon=":material/home:"),
st.Page("app_pages/analytics.py", title="Analytics", icon=":material/bar_chart:"),
st.Page("app_pages/settings.py", title="Settings", icon=":material/settings:"),
])
# App-level UI runs before page content
# Useful for shared elements like titles
st.title(f"{page.icon} {page.title}")
page.run()
Note: When you handle titles in streamlit_app.py, individual pages should NOT use st.title again.
Navigation position
Few pages (3-7) → Top navigation:
page = st.navigation([...], position="top")
Creates a clean horizontal menu. Great for simple apps. Sections are supported too—they appear as dropdowns in the top nav.
Many pages or nested sections → Sidebar:
page = st.navigation({
"Main": [
st.Page("app_pages/home.py", title="Home"),
st.Page("app_pages/analytics.py", title="Analytics"),
],
"Admin": [
st.Page("app_pages/settings.py", title="Settings"),
st.Page("app_pages/users.py", title="Users"),
],
}, position="sidebar")
Mixed: Some pages ungrouped:
Use an empty string key "" for pages that shouldn't be in a section. These ungrouped pages always appear first, before any named groups. Put all ungrouped pages in a single "" key:
page = st.navigation({
"": [
st.Page("app_pages/home.py", title="Home"),
st.Page("app_pages/about.py", title="About"),
],
"Analytics": [
st.Page("app_pages/dashboard.py", title="Dashboard"),
st.Page("app_pages/reports.py", title="Reports"),
],
}, position="top")
Page modules
# app_pages/analytics.py
import streamlit as st
# Access global state
api = st.session_state.api_client
user = st.session_state.user
# Page-specific content (title is handled in streamlit_app.py)
data = api.fetch_analytics(user.id)
st.line_chart(data)
Global state
Initialize state in the main module only if it's needed across multiple pages:
# streamlit_app.py
st.session_state.api = init_client()
st.session_state.user = get_user()
st.session_state.settings = load_settings()
Tip: Use st.session_state.setdefault("key", default_value) to initialize values only if they don't exist.
Why main module (for global state):
- Runs before every page
- Ensures state is initialized
- Single source of truth
Page-specific state
Use prefixed keys for page-specific state:
# app_pages/analytics.py
if "analytics_date_range" not in st.session_state:
st.session_state.analytics_date_range = default_range()
Share elements between pages
Put shared UI in the entrypoint (before page.run()) so it appears on all pages:
# streamlit_app.py
import streamlit as st
pages = [...]
page = st.navigation(pages)
# Shared title
st.title(f"{page.icon} {page.title}")
# Shared sidebar widgets
with st.sidebar:
st.selectbox("Theme", ["Light", "Dark"])
page.run()
Programmatic navigation
Navigate to another page programmatically:
if st.button("Go to Settings"):
st.switch_page("app_pages/settings.py")
Create navigation links with st.page_link:
st.page_link("app_pages/home.py", label="Home", icon=":material/home:")
st.page_link("https://example.com", label="External", icon=":material/open_in_new:")
Note: Prefer
st.navigationoverst.page_linkfor standard navigation. Do not usest.page_linkto recreate the nav bar you get withst.navigation. Only usest.page_linkwhen linking to pages from somewhere other than the sidebar, or when building a more complex navigation menu.
Conditional pages
Show different pages based on user role, authentication, or any other condition by building the pages list dynamically:
# streamlit_app.py
import streamlit as st
pages = [st.Page("app_pages/home.py", title="Home", icon=":material/home:")]
if st.user.is_logged_in:
pages.append(st.Page("app_pages/dashboard.py", title="Dashboard", icon=":material/bar_chart:"))
if st.session_state.get("is_admin"):
pages.append(st.Page("app_pages/admin.py", title="Admin", icon=":material/settings:"))
page = st.navigation(pages)
page.run()
Common conditions for showing/hiding pages:
st.user.is_logged_infor authenticated usersst.session_stateflags (roles, permissions, feature flags)- Environment variables or secrets
- Time-based access (e.g., beta features)
Imports from pages
When importing from page files in app_pages/, always import from the root directory perspective:
# app_pages/dashboard.py - GOOD
from utils.data import load_sales_data
# app_pages/dashboard.py - BAD (don't use relative imports)
from ..utils.data import load_sales_data
References
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
template-skill
Replace with description of the skill and when to use it.
developing-with-streamlit
**[REQUIRED]** Use for ALL Streamlit tasks: creating, editing, debugging, beautifying, styling, theming, optimizing, or deploying Streamlit applications. Also required for building custom components (inline or packaged), using st.components.v2, or any HTML/JS/CSS component work. Triggers: streamlit, st., dashboard, app.py, beautify, style, CSS, color, background, theme, button, widget styling, custom component, st.components, packaged component, pyproject.toml, asset_dir, CCv2, HTML/JS component.
organizing-streamlit-code
Organizing Streamlit code for maintainability. Use when structuring apps with separate modules and utilities. Covers separation of concerns, keeping UI code clean, and import patterns.
building-streamlit-chat-ui
Building chat interfaces in Streamlit. Use when creating conversational UIs, chatbots, or AI assistants. Covers st.chat_message, st.chat_input, message history, and streaming responses.
displaying-streamlit-data
Displaying charts, dataframes, and metrics in Streamlit. Use when visualizing data, configuring dataframe columns, or adding sparklines to metrics. Covers native charts, Altair, and column configuration.
creating-streamlit-themes
Creating and customizing Streamlit themes. Use when changing app colors, fonts, or appearance, or aligning apps to brand guidelines. Covers config.toml configuration, design principles, and CSS avoidance.
Didn't find tool you were looking for?