organizing-streamlit-code

Organize Streamlit projects into modular structure with app_pages and utils directories.

Updated Mar 7, 2026
One-click install
npx skills add https://github.com/randoneering/nix-flake-mirror --skill organizing-streamlit-code-randoneering
Or copy as Structured Prompt for Agent
Please help me install this Agent Skill.
Skill: organizing-streamlit-code
Source: https://github.com/randoneering/nix-flake-mirror/tree/main/home/programs/opencode/skills/snowflake/developing-with-streamlit/skills/organizing-streamlit-code
Command: npx skills add https://github.com/randoneering/nix-flake-mirror --skill organizing-streamlit-code-randoneering

SYSTEM DOCUMENTATION & REQUIREMENTS

What problem does it solve?

For most simple apps, keep everything in one file—it's cleaner and more straightforward. The app file should read like a normal Python script for data processing, with a few Streamlit commands sprinkled in.

Name the main file streamlit_app.py (Streamlit's default).

When to split

Keep in one file (most apps):

  • Apps under ~1000 lines
  • One-off scripts and prototypes
  • Apps where logic is straightforward

Consider splitting when:

  • Data processing is complex (50+ lines of non-UI code)
  • Multiple pages share logic
  • You want to test business logic separately

If splitting makes sense, here's how to organize it.

Directory structure

my-app/
├── streamlit_app.py      # Main entry point
├── app_pages/            # Page UI modules
│   ├── dashboard.py
│   └── settings.py
└── utils/                # Business logic & helpers
    ├── data.py
    └── api.py

Separating UI from logic

When you do split, keep Streamlit files focused on UI and move complex logic to utility modules:

# streamlit_app.py - UI-focused
import streamlit as st
from utils.data import load_sales_data, compute_metrics

st.title("Sales Dashboard")

start = st.date_input("Start")
end = st.date_input("End")

data = load_sales_data(start, end)
metrics = compute_metrics(data)

st.metric("Revenue", f"${metrics['revenue']:,.0f}")
st.dataframe(data)

Avoid if name == "main"

Streamlit apps run the entire file on each interaction. Don't use the main guard in Streamlit files.

# BAD - don't do this in streamlit_app.py or pages
if __name__ == "__main__":
    main()

# GOOD - just put the code directly
import streamlit as st

st.title("My App")

The main guard is fine in utility modules for quick testing:

# utils/data.py
def load_data(path):
    ...

# Optional: test this module directly with `python utils/data.py`
if __name__ == "__main__":
    print(load_data("test.csv"))

References

Frequently Asked Questions about organizing-streamlit-code

High-intent search queries and answers about installing and using this skill.

FAQPage Schema
When should I split my Streamlit app code into multiple files?

You should split Streamlit app code into multiple files when your app exceeds 1000 lines, has complex data processing logic, shares logic across multiple pages, or requires separate business logic testing.

How do I separate UI from business logic in a Streamlit project?

To separate UI from business logic in a Streamlit project, keep Streamlit files focused on UI components and move complex data processing into utility modules within a dedicated `utils` directory.

What is the best directory structure for a multi-page Streamlit app?

The best directory structure for a multi-page Streamlit app uses `streamlit_app.py` as the root entry point, an `app_pages` directory for UI modules, and a `utils` directory for business logic helpers.

Why does if __name__ == "__main__" not work in Streamlit app files?

The `if __name__ == "__main__"` guard does not work in Streamlit app files because Streamlit runs the entire script on each interaction, so you should place code directly instead of using a main guard.

Can I test business logic separately in a modular Streamlit app?

Yes, you can test business logic separately in a modular Streamlit app by moving data processing functions into utility modules, where the `if __name__ == "__main__"` guard works for direct module testing.

Should I keep my simple Streamlit script in a single file?

Yes, you should keep simple Streamlit scripts under 1000 lines in a single file named `streamlit_app.py`, as it is cleaner, more straightforward, and reads like a normal Python script.