| name | marimo-notebook |
| description | Write a marimo notebook in a Python file in the right format. |
Notes for marimo Notebooks
Running Marimo Notebooks
uv run <notebook.py>
uv run marimo run <notebook.py>
uv run marimo edit <notebook.py>
Script Mode Detection
Use mo.app_meta().mode == "script" to detect CLI vs interactive:
@app.cell
def _(mo):
is_script_mode = mo.app_meta().mode == "script"
return (is_script_mode,)
Key Principle: Keep It Simple
Show all UI elements always. Only change the data source in script mode.
- Sliders, buttons, widgets should always be created and displayed
- In script mode, just use synthetic/default data instead of waiting for user input
- Don't wrap everything in
if not is_script_mode conditionals
- Don't use try/except for normal control flow
Good Pattern
@app.cell
def _(ScatterWidget, mo):
scatter_widget = mo.ui.anywidget(ScatterWidget())
scatter_widget
return (scatter_widget,)
@app.cell
def _(is_script_mode, make_moons, scatter_widget, np, torch):
if is_script_mode:
X, y = make_moons(n_samples=200, noise=0.2)
X_data = torch.tensor(X, dtype=torch.float32)
y_data = torch.tensor(y)
data_error = None
else:
X, y = scatter_widget.widget.data_as_X_y
return X_data, y_data, data_error
@app.cell
def _(mo):
lr_slider = mo.ui.slider(start=0.001, stop=0.1, value=0.01)
lr_slider
return (lr_slider,)
@app.cell
def _(is_script_mode, train_button, lr_slider, run_training, X_data, y_data):
if is_script_mode:
results = run_training(X_data, y_data, lr=lr_slider.value)
else:
if train_button.value:
results = run_training(X_data, y_data, lr=lr_slider.value)
return (results,)
State and Reactivity
Variables between cells define the reactivity of the notebook for 99% of the use-cases out there. No special state management needed. Don't mutate objects across cells (e.g., my_list.append()); create new objects instead. Avoid mo.state() unless you need bidirectional UI sync or accumulated callback state. See STATE.md for details.
Don't Guard Cells with if Statements
Marimo's reactivity means cells only run when their dependencies are ready. Don't add unnecessary guards:
@app.cell
def _(plt, training_results):
if training_results:
fig, ax = plt.subplots()
ax.plot(training_results['losses'])
fig
return
@app.cell
def _(plt, training_results):
fig, ax = plt.subplots()
ax.plot(training_results['losses'])
fig
return
The cell won't run until training_results has a value anyway.
Don't Use try/except for Control Flow
Don't wrap code in try/except blocks unless you're handling a specific, expected exception. Let errors surface naturally.
@app.cell
def _(scatter_widget, np, torch):
try:
X, y = scatter_widget.widget.data_as_X_y
X = np.array(X, dtype=np.float32)
except Exception as e:
return None, None, f"Error: {e}"
@app.cell
def _(scatter_widget, np, torch):
X, y = scatter_widget.widget.data_as_X_y
X = np.array(X, dtype=np.float32)
Only use try/except when:
- You're handling a specific, known exception type
- The exception is expected in normal operation (e.g., file not found)
- You have a meaningful recovery action
Cell Output Rendering
Marimo only renders the final expression of a cell. Indented or conditional expressions won't render:
@app.cell
def _(mo, condition):
if condition:
mo.md("This won't show!")
return
@app.cell
def _(mo, condition):
result = mo.md("Shown!") if condition else mo.md("Also shown!")
result
return
Marimo Variable Naming
Variables in for loops that would conflict across cells need underscore prefix:
for _name, _model in items:
...
PEP 723 Dependencies
Notebooks created via marimo edit --sandbox have these dependencies added to the top of the file automatically but it is a good practice to make sure these exist when creating a notebook too:
marimo check
When working on a notebook it is important to check if the notebook can run. That's why marimo provides a check command that acts as a linter to find common mistakes.
uvx marimo check <notebook.py>
Make sure these are checked before handing a notebook back to the user.
api docs
If the user specifically wants you to use a marimo function, you can locally check the docs via:
uv --with marimo run python -c "import marimo as mo; help(mo.ui.form)"
Additional resources