nbdev1 Migration

How to change your nbdev1 repo to work with nbdev2

v3.3: Directives and notebook tools

Existing notebooks need no changes. Directives now accept values with or without a colon: #| default_exp: core, #| default_exp:core, and #| default_exp core are equivalent. Previously, the wrong delimiter could fail silently. A bare directive means true, making #| hide equivalent to #| hide: true.

You can put directives in cell metadata under an nbdev key. {"nbdev": {"hide": "true", "eval": "false"}} has the same effect as the corresponding comments. Values must be strings. JSON booleans raise an error. Notebook-level directives such as default_exp can use this format in notebook metadata. Comments take precedence over metadata.

Extension authors need to update their code:

  • Replace nbdev.process.extract_directives with the cell’s directives property. Use cell.remove_directives() to strip directives from source.
  • In cell.directives_, keys no longer have trailing colons. Values are raw strings, with '' for a bare directive. For example, directives_['eval:'] == ['false'] becomes directives_['eval'] == 'false'.

Processor methods still receive whitespace-split positional arguments.

nbdev-clean now repairs structural problems by default, including stray outputs attributes on Markdown cells. Git and Jupyter save hooks perform these repairs too. A previously invalid notebook will show a one-time diff. Use --repair false to disable repairs.

Migration options require an explicit command. Hooks never use them:

  • --dirs rewrites comment directives in canonical form.
  • --to-meta and --to-comments move named directives between comments and cell metadata.
  • --nb-meta moves default_exp into notebook metadata.

nbdev-install-hooks installs a diff driver for cell-by-cell notebook diffs (see nbdev.diff). Use --merge false or --diff false to disable either driver’s installation. --globally installs to ~/.gitconfig and the global attributes file instead of the current repo.

Both drivers now use the name jupyternotebook, matching nbdime. A committed .gitattributes therefore uses each collaborator’s configured driver. Existing nbdev-merge and nbdev-diff installations still work. Run nbdev-install-hooks again to adopt the new name. Its appended attributes take precedence over the old entries.

To view the same diff between two refs without changing Git configuration, use nbdev-diff.

🛑Jan 2026 Major Version Update – Breaking Change🛑

nbdev3 is here! As many of you have been requesting, configuration has moved from settings.ini to pyproject.toml, following modern Python packaging standards (PEP 621). Your project metadata now lives in the standard [project] section, while nbdev-specific settings go in [tool.nbdev].

Migrating from nbdev2: Run nbdev-migrate-config in your project root to automatically convert your settings.ini to pyproject.toml and update your GitHub Actions workflows to use nbdev3-compatible versions. Your existing notebooks and code don’t need any changes.

Status of this document: The rest of this doc describes migration from the very old nbdev1 to nbdev2, and is not likely to be relevant to most folks who haven’t been frozen in tundra for the last few years.

Nbdev2 - Initial setup

nbdev v2 is a new from-scratch rewrite of nbdev that’s not backwards compatible. This page describes the changes you need to make to upgrade your nbdev v1 repo to work with the new version. The steps shown here should work on macOS or Linux (including Windows WSL)

The biggest change is that nbdev2 uses Quarto to generate your website, whereas nbdev1 used nbconvert and jekyll. You can use all of Quarto’s features directly in nbdev, so checkout the Quarto website to see all the amazing functionality it supports.

If you’ve pinned nbdev in requirements.txt or pyproject.toml (e.g nbdev<2) remove the version pin. (If you don’t know what this means, then you don’t have it, so you can ignore this step).

Install the latest version of nbdev by typing:

pip install -U nbdev

or:

conda install -c fastai nbdev

You may need to restart your terminal for the new commands to be visible to your shell.

Upgrade directives

nbdev2 uses #| for directive comments to match Quarto’s syntax. For example, replace #export with #| export. A space after #| is optional.

To automatically upgrade your directives to the new format, run in the root of your repo:

nbdev-migrate

You should now test that you can export your module by running:

nbdev-export

Note that nbdev-export replaces nbdev_build_lib. Run nbdev-export -h to see the options you can pass to it (normally you won’t need to pass any). To see a list of all the commands available in nbdev2, run nbdev-help.

Add and remove files

First set a variable with the name of your library, by running the following (replacing “yourlib” with the name of your library’s subdirectory)

export LIBNAME=yourlib

Now run the following:

git rm Makefile
git add $LIBNAME/_modidx.py
rm -rf docs
rm -f .gitconfig 
rm -f .git/hooks/post-merge

rm -f setup.py
curl -O https://raw.githubusercontent.com/fastai/nbdev3-template/master/styles.css
curl -O https://raw.githubusercontent.com/fastai/nbdev3-template/master/setup.py

cat >>.gitignore <<EOF
_docs/
_proc/
EOF

As you see above, we’ve remove the Makefile – that’s because all the things done by make before are now handled by nbdev commands directly.

Note

All documentation related files should be included in your nbs_path, and all paths should be relative to it. If you have set the nbs_path in your pyproject.toml, then copy your styles.css file inside of your nbs_path folder.

If you use GitHub Actions for continuous integration (CI) you can update this to use nbdev too as follows:

rm -f .github/workflows/main.yml
curl -O https://raw.githubusercontent.com/fastai/nbdev3-template/master/.github/workflows/test.yaml
curl -O https://raw.githubusercontent.com/fastai/nbdev3-template/master/.github/workflows/deploy.yaml
mv deploy.yaml test.yaml .github/workflows/

Update directive names

A number of directives have changed names. We’ll use perl to fix them. Run these lines in the root of your repo:

find . -name '*.ipynb' -exec perl -pi -e 's/#\|\s*hide_input/#| echo: false/' {} +
find . -name '*.ipynb' -exec perl -pi -e 's/#\|\s*hide_output/#| output: false/' {} +
find . -name '*.ipynb' -exec perl -pi -e 's/#\|\s*skip/#| eval: false/' {} +
find . -name '*.ipynb' -exec perl -pi -e 's/from nbdev.export import notebook2script/from nbdev import nbdev_export/' {} +
find . -name '*.ipynb' -exec perl -pi -e 's/notebook2script/nbdev_export/' {} +

These change the following directives to use functionality built into Quarto:

  • hide_input –> echo: false
  • hide_output –> output: false
  • skip –> eval: false

They also update the new location and name of the nbdev_export python function.

If you used all_slow to skip a notebook in nbdev1, add YAML frontmatter in a raw cell at the top of that notebook, or update its existing frontmatter.

  • skip_showdoc: true skips execution when rendering docs.
  • skip_exec: true skips the notebook when running tests.

To skip both, use:

---
skip_showdoc: true
skip_exec: true
---

Or you can also add these flags in a markdown cell,

# title
> description

- skip_showdoc: true
- skip_exec: true

Edit Workflow Permissions

Make sure your workflow permissions are set to “Read and write permissions”, which you can find in Settings → Actions → General → Workflow permissions:

GitHub Pages settings
Important

Failure to set the correct permissions may result in an error message like this:

 fatal: unable to access 'https://github.com/user/repo.git/': The requested URL returned error: 403
  Error: Action failed with "The process '/usr/bin/git' failed with exit code 128"

Edit GitHub Pages Permissions

At this point you will want to commit the files with the changes you made to GitHub. Wait for GitHub Actions to run and pass. A new branch in your repo will automatically be created called gh-pages. You want to enable GitHub Pages to work off this branch by configuring your Pages to settings to look like this:

Access this screen under Settings → Pages

  • Select “Deploy from a branch” in the drop down list for Source.
  • Specify gh-pages as the branch
  • Specify the /root as the location
  • Click save

Actions workflow permissions

Final steps

You should now edit pyproject.toml, and change doc_path from docs to _docs in [tool.nbdev], since that’s where nbdev2 will build your website.

If you use a custom domain for your website, you should move your CNAME file into the directory containing your notebooks.

Before pushing to GitHub, check that your website looks OK locally by running:

nbdev-preview

Now prepare to commit to GitHub:

nbdev-prepare

You can now commit to GitHub as usual. Finally, update Github Pages by clicking on the Settings tab in your repo, then click Pages on the left side bar. Set “Source” to gh-pages branch and the /root folder.