Python framework comparison · Reviewed August 2026

Mercury vs Streamlit: Notebook-Native Python Apps Compared

Streamlit reruns the whole script after an interaction. Mercury reruns the changed widget’s cell and the cells below it, so model loading, warehouse queries, and other expensive setup above the widget stay put without cache decorators.

Streamlit remains a strong script-first option with a larger ecosystem. This comparison explains when Mercury’s notebook-native workflow saves the rewrite and the extra application structure.

hello.ipynb · Mercury
[1]
import mercury as mr
[2]
name = mr.TextInput(label="What is your name?")
[3]
mr.Markdown(f"## Hello {name.value}! 👋")
hello.py · Streamlit
import streamlit as st name = st.text_input("What is your name?") if name: st.markdown(f"## Hello {name}! 👋")

The short answer

Choose Mercury when notebook cell order should define the recomputation boundary and expensive setup should stay above the controls.

  • Recompute the changed widget’s cell and everything below it.
  • Leave model loading, data access, and setup cells above untouched.
  • Use ordinary variables instead of cache and session-state APIs.
  • Keep the notebook itself as the application artifact.

Quick answer

The rerun boundary is the real difference

Streamlit starts from the top of the script by default and provides caching, Session State, forms, and fragments to control that model. Mercury uses notebook position: the changed widget and downstream cells rerun, while earlier cells remain untouched.

Starting point

Mercury
Your existing Jupyter notebook (.ipynb)
Streamlit
A separate Python application script (.py)

Reuse existing analysis

Mercury
Keep notebook cells, outputs, and narrative in place
Streamlit
Move the relevant logic into the app script

Application structure

Mercury
Notebook cells plus inline reactive widgets
Streamlit
A script organized around Streamlit commands and state

On interaction

Mercury
Re-runs cells below the changed widget
Streamlit
Re-runs the whole script by default; fragments can rerun independently

Avoiding expensive recompute

Mercury
Place setup cells above the widget
Streamlit
Use @st.cache_data, @st.cache_resource, or a fragment

State management

Mercury
Ordinary notebook variables above the widget
Streamlit
st.session_state, a dict-like per-session API

Callbacks

Mercury
None offered or needed
Streamlit
Optional on_change and on_click callbacks

Notebook preview

Mercury
Live preview in JupyterLab and MLJAR Studio
Streamlit
Run the separate Streamlit application during development

Customization

Mercury
Ready-made styles plus configurable colors, typography, navigation, widgets, and app chrome
Streamlit
Theme configuration plus custom CSS and third-party components

Chat and streaming

Mercury
Chat, ChatInput, Message, and append_markdown()
Streamlit
st.chat_message, st.chat_input, and st.write_stream()

License

Mercury
Apache-2.0
Streamlit
Apache-2.0

Free hosting

Mercury
MLJAR Platform free plan or self-host with Docker
Streamlit
GitHub-linked Streamlit Community Cloud

Managed hosting

Mercury
MLJAR Platform with Studio publishing and file upload
Streamlit
Streamlit in Snowflake for Snowflake workloads

Ecosystem

Mercury
Smaller and growing
Streamlit
Larger community and component ecosystem

The starting point

A notebook or a Python script

For a small form, the code is similarly compact. Mercury keeps the notebook as the application; Streamlit uses a script as its entry point.

hello.ipynb · Mercury
[1]
import mercury as mr
[2]
name = mr.TextInput(label="What is your name?")
[3]
mr.Markdown(f"## Hello {name.value}! 👋")
hello.py · Streamlit
import streamlit as st name = st.text_input("What is your name?") if name: st.markdown(f"## Hello {name}! 👋")

For something this small, both are about equally simple. The difference becomes more visible when data loading, model initialization, or another expensive step happens before the widget.

Mercury customization

Make the notebook app look like your product

Start from a ready-made Mercury style and use config.toml to control colors, typography, surfaces, widgets, navigation, and application details—without maintaining a separate frontend.

Minimal Light style applied to a Mercury dashboard

Minimal Light

A clean, neutral application theme for reports and everyday dashboards.

Editorial Serif style applied to a Mercury dashboard

Editorial Serif

A publication-style theme for research, reports, and narrative analysis.

Dark Ops style applied to a Mercury dashboard

Dark Ops

A high-contrast dark theme for operational dashboards and internal tools.

The notebook remains the source artifact while the published application can match a report, internal product, or company brand.

Explore Mercury styles

Access protection

Put the notebook app behind a login screen

Publish an internal dashboard, report, or tool without exposing the notebook editor. Mercury can require a password before users can open the application.

  • Share private analytical results with authorized users.
  • Keep the Python implementation separate from the application view.
  • Use the same access-protected workflow for dashboards, reports, and internal tools.

Streamlit also supports OIDC authentication through st.login and st.user. Authentication itself is not the architectural difference; Mercury includes password protection in the notebook publishing workflow shown here.

Private Mercury application
Access protected
Mercury login screen protecting a private notebook web application
Viewers authenticate before opening the published notebook application.

One-click deployment

Publish from MLJAR Studio—or upload the files

Streamlit Community Cloud provides a free GitHub-linked deployment workflow. Mercury starts from the notebook instead: publish directly from MLJAR Studio or upload the notebook and its supporting files.

01

Publish from MLJAR Studio

Click Publish from the notebook workflow and send the Mercury application directly to MLJAR Platform.

02

Upload notebook files

Using another editor? Upload the .ipynb file, data files, and requirements.txt to create the web app.

03

Set application access

Share the result publicly or restrict the deployed dashboard, report, or tool behind login.

The real difference

What runs after an interaction?

The same sales filter shows how each framework avoids repeating expensive work in its normal application structure.

dashboard.ipynb · Mercury
[1]
import pandas as pd import altair as alt import mercury as mr df = pd.read_csv("sales.csv")
[2]
region = mr.Select( label="Region", choices=["All", "North", "South"] )
[3]
filtered = ( df if region.value == "All" else df[df["region"] == region.value] ) alt.Chart(filtered).mark_bar().encode( x="month", y="revenue" )

The loading cell is above the Select widget, so changing the selection only runs the cells below it.

dashboard.py · Streamlit
import streamlit as st import pandas as pd @st.cache_data def load_data(): return pd.read_csv("sales.csv") df = load_data() region = st.selectbox( "Region", ["All", "North", "South"] ) filtered = ( df if region == "All" else df[df["region"] == region] ) st.bar_chart(filtered)

In the default full-script flow, @st.cache_data prevents the CSV from being read again after every selection.

Streamlit reruns the full script by default, so the cache decorator prevents the CSV from loading again each time the dropdown changes. Mercury does not need that decorator here: the loading cell sits above the widget, and only downstream cells run again. For notebook authors, Mercury makes the recomputation boundary visible in the cell order without introducing a cache decorator or separate execution unit.

Current Streamlit also supports fragments, which let a function rerun independently of the rest of the app. That gives Streamlit an alternative to a full-app rerun, but it requires you to choose and define the fragment boundary yourself.

State management

Streamlit’s default rerun model starts regular Python variables again, so values that must persist—such as chat history—belong in st.session_state. It is a clear, dict-like API scoped to each user session. In Mercury, a plain variable in a cell above the changed widget remains available because that cell does not rerun.

AI and chat apps

Both support chat natively. Streamlit provides st.chat_message, st.chat_input, and st.write_stream(). Mercury provides Chat, ChatInput,Message, and streaming with .append_markdown(). The capability is comparable; state and execution are handled differently.

Build an AI app in Python

When Streamlit may fit better

Explicit application state and independent interaction regions

Streamlit’s Session State, forms, navigation, and fragments are real architectural advantages when an app is not naturally top-to-bottom. They support multi-step flows, batched input submission, multipage navigation, and isolated reruns without making notebook position carry those responsibilities.

Streamlit also has a larger component ecosystem and pool of examples, plus Community Cloud’s free, GitHub-linked deployment workflow. MLJAR Platform has a free publishing path too; its distinction is accepting the notebook artifact directly from MLJAR Studio or an upload.

Decision guide

Rerun the script, or rerun the cells below

Both re-execute Python when the user interacts, and both can avoid callbacks. The difference is the unit of re-execution. Streamlit reruns the whole script top to bottom, so you protect expensive work with caching and carry values across runs with session state. Mercury reruns the cells below the widget that changed, so anything above it survives without an API.

Choose Mercury if

  • Expensive setup—loading a model, querying a warehouse, or reading a large file—should stay above the controls and simply not run again.
  • The analysis already lives in a notebook and you want the notebook to be the app, not a prototype to port.
  • You would rather use ordinary variables and cell order than st.cache_data, st.cache_resource, and st.session_state.
  • The result reads as a document: narrative, tables, and charts in order, with controls attached.
  • You want widget changes to rerun the downstream notebook while leaving earlier setup cells untouched.
  • The people maintaining the application edit notebooks rather than a Python package.

Choose Streamlit if

  • You are starting from a script, and the app is the deliverable rather than a report.
  • The app needs explicit session state for multi-step flows, wizards, or accumulated input across interactions.
  • You want multipage apps with st.navigation or st.form to batch inputs before anything recomputes.
  • You need st.fragment to rerun one isolated piece of the page independently.
  • You want the component ecosystem—including AgGrid, Folium, and custom React components—and the largest pool of examples.
  • You use Streamlit in Snowflake or want Community Cloud’s free, GitHub-linked deployment workflow.
  • You want st.chat_message and st.write_stream for an LLM interface.

Streamlit’s full-script rerun is the source of both its simplicity and its caching APIs: every interaction produces a clean state, and you opt out of that with decorators where it is too slow. Mercury’s cell-order execution skips that step for the common notebook shape, where setup sits at the top and controls sit below it. When the interaction pattern is not top-to-bottom—a form that should not submit until complete, or a step that depends on what the user did two screens ago—Streamlit’s explicit state model is the better fit.

Compare more Python app frameworks

FAQ

Questions about Mercury and Streamlit

Is Streamlit or Mercury easier to learn?+

Both are simple for a basic app. Streamlit has a larger ecosystem, so it offers more tutorials, community examples, and third-party components. Mercury can feel more direct when the work already lives in a Jupyter notebook.

Can I convert a Streamlit app to Mercury automatically?+

No. There is no automatic migration. You need to rebuild the interface with Mercury widgets, although your pandas, plotting, model, and other ordinary Python logic can usually carry over.

Which is better for AI and chat apps?+

Both have native chat components and support streamed responses. The main difference is architectural: Streamlit usually stores chat history in Session State, while Mercury can keep it in a notebook variable above the input widget.

Can I self-host both for free?+

Yes. Mercury and Streamlit are both Apache-2.0 licensed and free to self-host.

Which has better free managed hosting?+

Both have free managed paths. Streamlit Community Cloud connects directly to GitHub and is especially convenient for public script-based apps. MLJAR Platform provides a free path for publishing Mercury notebooks from MLJAR Studio or uploaded files.

Can I customize the appearance of a Mercury application?+

Yes. Mercury supports ready-made styles and config.toml settings for colors, typography, surfaces, widgets, navigation, and application details. The notebook code can remain unchanged while the application shell is branded.

Can I protect a Mercury application with a login screen?+

Yes. Mercury can restrict access with a password, and private managed applications can be placed behind login. This is useful for internal dashboards, reports, and tools.

How do I deploy a Mercury application?+

In MLJAR Studio, use the integrated Publish action. From another notebook environment, upload the .ipynb file and supporting files to MLJAR Platform. Mercury can also be self-hosted with Docker.

Keep your notebook. Publish it with Mercury.

Add reactive widgets to the analysis you already have, preview it in your notebook environment, and deploy it as a web app.

pip install mercury