March 6th, 2025

Multi Root Workspaces in Visual Studio Code

Multi-Root Workspaces in Visual Studio Code

On a recent customer engagement we were presented with a monolithic Git repository containing more than 12 Python projects. A monolithic repo, or mono-repo, is a single repository housing multiple independent projects. Most of the projects were independent Azure ML components, with a couple of shared common code libraries. Each of the component projects had their own dependency trees, often using the same libraries but at different versions. The dependencies were managed using the Poetry toolset, rather than the more common pip tooling. The developers wanted a simple to use, but robust, experience that allowed them to work in multiple projects at the same time. In a C# solution in Visual Studio, this kind of multiple project setup is normal and easy to achieve, with each project having its own dependency tree, but it was less obvious to us how to achieve this using Python and VS Code. Fortunately, we discovered Multi-Root Workspaces, which provided exactly the desired functionality and when paired with Python’s virtual environments and Poetry’s shell features, allowed us to develop a single repo containing all of the AML components as independent projects.

Multi-Root Workspaces (MRW) offer each project an independent set of dependencies, as well as things like Black or Flake8 configurations or VS Code configuration files. The image below shows an example repository. There are two “common” libraries, used by the two components.

A Git repo containing multiple projects

Note the root level multiroot_workspaces.code-workspace file. This contains the MRW definition.

{
    "folders": [
        {
            "path": "common/configuration"
        },
        {
            "path": "common/telemetry"
        },
        {
            "path": "component_one"
        },
        {
            "path": "component_two"
        }
    ]
}

Other paths (folders) can be added manually or using the “Add Folder to Workspace…” menu option on the File menu. The folders being added do not need to live in the same Git repository as the existing folders, although that was the mono-repo approach taken in this engagement.

The "Add folder to Workspace" menu option

We can also see in the image above the “Open Workspace from File…” option. Clicking this and selecting the .code-workspace file will reopen Visual Studio Code in Workspace view. This can be seen in the image below, which shows a MRW with four independent projects.

An example multi root workspace

Each of these workspaces is an independent, Poetry managed, Python project. The following code block shows the pyproject.toml file for component_one.

[tool.poetry]
name        = component-one
version     = "0.1.0"
description = ""
authors    = ["Anne Author <anne.author@microsoft.com"]
readme      = "README.md"

[tool.poetry.dependencies]
python           = "^3.10"
numpy            = "^2.1.0"
configuration    = {path = "../common/configuration", develop = true}

[tool.poetry.dev-dependencies]
pytest = "^8.3.2"

[build-system]
requires        = ["poetry-core"]
build-backend   = "poetry.core.masonry.api"

It shows the runtime dependencies use in the [tool.poetry.dependencies] section and separately the development only dependencies in [tool.poetry.dev-dependencies]. We can see it is using numpy at a version greater than 2.1.0. It also has a dependency on the local configuration package, specified by a local path. Below is the pyproject.toml file for component_two..

[tool.poetry]
name        = component-two
version     = "0.1.0"
description = ""
authors    = ["Anne Author <anne.author@microsoft.com"]
readme      = "README.md"

[tool.poetry.dependencies]
python           = "^3.10"
numpy            = "^2.0.0"

[tool.poetry.dev-dependencies]
pytest = "^8.3.2"

[build-system]
requires        = ["poetry-core"]
build-backend   = "poetry.core.masonry.api"

This does not take a dependency on the local configuration project, and also accepts a lower version of numpy.

It is possible to have one or more VS Code Terminals per workspace open. Simply click on the “+” button in the terminal window.

How to add a new terminal

This will open a prompt to select which workspace to open the terminal in.

How to the workspace

Select the desired one, component_one in this example, and if the virtual environment has already been initialised, it will open it in the new terminal. If the virtual environment has not been set up, running poetry shell will create and configure it based on the settings in the relevant pyproject.toml file.

To make sure that the virtual environments are created within the desired project a poetry.toml configuration file should be added to the root folder, where the in-project configuration key is set to true.

[virtualenvs]
in-project = true

Running the poetry install command will then install all of the relevant packages for component_one into the virtual environment.

alt text

Further details of MRW can be found at Workspaces in Visual Studio Code.

The feature image was generated using Bing Image Creator. Terms can be found here.

Author