Convert a Streamlit app to a marimo notebook
Streamlit to Marimo is a code-conversion skill that maps a Streamlit application to an equivalent marimo notebook. It focuses specifically on translating Streamlit concepts to their marimo counterparts, deferring general marimo conventions (cell structure, PEP 723 metadata, output rendering, variable naming) to the companion marimo-notebook skill. It solves the problem of porting apps between two Python app frameworks with fundamentally different execution models, without losing widgets, layout, or state behavior.
The workflow reads the Streamlit app, creates a new marimo notebook (without overwriting the original) carrying over dependencies but replacing streamlit with marimo, maps components using extensive reference tables, handles conceptual differences, and validates the result by running `uvx marimo check`. The reference tables cover input widgets (sliders, text, checkboxes, file uploaders, buttons, forms), display elements (markdown, dataframes, metrics, media), charts (Plotly, Altair, matplotlib), and layout (sidebar, columns, tabs, expanders, progress, spinner). It explains the key conceptual shift from Streamlit's full top-to-bottom rerun to marimo's reactive cell DAG where only dependent cells re-execute, along with state management (session_state to plain variables, callbacks to reactive cells), caching (@st.cache_data to @mo.cache, @st.cache_resource to @mo.persistent_cache), multi-page approaches, deployment via molab, and the incompatibility of Streamlit custom components. Conversion is local and read-only against the source; it writes a new notebook file.
The target users are Python developers and data-app authors migrating existing Streamlit apps to marimo. Use cases include one-off app migrations, learning the marimo equivalents of familiar Streamlit APIs, and modernizing dashboards to a reactive notebook model.
It maps a Streamlit app to an equivalent marimo notebook, translating widgets, display elements, charts, layout, state, and caching. General marimo conventions are handled by the separate marimo-notebook skill it references.
No. It explicitly creates a new marimo notebook and instructs not to overwrite the original file, carrying over the app's dependencies but replacing streamlit with marimo.
Execution model. Streamlit reruns the whole script top-to-bottom on every interaction, while marimo uses a reactive cell DAG where only cells depending on changed variables re-run — so st.rerun() and st.stop() are no longer needed.
@st.cache_data maps to @mo.cache (marimo-aware, argument-based) and @st.cache_resource maps to @mo.persistent_cache, which persists results to disk across sessions for expensive computations.
Streamlit custom components are not compatible with marimo; an equivalent anywidget may be possible via the marimo-anywidget skill, but the guidance is to discuss that with the user first. Conversion results are validated with uvx marimo check.
Quick Setup:
.claude/skills/Repository
marimo-team/skills