Skip to content

Running cells

marimo reacts to your code changes: run a cell, and all other cells that refer to the variables it defines are automatically run with the latest data. This keeps your code and outputs consistent, and eliminates bugs before they happen.

Why run cells reactively?

marimo's "reactive" execution model makes your notebooks more reproducible by eliminating hidden state and providing a deterministic execution order. It also powers marimo's support for interactive elements, for running as apps, and executing as scripts.

How marimo runs cells is one of the biggest differences between marimo and traditional notebooks like Jupyter. Learn more at our FAQ.

Working with expensive notebooks

marimo provides tools for working with expensive notebooks, in which cells might take a long time to run or have side-effects.

  • The runtime can be configured to be lazy instead of automatic, marking cells as stale instead of running them.
  • Use mo.stop to conditionally stop execution at runtime.

See the expensive notebooks guide for more tips.

How marimo runs cells

marimo statically analyzes each cell (i.e., without running it) to determine its

  • references, the global variables it reads but doesn't define;
  • definitions, the global variables it defines.

It then forms a directed acyclic graph (DAG) on cells, with an edge from one cell to another if the latter references any of the definitions of the former. When a cell is run, its descendants are marked for execution.

Runtime Rule

When a cell is run, marimo automatically runs all other cells that reference any of the global variables it defines.

marimo does not track mutations to variables, nor assignments to attributes. That means that if you assign an attribute like foo.bar = 10, other cells referencing foo.bar will not be run.

Execution order

The order cells are executed in is determined by the relationships between cells and their variables, not by the order of cells on the page (similar to a spreadsheet). This lets you organize your code in whatever way makes the most sense to you. For example, you can put helper functions at the bottom of your notebook.

Deleting a cell deletes its variables

In marimo, deleting a cell deletes its global variables from program memory. Cells that previously referenced these variables are automatically re-run and invalidated (or marked as stale, depending on your runtime configuration). In this way, marimo eliminates a common cause of bugs in traditional notebooks like Jupyter.

Variable mutations are not tracked

marimo does not track mutations to objects, e.g., mutations like my_list.append(42) or my_object.value = 42 don't trigger reactive re-runs of other cells. Avoid defining a variable in one cell and mutating it in another.

Why not track mutations?

Tracking mutations reliably is impossible in Python. Reacting to mutations could result in surprising re-runs of notebook cells.

If you need to mutate a variable (such as adding a new column to a dataframe), you should perform the mutation in the same cell as the one that defines it, or try creating a new variable instead.

Create new variables, don't mutate existing ones
l = [1]
extended_list = l + [2]
l = [1]
l.append(2)
Mutate variables in the cells that define them
df = pd.DataFrame({"my_column": [1, 2]})
df["another_column"] = [3, 4]
df = pd.DataFrame({"my_column": [1, 2]})
df["another_column"] = [3, 4]

Global variable names must be unique

marimo requires that every global variable be defined by only one cell. This lets marimo keep code and outputs consistent.

Global variables

A variable can refer to any Python object. Functions, classes, and imported names are all variables.

This rule encourages you to keep the number of global variables in your program small, which is generally considered good practice.

Creating temporary variables

marimo provides two ways to define temporary variables, which can help keep the number of global variables in your notebook small.

Creating local variables

Variables prefixed with an underscore (e.g., _x) are "local" to a cell: they can't be read by other cells. Multiple cells can reuse the same local variables names.

Encapsulating code in functions

If you want most or all the variables in a cell to be temporary, prefixing each variable with an underscore to make it local may feel inconvenient. In these situations we recommend encapsulating the temporary variables in a function.

For example, if you find yourself copy-pasting the same plotting code across multiple cells and only tweaking a few parameters, try the following pattern:

def _():
    import matplotlib.pyplot as plt
    fig, ax = plt.subplots()
    ax.plot([1, 2])
    return ax

_()

Here, the variables plt, fig, and ax aren't added to the globals.

Configuring how marimo runs cells

Through the notebook settings menu, you can configure how and when marimo runs cells. In particular, you can disable autorun on startup, disable autorun on cell execution, and enable a module autoreloader. Read our runtime configuration guide to learn more.

Disabling cells

Sometimes, you may want to edit one part of a notebook without triggering automatic execution of its dependent cells. For example, the dependent cells may take a long time to execute, and you only want to iterate on the first part of a multi-cell computation.

For cases like this, marimo lets you disable cells: when a cell is disabled, it and its dependents are blocked from running.

Disabling a cell blocks it from running.

When you re-enable a cell, if any of the cell's ancestors ran while it was disabled, marimo will automatically run it.

Enable a cell through the context menu. Stale cells run automatically.