JupyterLab 2.x to 3.x Extension Migration Guide

This is a migration guide for updating extensions that support JupyterLab 2.x to work in JupyterLab 3.x.

Upgrading library versions manually

To update the extensions so it is compatible with the 3.0 release, update the compatibility range of the @jupyterlab dependencies in the package.json. The diff should be similar to:

index 6f1562f..3fcdf37 100644
--- a/package.json
+++ b/package.json
   "dependencies": {
-    "@jupyterlab/application": "^2.0.0",
+    "@jupyterlab/application": "^3.0.0",

Upgrading library versions using the upgrade script

JupyterLab 3.0 provides a script to upgrade an existing extension to use the new extension system and packaging.

First, make sure to update to JupyterLab 3.0 and install jupyter-packaging and cookiecutter. With pip:

pip install jupyterlab -U
pip install jupyter-packaging cookiecutter

Or with conda:

conda install -c conda-forge jupyterlab=3 jupyter-packaging cookiecutter

Then at the root folder of the extension, run:

python -m jupyterlab.upgrade_extension .

The upgrade script creates the necessary files for packaging the JupyterLab extension as a Python package, such as setup.py and pyproject.toml.

The upgrade script also updates the dependencies in package.json to the ^3.0.0 packages. Here is an example diff:

index 6f1562f..3fcdf37 100644
--- a/package.json
+++ b/package.json
@@ -29,9 +29,13 @@
   "scripts": {
-    "build": "tsc",
-    "build:labextension": "npm run clean:labextension && mkdirp myextension/labextension && cd myextension/labextension && npm pack ../..",
-    "clean": "rimraf lib tsconfig.tsbuildinfo",
+    "build": "jlpm run build:lib && jlpm run build:labextension:dev",
+    "build:prod": "jlpm run build:lib && jlpm run build:labextension",
+    "build:lib": "tsc",
+    "build:labextension": "jupyter labextension build .",
+    "build:labextension:dev": "jupyter labextension build --development True .",
+    "clean": "rimraf lib tsconfig.tsbuildinfo myextension/labextension",
+    "clean:all": "jlpm run clean:lib && jlpm run clean:labextension",
   "clean:labextension": "rimraf myextension/labextension",
   "eslint": "eslint . --ext .ts,.tsx --fix",
   "eslint:check": "eslint . --ext .ts,.tsx",
@@ -59,12 +63,12 @@
   "dependencies": {
-    "@jupyterlab/application": "^2.0.0",
-    "@jupyterlab/apputils": "^2.0.0",
-    "@jupyterlab/observables": "^3.0.0",
+    "@jupyterlab/builder": "^3.0.0",
+    "@jupyterlab/application": "^3.0.0",
+    "@jupyterlab/apputils": "^3.0.0",
+    "@jupyterlab/observables": "^3.0.0",
   "@lumino/algorithm": "^1.2.3",
   "@lumino/commands": "^1.10.1",
   "@lumino/disposable": "^1.3.5",
@@ -99,6 +103,13 @@
-    "typescript": "~3.8.3"
+    "typescript": "~4.0.1"
   "jupyterlab": {
-    "extension": "lib/plugin"
+    "extension": "lib/plugin",
+    "outputDir": "myextension/labextension/"

On the diff above, we see that additional development scripts are also added, as they are used by the new extension system workflow.

The diff also shows the new @jupyterlab/builder as a devDependency. @jupyterlab/builder is a package required to build the extension as a federated extension. It hides away internal dependencies such as webpack, and produces the assets that can then be distributed as part of a Python package.

Extension developers do not need to interact with @jupyterlab/builder directly, but instead can use the jupyter labextension build command. This command is run automatically as part of the build script (jlpm run build).

For more details about the new file structure and packaging of the extension, check out the extension tutorial: Let’s Make an Astronomy Picture of the Day JupyterLab Extension

Publishing the extension to PyPI and conda-forge

Starting from JupyterLab 3.0, extensions can be distributed as a Python package.

The extension tutorial provides explanations to package the extension so it can be published on PyPI and conda forge: Publishing your extension.


While publishing to PyPI is the new recommended way for distributing extensions to users, it is still useful to continue publishing extensions to npm as well, so other developers can extend them in their own extensions.