Deepnote research: our notes on building agents
Get started

Understanding notebook dependencies with the Deepnote CLI

See how the blocks of a Deepnote notebook depend on each other, find what to re-run after a change, run a block with only what it needs, and draw the dependency graph with deepnote dag and analyze

Every block in a notebook reads some variables and defines others. The Deepnote CLI works out those links from the code itself, so you can answer the questions that make long notebooks hard to work with: what does this block need?, what breaks if I change it? and what do I actually have to re-run?

It is the same idea behind the Block and dependent blocks execution mode in Deepnote, which runs a block together with the blocks below it that depend on it.

All commands work on local .deepnote files and need a Python 3 interpreter that can import jinja2 (deepnote-toolkit installs it); see Deepnote CLI for installation.

See the whole graph

deepnote dag show analysis.deepnote
Dependency Graph (5 blocks, 3 edges)

├── import pandas as pd [code]
│   defines: orders
│   └─► by_country = orders.groupby("country").revenue.su… [code] via orders
│       defines: by_country
│       └─► total = by_country.sum() [code] via by_country
│           defines: total
│           └─► print(total) [code] via total
└── unrelated = 42 [code]
    defines: unrelated

Each arrow names the variable that connects two blocks. Blocks with nothing above them are entry points; a block on its own, like unrelated = 42 here, is a candidate for deleting or moving to its own notebook.

To get a picture for a design review or documentation, render it with Graphviz:

deepnote dag show analysis.deepnote -o dot | dot -Tsvg -o dependencies.svg

What each block reads and defines

deepnote dag vars analysis.deepnote
by_country = orders.groupby("country").revenue.su… (code)
  Defines: by_country
  Uses: orders

Use it to find where a variable comes from, or which blocks still use a column or table you want to rename.

What to re-run after a change

deepnote dag downstream analysis.deepnote --block "by_country = orders.groupby(\"country\").revenue.su…"
Downstream Impact for by_country = orders.groupby("country").revenue.su…

2 blocks will need to re-run:

  • total = by_country.sum() (code)
  • print(total) (code)

--block takes a block id or the block's label as shown by dag show. Before you change a block that loads or cleans data, this tells you which charts, tables and exports downstream will change with it. -o json returns the same list with block ids, for scripts and AI agents.

Run a block with only what it needs

deepnote run --block runs a block together with the blocks its variables come from. Preview the plan with --dry-run:

deepnote run analysis.deepnote --block <block-id> --dry-run
Execution Plan (dry run)
──────────────────────────────────────────────────
[1/3] import pandas as pd
[2/3] by_country = orders.groupby("country").revenue.su…
[3/3] total = by_country.sum()
──────────────────────────────────────────────────
Total: 3 block(s) would be executed

Blocks outside the target block and the blocks it depends on, directly or through another block, are skipped. The analysis also links a block to the nearest earlier block that uses one of the same variables, so a block that only reads orders, such as an export, can still be part of the plan. Review the plan before running a block next to ones with side effects, such as writes to a database.

Imports are not followed: a block that only imports modules, such as import pandas as pd on its own, is left out even when the target uses pd, and the run fails with NameError. Put imports in the block that uses them, or in a block that also defines a variable the target needs.

In Deepnote Cloud, the API can do the reverse: run selected blocks and everything that depends on them with runDependentBlocks.

A health check for the whole notebook

deepnote analyze analysis.deepnote

analyze combines the graph with deepnote lint into one report: a quality score, the number of blocks and lines of code, entry and exit points, the longest chain of dependent blocks, imported packages, and any issues such as unused variables. A long chain or many disconnected blocks is a sign a notebook would be easier to work with split into several notebooks.

For AI agents

All of these commands accept -o json and -o llm, so a coding agent can check what a change affects before making it and run only what it needs afterwards. deepnote install-skills teaches agents such as Claude Code, Codex and Cursor to use them; see Deepnote CLI.

Limitations

The analysis reads Python and SQL source without running it, so it cannot see dependencies created at run time, for example variables set through globals(), exec or a %run of another file. A name that is never defined in the notebook, such as spark provided by the environment, links the blocks that use it, and the first of them is shown as defining it.

Related