{
  "generator": {
    "name": "Symvanta",
    "url": "https://symvanta.com"
  },
  "page": {
    "url": "https://symvanta.com/architecture/vscode",
    "title": "VS Code Architecture: How It Actually Works",
    "description": "How the VS Code codebase is structured: module map, load-bearing symbols, and dependency structure, generated by Symvanta.",
    "datePublished": "2026-08-25",
    "dateModified": "2026-08-25"
  },
  "repository": {
    "name": "microsoft/vscode",
    "url": "https://github.com/microsoft/vscode",
    "commit": "584b2da",
    "license": "MIT"
  },
  "graph": {
    "modules": 152,
    "dependencyCycles": 159,
    "modularityQ": 0.67,
    "largestCycleFiles": null,
    "mutuallyRecursiveGroups": 657
  },
  "summaryMarkdown": "Visual Studio Code is an Electron application whose window is a workbench\nshell: a title bar, an activity bar, a side bar, an editor area, a panel and a\nstatus bar, assembled from services that a dependency injector hands out, with\nthird-party extensions running in their own process. Symvanta's graph of the\nrepo at `584b2da` detects 152 functional modules (modularity Q=0.67), and the\nten largest hold 70.6% of the 202,577 clustered symbols. Nine of those ten take\ntheir hub from `src/vs/base`, `src/vs/platform`, or the editor core.\n\nThat is a platform layer sitting across the top of the map. Lifecycle, events,\nURIs, observables, cancellation, collections, the identifiers the service\ninjector is keyed on and the action registry are called from everywhere in the\ntree, so clustering gathers the files that use them around the primitive\nitself, and every one of the ten biggest modules carries a primitive as its\nhub. The product layer sits underneath. Below the top ten there are 36 modules\nof 200 symbols or more, and 24 of them take their hub from a file outside\n`src/vs/base`, the editor core and the shared platform services: notebooks\n(5,731 symbols), editor inputs and groups (4,941), the search result tree\n(2,722), chat prompt and AI customization files (1,711), source control\n(1,620), user data profiles (1,579), remote tunnels (645) and MCP server\nmanagement (617).\n\nThe map is a clustering of the call graph, so it is not a subsystem inventory,\nand two of the subsystems people look for first have no box of their own at\nthis resolution. The dominant member directory of the disposables module is the\ndebug UI at `src/vs/workbench/contrib/debug/browser`, and the dominant member\ndirectory of the collections module is the terminal UI at\n`src/vs/workbench/contrib/terminal/browser`. Each was absorbed into the\nprimitive its files reach for most.",
  "subsystems": [
    {
      "name": "Disposables and events",
      "descriptionMarkdown": "22,695 symbols, the largest module in the repo, hubbed on `IDisposable` in `src/vs/base/common/lifecycle.ts`. It holds the disposal primitives (`Disposable`, `DisposableStore`, `trackDisposable`) together with the event layer around `Emitter.fire`. Anything that subscribes to an event owns a disposable, so the two files travel together, and the files that use them are pulled in behind: the module's dominant member directory is the debug UI."
    },
    {
      "name": "Editor core model",
      "descriptionMarkdown": "22,619 symbols, hubbed on `Range` in `src/vs/editor/common/core/range.ts`, with `IRange`, `Position`, `Selection`, `ITextModel` and `ICodeEditor` beside it. This is the Monaco editor core: coordinates in a document, the model that stores the text, and the editor interface built over it. It is the only module in the top ten that comes from `src/vs/editor`."
    },
    {
      "name": "Resource URIs",
      "descriptionMarkdown": "18,789 symbols, hubbed on `URI` in `src/vs/base/common/uri.ts`, with `UriComponents`, `URI.toString`, `URI.scheme`, `URI.path` and `VSBuffer`. Every file, editor, extension and setting is addressed by a URI, including the ones served by remote and virtual file systems, so the type and its accessors are reached from every layer."
    },
    {
      "name": "Extension API declarations",
      "descriptionMarkdown": "16,230 symbols, hubbed on `Uri` in `src/vscode-dts/vscode.d.ts`, the file that declares the public extension API, and its dominant member directory is `src/vs/workbench/api/common`, the extension host side of that same API. The cluster is the API surface plus the code that implements it: `Uri`, `Position`, `Range`, `Event` and `Disposable` as an extension author sees them, next to `IExtensionDescription`."
    },
    {
      "name": "Service identifiers",
      "descriptionMarkdown": "13,563 symbols, hubbed on `ServiceIdentifier` in `src/vs/platform/instantiation/common/instantiation.ts`. A service here is an interface with a branded identifier, and the injector resolves a constructor parameter by that identifier, so the file is imported by nearly everything that consumes a service. The cluster holds the mechanism plus the services asked for most: `IInstantiationService`, `ILogService`, `IConfigurationService`, `IContextKeyService`, `IFileService`, `IStorageService`."
    },
    {
      "name": "Actions menus and context keys",
      "descriptionMarkdown": "12,683 symbols, hubbed on `Action2` in `src/vs/platform/actions/common/actions.ts`, clustered with `MenuId`, `ContextKeyExpression`, `ContextKeyExpr.and`, `ServicesAccessor` and `EditorAction`. A command, the menus it appears in and the `when` clause that decides whether it appears are one mechanism in this codebase, and the graph puts them in one module."
    },
    {
      "name": "Extension identity and manifests",
      "descriptionMarkdown": "8,161 symbols, hubbed on `ExtensionIdentifier` in `src/vs/platform/extensions/common/extensions.ts`, with `IExtensionManifest`, `ILocalExtension`, `TargetPlatform` and `Severity`. Installing, enabling, updating and reporting on an extension all key off that identifier."
    },
    {
      "name": "Other shared primitives",
      "descriptionMarkdown": "Three more of the ten are primitives the rest of the tree calls into.\nCancellation and markdown strings (10,124 symbols) holds `CancellationToken`\nfrom `src/vs/base/common/cancellation.ts` alongside `IMarkdownString` and\n`MarkdownString`. Observables (9,642 symbols) is `IObservable`, `IObserver`,\n`IReader` and `ISettable` from `src/vs/base/common/observableInternal`, the\nreactive layer the editor and the chat UI are built on. Collections and\nplatform checks (8,517 symbols) is `IStringDictionary` from\n`src/vs/base/common/collections.ts` with the platform predicates (`isWindows`,\n`OperatingSystem`), `IWorkspaceFolder` and `IChannel.call`; its dominant member\ndirectory is the terminal UI."
    },
    {
      "name": "The product layer",
      "descriptionMarkdown": "The feature code sits below the top ten and it is not small. The notebook\neditor model (5,731 symbols, hub `ICellViewModel`) and editor inputs and groups\n(4,941 symbols, hub `EditorInput`) are the two biggest. After them come the\nsearch result tree (2,722, `ISearchTreeFileMatch`), chat prompt and AI\ncustomization files (1,711, `PromptsType`), source control (1,620,\n`ISCMRepository`), the Electron-main browser view host (1,593), user data\nprofiles and sync (1,579, `IUserDataProfile`), GitHub API types (1,120,\n`GitHubAccountHandle`), chat request variables (981,\n`IChatRequestVariableEntry`), remote tunnels (645, `RemoteTunnel`), MCP server\nmanagement (617, `ILocalMcpServer`) and speech to text (445). Each of these\ntakes its hub from its own feature directory, which is what separates a\nsubsystem from a crowd of callers gathered around one primitive."
    }
  ],
  "startReading": {
    "symbols": [
      {
        "name": "trackDisposable",
        "sourceUrl": "https://github.com/microsoft/vscode/blob/584b2dacffdba8b29df943d8d6f99154c9f967e4/src/vs/base/common/lifecycle.ts#L271"
      },
      {
        "name": "URI.toString",
        "sourceUrl": "https://github.com/microsoft/vscode/blob/584b2dacffdba8b29df943d8d6f99154c9f967e4/src/vs/base/common/uri.ts#L386"
      },
      {
        "name": "Disposable.dispose",
        "sourceUrl": "https://github.com/microsoft/vscode/blob/584b2dacffdba8b29df943d8d6f99154c9f967e4/src/vs/base/common/lifecycle.ts#L542"
      },
      {
        "name": "DisposableStore.dispose",
        "sourceUrl": "https://github.com/microsoft/vscode/blob/584b2dacffdba8b29df943d8d6f99154c9f967e4/src/vs/base/common/lifecycle.ts#L432"
      },
      {
        "name": "ContextKeyExpr.and",
        "sourceUrl": "https://github.com/microsoft/vscode/blob/584b2dacffdba8b29df943d8d6f99154c9f967e4/src/vs/platform/contextkey/common/contextkey.ts#L608"
      },
      {
        "name": "IObservableWithChange.get",
        "sourceUrl": "https://github.com/microsoft/vscode/blob/584b2dacffdba8b29df943d8d6f99154c9f967e4/src/vs/base/common/observableInternal/base.ts#L33"
      },
      {
        "name": "onUnexpectedError",
        "sourceUrl": "https://github.com/microsoft/vscode/blob/584b2dacffdba8b29df943d8d6f99154c9f967e4/src/vs/base/common/errors.ts#L107"
      },
      {
        "name": "IChannel.call",
        "sourceUrl": "https://github.com/microsoft/vscode/blob/584b2dacffdba8b29df943d8d6f99154c9f967e4/src/vs/base/parts/ipc/common/ipc.ts#L26"
      },
      {
        "name": "IContextKey.set",
        "sourceUrl": "https://github.com/microsoft/vscode/blob/584b2dacffdba8b29df943d8d6f99154c9f967e4/src/vs/platform/contextkey/common/contextkey.ts#L2042"
      },
      {
        "name": "ITelemetryService.publicLog2",
        "sourceUrl": "https://github.com/microsoft/vscode/blob/584b2dacffdba8b29df943d8d6f99154c9f967e4/src/vs/platform/telemetry/common/telemetry.ts#L44"
      },
      {
        "name": "es5ClassCompat",
        "sourceUrl": "https://github.com/microsoft/vscode/blob/584b2dacffdba8b29df943d8d6f99154c9f967e4/src/vs/workbench/api/common/extHostTypes/es5ClassCompat.ts#L12"
      }
    ],
    "endpoints": []
  },
  "requestFlow": [
    {
      "position": 1,
      "symbol": "Workbench.startup",
      "sourceUrl": "https://github.com/microsoft/vscode/blob/584b2dacffdba8b29df943d8d6f99154c9f967e4/src/vs/workbench/browser/workbench.ts#L131",
      "markdown": "`Workbench.startup` ([`src/vs/workbench/browser/workbench.ts:131`](https://github.com/microsoft/vscode/blob/584b2dacffdba8b29df943d8d6f99154c9f967e4/src/vs/workbench/browser/workbench.ts#L131)) is the entry point. It raises the emitter leak-warning threshold, calls `initServices` to get an instantiation service, then runs every step below inside one `invokeFunction` block so they all share the same service accessor."
    },
    {
      "position": 2,
      "symbol": "Workbench.initServices",
      "sourceUrl": "https://github.com/microsoft/vscode/blob/584b2dacffdba8b29df943d8d6f99154c9f967e4/src/vs/workbench/browser/workbench.ts#L192",
      "markdown": "`Workbench.initServices` ([`src/vs/workbench/browser/workbench.ts:192`](https://github.com/microsoft/vscode/blob/584b2dacffdba8b29df943d8d6f99154c9f967e4/src/vs/workbench/browser/workbench.ts#L192)) registers the workbench layout service and creates the instantiation service the window is built from. Individual services come from `registerSingleton` calls in `workbench.common.main.ts`, which a capitalized comment block in this function points at."
    },
    {
      "position": 3,
      "symbol": "Layout.initLayout",
      "sourceUrl": "https://github.com/microsoft/vscode/blob/584b2dacffdba8b29df943d8d6f99154c9f967e4/src/vs/workbench/browser/layout.ts#L325",
      "markdown": "`Layout.initLayout` ([`src/vs/workbench/browser/layout.ts:325`](https://github.com/microsoft/vscode/blob/584b2dacffdba8b29df943d8d6f99154c9f967e4/src/vs/workbench/browser/layout.ts#L325)) takes the services the layout needs off that accessor: editor service, editor groups, pane composites, view descriptors, title, notifications and status bar. Nothing is drawn yet."
    },
    {
      "position": 4,
      "symbol": "IWorkbenchContributionsRegistry.start",
      "sourceUrl": "https://github.com/microsoft/vscode/blob/584b2dacffdba8b29df943d8d6f99154c9f967e4/src/vs/workbench/common/contributions.ts#L121",
      "markdown": "`IWorkbenchContributionsRegistry.start` ([`src/vs/workbench/common/contributions.ts:121`](https://github.com/microsoft/vscode/blob/584b2dacffdba8b29df943d8d6f99154c9f967e4/src/vs/workbench/common/contributions.ts#L121)) starts the workbench contributions registry, which instantiates each registered contribution at its declared lifecycle phase. This is how a feature attaches itself to the window without the window knowing about it."
    },
    {
      "position": 5,
      "symbol": "IEditorFactoryRegistry.start",
      "sourceUrl": "https://github.com/microsoft/vscode/blob/584b2dacffdba8b29df943d8d6f99154c9f967e4/src/vs/workbench/common/editor.ts#L457",
      "markdown": "`IEditorFactoryRegistry.start` ([`src/vs/workbench/common/editor.ts:457`](https://github.com/microsoft/vscode/blob/584b2dacffdba8b29df943d8d6f99154c9f967e4/src/vs/workbench/common/editor.ts#L457)) does the same for editor serializers, the registry that lets an editor input be written to storage and rebuilt in the next session."
    },
    {
      "position": 6,
      "symbol": "Workbench.registerListeners",
      "sourceUrl": "https://github.com/microsoft/vscode/blob/584b2dacffdba8b29df943d8d6f99154c9f967e4/src/vs/workbench/browser/workbench.ts#L231",
      "markdown": "`Workbench.registerListeners` ([`src/vs/workbench/browser/workbench.ts:231`](https://github.com/microsoft/vscode/blob/584b2dacffdba8b29df943d8d6f99154c9f967e4/src/vs/workbench/browser/workbench.ts#L231)) subscribes to configuration changes, storage save points, window focus changes and both shutdown events. The shutdown listener is what disposes the workbench."
    },
    {
      "position": 7,
      "symbol": "Workbench.renderWorkbench",
      "sourceUrl": "https://github.com/microsoft/vscode/blob/584b2dacffdba8b29df943d8d6f99154c9f967e4/src/vs/workbench/browser/workbench.ts#L320",
      "markdown": "`Workbench.renderWorkbench` ([`src/vs/workbench/browser/workbench.ts:320`](https://github.com/microsoft/vscode/blob/584b2dacffdba8b29df943d8d6f99154c9f967e4/src/vs/workbench/browser/workbench.ts#L320)) sets the ARIA container and the platform CSS classes, restores cached font information, creates the eight parts (title bar, banner, activity bar, side bar, editor, panel, auxiliary bar, status bar) with a performance mark around each one, and appends the container to the DOM."
    },
    {
      "position": 8,
      "symbol": "Layout.createWorkbenchLayout",
      "sourceUrl": "https://github.com/microsoft/vscode/blob/584b2dacffdba8b29df943d8d6f99154c9f967e4/src/vs/workbench/browser/layout.ts#L1644",
      "markdown": "`Layout.createWorkbenchLayout` ([`src/vs/workbench/browser/layout.ts:1644`](https://github.com/microsoft/vscode/blob/584b2dacffdba8b29df943d8d6f99154c9f967e4/src/vs/workbench/browser/layout.ts#L1644)) collects those eight parts as views and deserializes them into a `SerializableGrid` from a descriptor built out of the stored side bar, auxiliary bar and panel sizes. That descriptor is how a window remembers its splits."
    },
    {
      "position": 9,
      "symbol": "Layout.layout",
      "sourceUrl": "https://github.com/microsoft/vscode/blob/584b2dacffdba8b29df943d8d6f99154c9f967e4/src/vs/workbench/browser/layout.ts#L1753",
      "markdown": "`Layout.layout` ([`src/vs/workbench/browser/layout.ts:1753`](https://github.com/microsoft/vscode/blob/584b2dacffdba8b29df943d8d6f99154c9f967e4/src/vs/workbench/browser/layout.ts#L1753)) measures the client area, sizes the container, and hands the grid its width and height. The layout is marked initialized here."
    },
    {
      "position": 10,
      "symbol": "Workbench.restore",
      "sourceUrl": "https://github.com/microsoft/vscode/blob/584b2dacffdba8b29df943d8d6f99154c9f967e4/src/vs/workbench/browser/workbench.ts#L412",
      "markdown": "`Workbench.restore` ([`src/vs/workbench/browser/workbench.ts:412`](https://github.com/microsoft/vscode/blob/584b2dacffdba8b29df943d8d6f99154c9f967e4/src/vs/workbench/browser/workbench.ts#L412)) asks every part to restore its own state, then moves the lifecycle to the `Restored` phase once layout restoration settles or two seconds pass, whichever comes first, so a slow editor cannot hold contributions back. The `Eventually` phase follows on an idle callback a few seconds later."
    }
  ],
  "diagrams": [
    {
      "url": "https://symvanta.com/architecture/vscode/module-map.svg",
      "encodingFormat": "image/svg+xml"
    }
  ]
}
