I’ve been using Jupyter Notebooks for years - it’s been my go-to tool for data analysis and exploratory work. But recently, I came across Marimo, and it made me rethink some of the pain points I’ve experienced with Jupyter. You know those moments when you’ve run cells out of order and your notebook is in some weird state that you can’t reproduce? Or when you’re trying to review git diffs on a notebook file and it’s just a mess of JSON? Marimo promises to solve these issues and more.
In this post, I’ll share my comparison of both tools based on my experience. If you’re wondering which one to use for your workflow, this guide will help you decide.
What Are These Tools?
Before diving into the comparison, let me give you a quick overview of what these tools are.
Jupyter Notebooks
If you’ve done any data science work in the past decade, you’ve probably used Jupyter. It’s an interactive computing environment that lets you create documents with live code, visualizations, and narrative text all in one place. Created in 2014 as part of the IPython project, it’s become the industry standard. Notebooks are stored as JSON files with the .ipynb extension and run in a web-based interface (though VS Code has excellent support for them too!).
Marimo
Marimo is a more recent open-source reactive notebook for Python that takes a different approach. The key difference? Marimo notebooks are stored as pure Python files (.py), which means they’re git-friendly, executable as scripts, and deployable as web apps. The reactive execution model is particularly interesting - when you change a variable in one cell, all dependent cells automatically re-run. This eliminates those frustrating “hidden state” issues I mentioned earlier.
What They Have in Common
Despite their differences, both tools share the core features that make notebooks so useful for data science work:
- Interactive Execution: Write code in cells and see results immediately - this is the bread and butter of exploratory data analysis
- Rich Output Support: Display plots, tables, images, and interactive widgets right alongside your code
- Markdown Support: Write documentation and explanations using Markdown - essential for making your analysis understandable
- Data Visualization: Both work seamlessly with popular libraries like Matplotlib, Plotly, and Seaborn
- VS Code Integration: Both have excellent VS Code extensions, which is great if you prefer working in your favorite editor (like I do!)
- Package Management: Standard Python package management with pip, uv, poetry, conda - whatever you prefer
- Export Capabilities: Export your work to HTML, PDF, and other formats for sharing
The Key Differences
Here’s where things get interesting. Let me walk you through the main differences I’ve noticed.
1. Execution Model
This is the biggest difference and honestly the one that made me pay attention to Marimo.
Jupyter: Uses a linear execution model, but here’s the catch - you can run cells in any order. This flexibility is great for experimentation, but it can lead to some confusing situations. I can’t count how many times I’ve run Cell 1, then jumped to Cell 3, then back to Cell 2, and ended up with a notebook state that doesn’t match what someone else would see running it top to bottom. It’s one of those things you learn to work around, but it’s definitely a pain point.
Marimo: Takes a completely different approach with reactive execution. When you change a variable in one cell, all dependent cells automatically re-run. Think of it like a spreadsheet - change one cell and everything that depends on it updates. This keeps your code, outputs, and program state consistent. No more “wait, why isn’t this working?” moments when you realize you forgot to re-run a cell.
# In Jupyter: This can cause inconsistencies
# Cell 1: x = 5
# Cell 2: y = x * 2
# If you go back and change Cell 1 to x = 10, Cell 2 doesn't update automatically
# In Marimo: Changing x automatically re-runs all cells that depend on it
2. File Format and Version Control
This is where Marimo really shines, especially if you’re working in a team environment.
Jupyter: Stores notebooks as JSON files (.ipynb). If you’ve ever tried to review a Jupyter notebook in a git diff, you know what I’m talking about - it’s a mess. The JSON format includes your code, outputs, metadata, and sometimes embedded media. This makes diffs noisy and merge conflicts nearly impossible to resolve without opening the notebook. I’ve had to choose “accept theirs” or “accept mine” more times than I’d like to admit because I couldn’t make sense of the conflict.
Marimo: Stores notebooks as pure Python files (.py). Just regular Python code that you can read, diff, and merge like any other Python file. Want to see what changed? The git diff actually makes sense. Need to resolve a merge conflict? Use your normal merge tools. Plus, you can execute the notebook as a regular Python script: python notebook.py. This is a game-changer for version control and collaboration.
3. State Management
This ties back to the execution model, but it’s worth highlighting separately because it’s such a common source of bugs.
Jupyter: You can define the same variable multiple times across different cells, and the order you run them matters. Here’s a scenario I’ve hit countless times:
# You run this sequence:
x = 10 # Cell 1
print(x) # Cell 2: prints 10
x = 20 # Cell 3
# Now you go back and rerun Cell 2 without running Cell 3
# It prints 20! But someone reading your notebook top to bottom would expect 10
This is confusing and makes notebooks hard to reproduce. You end up with different results depending on the order you executed cells.
Marimo: The reactive execution model handles this elegantly. When you change a variable in any cell, all downstream cells that depend on it automatically re-run:
# Define x in Cell 1 and use it in Cell 2:
x = 10 # Cell 1
print(x) # Cell 2: prints 10
# Change Cell 1 to x = 20? Cell 2 automatically re-runs and prints 20
# The dependency graph keeps everything synchronized
No more hidden state, no more confusion about what value a variable actually has.
4. Deployment
Jupyter: It’s primarily designed for interactive development and exploration. If you want to turn your notebook into a web app, you’ll need additional tools like Voila or Streamlit. It’s not impossible, but it’s an extra step.
Marimo: Here’s something cool - every Marimo notebook can be instantly deployed as an interactive web app:
marimo run notebook.py
That’s it. Your notebook becomes a web app that others can interact with. This dual-purpose design is pretty elegant - use it as a notebook during development, then deploy it as an app for others to use.
What Each Tool Does Best
Let me break down the strengths of each tool based on what I’ve found works well.
Why Jupyter Still Rocks
- Mature Ecosystem: Ten years of development means there’s a plugin or integration for almost anything you need. The community is huge and active.
- Everyone Knows It: When you join a new team, chances are they’re already using Jupyter. There’s no learning curve for your collaborators.
- Rich Extension Support: Thousands of extensions for specialized workflows - whatever niche thing you need to do, someone’s probably built an extension for it.
- Cloud Options Everywhere: Google Colab, JupyterHub, Azure Notebooks - if you want to run notebooks in the cloud, Jupyter has you covered with established, reliable options.
- Multi-Language Support: Need to work with R, Julia, or Scala? Jupyter supports 40+ programming languages through different kernels. It’s not just Python.
- Learning Resources: If you get stuck, there are countless tutorials, courses, Stack Overflow answers, and documentation to help you out.
- Flexibility for Exploration: Being able to run cells in any order is actually useful when you’re debugging or exploring data interactively. Sometimes you need that freedom.
Why Marimo is Exciting
- True Reproducibility: Your notebook’s state is always consistent. If it runs on your machine, it’ll run the same way on someone else’s. No more “works on my machine” situations with notebooks.
- Git-Friendly: Plain Python files mean meaningful diffs and manageable merge conflicts. This alone makes Marimo worth considering if you’re working in a team.
- No Hidden State: The reactive execution model eliminates those frustrating debugging sessions where you can’t figure out why something isn’t working.
- Modern Development Features Built In:
- Ruff code formatting out of the box
- Fast code completion
- SQL cell support for database work
- Notebook and App in One: Develop interactively, then deploy the same file as a web app. No conversion needed.
- Works with Your Tools: Compatible with pip, uv, poetry, conda - use whatever package manager you prefer.
- Cleaner Mental Model: Once you get used to reactive execution, it actually makes more sense than manually tracking which cells to re-run.
- Interactive UI Elements: Sliders, dropdowns, and other UI elements automatically sync with your Python code. Great for building interactive dashboards.
Getting Started
Alright, enough theory - let’s get these tools set up! I’ll show you how to get both Jupyter and Marimo running in VS Code using UV (my current favorite Python package manager).
Setting Up Jupyter in VS Code
-
Install Required Extensions:
-
Install UV (Modern Python Package Manager):
brew install uv -
Initialize Your Project:
uv init echo "3.13" > .python-version -
Install Jupyter and Dependencies:
uv add jupyter ipykernel notebook uv add matplotlib pandas numpy uv sync -
Create and Run Notebooks:
- Open Command Palette (
Ctrl+Shift+PorCmd+Shift+P) - Type “Jupyter: Create New Blank Notebook”
- Select your kernel from the kernel picker in the top right
- Start coding!
- Open Command Palette (
For detailed setup instructions and troubleshooting, check out my complete guide on using Jupyter Notebooks in VS Code.
Setting Up Marimo in VS Code
-
Install Required Extensions:
-
Install UV (if not already installed):
brew install uv -
Install Marimo Globally (Recommended):
Marimo can be installed globally using UV’s tool installation feature, making it available across all your projects:
uv tool install marimoThis is a one-time installation. After this, you can use
marimocommands directly from anywhere without needing to add it to each project. -
Initialize Your Project:
uv init echo "3.13" > .python-version -
Install Project Dependencies:
uv add matplotlib pandas numpy uv sync -
Create and Run Marimo Notebooks:
Option 1: Using CLI (with global install)
# Create a new notebook marimo edit notebook.py # Run an existing notebook as an app marimo run notebook.pyOption 2: Using VS Code
- Create a new
.pyfile - Open it with the Marimo extension
- Start adding cells using the Marimo UI
- Create a new
Alternative: Per-Project Installation
If you prefer to install Marimo per-project rather than globally:
uv add marimo
uv sync
# Then run using uv run prefix
uv run marimo edit notebook.py
uv run marimo run notebook.py
So Which One Should You Use?
Here’s my take on when to use each tool, based on my experience with both.
Stick with Jupyter If:
- Your team already uses it: Don’t be the person who forces everyone to learn something new unless there’s a really good reason. If your team is productive with Jupyter, that’s what matters.
- You need multi-language support: Working with R, Julia, or other languages? Jupyter’s got you covered, Marimo is Python-only.
- You rely on specific extensions: If your workflow depends on particular Jupyter extensions or widgets, you’ll need to stay with Jupyter or find alternatives.
- You’re teaching or learning: Jupyter is what most courses and tutorials use. If you’re creating educational materials, stick with what your audience knows.
- You love Google Colab: If you’re heavily invested in Colab or other cloud Jupyter services, there’s no Marimo equivalent yet.
- Flexibility matters more than reproducibility: Sometimes you really do need to run cells out of order for debugging or exploration, and that’s okay.
Give Marimo a Try If:
- You’re tired of hidden state issues: If you’ve been burned by out-of-order execution one too many times, Marimo will feel like a breath of fresh air.
- Version control is important: Working in a team with git? Marimo’s plain Python files will make your life so much easier.
- You want to deploy notebooks as apps: The ability to turn a notebook into a web app with one command is genuinely useful.
- You’re starting fresh: New project with no legacy constraints? This is the perfect time to try something new.
- SQL + Python is your jam: The built-in SQL cell support is really nice if you work with databases frequently.
- Reproducibility is non-negotiable: If your work needs to be reproducible for compliance, research, or just peace of mind, Marimo’s execution model is a big win.
You Can Use Both!
Here’s the thing - you don’t have to choose just one. I currently use:
- Jupyter for quick experiments, exploratory work, and when collaborating with teams that use it
- Marimo for projects that need to be reproducible, anything I’m putting in git, and notebooks I want to share as web apps
Different tools for different jobs. That’s perfectly fine.
Wrapping Up
Both Jupyter and Marimo are excellent tools - they just solve different problems. Jupyter gives you a mature ecosystem, widespread adoption, and the flexibility to work however you want. It’s reliable, it’s everywhere, and it’s not going anywhere. Marimo brings fresh ideas to the table with reactive execution, git-friendly files, and built-in deployment. It solves real pain points that I’ve experienced with Jupyter over the years.
My honest recommendation? If you’re happy with Jupyter and it’s working for your team, there’s no urgent need to switch. But if you’ve been frustrated by hidden state issues, messy git diffs, or the hassle of deploying notebooks, give Marimo a try on a side project. The worst that happens is you learn about a different approach to notebooks. The best that happens is you find a tool that clicks with your workflow.
The good news is that both integrate beautifully with VS Code and modern Python tooling like UV, so you can experiment with both and see what works best for you.
Happy coding!