# Cordis Architecture: Understanding the Relationship Between Context, Service, and Fiber

> Understand Cordis architecture: Explore the relationship between Context, Service, and Fiber. Learn how Context instantiates Fiber and Service connects functionality to lifecycle management.

- Repository: [Cordiverse/cordis](https://github.com/cordiverse/cordis)
- Tags: architecture
- Published: 2026-09-12

---

**In Cordis, `Context` acts as the global service container that instantiates the root `Fiber`, while `Service` provides the base abstraction that connects user-defined functionality to the fiber's lifecycle management system.**

Cordis is a hot-reloadable plugin framework designed for complex Node.js applications. Its **Cordis architecture** revolves around three tightly-coupled core abstractions that work together to provide dependency injection, lifecycle management, and stateful service orchestration.

## The Three Pillars of Cordis Architecture

### Context: The Service Container

The **`Context`** class serves as the root environment and dependency container. When instantiated, it immediately creates the root `Fiber` that drives the entire application lifecycle.

In [`packages/core/src/context.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/context.ts) (lines 36-48), the constructor establishes this relationship:

```typescript
this.fiber = new Fiber(self, {}, Object.create(null), null, () => [])

```

The `Context` holds global state, manages configuration isolation via `[symbols.isolate]` maps, and maintains intercept maps (`[symbols.intercept]`) for dependency injection. All services receive the same `Context` instance, giving them shared access to core facilities like `events`, `logger`, `reflect`, and `registry`.

### Fiber: The Lifecycle Engine

The **`Fiber`** class manages the execution lifecycle of plugins and the root context itself. It runs **effects**, tracks disposables, and coordinates reload/unload cycles with a sophisticated state machine (`FiberState`).

Each `Fiber` maintains a back-reference to its `Context` (`public readonly ctx: Context`) as implemented in [`packages/core/src/fiber.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/fiber.ts). The root fiber handles application-wide effects, while child fibers manage individual plugin scopes. Services interact with the fiber primarily through the `effect()` method (lines 75-84), which registers cleanup-aware side effects that automatically dispose when the plugin reloads or unloads.

### Service: The Developer Abstraction

The **`Service`** base class provides the standard API for building user-defined services (timers, loaders, database connectors). It abstracts the underlying context and fiber mechanics into a convenient interface.

In [`packages/core/src/service.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/service.ts) (lines 33-35), the constructor stores the context reference and registers the instance with the reflection system:

```typescript
this.ctx = ctx
ctx.reflect.provide(name, self, this[symbols.check])

```

Because services hold the context, they can access the fiber via `this.ctx.fiber` to invoke lifecycle methods like `effect()`, `update()`, and `restart()`.

## How Context, Service, and Fiber Interact

The relationship between these components follows a specific initialization and communication pattern:

1. **Root Creation** – `Context` instantiates the root `Fiber` during construction, establishing the execution engine for all effects.

2. **Service Registration** – When extending `Service`, the base class automatically registers the implementation with `ctx.reflect.provide()`, making it discoverable by the fiber's dependency injection system.

3. **Effect Handling** – Services call `ctx.fiber.effect(() => { /* ... */ })` to register side effects. The fiber tracks these as disposables and executes them during reload/unload cycles with proper error handling and ordering guarantees.

4. **State Coordination** – `Fiber` maintains a `FiberState` machine (pending, loading, active, failed, disposed, unloading). Services request state transitions indirectly via `ctx.fiber.update(config)` or `ctx.fiber.restart()`, while the fiber manages the actual transition logic and notifies listeners through the `internal/status` event channel.

5. **Isolation Propagation** – When spawning child fibers for plugins, the system copies parent intercepts (`ctx.intercept(name, config)`) and checks implementations (`_checkImpl`) against the reflection registry to determine plugin activation status, as seen in [`packages/core/src/fiber.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/fiber.ts) lines 38-45 and 71-83.

## Practical Implementation Examples

### Creating the Root Context

Every Cordis application begins with a `Context`, which automatically initializes the root fiber:

```typescript
import { Context } from 'cordis';

// Instantiates Context and creates root Fiber automatically
const ctx = new Context();

// Access lifecycle engine
console.log(ctx.fiber.name); // → 'root'

```

### Defining a Custom Service

Services extend the base `Service` class and leverage the fiber for lifecycle-aware operations:

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

class TimerService extends Service {
  constructor(ctx: Context) {
    super(ctx, 'timer');
    
    // Register effect with automatic cleanup
    this.ctx.fiber.effect(() => {
      const timer = setInterval(() => {
        this.ctx.logger.info('tick');
      }, 1000);
      
      // Return disposer for hot-reload support
      return () => clearInterval(timer);
    }, 'timer.tick');
  }
}

```

### Service Registration and Hot Reload

Register the service and utilize the fiber's update capabilities:

```typescript
// Instantiate and register
const timer = new TimerService(ctx);

// Trigger hot-reload with new configuration
await ctx.fiber.update({ /* new config */ });

```

### Low-Level Fiber Access

For scenarios requiring direct interaction outside the `Service` abstraction:

```typescript
// Schedule standalone effect
ctx.fiber.effect(() => {
  console.log('One-off effect executed');
  // Return optional cleanup function
  return () => console.log('Cleanup executed');
});

```

## Core Source Files and Their Roles

The Cordis architecture implementation spans these critical files in the `cordiverse/cordis` repository:

- **[`packages/core/src/context.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/context.ts)** – Defines the `Context` class, root fiber creation, and isolation/intercept maps.
- **[`packages/core/src/fiber.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/fiber.ts)** – Implements the `Fiber` class, effect tracking, state machine (`FiberState`), and plugin lifecycle coordination.
- **[`packages/core/src/service.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/service.ts)** – Base class for services; handles context storage and reflection registration via `ctx.reflect.provide()`.
- **[`packages/core/src/reflect.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/reflect.ts)** – Provides the reflection registry used for dependency injection and implementation lookup.
- **[`packages/core/src/utils.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/utils.ts)** – Contains shared symbols (`symbols.fiber`, `symbols.isolate`, `symbols.intercept`) utilized across all three core components.

## Summary

- **Context** supplies the shared runtime environment and creates the root fiber upon instantiation.
- **Fiber** serves as the execution engine, managing effects, state transitions, and cleanup cycles for plugins and services.
- **Service** provides the developer-facing abstraction that bridges user code to the underlying fiber lifecycle system through the context reference.
- The three components form a closed loop: Context creates Fiber, Service receives Context (and thus Fiber), and Fiber orchestrates the lifecycle of Services.

## Frequently Asked Questions

### What is the difference between Context and Fiber in Cordis?

**Context** is the static container holding configuration, services, and state, while **Fiber** is the dynamic execution engine managing lifecycles and effects. The Context instantiates the Fiber (`this.fiber = new Fiber(...)`) and stores a reference to it, but the Fiber controls when code runs, stops, and cleans up. Think of Context as the environment and Fiber as the process scheduler.

### How does Cordis handle hot-reloading of services?

Cordis handles hot-reloading through the **Fiber's effect system**. When `ctx.fiber.update(config)` is called, the Fiber transitions through states (loading, active, unloading) and executes all registered disposables from previous `effect()` calls. Services don't manage reload logic directly; they register cleanup functions when calling `effect()`, and the Fiber guarantees these run before reinitializing with new configuration.

### Why does Service need to register with ctx.reflect?

Registration with `ctx.reflect.provide()` (as seen in [`packages/core/src/service.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/service.ts)) makes the service discoverable by Cordis's **dependency injection system**. When the Fiber checks implementations (`_checkImpl`) or resolves dependencies for plugins, it queries the reflection registry to locate service instances. Without this registration, the Fiber cannot inject the service into dependent components or verify that required dependencies exist.

### Can I access the Fiber directly without using the Service base class?

**Yes.** While extending `Service` provides conveniences like automatic reflection registration, you can interact with the Fiber directly through any `Context` instance. Simply call `ctx.fiber.effect()`, `ctx.fiber.update()`, or other Fiber methods directly. This pattern is useful for lightweight scripts or when integrating Cordis into existing codebases where inheriting from `Service` isn't practical.