English for Marimo Developers
Vocabulary for developers building reactive Python notebooks with marimo — cell dependencies, reactivity, and app export — for teams discussing reproducible notebooks in English.
marimo is a Python notebook that stores itself as a plain .py file and automatically re-runs any cell affected by a change — no hidden execution order, no stale state left over from a cell you deleted three edits ago. Because it fixes a well-known Jupyter pain point (execution order vs. visual order), review conversations often center on that specific distinction. Here’s the English you need.
Reactivity and Dependency Graph
Reactive execution — marimo’s core behavior: when a variable changes in one cell, every other cell that depends on it automatically re-runs, in dependency order, not visual top-to-bottom order.
“You don’t need to manually re-run the plotting cell — reactive execution already reran it the moment you changed the filter above.”
Dependency graph — the internal structure marimo builds by statically analyzing which variables each cell reads and writes, determining which cells must re-run when a given cell changes.
“marimo caught that unused import because it’s tracked in the dependency graph — Jupyter would have just let it silently sit there.”
Hidden state — the classic Jupyter problem where a notebook’s visible cell order doesn’t match its actual execution history, leaving stale variables from deleted or reordered cells.
“That bug only existed because of hidden state — a variable from a cell you’d already deleted was still lingering in the kernel. marimo’s reactive model makes that class of bug structurally impossible.”
Cells and Variables
Cell — marimo’s unit of code, similar to a Jupyter cell, but with the constraint that a variable can only be defined in one cell across the whole notebook, enforced to keep the dependency graph unambiguous.
“You can’t redefine
dfin a second cell like you would in Jupyter — marimo needs each variable’s definition to be traceable to exactly one place.”
UI element — an interactive widget (mo.ui.slider, mo.ui.dropdown) that, like a normal variable, triggers reactive re-runs of dependent cells whenever its value changes.
“Bind the slider’s value to a variable and let reactive execution handle the redraw — you don’t need a manual callback like you would in a plain script.”
Pure functions between cells — the practice of keeping cross-cell dependencies limited to simple variable reads rather than complex mutable objects, so the dependency graph stays predictable.
“Don’t mutate that dataframe in place across three different cells — split it into pure transformations so the dependency graph actually reflects what’s happening.”
Notebook as Code and Export
Notebook-as-.py-file — marimo’s decision to store notebooks as plain, git-diffable Python files instead of JSON, so version control and code review work the same as for any other Python module.
“We can finally do a real code review on this notebook — the diff is readable Python, not a JSON blob of cell outputs and metadata.”
App export — converting a marimo notebook directly into a standalone, deployable web app (via marimo run) without rewriting it in a separate framework like Streamlit.
“We don’t need to rebuild this as a separate Streamlit app — marimo can export the same notebook directly as a shareable app.”
Common Mistakes
- Saying “the notebook re-ran everything” as a complaint, without recognizing that’s reactive execution correctly propagating a change — often the exact behavior that prevents hidden-state bugs.
- Trying to redefine the same variable name in two different cells out of Jupyter habit, then being confused by marimo’s error instead of restructuring the cells.
- Treating the dependency graph as something the developer must manually manage, when it’s inferred automatically from static analysis of variable reads and writes.
Practice Exercise
- Explain, in two sentences, how marimo’s reactive execution prevents the “hidden state” bug common in traditional Jupyter notebooks.
- Write a short PR description for splitting an in-place dataframe mutation across cells into pure, dependency-graph-friendly transformations.
- Draft a code review comment explaining why a notebook stored as
.pyis easier to review than one stored as.ipynb.