# What Is a Fiber in Cordis and What Is Its Purpose?

> Understand what a Fiber is in Cordis, the core runtime unit managing plugin lifecycles, configuration, and dependencies. Learn its essential purpose for efficient plugin execution.

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

---

**A Fiber in Cordis is the fundamental runtime unit that encapsulates a single plugin instance and its execution context, managing everything from lifecycle states and configuration validation to dependency injection and hot‑reloading.**

In the [cordiverse/cordis](https://github.com/cordiverse/cordis) framework, every plugin you register becomes a Fiber. This architecture abstracts the complex orchestration of plugin systems, ensuring side‑effects are tracked deterministically and the runtime remains stable even when individual plugins fail.

## Core Responsibilities of a Fiber

The Fiber class in [`packages/core/src/fiber.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/fiber.ts) handles seven critical responsibilities that make Cordis plugins robust and predictable.

### Lifecycle State Management

A Fiber tracks its current state through the `FiberState` enum, which defines six possible states:

- `PENDING` – initial state before loading begins
- `LOADING` – actively executing the plugin function
- `ACTIVE` – successfully loaded and running
- `FAILED` – encountered an error during load or reload
- `UNLOADING` – actively disposing and cleaning up
- `DISPOSED` – fully cleaned up and inactive

The internal state machine transitions between these states based on method calls and async operations. You can inspect `fiber.state` at any time to check a plugin's health.

### Configuration Validation

Before a plugin executes, the Fiber validates its configuration against a `StandardSchemaV1` definition. The `resolveConfig` function handles this validation, throwing a `ValidationError` when the provided config fails schema requirements.

This validation happens in the Fiber constructor and during `fiber.update()` calls, ensuring malformed configuration never reaches plugin code.

### Effect Execution and Disposal

The `effect` method registers side‑effects that automatically clean up when the Fiber unloads:

```typescript
ctx.fiber.effect(() => {
  const timer = setInterval(() => ctx.logger.info('tick'), 1000)
  return () => clearInterval(timer)  // disposer
}, 'periodic tick')

```

Effects can return:
- A function (disposer)
- An iterable of disposers
- A promise resolving to either

The `_execute` helper in [`packages/core/src/fiber.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/fiber.ts) manages execution and guarantees proper disposal ordering—inner effects dispose before outer effects.

### Dependency Injection

When created, a Fiber instantiates a child `Context` that inherits from its parent while exposing itself via `ctx.fiber`. This context is injected into the plugin function, allowing access to services declared by other plugins.

The constructor injection logic (`packages/core/src/fiber.ts#L33-L45`) validates that required services exist and satisfy interface constraints before activation proceeds.

### Hot‑Reloading and Inertia Locking

Cordis supports dynamic plugin updates through the `_setEpoch`, `_reload`, and `_unload` methods. When configuration changes or dependencies update, the Fiber:

1. Computes a new epoch string identifying the desired state
2. Acquires the `inertia` promise as a lock to prevent overlapping operations
3. Executes unload then reload in sequence
4. Releases the lock for the next operation

This inertia mechanism ensures consistent state even during rapid successive changes.

### Error Propagation

Runtime errors in plugins transition the Fiber to `FiberState.FAILED` and reject the `await()` promise. Callers can handle failures through standard promise methods:

```typescript
const badFiber = await root.plugin(faultyPlugin)
await badFiber.catch(err => {
  console.error('Plugin failed:', err)  // fiber.state === FiberState.FAILED
})

```

Errors in `_reload` and other internal methods follow the same propagation path through the `await` implementation (`packages/core/src/fiber.ts#L22-L27`).

### Public Control API

The Fiber exposes three primary control methods for runtime interaction:

| Method | Purpose |
|--------|---------|
| `update(config)` | Change configuration and trigger hot‑reload |
| `restart()` | Force unload and reload with current configuration |
| `await()` | Returns a promise that resolves when Fiber reaches `ACTIVE` or rejects on `FAILED` |

## Creating and Using Fibers

### Basic Plugin Registration

Registering a plugin always returns a Fiber instance:

```typescript
import { Context } from '@cordis/core'

function hello(ctx: Context) {
  ctx.logger.info('Hello, world!')
}

const root = new Context()
const fiber = await root.plugin(hello)  // ← Fiber created

await fiber  // resolves when ACTIVE

```

The `root.plugin()` method internally constructs a new Fiber, executes its loading sequence, and returns the instance for control and monitoring.

### Configuration Updates and Hot‑Reload

Plugins accepting configuration can be updated dynamically:

```typescript
function greeter(ctx: Context, config: { greeting: string }) {
  ctx.logger.info(config.greeting)
}

const fiber = await root.plugin(greeter, { greeting: 'Hi' })
await fiber  // ACTIVE

fiber.update({ greeting: 'Hello again' })
await fiber  // waits for reload completion

```

The `update` method triggers `_setEpoch` with new configuration, queueing a reload through the inertia lock system.

## Fiber Implementation Architecture

The core implementation lives in [`packages/core/src/fiber.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/fiber.ts) with supporting systems throughout the codebase:

- **[`packages/core/src/context.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/context.ts)** – Defines `Context` with `ctx.fiber` reference and the `extend` method Fibers use for context inheritance
- **[`packages/core/src/service.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/service.ts)** – Base class for injectable services that integrate with Fiber lifecycle
- **[`packages/core/tests/fiber.spec.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/tests/fiber.spec.ts)** – Comprehensive tests for state transitions, locking behavior, and error scenarios
- **[`packages/core/src/events.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/events.ts)** – Event system emitting `internal/plugin` and `internal/status` lifecycle events

## Summary

- **A Cordis Fiber is the runtime container for a single plugin**, managing its complete lifecycle from loading through disposal
- **State machine tracking** via `FiberState` enum provides visibility into plugin health
- **Automatic effect disposal** ensures resources clean up in correct order when plugins unload
- **Hot‑reload with inertia locking** prevents race conditions during configuration changes
- **Configuration validation** through `StandardSchemaV1` rejects invalid configs before plugin execution
- **Promise-based control** via `await()`, `update()`, and `restart()` enables reactive plugin management

## Frequently Asked Questions

### How does a Fiber differ from a Context in Cordis?

A **Context** (`ctx`) is the dependency injection container passed to plugins, while a **Fiber** is the lifecycle manager that creates and owns that Context. Every Fiber has exactly one Context accessible via `ctx.fiber`, but Contexts can form hierarchies where child contexts inherit parent services. The Fiber handles the plugin's execution state; the Context handles service resolution and event routing.

### What triggers a Fiber to reload automatically?

Automatic reloads occur when: (1) `fiber.update(newConfig)` is called with different configuration, (2) a service declared as a dependency is added, removed, or modified in a parent context, or (3) `fiber.restart()` is invoked explicitly. The `_setEpoch` method computes a string fingerprint of the desired state; when this differs from the current epoch, the Fiber queues an unload/reload cycle through the inertia lock.

### Can multiple Fibers share the same plugin function?

Yes. The plugin function is just a factory; each call to `ctx.plugin(myFunction)` creates a distinct Fiber with its own state, context, and configuration. Multiple Fibers from the same function operate independently—one can be `ACTIVE` while another is `FAILED` or `DISPOSED`, with no shared state unless explicitly designed through external variables or injected services.

### What happens if a Fiber's effect throws during disposal?

Disposal errors are caught and logged, but they do not prevent subsequent effects from disposing. The Fiber proceeds through its cleanup sequence, transitioning to `DISPOSED` once all registered disposers have executed. If critical cleanup is required, effects should implement their own error handling and retry logic rather than relying on the Fiber's default behavior.