JupyterLab can be extended in several ways:

  • Extensions (top level): Application extensions extend the functionality of JupyterLab itself, and we cover them in the Extension Developer Guide.

  • Document widget extensions (lower level): Document widget extensions extend the functionality of document widgets added to the application, and we cover them in this section.

For this section, the term ‘document’ refers to any visual thing that is backed by a file stored on disk (i.e. uses Contents API).

Overview of document architecture

A ‘document’ in JupyterLab is represented by a model instance implementing the IModel interface. The model interface is intentionally fairly small, and concentrates on representing the data in the document and signaling changes to that data. Each model has an associated context instance as well. The context for a model is the bridge between the internal data of the document, stored in the model, and the file metadata and operations possible on the file, such as save and revert. Since many objects will need both the context and the model, the context contains a reference to the model as its .model attribute.

A single file path can have multiple different models (and hence different contexts) representing the file. For example, a notebook can be opened with a notebook model and with a text model. Different models for the same file path do not directly communicate with each other.

Models contain an instance of ModelDB that acts as data storage for the model’s content. In JupyterLab 3.1, we introduced the package @jupyterlab/shared-models to swap ModelDB as a data storage to make ‘documents’ collaborative. We implemented these shared models using Yjs, a high-performance CRDT for building collaborative applications that automatically sync. Starting with JupyterLab 3.6, the shared models have been extracted in the external package @jupyter/ydoc. At the moment, models contain both a ModelDB and a Shared Model instance, so it is possible to access ModelDB yet. But starting with JupyterLab 4, the ModelDB storage will be removed.

Document widgets represent a view of a document model. There can be multiple document widgets associated with a single document model, and they naturally stay in sync with each other since they are views on the same underlying data model.

Shared Models are models using Yjs’ shared types as a data structures instead of ModelDB.

The Document Registry is where document types and factories are registered. Plugins can require a document registry instance and register their content types and providers.

The Document Manager uses the Document Registry to create models and widgets for documents. The Document Manager handles the lifecycle of documents for the application.

The Document Provider is a WebSocket provider that syncs documents through a new end-point (api/yjs) in the JupyterLab server. Providers abstract Yjs from the network technology your application uses. They sync Yjs documents through a communication protocol or a database. Most providers have in common that they use the concept of room names to connect Yjs documents.

Document Registry

Document widget extensions in the JupyterLab application can register:

  • file types

  • model factories for specific file types

  • widget factories for specific model factories

  • widget extension factories

Widget Factories

Create a widget for a given file.


  • The notebook widget factory that creates NotebookPanel widgets.

Model Factories

Create a model for a given file.

Models are generally differentiated by the contents options used to fetch the model (e.g. text, base64, notebook).

Widget Extension Factories

Adds additional functionality to a widget type. An extension instance is created for each widget instance, enabling the extension to add functionality to each widget or observe the widget and/or its context.


  • The ipywidgets extension that is created for NotebookPanel widgets.

  • Adding a button to the toolbar of each NotebookPanel widget.

File Types

Document Models

Created by the model factories and passed to widget factories and widget extension factories. Models are the way in which we interact with the data of a document. For a simple text file, we typically only use the to/fromString() methods. A more complex document like a Notebook contains more points of interaction like the Notebook metadata.

Document Contexts

Created by the Document Manager and passed to widget factories and widget extensions. The context contains the model as one of its properties so that we can pass a single object around.

They are used to provide an abstracted interface to the session and Contents API from @jupyterlab/services for the given model. They can be shared between widgets.

The reason for a separate context and model is so that it is easy to create model factories and the heavy lifting of the context is left to the Document Manager. Contexts are not meant to be subclassed or re-implemented. Instead, the contexts are intended to be the glue between the document model and the wider application.

Shared Models

The @jupyter/ydoc package contains an ISharedNotebook and an ISharedFile which are the abstract interfaces to work against if you want to manipulate a notebook or a text file.

These models wrap a Yjs document (Y.Doc) which represents a shared document between clients and hold multiple shared objects. They enable you to share different data types like text, Array, Map or set, to make different types of collaborative applications.

In addition, a shared model has an Awareness attribute. This attribute is linked to the Y.Doc which means there is one Awareness object per document and is used for sharing cursor locations and presence information. The Awareness is an implementation detail of Yjs and is not part of the ISharedDocument interface.

Please, check out the @jupyter/ydoc documentation to know more about this package.

Document Manager

The Document Manager handles:

  • document models

  • document contexts

The File Browser uses the Document Manager to open documents and manage them.