marimo
Explore data and build apps seamlessly with marimo, a next-generation Python notebook.
marimo is an open-source reactive Python notebook: run a cell or interact with a UI element, and marimo automatically runs dependent cells (or marks them as stale), keeping code and outputs consistent and preventing bugs before they happen. Every marimo notebook is stored as pure Python (Git-friendly), executable as a script, and deployable as an app; while stored as Python, marimo notebooks also have native support for SQL.
Get started instantly with molab, our free online notebook. Or get started locally by installing marimo with your favorite package manager:
install with pipinstall with uvinstall with conda
[](#__codelineno-0-1)pip install marimo && marimo tutorial intro
[](#__codelineno-1-1)uv add marimo && uv run marimo tutorial intro
[](#__codelineno-2-1)conda install -c conda-forge marimo && marimo tutorial intro
Developer experience is core to marimo, with an emphasis on reproducibility, maintainability, composability, and shareability.
Highlights¶
- 🚀 batteries-included: replaces
jupyter,streamlit,jupytext,ipywidgets,papermill, and more - ⚡️ reactive: run a cell, and marimo reactively runs all dependent cells or marks them as stale
- 🖐️ interactive: bind sliders, tables, plots, and more to Python — no callbacks required
- 🐍 git-friendly: stored as
.pyfiles - 🛢️ designed for data: query dataframes, databases, warehouses, and lakehouses with SQL; filter and search dataframes
- 🤖 AI-native: connect agent CLIs like Claude Code to notebooks, or use our editor's built-in AI features
- 🔬 reproducible: no hidden state, deterministic execution, built-in package management
- 🏃 executable: execute as a Python script, parameterized by CLI args
- 🛜 shareable: deploy as an interactive web app or slides, run in the browser via WASM
- 🧩 reusable: import functions and classes from one notebook to another
- 🧪 testable: run pytest on notebooks
- ⌨️ a modern editor: GitHub Copilot, AI assistants, vim keybindings, variable explorer, and more
- 🧑💻 use your favorite editor: run in VS Code or Cursor, or edit in neovim, Zed, or any other text editor
A reactive programming environment¶
marimo guarantees your notebook code, outputs, and program state are consistent. This solves many problems associated with traditional notebooks like Jupyter.
A reactive programming environment. Run a cell and marimo reacts by automatically running the cells that reference its variables, eliminating the error-prone task of manually re-running cells. Delete a cell and marimo scrubs its variables from program memory, eliminating hidden state.
Compatible with expensive notebooks. marimo lets you configure the runtime to be lazy, marking affected cells as stale instead of automatically running them. This gives you guarantees on program state while preventing accidental execution of expensive cells.
Synchronized UI elements. Interact with UI elements like sliders, dropdowns, dataframe transformers, and chat interfaces, and the cells that use them are automatically re-run with their latest values.
Interactive dataframes. Page through, search, filter, and sort millions of rows blazingly fast, no code required.
Generate cells with data-aware AI. Collaborate on marimo notebooks with your favorite agent, such as Claude Code, Codex, or OpenCode, using marimo pair. Or, generate code in the marimo editor with an AI assistant that is highly specialized for working with data, with context about your variables in memory. Customize the system prompt, bring your own API keys, or use local models.
Query data with SQL. Build SQL queries that depend on Python values and execute them against dataframes, databases, lakehouses, CSVs, Google Sheets, or anything else using our built-in SQL engine, which returns the result as a Python dataframe.
Your notebooks are still pure Python, even if they use SQL.
Dynamic markdown. Use markdown parametrized by Python variables to tell dynamic stories that depend on Python data.
Built-in package management. marimo has built-in support for all major package managers, letting you install packages on import. marimo can even serialize package requirements in notebook files, and auto install them in isolated venv sandboxes.
Deterministic execution order. Notebooks are executed in a deterministic order, based on variable references instead of cells' positions on the page. Organize your notebooks to best fit the stories you'd like to tell.
Performant runtime. marimo runs only those cells that need to be run by statically analyzing your code.
Batteries-included. marimo comes with GitHub Copilot, AI assistants, Ruff code formatting, HTML export, fast code completion, a VS Code extension, an interactive dataframe viewer, and many more quality-of-life features.
Quickstart¶
The marimo concepts playlist on our YouTube channel gives an overview of many features.
Installation. In a terminal, run
[](#__codelineno-3-1)pip install marimo # or conda install -c conda-forge marimo [](#__codelineno-3-2)marimo tutorial intro
To install with additional dependencies that unlock SQL cells, AI completion, and more, run
[](#__codelineno-4-1)pip install marimo[recommended]
Create notebooks.
Create or edit notebooks with
Run apps. Run your notebook as a web app. By default, the Python source code is not sent to the browser, so it stays hidden and uneditable:
[](#__codelineno-6-1)marimo run your_notebook.py
Execute as scripts. Execute a notebook as a script at the command line:
Automatically convert Jupyter notebooks. Automatically convert Jupyter notebooks to marimo notebooks with the CLI
[](#__codelineno-8-1)marimo convert your_notebook.ipynb > your_notebook.py
or use our web interface.
Tutorials. List all tutorials:
Share cloud-based notebooks. Use molab, a cloud-based marimo notebook service similar to Google Colab, to create and share notebook links.
Questions?¶
See our FAQ.
Learn more¶
marimo is easy to get started with, with lots of room for power users. For example, here's an embedding visualizer made in marimo (try the notebook live on molab!):
Check out our guides, usage examples, and our gallery to learn more.
Contributing¶
We appreciate all contributions! You don't need to be an expert to help out. Please see CONTRIBUTING.md for more details on how to get started.
Questions? Reach out to us on Discord.
We're building a community. Come hang out with us!
- 🌟 Star us on GitHub
- 💬 Chat with us on Discord
- 📧 Subscribe to our Newsletter
- ☁️ Join our Cloud Waitlist
- ✏️ Start a GitHub Discussion
- 💬 Follow us on Bluesky
- 🐦 Follow us on Twitter
- 🎥 Subscribe on YouTube
- 💬 Follow us on Mastodon
- 🤖 Follow us on Reddit
- 🕴️ Follow us on LinkedIn
A NumFOCUS affiliated project. marimo is a core part of the broader Python ecosystem and is a member of the NumFOCUS community, which includes projects such as NumPy, SciPy, and Matplotlib.
Inspiration ✨¶
marimo is a reinvention of the Python notebook as a reproducible, interactive, and shareable Python program, instead of an error-prone JSON scratchpad.
We believe that the tools we use shape the way we think — better tools, for better minds. With marimo, we hope to provide the Python community with a better programming environment to do research and communicate it; to experiment with code and share it; to learn computational science and teach it.
Our inspiration comes from many places and projects, especially Pluto.jl, ObservableHQ, and Bret Victor's essays. marimo is part of a greater movement toward reactive dataflow programming. From IPyflow, streamlit, TensorFlow, PyTorch, JAX, and React, the ideas of functional, declarative, and reactive programming are transforming a broad range of tools for the better.
Finally, we would like to acknowledge Bennet Meyers and David Chassin for believing in marimo from the very beginning: this work was supported in part by U.S. DOE Office of Critical Minerals and Energy Innovation (CMEI) Integrated Energy Systems Office (IESO), Agreement 34368.
| Guide | Description |
|---|---|
| Installation | Installing marimo |
| Quickstart | Create notebooks, run apps, and more from the marimo command-line |
| Key Concepts | A tour of key features and concepts |
These guides cover marimo's core concepts.
Learn by doing!
Prefer a hands-on learning experience? marimo comes packaged with interactive tutorials that you can launch with marimo tutorial at the command line.
| Guide | Description |
|---|---|
| Running cells | Understanding how marimo runs cells |
| Interactive elements | Using interactive UI elements |
| Visualizing outputs | Creating markdown, plots, and other visual outputs |
| Migrating from Jupyter | Tips for transitioning from Jupyter |
| Expensive notebooks | Tips for working with expensive notebooks |
| Understanding errors | Understanding marimo's constraints on notebook code |
| Lint rules | Comprehensive linting system and rule reference |
| Working with data | Using SQL cells, no-code dataframe, and reactive plots |
| Package management | Inlining dependencies in notebook files and other package management guides |
| Generate with AI | Generate notebooks with AI |
| Editor features | View variables, dataframe schemas, docstrings, and more |
| Using your own editor | Edit notebooks in your own editor and stream changes back to the browser |
| Apps | Running notebooks as apps |
| Scripts | Running notebooks as scripts |
| Reusing functions and classes | Importing functions and classes defined in marimo notebooks |
| Tests | Running unit tests in notebooks |
| Export to other formats | Export notebooks to HTML, PDF, ipynb, scripts, and more |
| Run and share in the cloud with molab | Share cloud-hosted notebooks for free, preview from GitHub, embed in webpages |
| Publish to the web | Publish notebooks to molab, embed in webpages, to/from GitHub, and more |
| Deploy notebook servers or apps | Deploy notebook servers (JupyterHub, Kubernetes) or read-only apps |
| WebAssembly notebooks | Run notebooks entirely in the browser with WebAssembly |
| Configuration | Configure various settings |
| Coming from other tools | Transitioning from Jupyter and other tools |
| Extending marimo | Rich displays of objects, custom UI plugins |
| State management | Advanced: mutable reactive state |
| Best practices | Best practices to help you get the most out of marimo |
| Debugging | Interactive debugging with pdb, debugpy, and AI assistance |
| Troubleshooting | Troubleshooting notebooks |
Get inspired at our gallery!
For inspirational examples, including embedding-driven data labelers, Stanford-scientist authored tutorials, and more, check out our public gallery.
Running cells¶
Visual Outputs¶
Writing markdown¶
Working with data¶
Dataframes¶
marimo is designed for working with dataframes. Here are a few examples; see the dataframes guide for details.
SQL¶
Here are some basic examples, see the SQL guide for more details.
Plots¶
See the plotting guide for a full overview.
Progress bars and status elements¶
Layouts¶
Input elements¶
Basic input elements¶
marimo has a large library of interactive UI elements, which you can use without callbacks — just make sure to assign elements to global variables. See the API reference for a full list, and the interactivity guide for rules governing how UI elements work.
-
🎚️ Slider
-
🧾 Dropdown
-
-
-
☑️ Checkbox
-
📅 Date
-
📁 File
-
-
-
🧑💻 Code editor
-
🔍 Table
-
🎙️ Microphone
-
💬 Chat
-
🔢 Matrix
Composite input elements¶
Composite input elements let you create a single UI element from multiple other UI elements.
- connect interactive inputs like sliders, dropdowns, and tables to Python,
- express yourself with dynamically created markdown,
- layout information with tabs or grids,
- output media like images and audio,
- and more!
| markdown | Write markdown with mo.md |
| inputs | Connect sliders, dropdowns, tables, and more to Python |
| layouts | Customize outputs with accordions, tabs, stacks, and more |
| plotting | Output interactive plots |
| media | Output media like images, audio, PDFs, and plain text |
| diagrams | Flow charts, graphs, statistic cards, and more |
| status | Display progress indicators |
| outputs | Modify cell outputs, redirect console output |
| control_flow | Control how cells execute |
| html | Manipulate HTML objects |
| query_params | Access and set query parameters with mo.query_params |
| cli_args | Access command-line arguments with mo.cli_args |
| caching | Cache expensive computations in memory or on disk |
| state | Synchronize multiple UI elements with mo.state |
| app | Embed notebooks in other notebooks |
| cell | Run cells defined in another notebook |
| watch | Reactively respond to file changes on disk |
| miscellaneous | Miscellaneous utilities |
- marimo tutorial intro
Example usage:
- marimo edit create or edit notebooks
- marimo edit notebook.py create or edit a notebook called notebook.py
- marimo run notebook.py run a notebook as a read-only app
- marimo tutorial --help list tutorials
Usage:
[](#__codelineno-0-1)marimo [OPTIONS] COMMAND [ARGS]...
Options:
| Name | Type | Description | Default |
|---|---|---|---|
--version | boolean | Show the version and exit. | False |
-l, --log-level | choice (DEBUG | INFO | WARN |
-q, --quiet | boolean | Suppress standard out. | False |
-y, --yes | boolean | Automatic yes to prompts, running non-interactively. | False |
-d, --development-mode | boolean | Run in development mode; enables debug logs and server autoreload. | False |
-h, --help | boolean | Show this message and exit. | False |
marimo check¶
Check and format marimo files.
Usage:
[](#__codelineno-1-1)marimo check [OPTIONS] [FILES]...
Options:
| Name | Type | Description | Default |
|---|---|---|---|
--fix | boolean | Whether to in place update files. | False |
--strict | boolean | Whether warnings return a non-zero exit code. | False |
-v, --verbose / -q, --quiet | boolean | Whether to print detailed messages. | True |
--unsafe-fixes | boolean | Enable fixes that may change code behavior (e.g., removing empty cells). | False |
--ignore-scripts | boolean | Ignore files that are not recognizable as marimo notebooks. | False |
--format | choice (full | json) | Output format for diagnostics. |
--select | text | Comma-separated rule codes/prefixes to enable, replacing config. e.g. --select MB,MR001 | None |
--ignore | text | Comma-separated rule codes/prefixes to ignore. e.g. --ignore MF004,MF007 | None |
-h, --help | boolean | Show this message and exit. | False |
marimo config¶
Various commands for the marimo config.
Usage:
[](#__codelineno-2-1)marimo config [OPTIONS] COMMAND [ARGS]...
Options:
| Name | Type | Description | Default |
|---|---|---|---|
-h, --help | boolean | Show this message and exit. | False |
marimo config describe¶
Describe the marimo config.
Usage:
[](#__codelineno-3-1)marimo config describe [OPTIONS]
Options:
| Name | Type | Description | Default |
|---|---|---|---|
-h, --help | boolean | Show this message and exit. | False |
marimo config show¶
Show the marimo config.
Usage:
[](#__codelineno-4-1)marimo config show [OPTIONS]
Options:
| Name | Type | Description | Default |
|---|---|---|---|
-h, --help | boolean | Show this message and exit. | False |
marimo convert¶
Convert a Jupyter notebook, Markdown file, or Python script to a marimo notebook.
Supported input formats: - .ipynb (local or GitHub-hosted) - .md files with {python} code fences - .py scripts in py:percent format
Behavior: - Jupyter notebooks: outputs are stripped.
- Markdown files: only
{python}fenced code blocks are converted.
Example:
- Python scripts: - If already a valid marimo notebook, no conversion is performed. - Otherwise, marimo attempts to convert using py:percent formatting, preserving top-level comments and docstrings.
Example usage:
marimo convert your_nb.ipynb -o your_nb.py
or
marimo convert your_nb.md -o your_nb.py
or
marimo convert script.py -o your_nb.py
You can also pass global flags to the main marimo command. For example, use -q to suppress output or -y to automatically accept all prompts of the command.
marimo -q -y convert script.py -o your_nb.py
After conversion:
Note: Since marimo's reactive execution differs from traditional notebooks, you may need to refactor code that mutates variables across cells (e.g., modifying a dataframe in multiple cells), which can lead to unexpected behavior.
Usage:
[](#__codelineno-6-1)marimo convert [OPTIONS] FILENAME
Options:
| Name | Type | Description | Default |
|---|---|---|---|
-o, --output | path | Output file to save the converted notebook to. If not provided, the converted notebook will be printed to stdout. | None |
-h, --help | boolean | Show this message and exit. | False |
marimo edit¶
Create or edit notebooks. If NAME is a url, the notebook will be downloaded to a temporary file. * marimo edit Start the marimo notebook server * marimo edit notebook.py Create or edit notebook.py
Usage:
[](#__codelineno-7-1)marimo edit [OPTIONS] [NAME] [ARGS]...
Options:
| Name | Type | Description | Default |
|---|---|---|---|
-p, --port | integer | Port to attach to. | None |
--host | text | Host to attach to. | 127.0.0.1 |
--proxy | text | Address of reverse proxy. | None |
--headless | boolean | Don't launch a browser. | False |
--token / --no-token | boolean | Use a token for authentication. This enables session-based authentication. A random token will be generated if --token-password is not set. If --no-token is set, session-based authentication will not be used. | True |
--token-password | text | Use a specific token for authentication. This enables session-based authentication. A random token will be generated if not set. | None |
--token-password-file | text | Path to file containing token password, or '-' for stdin. Mutually exclusive with --token-password. | None |
--base-url | text | Base URL for the server. Should start with a /. | `` |
--allow-origins | text | Allowed origins for CORS. Can be repeated. Use * for all origins. | None |
--skip-update-check | boolean | Don't check if a new version of marimo is available for download. | False |
--sandbox / --no-sandbox | boolean | Run the notebook in an isolated environment, with dependencies tracked via PEP 723 inline metadata. If already declared, dependencies will install automatically. Requires uv. | None |
--trusted / --untrusted | boolean | Run notebooks hosted remotely on the host machine; if --untrusted, runs marimo in a Docker container. | None |
--watch | boolean | Watch the file for changes and reload the code when saved in another editor. | False |
--skew-protection / --no-skew-protection | boolean | Enable skew protection middleware to prevent version mismatch issues. | True |
--timeout | float | Enable a global timeout to shut down the server after specified number of minutes of no connection | None |
--session-ttl | integer | Seconds to wait before closing a session on websocket disconnect. If None is provided, sessions are not automatically closed. | None |
-h, --help | boolean | Show this message and exit. | False |
marimo env¶
Print out environment information for debugging purposes.
Usage:
Options:
| Name | Type | Description | Default |
|---|---|---|---|
-h, --help | boolean | Show this message and exit. | False |
marimo export¶
Export a notebook to various formats.
Usage:
[](#__codelineno-9-1)marimo export [OPTIONS] COMMAND [ARGS]...
Options:
| Name | Type | Description | Default |
|---|---|---|---|
-h, --help | boolean | Show this message and exit. | False |
marimo export html¶
Run a notebook and export it as an HTML file.
Example:
marimo export html notebook.py -o notebook.html
Optionally pass CLI args to the notebook:
marimo export html notebook.py -o notebook.html -- -arg1 foo -arg2 bar
Usage:
[](#__codelineno-10-1)marimo export html [OPTIONS] NAME [ARGS]...
Options:
| Name | Type | Description | Default |
|---|---|---|---|
--include-code / --no-include-code | boolean | Include notebook code in the exported HTML file. | True |
--watch / --no-watch | boolean | Watch notebook for changes and regenerate the output on modification. If watchdog is installed, it will be used to watch the file. Otherwise, file watcher will poll the file every 1s. | False |
-o, --output | path | Output file to save the HTML to. If not provided, the HTML will be printed to stdout. | None |
--sandbox / --no-sandbox | boolean | Run the command in an isolated virtual environment using uv run --isolated. Requires uv. | None |
-f, --force | boolean | Force overwrite of the output file if it already exists. | False |
-h, --help | boolean | Show this message and exit. | False |
marimo export html-wasm¶
Export a notebook as a WASM-powered standalone HTML file.
Example:
marimo export html-wasm notebook.py -o notebook.wasm.html
The exported HTML file will run the notebook using WebAssembly, making it completely self-contained and executable in the browser. This lets you share interactive notebooks on the web without setting up infrastructure to run Python code.
The exported notebook runs using Pyodide, which supports most but not all Python packages. To learn more, see the Pyodide documentation.
In order for this file to be able to run, it must be served over HTTP, and cannot be opened directly from the file system (e.g. file://).
Usage:
[](#__codelineno-11-1)marimo export html-wasm [OPTIONS] NAME [ARGS]...
Options:
| Name | Type | Description | Default |
|---|---|---|---|
-o, --output | path | Output directory to save the HTML to. | _required |
--mode | choice (edit | run) | Whether the notebook code should be editable or readonly. |
--watch / --no-watch | boolean | Whether to watch the original file and export upon change | False |
--show-code / --no-show-code | boolean | Whether to show code by default in the exported HTML file; only relevant for run mode. | False |
--include-cloudflare / --no-include-cloudflare | boolean | Whether to include Cloudflare Worker configuration files (index.js and wrangler.jsonc) for easy deployment. | False |
--sandbox / --no-sandbox | boolean | Run the command in an isolated virtual environment using uv run --isolated. Requires uv. | None |
-f, --force | boolean | Force overwrite of the output file if it already exists. | False |
--execute / --no-execute | boolean | Execute the notebook before exporting and embed outputs as a preview. Runs in an isolated environment pinned to WASM-compatible packages when possible. | False |
-h, --help | boolean | Show this message and exit. | False |
marimo export ipynb¶
Export a marimo notebook as a Jupyter notebook in topological order.
Example:
marimo export ipynb notebook.py -o notebook.ipynb
Watch for changes and regenerate the script on modification:
marimo export ipynb notebook.py -o notebook.ipynb --watch
Optionally pass CLI args to the notebook:
marimo export ipynb notebook.py -o notebook.ipynb --include-outputs -- -arg1 foo -arg2 bar
Requires nbformat to be installed.
Usage:
[](#__codelineno-12-1)marimo export ipynb [OPTIONS] NAME [ARGS]...
Options:
| Name | Type | Description | Default |
|---|---|---|---|
--sort | choice (top-down | topological) | Sort cells top-down or in topological order. |
--watch / --no-watch | boolean | Watch notebook for changes and regenerate the output on modification. If watchdog is installed, it will be used to watch the file. Otherwise, file watcher will poll the file every 1s. | False |
-o, --output | path | Output file to save the ipynb file to. If not provided, the ipynb contents will be printed to stdout. | None |
--include-outputs / --no-include-outputs | boolean | Run the notebook and include outputs in the exported ipynb file. | False |
--sandbox / --no-sandbox | boolean | Run the command in an isolated virtual environment using uv run --isolated. Requires uv. | None |
-f, --force | boolean | Force overwrite of the output file if it already exists. | False |
-h, --help | boolean | Show this message and exit. | False |
marimo export md¶
Export a marimo notebook as a code fenced Markdown file.
Example:
marimo export md notebook.py -o notebook.md
Watch for changes and regenerate the script on modification:
marimo export md notebook.py -o notebook.md --watch
Usage:
[](#__codelineno-13-1)marimo export md [OPTIONS] NAME
Options:
| Name | Type | Description | Default |
|---|---|---|---|
--watch / --no-watch | boolean | Watch notebook for changes and regenerate the output on modification. If watchdog is installed, it will be used to watch the file. Otherwise, file watcher will poll the file every 1s. | False |
-o, --output | path | Output file to save the markdown to. If not provided, markdown will be printed to stdout. | None |
--sandbox / --no-sandbox | boolean | Run the command in an isolated virtual environment using uv run --isolated. Requires uv. | None |
-f, --force | boolean | Force overwrite of the output file if it already exists. | False |
-h, --help | boolean | Show this message and exit. | False |
marimo export pdf¶
Export a marimo notebook as a PDF file.
Example:
marimo export pdf notebook.py -o notebook.pdf
Optionally pass CLI args to the notebook:
marimo export pdf notebook.py -o notebook.pdf -- -arg1 foo -arg2 bar
Export PDFs in a specific format such as slides:
marimo export pdf notebook.py -o notebook.pdf --as=slides
Requires nbformat and nbconvert to be installed.
Usage:
[](#__codelineno-14-1)marimo export pdf [OPTIONS] NAME [ARGS]...
Options:
| Name | Type | Description | Default |
|---|---|---|---|
--include-outputs / --no-include-outputs | boolean | Run the notebook and include outputs in the exported PDF file. | True |
--include-inputs / --no-include-inputs | boolean | Include code cell inputs in the exported PDF file. | True |
--webpdf / --no-webpdf | boolean | Use nbconvert's WebPDF exporter (Chromium). If disabled, marimo will try standard PDF export (pandoc + TeX) first and fall back to WebPDF. | True |
--rasterize-outputs / --no-rasterize-outputs | boolean | Rasterize marimo widget HTML and Vega outputs to PNG fallbacks before PDF conversion (enabled by default). | True |
--raster-scale | float range (between 1.0 and 4.0) | Scale factor for rasterized output screenshots. | 4.0 |
--raster-server | choice (static | live) | Server mode used for raster capture. Use 'static' (default) for faster captures, or 'live' if outputs require a live Python connection. For --as=slides, 'live' is recommended. |
--as | choice (document | slides) | PDF export preset. Use slides for reveal.js slide-style output. If omitted, marimo exports as a standard document PDF. |
--watch / --no-watch | boolean | Watch notebook for changes and regenerate the output on modification. If watchdog is installed, it will be used to watch the file. Otherwise, file watcher will poll the file every 1s. | False |
-o, --output | path | Output PDF file to save to. | _required |
--sandbox / --no-sandbox | boolean | Run the command in an isolated virtual environment using uv run --isolated. Requires uv. | None |
-f, --force | boolean | Force overwrite of the output file if it already exists. | False |
-h, --help | boolean | Show this message and exit. | False |
marimo export script¶
Export a marimo notebook as a flat script, in topological order.
Example:
marimo export script notebook.py -o notebook.script.py
Watch for changes and regenerate the script on modification:
marimo export script notebook.py -o notebook.script.py --watch
Usage:
[](#__codelineno-15-1)marimo export script [OPTIONS] NAME
Options:
| Name | Type | Description | Default |
|---|---|---|---|
--watch / --no-watch | boolean | Watch notebook for changes and regenerate the output on modification. If watchdog is installed, it will be used to watch the file. Otherwise, file watcher will poll the file every 1s. | False |
-o, --output | path | Output file to save the script to. If not provided, the script will be printed to stdout. | None |
--sandbox / --no-sandbox | boolean | Run the command in an isolated virtual environment using uv run --isolated. Requires uv. | None |
-f, --force | boolean | Force overwrite of the output file if it already exists. | False |
-h, --help | boolean | Show this message and exit. | False |
marimo export session¶
Execute a notebook or directory of notebooks and export session snapshots.
Usage:
[](#__codelineno-16-1)marimo export session [OPTIONS] NAME [ARGS]...
Options:
| Name | Type | Description | Default |
|---|---|---|---|
--sandbox / --no-sandbox | boolean | Run the command in an isolated virtual environment using uv run --isolated. Requires uv. | None |
--force-overwrite / --no-force-overwrite | boolean | Overwrite all existing session snapshots, even if they are already up-to-date. | False |
--continue-on-error / --no-continue-on-error | boolean | Continue processing other notebooks if one notebook fails. | True |
-h, --help | boolean | Show this message and exit. | False |
marimo export thumbnail¶
Generate OpenGraph thumbnails for notebooks.
Usage:
[](#__codelineno-17-1)marimo export thumbnail [OPTIONS] NAME [ARGS]...
Options:
| Name | Type | Description | Default |
|---|---|---|---|
--width | integer | Viewport width for the screenshot. | 1200 |
--height | integer | Viewport height for the screenshot. | 630 |
--scale | integer range (between 1 and 4) | Device scale factor for screenshots. Output resolution will be width*scale x height*scale. | 2 |
--timeout-ms | integer | Additional time to wait after page load before screenshot. | 1500 |
--output | path | Output filename. If omitted, writes to <notebook_dir>/__marimo__/assets/<notebook_stem>/opengraph.png. | None |
--overwrite / --no-overwrite | boolean | Overwrite existing thumbnails. | False |
--include-code / --no-include-code | boolean | Whether to include code in the rendered HTML before screenshot. | False |
--execute / --no-execute | boolean | Execute notebooks and include their outputs in thumbnails. In --no-execute mode (default), thumbnails are generated from notebook structure without running code (and will not include outputs). | False |
--sandbox / --no-sandbox | boolean | Render notebooks in an isolated environment, with dependencies tracked via PEP 723 inline metadata. If already declared, dependencies will install automatically. Requires uv. Only applies when --execute is used. | None |
--continue-on-error / --fail-fast | boolean | Continue processing other notebooks if one notebook fails. | True |
-h, --help | boolean | Show this message and exit. | False |
marimo new¶
Create an empty notebook, or generate from a prompt with AI
- marimo new Create an empty notebook
- marimo new prompt.txt Generate a notebook from a prompt in a file.
- marimo new "Plot an interactive 3D surface with matplotlib." Generate a notebook from a prompt.
Visit https://marimo.app/ai for more prompt examples.
Usage:
[](#__codelineno-18-1)marimo new [OPTIONS] [PROMPT]
Options:
| Name | Type | Description | Default |
|---|---|---|---|
-p, --port | integer | Port to attach to. | None |
--host | text | Host to attach to. | 127.0.0.1 |
--proxy | text | Address of reverse proxy. | None |
--headless | boolean | Don't launch a browser. | False |
--token / --no-token | boolean | Use a token for authentication. This enables session-based authentication. A random token will be generated if --token-password is not set. If --no-token is set, session-based authentication will not be used. | True |
--token-password | text | Use a specific token for authentication. This enables session-based authentication. A random token will be generated if not set. | None |
--token-password-file | text | Path to file containing token password, or '-' for stdin. Mutually exclusive with --token-password. | None |
--base-url | text | Base URL for the server. Should start with a /. | `` |
--sandbox / --no-sandbox | boolean | Run the notebook in an isolated environment, with dependencies tracked via PEP 723 inline metadata. If already declared, dependencies will install automatically. Requires uv. | None |
--skew-protection / --no-skew-protection | boolean | Enable skew protection middleware to prevent version mismatch issues. | True |
--timeout | float | Enable a global timeout to shut down the server after specified number of minutes of no connection | None |
-h, --help | boolean | Show this message and exit. | False |
marimo pair¶
Commands for pair programming with AI.
Usage:
[](#__codelineno-19-1)marimo pair [OPTIONS] COMMAND [ARGS]...
Options:
| Name | Type | Description | Default |
|---|---|---|---|
-h, --help | boolean | Show this message and exit. | False |
marimo pair prompt¶
Generate a prompt for pair programming on a running marimo notebook.
Usage:
[](#__codelineno-20-1)marimo pair prompt [OPTIONS]
Options:
| Name | Type | Description | Default |
|---|---|---|---|
--url | text | URL of the running marimo kernel. | _required |
--claude | boolean | Validate that the marimo-pair Claude Code skill is installed. | False |
--codex | boolean | Validate that the marimo-pair Codex skill is installed. | False |
--opencode | boolean | Validate that the marimo-pair opencode skill is installed. | False |
--with-token | boolean | Prompt for an auth token and store it in a temp file. | False |
-h, --help | boolean | Show this message and exit. | False |
marimo recover¶
Recover a marimo notebook from a JSON file.
When the frontend loses its connection to the kernel, marimo auto-saves unsaved cell changes to a JSON recovery file. Use this command to convert that JSON file back into a marimo notebook (.py), printing the recovered source to stdout.
Example:
marimo recover notebook_recovery.json > recovered_notebook.py
Usage:
[](#__codelineno-21-1)marimo recover [OPTIONS] NAME
Options:
| Name | Type | Description | Default |
|---|---|---|---|
-h, --help | boolean | Show this message and exit. | False |
marimo run¶
Run a notebook as an app in read-only mode.
If NAME is a url, the notebook will be downloaded to a temporary file.
Example:
marimo run notebook.py marimo run folder another_folder marimo run app.py -- --arg value
Usage:
[](#__codelineno-22-1)marimo run [OPTIONS] NAME [ARGS]...
Options:
| Name | Type | Description | Default |
|---|---|---|---|
-p, --port | integer | Port to attach to. | None |
--host | text | Host to attach to. | 127.0.0.1 |
--proxy | text | Address of reverse proxy. | None |
--headless | boolean | Don't launch a browser. | False |
--token / --no-token | boolean | Use a token for authentication. This enables session-based authentication. A random token will be generated if --token-password is not set. If --no-token is set, session-based authentication will not be used. | False |
--token-password | text | Use a specific token for authentication. This enables session-based authentication. A random token will be generated if not set. | None |
--token-password-file | text | Path to file containing token password, or '-' for stdin. Mutually exclusive with --token-password. | None |
--include-code | boolean | Send notebook source code to the client. By default, code is not sent to the client and cannot be viewed in the browser. | False |
--session-ttl | integer | Seconds to wait before closing a session on websocket disconnect. | 120 |
--watch | boolean | Watch the file for changes and reload the app. If watchdog is installed, it will be used to watch the file. Otherwise, file watcher will poll the file every 1s. | False |
--skew-protection / --no-skew-protection | boolean | Enable skew protection middleware to prevent version mismatch issues. | True |
--base-url | text | Base URL for the server. Should start with a /. | `` |
--allow-origins | text | Allowed origins for CORS. Can be repeated. | None |
--redirect-console-to-browser | boolean | Redirect console logs to the browser console. | False |
--sandbox / --no-sandbox | boolean | Run the notebook in an isolated environment, with dependencies tracked via PEP 723 inline metadata. If already declared, dependencies will install automatically. Requires uv. | None |
--check / --no-check | boolean | Disable a static check of the notebook before running. | True |
--trusted / --untrusted | boolean | Run notebooks hosted remotely on the host machine; if --untrusted, runs marimo in a Docker container. | None |
--show-tracebacks / --no-show-tracebacks | boolean | Show detailed error tracebacks in a modal when exceptions occur. | None |
-h, --help | boolean | Show this message and exit. | False |
marimo shell-completion¶
Install shell completions for marimo. Supports bash, zsh, and fish.
Usage:
[](#__codelineno-23-1)marimo shell-completion [OPTIONS]
Options:
| Name | Type | Description | Default |
|---|---|---|---|
-h, --help | boolean | Show this message and exit. | False |
marimo tutorial¶
Open a tutorial.
marimo is a powerful library for making reactive notebooks and apps. To get the most out of marimo, get started with a few tutorials, starting with the intro:
Recommended sequence:
- intro - dataflow - ui - markdown - plots - sql - layout - fileformat - external-dependencies - markdown-format - for-jupyter-users
Usage:
[](#__codelineno-24-1)marimo tutorial [OPTIONS] {intro|dataflow|ui|markdown|plots|sql|layout|filefor [](#__codelineno-24-2) mat|external-dependencies|markdown-format|for-jupyter-users}
Options:
| Name | Type | Description | Default |
|---|---|---|---|
-p, --port | integer | Port to attach to. | None |
--host | text | Host to attach to. | 127.0.0.1 |
--proxy | text | Address of reverse proxy. | None |
--headless | boolean | Don't launch a browser. | False |
--token / --no-token | boolean | Use a token for authentication. This enables session-based authentication. A random token will be generated if --token-password is not set. If --no-token is set, session-based authentication will not be used. | True |
--token-password | text | Use a specific token for authentication. This enables session-based authentication. A random token will be generated if not set. | None |
--token-password-file | text | Path to file containing token password, or '-' for stdin. Mutually exclusive with --token-password. | None |
--skew-protection / --no-skew-protection | boolean | Enable skew protection middleware to prevent version mismatch issues. | True |
-h, --help | boolean | Show this message and exit. | False |
How is marimo different from Jupyter?¶
marimo is a reinvention of the Python notebook as a reproducible, interactive, and shareable Python program that can be executed as scripts or deployed as interactive web apps.
Consistent state. In marimo, your notebook code, outputs, and program state are guaranteed to be consistent. Run a cell and marimo reacts by automatically running the cells that reference its variables. Delete a cell and marimo scrubs its variables from program memory, eliminating hidden state.
Built-in interactivity. marimo also comes with UI elements like sliders, a dataframe transformer, and interactive plots that are automatically synchronized with Python. Interact with an element and the cells that use it are automatically re-run with its latest value.
Pure Python programs. Unlike Jupyter notebooks, marimo notebooks are stored as pure Python files that can be executed as scripts, deployed as interactive web apps, and versioned easily with Git.
What problems does marimo solve?¶
marimo solves problems in reproducibility, maintainability, interactivity, reusability, and shareability of notebooks.
Reproducibility. In Jupyter notebooks, the code you see doesn't necessarily match the outputs on the page or the program state. If you delete a cell, its variables stay in memory, which other cells may still reference; users can execute cells in arbitrary order. This leads to widespread reproducibility issues. One study analyzed 10 million Jupyter notebooks and found that 36% of them weren't reproducible.
In contrast, marimo guarantees that your code, outputs, and program state are consistent, eliminating hidden state and making your notebook reproducible. marimo achieves this by intelligently analyzing your code and understanding the relationships between cells, and automatically re-running cells as needed.
In addition, marimo notebooks can serialize package requirements inline; marimo runs these "sandboxed" notebooks in temporary virtual environments, making them reproducible down to the packages.
Maintainability. marimo notebooks are stored as pure Python programs (.py files). This lets you version them with Git; in contrast, Jupyter notebooks are stored as JSON and require extra steps to version.
Interactivity. marimo notebooks come with UI elements that are automatically synchronized with Python (like sliders, dropdowns); eg, scrub a slider and all cells that reference it are automatically re-run with the new value. This is difficult to get working in Jupyter notebooks.
Reusability. marimo notebooks can be executed as Python scripts from the command-line (since they're stored as .py files). In contrast, this requires extra steps to do for Jupyter, such as copying and pasting the code out or using external frameworks. We also let you import symbols (functions, classes) defined in a marimo notebook into other Python programs/notebooks, something you can't easily do with Jupyter.
Shareability. Every marimo notebook can double as an interactive web app, complete with UI elements, which you can serve using the marimo run command. This isn't possible in Jupyter without substantial extra effort.
To learn more about problems with traditional notebooks, see these references [1] [2].
How is marimo.ui different from Jupyter widgets?¶
Unlike Jupyter widgets, marimo's interactive elements are automatically synchronized with the Python kernel: no callbacks, no observers, no manually re-running cells.
Using marimo¶
Is marimo a notebook or a library?¶
marimo is both a notebook and a library.
- Create marimo notebooks with the editor that opens in your browser when you run
marimo edit. - Use the marimo library (
import marimo as mo) in marimo notebooks. Write markdown withmo.md(...), create stateful interactive elements withmo.ui(mo.ui.slider(...)), and more. See the docs for an API reference.
What's the difference between a marimo notebook and a marimo app?¶
marimo programs are notebooks, apps, or both, depending on how you use them.
There are two ways to interact with a marimo program:
- open it as a computational notebook with
marimo edit - run it as an interactive app with
marimo run
All marimo programs start as notebooks, since they are created with marimo edit. Because marimo notebooks are reactive and have built-in interactive elements, many can easily be made into useful and beautiful apps by simply hiding the notebook code: this is what marimo run does.
Not every notebook needs to be run as an app — marimo notebooks are useful in and of themselves for rapidly exploring data and doing reproducible science. And not every app is improved by interacting with the notebook. In some settings, such as collaborative research, education, and technical presentations, going back and forth between the notebook view and app view (which you can do from marimo edit) can be useful!
How does marimo know what cells to run?¶
marimo reads each cell once to determine what global names it defines and what global names it reads. When a cell is run, marimo runs all other cells that read any of the global names it defines. A global name can refer to a variable, class, function, or import.
In other words, marimo uses static analysis to make a dataflow graph out of your cells. Each cell is a node in the graph across which global variables "flow". Whenever a cell is run, either because you changed its code or interacted with a UI element it reads, all its descendants run in turn.
Does marimo slow my code down?¶
No, marimo doesn't slow your code down. marimo determines the dependencies among cells by reading your code, not running or tracing it, so there's zero runtime overhead.
How do I prevent automatic execution from running expensive cells?¶
Reactive (automatic) execution ensures your code and outputs are always in sync, improving reproducibility by eliminating hidden state and out-of-order execution; marimo also takes care to run only the minimal set of cells needed to keep your notebook up to date. But when some cells take a long time to run, it's understandable to be concerned that automatic execution will kick off expensive cells before you're ready to run them.
Here are some tips to avoid accidental execution of expensive cells:
- Disable expensive cells. When a cell is disabled, it and its descendants are blocked from running.
- Wrap UI elements in a form.
- Use
mo.stopto conditionally stop execution of a cell and its descendants. - Decorate functions with marimo's
mo.cacheto cache expensive intermediate computations. - Use
mo.persistent_cacheto cache variables to disk; on re-run, marimo will read values from disk instead of recalculating them as long as the cell is not stale. - Disable automatic execution in the runtime configuration.
How do I disable automatic execution?¶
You can disable automatic execution through the notebook runtime settings; see the guide on runtime configuration.
When automatic execution is disabled, marimo still gives you guarantees on your notebook state and automatically marks cells as stale when appropriate.
How do I use sliders and other interactive elements?¶
Interactive UI elements like sliders are available in marimo.ui.
- Assign the UI element to a global variable (
slider = mo.ui.slider(0, 100)) - Include it in the last expression of a cell to display it (
sliderormo.md(f"Choose a value: {slider}")) - Read its current value in another cell via its
valueattribute (slider.value)
When a UI element bound to a global variable is interacted with, all cells referencing the global variable are run automatically.
If you have many UI elements or don't know the elements you'll create until runtime, use marimo.ui.array and marimo.ui.dictionary to create UI elements that wrap other UI elements (sliders = mo.ui.array([slider(1, 100) for _ in range(n_sliders)])).
All this and more is explained in the UI tutorial. Run it with
at the command line.
How do I add a submit button to UI elements?¶
Use the form method to add a submit button to a UI element. For example,
[](#__codelineno-1-1)form = marimo.ui.text_area().form()
When wrapped in a form, the text area's value will only be sent to Python when you click the submit button. Access the last submitted value of the text area with form.value.
How do I write markdown?¶
Import marimo (as mo) in a notebook, and use the mo.md function. Learn more in the outputs guide or by running marimo tutorial markdown.
How do I display plots?¶
Include plots in the last expression of a cell to display them, just like all other outputs. If you're using matplotlib, you can display the Figure object (get the current figure with plt.gcf()). For examples, run the plots tutorial:
Also see the plotting API reference.
How do I prevent matplotlib plots from being cut off?¶
If your legend or axes labels are cut off, try calling plt.tight_layout() before outputting your plot:
[](#__codelineno-3-1)import matplotlib.pyplot as plt [](#__codelineno-3-2)[](#__codelineno-3-3)plt.plot([-8, 8]) [](#__codelineno-3-4)plt.ylabel("my variable") [](#__codelineno-3-5)plt.tight_layout() [](#__codelineno-3-6)plt.gca()
How do I display interactive matplotlib plots?¶
[](#__codelineno-4-1)fig, ax = plt.subplots() [](#__codelineno-4-2)ax.plot([1, 2]) [](#__codelineno-4-3)mo.mpl.interactive(ax)
How do I display objects in rows and columns?¶
Use marimo.hstack and marimo.vstack. See the layout tutorial for details:
How do I show cell code in the app view?¶
Use mo.show_code.
How do I create an output with a dynamic number of UI elements?¶
Use mo.ui.array, mo.ui.dictionary, or mo.ui.batch to create a UI element that wraps a dynamic number of other UI elements.
If you need custom formatting, use mo.ui.batch, otherwise use mo.ui.array or mo.ui.dictionary.
For usage examples, see the recipes for grouping UI elements together.
How do I let users interrupt a progress bar iteration?¶
To create an interruptible progress bar, run the progress bar in its own thread, and create a button that on change signals to the thread that it should exit.
Example:
[](#__codelineno-6-1)import marimo [](#__codelineno-6-2)[](#__codelineno-6-3)__generated_with = "0.20.1" [](#__codelineno-6-4)app = marimo.App() [](#__codelineno-6-5) [](#__codelineno-6-6)[](#__codelineno-6-7)@app.cell [](#__codelineno-6-8)def _(): [](#__codelineno-6-9) import marimo as mo [](#__codelineno-6-10) import time [](#__codelineno-6-11) from threading import Event [](#__codelineno-6-12) return Event, mo, time [](#__codelineno-6-13) [](#__codelineno-6-14)[](#__codelineno-6-15)@app.cell [](#__codelineno-6-16)def _(Event): [](#__codelineno-6-17) cancelled = Event() [](#__codelineno-6-18) return (cancelled,) [](#__codelineno-6-19) [](#__codelineno-6-20)[](#__codelineno-6-21)@app.cell [](#__codelineno-6-22)def _(cancelled, mo): [](#__codelineno-6-23) cancel = mo.ui.button( [](#__codelineno-6-24) label="Interrupt the progress bar", on_change=lambda _: cancelled.set() [](#__codelineno-6-25) ) [](#__codelineno-6-26) cancel [](#__codelineno-6-27) return [](#__codelineno-6-28) [](#__codelineno-6-29)[](#__codelineno-6-30)@app.cell [](#__codelineno-6-31)def _(cancelled, mo, time): [](#__codelineno-6-32) def progress(total): [](#__codelineno-6-33) with mo.status.progress_bar(total=10) as pbar: [](#__codelineno-6-34) for _ in range(10): [](#__codelineno-6-35) if cancelled.is_set(): [](#__codelineno-6-36) pbar.update( [](#__codelineno-6-37) increment=0, subtitle="The user cancelled the iteration" [](#__codelineno-6-38) ) [](#__codelineno-6-39) break [](#__codelineno-6-40) # Sleep... or anything else that releases GIL [](#__codelineno-6-41) time.sleep(0.5) [](#__codelineno-6-42) pbar.update() [](#__codelineno-6-43) [](#__codelineno-6-44) return (progress,) [](#__codelineno-6-45) [](#__codelineno-6-46)[](#__codelineno-6-47)@app.cell [](#__codelineno-6-48)def _(mo, progress): [](#__codelineno-6-49) mo.Thread(target=progress, args=(10,)).start() [](#__codelineno-6-50) return [](#__codelineno-6-51) [](#__codelineno-6-52)[](#__codelineno-6-53)if __name__ == "__main__": [](#__codelineno-6-54) app.run()
How do I restart a notebook?¶
To clear all program memory and restart the notebook from scratch, open the notebook menu in the top right and click "Restart kernel".
How do I reload modules?¶
Enable automatic reloading of modules via the runtime settings in your marimo installation's user configuration. (Click the "gear" icon in the top right of a marimo notebook).
When enabled, marimo will automatically hot-reload modified modules before executing a cell.
Why aren't my on_change/on_click handlers being called?¶
A UI Element's on_change (or for buttons, on_click) handlers are only called if the element is bound to a global variable. For example, this won't work
[](#__codelineno-7-1)mo.vstack([mo.ui.button(on_change=lambda _: print("I was called")) for _ in range(10)])
In such cases (when you want to output a dynamic number of UI elements), you need to use mo.ui.array, mo.ui.dictionary, or mo.ui.batch.
See the recipes for grouping UI elements together for example code.
Why are my on_change handlers in an array all referencing the last element?¶
Don't do this: In the below snippet, every on_change will print 9!.
[](#__codelineno-8-1)array = mo.ui.array( [](#__codelineno-8-2) [mo.ui.button(on_change=lambda value: print(i)) for i in range(10) [](#__codelineno-8-3)])
Instead, do this: Explicitly bind i to the current loop value:
[](#__codelineno-9-1)array = mo.ui.array( [](#__codelineno-9-2) [mo.ui.button(on_change=lambda value, i=i: print(i)) for i in range(10)] [](#__codelineno-9-3)) [](#__codelineno-9-4)array
This is necessary because in Python, closures are late-binding.
Why aren't my SQL brackets working?¶
Our "SQL" cells are really just Python under the hood to keep notebooks as pure Python scripts. By default, we use f-strings for SQL strings, which allows for parameterized SQL like SELECT * from table where value < {min}.
To escape real { / } that you don't want parameterized, use double \{\{...\}\}:
[](#__codelineno-10-1)SELECT unnest([\{\{'a': 42, 'b': 84\}\}, \{\{'a': 100, 'b': NULL\}\}]);
How does marimo treat type annotations?¶
Type annotations are registered as references of a cell, unless they are explicitly written as strings. This helps ensure correctness of code that depends on type annotations at runtime (e.g., Pydantic), while still providing a way to omit annotations from affecting dataflow graph.
For example, in
A is treated as a reference, used in determining the dataflow graph, but in
A isn't made a reference.
For Python 3.12+, marimo additionally implements annotation scoping.
How do I use dotenv?¶
The package dotenv's loadenv() function does not work out-of-the box in marimo. Instead, use dotenv.load_dotenv(dotenv.find_dotenv(usecwd=True)).
What packages can I use?¶
You can use any Python package. marimo cells run arbitrary Python code.
How do I use marimo on a remote server?¶
We recorded a video tutorial on how to use marimo on a remote server. Check it out here.
Use SSH port-forwarding to run marimo on a remote server and connect to it from a browser on your local machine. Make sure to pass the --headless flag when starting marimo on remote; on the remote machine, we also recommend using a port other than marimo's default port, such as 8080:
On the remote machine, run:
[](#__codelineno-13-1)marimo edit --headless --port 8080
or, if you want to set a custom host:
[](#__codelineno-14-1)marimo edit --headless --host 0.0.0.0 --port 8080
On local, run:
[](#__codelineno-15-1)ssh -N -L 3718:127.0.0.1:8080 REMOTE_USER@REMOTE_HOST
Then open localhost:3718 in your browser.
How do I make marimo accessible on all network interfaces?¶
Use --host 0.0.0.0 with marimo edit, marimo run, or marimo tutorial:
[](#__codelineno-16-1)marimo edit --host 0.0.0.0
How do I use marimo behind JupyterHub?¶
JupyterHub can be configured to launch marimo using the marimo-jupyter-extension.
How do I use marimo with JupyterBook?¶
JupyterBook makes it easy to create static websites with markdown and Jupyter notebooks.
To include a marimo notebook in a JupyterBook, you can either export your notebook to an ipynb file, or export to HTML:
- export to ipynb:
marimo export ipynb my_notebook.py -o my_notebook.ipynb --include-outputs - export to HTML:
marimo export html my_notebook.py -o my_notebook.html
How do I deploy apps?¶
Use the marimo CLI's run command to serve a notebook as an app:
If you are running marimo inside a Docker container, you may want to run under a different host and port:
[](#__codelineno-18-1)marimo run notebook.py --host 0.0.0.0 --port 8080
Is marimo free?¶
Yes!
- 🌟 Star us on GitHub
- 💬 Chat with us on Discord
- 📧 Subscribe to our Newsletter
- ☁️ Join our Cloud Waitlist
- ✏️ Start a GitHub Discussion
- 🦋 Follow us on Bluesky
- 🐦 Follow us on Twitter
- 🎥 Subscribe on YouTube
- 🕴️ Follow us on LinkedIn
Shields¶
You can use our shield for opening a marimo application:
Markdown
[](#__codelineno-0-1)[](https://marimo.app/l/c7h6pz)
HTML
[](#__codelineno-1-1)<a target="_blank" href="https://marimo.app/l/c7h6pz"> [](#__codelineno-1-2) <img src="https://marimo.io/shield.svg" /> [](#__codelineno-1-3)</a>
| Integration | Description |
|---|---|
| MotherDuck | Integrating with MotherDuck |
| Google Cloud Storage | Integrating with Google Cloud Storage |
| Google Cloud BigQuery | Integrating with Google Cloud BigQuery |
| Google Sheets | Integrating with Google Sheets |
Security Model¶
When you open a notebook, marimo assumes you might not trust its contents until you explicitly choose to run it. Once you've run code, marimo treats the outputs as trusted since they came from your execution.
Like other notebooks, marimo allows arbitrary code execution when you run cells. This means that if you run code from untrusted sources, you could inadvertently execute malicious code. Therefore, it's important to only run notebooks from sources you trust or to review the code before executing it.
However, marimo implements several security measures to minimize risks when opening and editing notebooks. Our blanket policy is that no user code is executed without explicit user action (either as javascript or python).
Content sanitization¶
marimo sanitizes HTML and JavaScript in specific contexts to prevent malicious code from executing when you open untrusted notebooks. All user content shown before execution is sanitized to remove all scripts (including markdown and custom HTML outputs).
After initial execution, outputs are trusted since they were generated by your code. Being a responsible notebook user means running code from sources you trust, and/or reviewing code before executing it.
Static loading¶
Although marimo notebook are just python files, opening a notebook through marimo edit does not execute it as a module. marimo notebooks are statically loaded, meaning they are parsed but not executed as Python modules when opened. This prevents arbitrary code execution at load time. Code only runs when you explicitly execute cells.
Run modes and trust¶
marimo behaves differently depending on how you run it:
Edit mode (marimo edit):
- Content is sanitized until you run your first cell or
auto_instantiateis enabled (by default it isdisabled) - After you run code, subsequent outputs are trusted (you created them)
- Token authentication enabled by default for remote access
Run mode (marimo run):
- Notebooks run as web applications
- Content is treated as a trusted website (no sanitization)
- Token authentication can be configured via CLI flags or custom middleware
- With
marimo run <folder> --watch, newly created notebooks in the watched folder can appear in gallery mode without restarting the server
This distinction reflects the different threat models: editing is exploratory and may involve untrusted notebooks; deployed apps are intentional publications.
Authentication¶
marimo provides token-based authentication:
- Enabled by default when running
marimo edit - Configurable in run mode via
--tokenand--token-passwordflags - Extensible through ASGI middleware for custom authentication schemes
See the Authentication guide for more details.
Added security measures on https://molab.marimo.io¶
molab takes a few other addition precautions.
- Auto-running cells is disabled on notebook load (you can disable this during your session)
- Custom head tags are disabled
These restrictions prevent code execution without explicit user consent.
Security Advisories¶
marimo publishes security advisories for vulnerabilities that affect production deployments, particularly long-running applications. We follow responsible disclosure practices and work with security researchers to address issues.
CVE Policy¶
We issue CVEs and security advisories when:
- A vulnerability could affect long-running app deployments
- End-users are directly impacted
- The issue has security implications beyond normal bug fixes
For general safety improvements and hardening work, we document changes in our release notes without issuing formal advisories.
molab Security¶
molab is marimo's hosted notebook platform. For security issues affecting molab:
- We handle disclosure on a case-by-case basis
- General security improvements are disclosed publicly when applicable, and will be documented on this page.
- User-specific issues are handled privately through direct notification
- Reports can be submitted through the same channels: GitHub advisories or security [at] marimo [dot] io
Reporting Vulnerabilities¶
We appreciate the security research community's efforts to improve marimo's security. If you discover a vulnerability:
How to report:
- Draft a security advisory on GitHub, or
- Email the marimo team at security [at] marimo [dot] io
What to expect:
- We review all reports and respond to actionable issues
- Advisories affecting end-users are escalated to CVEs when appropriate
- We provide attribution for all reports (unless you prefer to remain anonymous)
- We have a small allocation for bug bounties; please inquire if interested.
Recognition:
We're grateful to the security researchers who have responsibly disclosed vulnerabilities. Your contributions help keep marimo safe for the entire community. We encourage responsible disclosure and recognize all security researchers who help improve marimo.
Staying Up to Date¶
marimo ships new releases approximately once per week, and we provide immediate updates for major security disclosures. To ensure you have the latest security fixes, we recommend using uv to keep marimo up to date:
[](#__codelineno-0-1)# Install or update to the latest version [](#__codelineno-0-2)uv pip install --upgrade marimo
Using uv ensures you benefit from the latest security improvements and patches as soon as they're available.
Questions?¶
For security questions or concerns, please reach out to security [at] marimo [dot] io. For general questions about marimo, see our FAQ or join us on Discord.
Previous Advisories¶
Click to expand previous security advisories
- [GHSA-xjv7-6w92-42r7]: Unauthenticated proxy vulnerability in matplotlib endpoint. The
/mpl/[port]/[route]endpoint allowed external attackers to reach internal services. Affected versions 0.9.20 through 0.16.3. Fixed in 0.16.4. - [GHSA-2679-6mx9-h9xc]: Remote code execution via unauthenticated terminal access in edit mode. The terminal panel did not require authentication, allowing unauthenticated users to execute arbitrary commands on instances of
marimo editexposed to the internet. Run mode (marimo run) is not affected. Affected versions 0.7.10 through 0.22.x. Fixed in 0.23.0. See our advisory for more information. - [molab-0]: iframe sandbox escape via markdown render. In molab, an attacker could exploit a vulnerability in the iframe sandboxing to escape the iframe and execute code in the parent context. Fixed in molab deployment on 2025-10-19.
Setting up a virtual environment
Python uses virtual environments to minimize conflicts among packages. Here's a quickstart for pip users. If you use conda, please use a conda environment instead.
Run the following in the terminal:
- create an environment with
python -m venv marimo-env - activate the environment:
- macOS/Unix:
source marimo-env/bin/activate - Windows:
marimo-env\Scripts\activate
Make sure the environment is activated before installing marimo and when using marimo. Install other packages you may need, such as numpy, pandas, matplotlib, and altair, in this environment. When you're done, deactivate the environment with deactivate in the terminal.
Learn more from the official Python tutorial.
Using uv?
uv is a next-generation Python package installer and manager that is 10-100x faster than pip, and also makes it easy to install Python and manage projects. Create a uv project with uv init; this creates and manages a virtual environment for you behind-the-scenes. For detailed information on using marimo with uv, see our uv guide.
Prefer VS Code/Cursor?
Try our extension, which works in VS Code, Cursor, and other VS Code forks.
Install with minimal dependencies¶
To install marimo, run the following in a terminal:
install with pipinstall with uvinstall with conda
To check if the install worked, run
To check if the install worked, run
[](#__codelineno-3-1)uv run marimo tutorial intro
[](#__codelineno-4-1)conda install -c conda-forge marimo
To check if the install worked, run
A tutorial notebook should open in your browser.
Install with recommended dependencies¶
marimo is lightweight, with few dependencies, to maximize compatibility with your own environments.
To unlock additional features in the marimo editor, including SQL cells, AI completion, server-side plotting of dataframe columns, and more, we suggest installing marimo[recommended]:
install with pipinstall with uvinstall with conda
[](#__codelineno-6-1)pip install "marimo[recommended]"
[](#__codelineno-7-1)uv add "marimo[recommended]"
[](#__codelineno-8-1)conda install -c conda-forge marimo "duckdb>=1.0.0" "altair>=5.4.0" pyarrow "polars>=1.9.0" "sqlglot[c]>=23.4" "openai>=1.55.3" "ruff" "nbformat>=5.7.0" "vegafusion>=2.0.0" "vl-convert-python>=1.0.0"
Installing marimo in this way installs the following additional dependencies and unlocks the following features:
| Dependency | Feature |
|---|---|
| duckdb>=1.0.0 | SQL cells |
| altair>=5.4.0 | Plotting in datasource viewer |
| polars[pyarrow]>=1.9.0 | SQL output back in Python |
| sqlglot[c]>=23.4 | SQL cells parsing |
| openai>=1.55.3 | AI features |
| ruff | Formatting |
| nbformat>=5.7.0 | Export as IPYNB |
| vegafusion>=2.0.0 | Performant charting |
| vl-convert-python>=1.0.0 | Required by vegafusion |
marimo is a reinvention of the Python notebook. As a reinvention, marimo may push to you rethink what a notebook is. The following readings and videos might help you do just that.
To dive deep into what we're building and why, check out these readings:
- Our HackerNews launch, the second most upvoted Python ShowHN of all time
- Our r/machinelearning launch
- Lessons Learned Reinventing the Python Notebook
- Why Stanford Scientists Needed a New Notebook
- Reinventing Python Notebooks as Reusable Python Programs
- Representing Python Notebooks as Dataflow Graphs
- Nature: a Notebook for Reproducible Code
See our blog for more.
YouTube¶
Our YouTube channel shows you the ins and outs of using marimo for many applications, including AI, ML, data engineering, and more. You can also get started with the marimo concepts playlist, which tours many of our features.
You may also enjoy this video, which highlights some of the more advanced features that can really help you get the most out of marimo.
- marimo lets you rapidly experiment with data using Python, SQL, and interactive elements in a reproducible notebook environment.
- Unlike Jupyter notebooks, marimo notebooks are reusable software artifacts. marimo notebooks can be shared as as interactive web apps and executed as Python scripts.
Editing notebooks¶
marimo notebooks are reactive: they automatically react to your code changes and UI interactions and keep your notebook up-to-date, not unlike a spreadsheet. This makes your notebooks reproducible, eliminating hidden state; it's also what enables marimo notebooks to double as apps and Python scripts.
Working with expensive notebooks
If you don't want cells to run automatically, the runtime can be configured to be lazy, only running cells when you ask for them to be run and marking affected cells as stale. See our guide on working with expensive notebooks for more tips.
Create your first notebook. After installing marimo, create your first notebook with
[](#__codelineno-0-1)marimo edit my_notebook.py
at the command-line.
The marimo library. We recommend starting each marimo notebook with a cell containing a single line of code,
The marimo library lets you use interactive UI elements, layout elements, dynamic markdown, and more in your marimo notebooks.
How marimo executes cells¶
A marimo notebook is made of small blocks of Python code called cells. When you run a cell, marimo automatically runs all cells that read any global variables defined by that cell. This is reactive execution.
Execution order. The order of cells on the page has no bearing on the order cells are executed in: execution order is determined by the variables cells define and the variables they read.
You have full freedom over how to organize your code and tell your stories: move helper functions and other "appendices" to the bottom of your notebook, or put cells with important outputs at the top.
No hidden state. marimo notebooks have no hidden state because the program state is automatically synchronized with your code changes and UI interactions. And if you delete a cell, marimo automatically deletes that cell's variables, preventing painful bugs that arise in traditional notebooks.
No magical syntax. There's no magical syntax or API required to opt-in to reactivity: cells are Python and only Python. Behind-the-scenes, marimo statically analyzes each cell's code just once, creating a directed acyclic graph based on the global names each cell defines and reads. This is how data flows in a marimo notebook.
Minimize variable mutation.
marimo's understanding of your code is based on variable definitions and references; marimo does not track mutations to objects at runtime. For this reason, 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.
Learn more in our reactivity guide.
For more on reactive execution, open the dataflow tutorial
or read the reactivity guide. To visualize and understand how data flows through your notebook, check out our dataflow tools.
Visualizing outputs¶
marimo visualizes the last expression of each cell as its **ou
… [truncated — open the raw llms.txt above for the full file]
Meet the modern standard for public facing documentation. Beautiful out of the box, easy to maintain, and optimized for user engagement.
Search through billions of items for similar matches to any object, in milliseconds. It’s the next generation of search, an API call away.
Build and deploy reliable background jobs with no timeouts and no infrastructure to manage.
Get the simple developer experience of SQLite in production, and scale your multi-tenant backend with unlimited databases.
Upstash is a serverless data platform providing low latency and high scalability for real-time applications.
One-click deployments built for teams, tuned for Laravel, loaded with tools and goodies you're going to love.