Library / SDK
ipyflow/ipyflow avatar
ipyflow/ipyflow

IPyflow: a reactive kernel for Jupyter notebooks that re-runs what your edit invalidated

A reactive Python kernel for Jupyter notebooks.

1,275 stars25 forksPythonBSD-3-Clause

At a glance

What is it?
IPyflow tracks dataflow between cells and symbols inside a live Jupyter session, then re-executes the minimal set of stale cells. It is a drop-in ipykernel replacement, but reactivity is opt-in and the dependency inference has limits.
Who is it for?
Adopt IPyflow if you run long notebooks where a hidden stale variable has already cost you a debugging session, or if you want to see cell dependencies before you execute anything. Do not adopt it if you need deterministic, fully offline dependency analysis, or if your workflow depends on executing cells in an order the notebook author never intended.
Can I use it commercially?
Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 20 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The stale-variable problem IPyflow is built around

Notebook state is a function of execution order, not of the code you can see on screen. You define x in cell 2, mutate it in cell 7, then edit cell 2 and re-run it. Cell 7 still holds the old value. The output looks plausible and is wrong. This is the failure mode IPyflow targets.

The README states the invariant directly: whenever you execute a cell, the resulting output should appear as it would if you had performed a restart plus run-all. The project calls this "fearless execution." The audience is Jupyter users who already understand that out-of-order execution is the price of the notebook model and want that price reduced without abandoning JupyterLab or Notebook 7 for a different notebook format.

IPyflow is not a new notebook environment. It is a kernel plus a frontend extension, and the README describes it as a drop-in replacement for ipykernel that provides a strict superset of ipykernel's features.

How the dataflow tracking actually works in a live session

The mechanism is runtime observation, not static parsing. IPyflow watches symbols as they are defined and referenced during execution, and records which cells produced or consumed them. Because it peeks at runtime state, the README notes that the kernel needs to keep the notebook content in sync with kernel memory even across browser refreshes, which is why autosave-on-change is enabled by default.

The dependency model goes past whole variables. The README gives the example of a subscript reference: if cell B reads x[0], IPyflow records a dependency on that element, and a change to x[1] does not trigger B. That precision is the difference between a reactive notebook that is usable and one that re-runs half the document on every keystroke.

Dependency information is persisted into notebook metadata. The README describes the consequence: after starting a fresh kernel, you can jump to any cell, run it, and be confident the output matches what the notebook author intended. That persistence is what makes the feature survive a restart, which a purely in-memory graph would not.

Even with reactivity off, the JupyterLab extension color-codes cells. Selecting a cell marks cells that would re-execute with an orange dot, and up-to-date upstream cells with purple dots. This is arguably the most useful part of the project for a skeptical user, since it shows the inferred graph before you trust it with execution.

Installing IPyflow and running your first reactive cell

Installation is a single pip command, per the README. The package pulls in ipyflow-core and the Jupyter stack, including jupyterlab>=3.0, nbclassic and notebook, according to requirements.txt.

bash
pip install ipyflow

After installation, open JupyterLab or Notebook 7 and pick the kernel from the launcher. The README names it "Python 3 (ipyflow)". For an existing notebook, use the "Change kernel" menu item instead.

Reactive execution is opt-in. By default, IPyflow behaves like a normal kernel and runs only the cell you execute. To reactively run one cell together with its dependents without changing the default mode, use ctrl+shift+enter, or cmd+shift+enter on Mac.

To make reactivity the default for the session, run the magic command in a cell.

python
%flow mode reactive

The README states that in reactive mode, executing cell C causes C's output, the outputs of the cells C depends on, and the outputs of the cells that depend on C to all appear as they would under restart and run-all.

If a reactive execution overwrites an output you wanted, the package exposes a recovery helper. The README gives this example, which reproduces the previous execution of cell 4.

python
from ipyflow import reproduce_cell
reproduce_cell(4, lookback=1)

Where the reactivity model breaks down

The dependency graph is inferred from what happened at runtime, so it only knows what it has seen. A cell that has never been executed in the current kernel session contributes nothing to the graph, and the README's own framing of the persisted metadata is about recovering intent after a restart, not about deriving dependencies from source alone. If your workflow is to write all cells first and execute them once, the graph is empty until you start running things.

Autosave-on-change being the default is a real trade-off, not a neutral convenience. It exists because the kernel must stay in sync with the file, but it means the notebook on disk changes without you asking. The reproduce_cell helper is the mitigation, and its signature takes a cell index and a lookback count, which implies you need to know which execution you want back. That is workable, not free.

Precision has a cost too. Tracking subscript-level dependencies requires observing container access, and the README does not document the overhead of that observation. Nothing in the repository files given here quantifies it.

The project also assumes you want Jupyter. It ships a JupyterLab extension and a Notebook 7 kernel, and the README positions it against Observable, Pluto.jl and Marimo as notebooks with different execution semantics. If you have already decided that reactive-by-default notebooks are the right model, those tools make reactivity a property of the document rather than an opt-in mode on top of ipykernel. IPyflow's bet is the opposite one: keep the notebook format and the kernel interface, and add reactivity as a layer you can switch on and off.

Choosing between IPyflow and a reactive notebook from scratch

The closest comparison in the README is Marimo, alongside Observable and Pluto.jl. The difference is architectural rather than cosmetic. Marimo and Pluto.jl treat the notebook as a dependency graph and make reactivity the default execution model, so a stale cell is not representable in the first place. IPyflow keeps .ipynb files and the ipykernel protocol, and adds a dataflow layer that can be toggled with %flow mode reactive.

That means the migration cost is near zero in one direction and non-trivial in the other. You can install IPyflow, keep your existing notebooks, and disable reactivity when it gets in the way. You cannot take an IPyflow notebook and get the same guarantees in a tool that never recorded the dependency metadata, because the metadata lives in the notebook file only after IPyflow has written it.

The other axis is precision. IPyflow's subscript-level tracking is a deliberate attempt to avoid over-execution, and the README frames limiting unnecessary re-execution as a design goal. A graph-based notebook that re-runs every dependent on every change has no equivalent problem, because it never tries to run a subset.

Maintenance, licence and the upgrade path

The repository is not archived, and the last push was on 2026-09-10. Releases are frequent but the version numbers are pre-1.0: 0.0.228 on 2026-06-11, with 0.0.217 and 0.0.212 both on 2025-11-22. The 0.0.x line means the API and the dependency metadata format should be treated as movable.

The packaging split matters for upgrades. requirements.txt pins ipyflow-core==0.0.231 while the root package version is driven by versioneer. The Makefile's devdeps target carries an explicit warning about this: installing the root pins ipyflow-core to the released version on PyPI, so the local checkout has to be reinstalled editable last. Expect the same ordering issue if you vendor or patch the core.

The licence is BSD-3-Clause, per the repository and the README badge. That is a permissive licence, and the practical implication is that redistribution and modification are allowed provided the copyright notice and licence text are retained; the LICENSE.txt file is the authoritative text. This is not legal advice, and if you are redistributing the bundled JupyterLab extension assets you should read the licence file rather than this paragraph.

Upgrade cost is mostly the frontend. setup.py installs the labextension under share/jupyter/labextensions/jupyterlab-ipyflow and the kernel spec under share/jupyter/kernels/ipyflow, so a version bump can require rebuilding the extension assets, not just restarting the kernel.

Editorial conclusion

Adopt IPyflow if you run long notebooks where a hidden stale variable has already cost you a debugging session, or if you want to see cell dependencies before you execute anything. Do not adopt it if you need deterministic, fully offline dependency analysis, or if your workflow depends on executing cells in an order the notebook author never intended. Before switching a real project, run the notebook once with the ipyflow kernel and check the orange and purple dots on a few cells: they tell you whether the inference matches how you actually use the notebook.

Frequently asked questions

Is IPyflow a replacement for ipykernel?

The README describes it as a drop-in replacement for ipykernel that provides a strict superset of its features, with full backwards compatibility as a stated goal. You select it as a kernel rather than installing it alongside a different execution model.

Does IPyflow re-run cells automatically by default?

No. The README states that reactivity is opt-in and that by default IPyflow uses normal, non-reactive execution and runs only the cell you execute. You can enable it for one execution with ctrl+shift+enter, or for the session with %flow mode reactive.

Can IPyflow recover an output that a reactive execution overwrote?

The README documents a library utility called reproduce_cell that recovers the input and output of previous cell executions within a given kernel session, using a cell index and a lookback argument.

How do I install IPyflow?

The README gives a single command, pip install ipyflow, after which you pick the Python 3 (ipyflow) kernel from the JupyterLab or Notebook 7 launcher, or switch to it from the Change kernel menu.

Official sources

  1. ipyflow/ipyflow on GitHub
  2. Issues
  3. License: BSD-3-Clause
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/ipyflow-ipyflow.svg)](https://hysenlabs.com/projects/ipyflow-ipyflow)