Blog

Streamlit vs. a Shareable Dashboard: When You Don't Need an App

January 1, 1970

streamlitpythondashboardsinternal-tools

Streamlit solved a real problem: turning a Python script into a usable web app without writing frontend code. For internal tools with genuine interactivity — parameters someone adjusts, models someone reruns, workflows someone steps through — it's a good, fast answer.

The pattern worth questioning is reaching for it by default, for things that aren't actually apps.

The tell: what are people doing with it?

A useful test — watch how people actually use the Streamlit dashboards your team has shipped. If the honest answer is "they change a date filter and look at the same three charts," that's not app usage. That's report usage wearing an app's clothes.

import streamlit as st
import pandas as pd

st.title("Quarterly Revenue")
region = st.selectbox("Region", ["All", "North", "South", "East", "West"])
quarter = st.select_slider("Quarter", options=["Q1", "Q2", "Q3", "Q4"])

df = load_data()
filtered = df[df.region == region] if region != "All" else df
st.line_chart(filtered.set_index("quarter").revenue)

This is a complete, working app. It's also, functionally, four fixed views (one per region) with a filter bolted on top to make them look like one flexible thing. Nothing here needs a running Python process behind it.

What an app costs you that a document doesn't

Every Streamlit app needs somewhere to run. That means hosting, a process that needs to stay alive, cold-start latency if it spins down, and — the part that actually causes friction — someone eventually has to maintain that infrastructure. For genuinely interactive tools, that's a fair trade. For something that's really just "here are the numbers, filtered a few predictable ways," it's overhead with no corresponding benefit.

The alternative: pre-compute the views, not the app

If the actual usage pattern is "look at this data, sliced a few known ways," the filters can often be replaced with the finished views themselves — no server, no process to keep alive, nothing to maintain beyond the query.

-- one query, faceted by region — computed once,
-- not re-run per filter click on a live server
select region, quarter, sum(revenue) as revenue
from quarterly_revenue
group by region, quarter
# a Pyodide node rendering the faceted view directly —
# runs client-side against a cached query result, no backend process
import plotly.express as px

df = infig.query("quarterly_revenue_by_region")
px.line(df, x="quarter", y="revenue", facet_col="region")

The result looks similar to the Streamlit version at a glance — same chart, same slices of data — but it's a static published page rather than a running app. There's no server to keep alive, and because it's backed by a query object with a defined cache policy rather than a live re-execution on every click, it costs nothing to leave published indefinitely.

When Streamlit is still the right call

None of this is an argument against Streamlit for what it's actually good at — parameter sweeps, model exploration, anything where the interaction genuinely changes the computation, not just the view. The distinction worth making before reaching for it: is this an app, or is it a report that a few filter dropdowns made look like one?


Related: How to Embed a Live Chart in Notion, a Blog, or Docs

Continue the workflow

Explore related guides

Next step

Move from insight to a stakeholder-ready story.

Infigure helps teams replace the export-to-slides loop with one connected reporting workflow for analysis, narrative, and delivery.