Runtime Configuration Files

The behavior JupyterLite in the browser can be controlled by creating specially-named files at any level of the file tree. It is expected each file conforms to the schema. For an example, see the demo configuration.


Config Location






integrates into existing Jupyter workflows


whole file


good for simple/automated configuration




configuration of last resort, not recommended

Each can be omitted from the file tree, and will result in a harmless (though noisy) 404 response.


Configuration cascades down, such that the closest, most-user-editable file to the index.html being served takes highest precedence. Like-named keys will be replaced by higher-priority files, with the notable exceptions of:

  • the federated_extensions and disabledExtensions lists are appended and deduplicated

  • the settingsOverrides dictionary will be merged at the top level of each plugin



The current schema version is 0, and as such is subject to change. Once it has stabilized, we hope to provide similar backwards-compatibility guarantees as the Jupyter Notebook Format.

As the schema provides many options, please see the dedicated pages below.

Adding Content

Content with the CLI

With the CLI installed, run

jupyter lite build

…any contents of {lite-dir}/files/ (and any added --contents) will be:

  • copied to the built site under {output-dir}/files/

    • may have timestamps changed if --source-date-epoch is provided.

  • indexed to provide {output-dir}/api/contents/{subdir?}/all.json

Adding Extensions

JupyterLab 3 federated extensions allow for adding new capabilities to JupyterLite without rebuilding the entire web application. A good starting point for extensions that might work is the JupyterLab issue Extension Compatibility with 3.0 (#9461). Additionally, this site demonstrates a few extensions.

Extensions with the CLI

Environment Extensions

When you jupyter lite build, all federated extensions in your JupyterLab environment, e.g. {sys.prefix}/share/jupyter/labextensions will be:

  • copied to {output-dir}/lab/extensions

  • have its theme information copied to {output-dir}/{app/?}theme/

Extensions for a Specific App

Similar to the above, by updating $YOUR_JUPYTERLITE/{app}/jupyter-lite.json, the federated extensions will only be avaialable for pages within that file tree.

Custom Extensions

By placing extensions under {lite-dir}/lab/extensions/{org/?}{package}/, these will also be copied into the output-dir after any environment extensions, and all will be added to {output-dir}/jupyter-lite.json#jupyter-config-data/federated_extensions.


For example, after building a lab extension, you can copy the contents of packages.json#/jupyterlab/outputDir right into the lite-dir to preview your extension.

Customizing Settings

With the CLI, if you create an overrides.json in either the root, or a specific app directory, these will be:

  • merged into {output-dir}/{app?}/jupyter-lite.json#/jupyter-config-data/settingsOverrides

About the Demo

This documentation site contains the JupyterLite Demo (the Try buttons on the top of the screen) and uses a number of techniques described on this page.

Demo Configuration

The following generated configuration powers the Demo, and is generated prior to building the docs site, copied in during the build, and fetched by browsers from /_static/jupyter-lite.json.

{ “jupyter-config-data”: { “appName”: “JupyterLite Examples”, “appUrl”: “./lab”, “appVersion”: “0.1.0-alpha.14”, “baseUrl”: “./”, “collaborative”: true, “disabledExtensions”: [ “@jupyterlab/server-proxy”, “jupyterlab-server-proxy”, “nbdime-jupyterlab” ], “faviconUrl”: “./lab/favicon.ico”, “federated_extensions”: [ { “extension”: “./extension”, “liteExtension”: false, “load”: “static/remoteEntry.f6574b55a223d23e7a04.js”, “name”: “@jupyter-widgets/jupyterlab-manager” }, { “liteExtension”: false, “load”: “static/remoteEntry.9c506278e545a18a8cc2.js”, “mimeExtension”: “./mimeExtension”, “name”: “@jupyterlab/fasta-extension”, “style”: “./style” }, { “liteExtension”: false, “load”: “static/remoteEntry.a6d92e11d5e8c375cfe6.js”, “mimeExtension”: “./mimeExtension”, “name”: “@jupyterlab/geojson-extension”, “style”: “./style” }, { “extension”: “./extension”, “liteExtension”: true, “load”: “static/remoteEntry.4ba93726087006d2f61b.js”, “name”: “@jupyterlite/p5-kernel-extension”, “style”: “./style” }, { “extension”: “./extension”, “liteExtension”: false, “load”: “static/remoteEntry.c7d5ca84bbdfef35f278.js”, “name”: “@telamonian/theme-darcula” }, { “extension”: “./extension”, “liteExtension”: false, “load”: “static/remoteEntry.145e469029155b53b350.js”, “name”: “@timkpaine/jupyterlab_miami_nights” }, { “extension”: “./extension”, “liteExtension”: false, “load”: “static/remoteEntry.e9a229a6deef8e3c895b.js”, “name”: “bqplot” }, { “extension”: “./extension”, “liteExtension”: false, “load”: “static/remoteEntry.5459894d80c1201f22ae.js”, “name”: “ipycanvas” }, { “extension”: “./extension”, “liteExtension”: false, “load”: “static/remoteEntry.422e89a36ce1df74544d.js”, “name”: “jupyter-cytoscape” }, { “extension”: “./extension”, “liteExtension”: false, “load”: “static/remoteEntry.8c5efb3516d04e6a5bb7.js”, “name”: “jupyter-leaflet” }, { “extension”: “./extension”, “liteExtension”: false, “load”: “static/remoteEntry.a458e80b4361f068e82d.js”, “name”: “jupyter-matplotlib” }, { “extension”: “./extension”, “liteExtension”: false, “load”: “static/remoteEntry.8b2d16b6f8ed831ddea6.js”, “name”: “jupyter-vue” }, { “extension”: “./extension”, “liteExtension”: false, “load”: “static/remoteEntry.fcff606ae435a57ff541.js”, “name”: “jupyter-vuetify” }, { “extension”: “./extension”, “liteExtension”: false, “load”: “static/remoteEntry.8f896d6ad92823566c46.js”, “name”: “jupyterlab-drawio”, “style”: “./style” }, { “extension”: “./extension”, “liteExtension”: false, “load”: “static/remoteEntry.c6e727a2dea5913e60d7.js”, “name”: “jupyterlab-kernelspy”, “style”: “./style” }, { “extension”: “./extension”, “liteExtension”: false, “load”: “static/remoteEntry.7b0dfd91a418a1e7eb37.js”, “mimeExtension”: “./mimeExtension”, “name”: “jupyterlab-plotly” }, { “extension”: “./extension”, “liteExtension”: false, “load”: “static/remoteEntry.faa0ac63a9a4b6b01f44.js”, “name”: “jupyterlab-tour”, “style”: “./style” } ], “fullLabextensionsUrl”: “./lab/extensions”, “fullMathjaxUrl”: “”, “fullStaticUrl”: “./lab/build”, “mathjaxConfig”: “TeX-AMS_CHTML-full,Safe”, “settingsOverrides”: { “jupyterlab-tour:user-tours”: { “tours”: [ { “id”: “jupyter-lite”, “label”: “Welcome to JupyterLite”, “options”: {}, “steps”: [ { “content”: “This is JupyterLite”, “target”: “#jp-MainLogo” } ] } ] } }, “settingsUrl”: “./lab/build/schemas”, “themesUrl”: “./lab/build/themes” }, “jupyter-lite-schema-version”: 0 }

Demo Extension Notes

The federated_extensions above are copied from the documentation environment prior to building this site with Sphinx, and are meant to exercise different kinds of extensions, including themes, MIME renderers, and Widgets. Some transient dependencies also include labextensions, but don’t work entirely correctly.



working issue


needs Jupyter Kernel Comms



needs server extension


needs server extension

The Hard Way

Content, The Hard Way


  • you have a running JupyterLab 3

  • you want to add all of the files in the root folder of the current JupyterLab to your JupyterLite.

Open a browser:

  • view the Contents API, e.g. http://localhost:8888/api/contents, which should look something like:

  "name": "",
  "path": "",
  "last_modified": "2021-05-15T20:16:17.753908Z",
  "created": "2021-05-15T20:16:17.753908Z",
  "format": "json",
  "mimetype": null,
  "size": null,
  "writable": true,
  "type": "directory",
  "content": [
      "name": "",
      "path": "",
      "last_modified": "2021-05-15T20:12:22.261076Z",
      "created": "2021-05-15T20:12:22.261076Z",
      "content": null,
      "format": null,
      "mimetype": "text/markdown",
      "size": 3735,
      "writable": true,
      "type": "file"
  • Paste this JSON in $YOUR_JUPYTERLITE/api/contents/all.json

  • Copy your files in $YOUR_JUPYTERLITE/files

  • Repeat this for every subfolder :(

Now, when the app reloads, these files will appear in the File Browser if there isn’t an existing file of that name in browser storage. If a user has created such a file, and is deleted, the original server-backed file will become visible.

Extensions, The Hard Way


This is a heavily work-in-progress procedure, and will hopefully soon be improved with convenience tools in (at least) python and JavaScript.

Get the extension assets

Assuming you have a working JupyterLab 3 installation, look in your {sys.prefix}/share/jupyter/labextensions. Each folder contains either:

  • if it begins with @, a collection of packages

  • otherwise, a single federated extension

mkdir -p lab/extensions
cd lab/extensions
cp -r $PREFIX/share/jupyter/labextensions/@jupyter-widgets/jupyterlab-manager .


Some extensions will require other extensions to be available. This can be determined by looking in package.json for the extension, specifically #/jupyterlab/sharedPackages.

Handle theme assets

The Theme Manager expects to be able to load theme CSS/font assets from {:app}/build/themes/({:org}/){:package}, where app is usually lab.

Continuing the example above:

cd $YOUR_JUPYTERLITE/lab/extensions
mkdir -p ../build/themes
cp -r @*/*/themes/* ../build/themes/
cp -r @*/themes/* ../build/themes/
# To also ensure these are available for JupyterLite Retro:
mkdir -p ../../retro/build/themes
cp -r @*/*/themes/* ../../retro/build/themes/
cp -r @*/themes/* ../../retro/build/themes/

Fill Out federated_extensions

Again, assuming you have a working JupyterLab, click Inspect Element in your Lab and inspect the <script id="jupyter-config-data"> in the <head>. The entry you need will be contained there.

Update your /app/jupyter-lite.json like so:

  "federated_extensions": [
      "extension": "./extension",
      "load": "static/remoteEntry.ca1efc27dc965162ca86.js",
      "name": "@jupyter-widgets/jupyterlab-manager"


Some extensions also include a style key, and may look off if omitted.