Skip to main content
Services form the backbone of VS Code’s architecture. They provide reusable functionality through a dependency injection system, enabling loose coupling and testability.

What are Services?

Services are singleton instances that:
  • Provide specific functionality (editor management, lifecycle, configuration, etc.)
  • Use dependency injection for loose coupling
  • Follow a clear interface-based design
  • Are instantiated on-demand or at specific lifecycle phases
All services in VS Code follow the pattern: Define an interface starting with I, then implement it in a concrete class.

Creating a Service

1. Define the Service Interface

First, create a service decorator and interface:
The _serviceBrand property is a type-only brand that ensures type safety in TypeScript. It’s never actually implemented.

2. Implement the Service

Create the concrete implementation:

3. Register the Service

Register the service as a singleton:
InstantiationType.Delayed (Recommended)
  • Service is created only when first requested
  • Reduces startup time
  • Most services should use this
InstantiationType.Eager
  • Service is created immediately at startup
  • Only use for critical services that must exist early
  • Examples: lifecycle service, log service

Common Workbench Services

VS Code provides many built-in services. Here are the most commonly used:

Editor Service

Manages editor instances and their lifecycle:
Usage example:

Lifecycle Service

Manages application lifecycle phases and shutdown:
Usage example:

View Descriptor Service

Manages views and view containers:

Configuration Service

Accesses and modifies user/workspace settings:

Storage Service

Persists data across sessions:

Service Location

Services are organized by scope:
Platform services are environment-agnostic and reusable.

Dependency Injection Patterns

Constructor Injection

The most common pattern - inject dependencies through the constructor:

Accessor Injection

For command handlers and contributions:

Manual Instantiation

For creating instances manually:

Best Practices

  1. Single Responsibility: Each service should have one clear purpose
  2. Interface First: Always define the interface before implementation
  3. Immutable APIs: Service methods should not modify internal state unexpectedly
  4. Event-Driven: Use events (Emitter) for state changes
  5. Lazy Initialization: Use InstantiationType.Delayed unless eager loading is required
  6. Proper Disposal: Extend Disposable and register disposables with _register()
  7. Avoid Circular Dependencies: Design services to avoid circular references

Testing Services

Create mock services for testing:

Next Steps

Workbench Contributions

Learn how to register contributions that use services

Extension API

Understand how services relate to the extension API