Multipage apps with st.navigation

Streamlit · Practical · 12 min

Real apps grow beyond one screen; structured navigation keeps code and UI organized.

The recommended way to build multipage apps is an entrypoint file that defines pages and calls st.navigation:

pg = st.navigation([
    st.Page("pages/dashboard.py", title="Dashboard", icon=":material/dashboard:"),
    st.Page("pages/settings.py", title="Settings"),
])
pg.run()

st.Page accepts a file path or a function, so small pages can live in one file. Pass a dict to group pages into sections: {"Reports": [...], "Admin": [...]}. position="top" puts navigation in a top bar instead of the sidebar. default=True marks the home page, and url_path= sets the page's URL.

The entrypoint runs on every rerun before the page, so it is the place for shared things: st.set_page_config, login checks, common sidebar widgets and building the page list. Because the list is built in code, you can show admin pages only to admins.

Move between pages with st.page_link(page, label=...) (a link) or st.switch_page(page) (programmatic, for example after a form submits).

Session state is shared across pages within a session, so a selection made on one page can be used on another. Widget values themselves are cleaned up when their page is not shown; copy what you need into your own state keys.

The older convention, a pages/ directory next to the main script that Streamlit turns into pages automatically, still works but offers less control.

Example

# streamlit_app.py  (entrypoint)
import streamlit as st

def home():
    st.title("Home")
    st.page_link(settings, label="Go to settings", icon=":material/settings:")

def settings():
    st.title("Settings")
    st.session_state.theme = st.radio("Theme", ["light", "dark"])

def admin():
    st.title("Admin")

home_page = st.Page(home, title="Home", icon=":material/home:", default=True)
settings = st.Page(settings, title="Settings")
pages = {"App": [home_page, settings]}
if st.session_state.get("is_admin"):            # pages can depend on the user
    pages["Admin"] = [st.Page(admin, title="Admin")]

st.set_page_config(page_title="My app")
pg = st.navigation(pages, position="sidebar")
pg.run()

Remember

  • Define pages with st.Page and run the selected one via st.navigation(...).run()
  • The entrypoint runs every rerun: put shared config, auth and widgets there
  • Navigate with st.page_link or st.switch_page; session state is shared across pages

Watch out for

  • Forgetting to call .run() on the page returned by st.navigation, so no page content appears.

Check yourself

  1. Where should a login check that protects every page go in an st.navigation app?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.streamlit.io/develop/concepts/multipage-apps/page-and-navigation