Skip to main content

Overview

Visual Studio Code follows a strict layered architecture where each layer builds upon the one below it. This design promotes code reusability, maintainability, and ensures that lower-level components remain independent of higher-level features.
Key Rule: Each layer can only depend on layers below it, never above. This is enforced using the npm run valid-layers-check command.

The Four Layers

Layer 1: Base

Location: src/vs/base/ The base layer provides foundational utilities and cross-platform abstractions. It has no dependencies on any other VS Code layer.

Structure

Location: src/vs/base/common/Universal utilities that work in any JavaScript environment:
  • Data Structures: Arrays, maps, sets, trees, linked lists
  • Async Primitives: Promises, cancellation tokens, throttling, debouncing
  • Events: Event emitter implementation
  • Lifecycle: Disposable pattern for resource management
  • Strings: String manipulation utilities
  • URI: Universal resource identifier handling
// Example: Disposable pattern from src/vs/base/common/lifecycle.ts
import { Disposable } from 'vs/base/common/lifecycle';

export class MyComponent extends Disposable {
  constructor() {
    super();
    
    // Register disposables that will be cleaned up
    this._register(someEventListener);
    this._register(someResource);
  }
}

Key Concepts

The IDisposable interface is fundamental to VS Code’s resource management:
// src/vs/base/common/lifecycle.ts:312
export interface IDisposable {
  dispose(): void;
}

// Usage examples:

// 1. DisposableStore - manage multiple disposables
const store = new DisposableStore();
store.add(eventListener1);
store.add(eventListener2);
store.dispose(); // Disposes all

// 2. MutableDisposable - replace disposable values
const mutable = new MutableDisposable();
mutable.value = resource1;
mutable.value = resource2; // Disposes resource1 automatically

// 3. Disposable base class
class MyClass extends Disposable {
  constructor() {
    super();
    this._register(myDisposable);
  }
}
Critical Rule: Always register disposables immediately after creation. Use DisposableStore, MutableDisposable, or DisposableMap to manage them.
Type-safe event system used throughout VS Code:
// src/vs/base/common/event.ts
import { Emitter, Event } from 'vs/base/common/event';

class MyService {
  private readonly _onDidChange = new Emitter<string>();
  readonly onDidChange: Event<string> = this._onDidChange.event;
  
  private fireChange(value: string): void {
    this._onDidChange.fire(value);
  }
}

// Usage:
const disposable = myService.onDidChange(value => {
  console.log('Changed:', value);
});

Layer 2: Platform

Location: src/vs/platform/ The platform layer provides core services and the dependency injection infrastructure. Services in this layer are shared across the editor and workbench.

Key Services

1

Instantiation Service

Location: src/vs/platform/instantiation/common/instantiation.tsThe dependency injection container that manages service lifecycles:
// Creating a service identifier
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';

export const IMyService = createDecorator<IMyService>('myService');

export interface IMyService {
  readonly _serviceBrand: undefined;
  doSomething(): void;
}
2

Configuration Service

Location: src/vs/platform/configuration/common/configuration.tsManages all VS Code settings with support for multiple scopes.
3

File Service

Location: src/vs/platform/files/common/files.tsAbstraction over file system operations with support for multiple providers.
4

Storage Service

Location: src/vs/platform/storage/common/storage.tsPersistent key-value storage with workspace and global scopes.
5

Log Service

Location: src/vs/platform/log/common/log.tsCentralized logging system with different log levels.

Platform Architecture

// Example service implementation
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { ILogService } from 'vs/platform/log/common/log';

export const IExampleService = createDecorator<IExampleService>('exampleService');

export interface IExampleService {
  readonly _serviceBrand: undefined;
  performAction(): Promise<void>;
}

export class ExampleService implements IExampleService {
  declare readonly _serviceBrand: undefined;
  
  constructor(
    @ILogService private readonly logService: ILogService
  ) {
    this.logService.info('ExampleService initialized');
  }
  
  async performAction(): Promise<void> {
    this.logService.info('Action performed');
  }
}

Layer 3: Editor

Location: src/vs/editor/ The editor layer implements the Monaco Editor, which is the core text editing component of VS Code. Monaco can be used as a standalone library.

Editor Components

Core Editor

  • Text buffer and model
  • Cursor and selection management
  • View rendering
  • Editor options and configuration

Language Features

  • Tokenization and syntax highlighting
  • Language services integration
  • IntelliSense and completions
  • Code actions and quick fixes

Editor Widgets

  • Content widgets
  • Overlay widgets
  • Glyphs and decorations
  • Hover providers

Browser Integration

  • Standalone editor support
  • Diff editor
  • Configuration editor
  • Editor commands

Editor Structure

src/vs/editor/
├── common/           # Core editor logic
│   ├── model/       # Text model implementation
│   ├── languages/   # Language features
│   └── services/    # Editor services
├── browser/         # Browser-specific editor
│   ├── widget/      # Editor widgets
│   └── services/    # Browser editor services
├── contrib/         # Editor contributions
│   ├── hover/       # Hover support
│   ├── suggest/     # IntelliSense
│   └── ...
└── standalone/      # Standalone Monaco editor

Layer 4: Workbench

Location: src/vs/workbench/ The workbench layer is the main application that brings everything together. It provides the VS Code UI and all user-facing features.

Workbench Structure

Location: src/vs/workbench/browser/Core workbench UI components:
  • Parts: Title bar, activity bar, sidebar, editor, panel, status bar
  • Layout: Window layout management
  • Actions: Command and action infrastructure
  • Workbench: Main workbench class
// src/vs/workbench/browser/workbench.ts:67
export class Workbench extends Layout {
  constructor(
    parent: HTMLElement,
    private readonly options: IWorkbenchOptions | undefined,
    private readonly serviceCollection: ServiceCollection,
    logService: ILogService
  ) {
    super(parent, { resetLayout: Boolean(options?.resetLayout) });
    this.registerErrorHandler(logService);
  }
  
  startup(): IInstantiationService {
    // Initialize services, layout, and contributions
    const instantiationService = this.initServices(this.serviceCollection);
    // ...
    return instantiationService;
  }
}

Workbench Parts

Layer Validation

VS Code enforces layer dependencies using a validation tool:
# Check for layer violations
npm run valid-layers-check
Common violations:
  • Importing from a higher layer (e.g., base importing from platform)
  • Importing platform-specific code in common modules
  • Circular dependencies between layers

Benefits of Layered Architecture

Lower layers can be reused in different contexts:
  • Monaco Editor can be used standalone
  • Base utilities work in any JavaScript environment
  • Platform services can be shared across different UIs
Clear boundaries make the codebase easier to understand:
  • Developers know where to find specific functionality
  • Changes are isolated to specific layers
  • Testing is simplified with clear dependencies
The architecture supports growth:
  • New features are added as contributions
  • Services can be extended without modifying core code
  • Platform abstractions enable new runtimes (web, desktop)

Next Steps

Dependency Injection

Learn how services are created and managed

Contribution Model

Understand how features extend the workbench