# What Is a Service in Cordis and How to Extend It

> Learn what a Service is in Cordis, a reusable functionality wrapper with lifecycle management. Discover how to extend Cordis Services for your projects.

- Repository: [Cordiverse/cordis](https://github.com/cordiverse/cordis)
- Tags: deep-dive
- Published: 2026-08-24

---

**A Service in Cordis is an abstract base class that encapsulates reusable functionality, automatically registers instances with a Context, and provides lifecycle management, callable proxies, and configuration resolution.**

In the `cordiverse/cordis` framework, the **Service** class serves as the fundamental building block for modular, context-aware architecture. Every Service instance binds to a **Context** that manages its lifecycle, isolation, and effect system, making it essential to understand how to properly extend Service in Cordis when building plugins or custom components.

## Core Architecture of Service in Cordis

### The Service Base Class

The abstract **Service** class is defined in **[`packages/core/src/service.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/service.ts)** and provides the foundation for all reusable components in the framework. When you extend this class, the constructor automatically registers the instance with the current Context via `ctx.reflect.provide(name, this, this[Service.check])` at lines 33-35.

Every service receives a **name** that determines how other components access it. This name defaults to the class's static `provide` property or can be passed explicitly via `super(ctx, name)` at lines 18-21. Once registered, the service gains access to the surrounding Context through `this.ctx` (lines 29-31), which exposes utilities like `events`, `logger`, and the effect system.

### Callable Services and Proxy Behavior

Cordis supports **callable services** through the `Service.invoke` symbol defined at lines 26-28. If your subclass implements this symbol, the constructor wraps the instance with a callable proxy using `createCallable`, allowing the service to be invoked directly as a function while retaining its methods and properties.

## How to Extend a Service in Cordis

### Creating a Basic Subclass

To create a custom service, extend the `Service` class, call `super(ctx, name)` in your constructor, and define your public methods. The subclass automatically registers itself in the Context and inherits full lifecycle management.

```typescript
import { Context, Service } from 'cordis'

class GreeterService extends Service {
  constructor(ctx: Context) {
    super(ctx, 'greeter')          // registers as ctx.greeter
  }

  greet(name: string) {
    return `Hello, ${name}!`
  }
}

// Usage
const ctx = new Context()
ctx.registry.add(GreeterService)
ctx.greeter.greet('Alice') // → "Hello, Alice!"

```

### Implementing Callable Services

To make your service callable like a function, implement the `Service.invoke` symbol. This creates a proxy that intercepts direct function calls while preserving method access.

```typescript
class CounterService extends Service {
  static [Service.invoke] = Symbol('invoke') // enable callable proxy

  private count = 0

  [Service.invoke](step = 1) {
    this.count += step
    return this.count
  }

  reset() {
    this.count = 0
  }
}

// Usage
ctx.registry.add(CounterService)
ctx.counter(2)   // → 2
ctx.counter()    // → 3
ctx.counter.reset()

```

### Runtime Extension and Inheritance

You can extend existing services at runtime using standard class inheritance. The new subclass inherits all functionality while adding or overriding methods, and `ctx.registry.add()` replaces the original registration.

```typescript
class AdvancedGreeter extends GreeterService {
  shout(name: string) {
    return this.greet(name).toUpperCase()
  }
}

// Replace the original service dynamically
ctx.registry.add(AdvancedGreeter)
ctx.greeter.shout('Bob') // → "HELLO, BOB!"

```

## Configuration and Advanced Features

### Config Resolution with Service[resolveConfig]

The framework provides **`Service[resolveConfig]`** at lines 51-66 in [`packages/core/src/service.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/service.ts) for merging configuration objects from the context hierarchy. This method supports custom merge logic and integrates with `Context.intercept` (defined in **[`packages/core/src/context.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/context.ts)** at lines 9-26) to resolve layered configuration settings.

### Internal Extension Mechanics

Cordis includes an internal extension helper **`Service[extend]`** at lines 41-48 that creates shallow copies (or callable copies) of services and merges additional properties. The framework uses this for plugin mocks and creating "shadow" services, though direct subclassing remains the recommended approach for application code.

## Summary

- A **Service** in Cordis is an abstract class in [`packages/core/src/service.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/service.ts) that encapsulates functionality and automatically registers with a Context.
- Extend services by subclassing `Service`, calling `super(ctx, name)`, and implementing your methods.
- Make services callable by defining the `Service.invoke` symbol, which triggers the `createCallable` proxy wrapper.
- Access configuration merging through `Service[resolveConfig]` and context hierarchy isolation via `Context.isolate`.
- Reference implementation examples exist in [`packages/timer/src/index.ts`](https://github.com/cordiverse/cordis/blob/main/packages/timer/src/index.ts) and test coverage in [`packages/core/tests/service.spec.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/tests/service.spec.ts).

## Frequently Asked Questions

### What file contains the Service class in Cordis?

The **Service** abstract class is located in **[`packages/core/src/service.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/service.ts)**. This file defines the core lifecycle methods, callable service logic, and configuration resolution symbols used throughout the framework.

### How do I make a Cordis service callable like a function?

Implement the static **`Service.invoke`** symbol in your subclass and define a method using that symbol as the key. The constructor detects this at lines 26-28 and wraps the instance with a callable proxy via `createCallable`, allowing direct invocation syntax like `ctx.serviceName()`.

### Can I extend an existing Cordis service at runtime?

Yes, use standard JavaScript class inheritance to create a subclass of the existing service, then register it with `ctx.registry.add()`. The new class inherits all parent methods and can override or extend functionality, effectively replacing the original service in the context.

### What is the difference between Service[extend] and subclassing?

**Subclassing** creates a new class definition for permanent extension, while **`Service[extend]`** (lines 41-48) creates runtime shallow copies of existing service instances for temporary modifications or mocking. Application developers should use subclassing; `Service[extend]` is primarily for internal framework operations and testing utilities.