# Cordis vs Koa vs Fastify: Plugin Framework Comparison

> Compare Cordis Koa and Fastify plugin frameworks Discover Cordis advanced features like HMR and lifecycle control alongside Koa middleware and Fastify encapsulation for better application structure.

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

---

**Cordis provides a fiber-based plugin system with built-in hot-module replacement and granular lifecycle control, while Koa relies on simple middleware functions without native plugin management, and Fastify offers encapsulated plugin scopes with manual teardown hooks.**

When evaluating Node.js frameworks for building modular applications, understanding the plugin architecture is critical. This comparison examines how **Cordis** (from the `cordiverse/cordis` repository), **Koa**, and **Fastify** handle plugin registration, lifecycle management, and code reloading. Unlike traditional middleware-based systems, Cordis treats plugins as first-class objects with dedicated fibers and registries, whereas Koa and Fastify take different approaches to composition and isolation.

## Cordis: Fiber-Based Plugin Registry

Cordis implements a dedicated, composable plugin system built on top of a **fiber-based** runtime. According to the Cordis source code, the core runtime maintains a **registry** of plugin metadata and creates a **fiber** for each plugin, enabling independent lifecycle control.

### Core Registry and Fiber Management

In [`packages/core/src/registry.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/registry.ts), the `Registry` class tracks plugin metadata including name, entry, group flags, and configuration. When you register a plugin using `ctx.plugin(plugin, config?)`, the system creates an isolated fiber:

```typescript
// packages/core/src/registry.ts
export class Registry { 
  // Tracks plugin metadata and fiber instances
}

```

The loader, implemented in [`packages/loader/src/index.ts`](https://github.com/cordiverse/cordis/blob/main/packages/loader/src/index.ts), resolves plugin entry points and creates fibers through the `internal/plugin` event:

```typescript
// packages/loader/src/index.ts
ctx.on('internal/plugin', (fiber) => { 
  // Fiber creation and management logic 
})

```

### Hierarchical and Dynamic Plugins

Cordis supports nested plugins through the **group** plugin (`@cordisjs/plugin-group`), defined in [`packages/loader/src/config/group.ts`](https://github.com/cordiverse/cordis/blob/main/packages/loader/src/config/group.ts). For configuration-based loading, the **include** plugin (`@cordisjs/plugin-include`) watches YAML/JSON files and hot-reloads changes. The explicit **HMR** layer in `@cordisjs/plugin-hmr` watches source files and reloads fibers without restarting the application.

## Koa: Middleware Stack Pattern

**Koa** (v2) functions as a lightweight web framework that relies on a **middleware stack** rather than a formal plugin system. A "plugin" in Koa is typically a function that returns middleware:

```javascript
app.use(async (ctx, next) => {
  await next()
})

```

Koa does not provide a built-in plugin registry, scoping mechanism, or lifecycle hooks. Developers must manually manage registration order by pushing functions onto the stack, and hot-reloading requires external tools like `nodemon`. Because middleware are simple functions, there is no explicit enable/disable lifecycle beyond adding or removing functions from the stack.

## Fastify: Encapsulated Plugin Scopes

**Fastify** ships with a structured plugin system that creates **encapsulation scopes** for each registered plugin. Plugins are functions that receive a Fastify instance and options object, registered via `fastify.register(plugin, opts)`:

```typescript
await app.register(plugin, { prefix: '/api' })

```

Each registration creates an isolated instance with its own decorators, hooks, and routes. Fastify provides the `fastify-plugin` helper for autoinjecting dependencies across scopes and supports lifecycle hooks like `onClose` for graceful teardown. However, hot-module-replacement is not native; developers typically rely on external tools such as `fastify-cli` with `ts-node-dev`.

## Feature Comparison

**Plugin Registration**

- **Cordis**: Uses `ctx.plugin(plugin, config?)` with a centralized registry tracking all metadata and fiber states.
- **Koa**: Pushes middleware functions onto a stack via `app.use(fn)` with no registry or metadata tracking.
- **Fastify**: Uses `fastify.register(plugin, opts)` to create encapsulated scopes with isolated state.

**Lifecycle Control**

- **Cordis**: Supports enable, disable, dispose, and HMR operations through fiber management.
- **Koa**: Requires manual stack manipulation; no built-in lifecycle hooks for activation or deactivation.
- **Fastify**: Provides `onClose` and `onRegister` hooks, but teardown is largely manual.

**Hot Module Replacement**

- **Cordis**: Built-in HMR via `@cordisjs/plugin-hmr` watches files and reloads individual fibers.
- **Koa**: No native support; requires external process managers.
- **Fastify**: No native support; relies on external development tools.

**Dependency Injection**

- **Cordis**: Plugins declare an `inject` array; the loader resolves dependencies automatically.
- **Koa**: No DI system; dependencies shared via closure or external containers.
- **Fastify**: `fastify-plugin` exposes decorators for later plugins to consume.

**Scope Isolation**

- **Cordis**: Fibers isolate state per plugin; sharing occurs through the shared context.
- **Koa**: Uses a shared `ctx` object with no isolation between middleware.
- **Fastify**: Encapsulation scopes isolate decorators, hooks, and routes per plugin.

## Implementation Examples

### Cordis Plugin Registration

In [`packages/timer/tests/index.spec.ts`](https://github.com/cordiverse/cordis/blob/main/packages/timer/tests/index.spec.ts), the timer plugin demonstrates how Cordis handles configuration and events:

```typescript
import { Context } from '@cordisjs/core'
import Timer from '@cordisjs/plugin-timer'

async function main() {
  const ctx = new Context()
  await ctx.plugin(Timer, { interval: 1000 })
  ctx.on('timer', (msg) => console.log('tick:', msg))
}
main()

```

### Koa Middleware Pattern

Standard Koa usage involves adding logging or utility middleware directly:

```javascript
const Koa = require('koa')
const app = new Koa()

app.use(async (ctx, next) => {
  console.log('Request start')
  await next()
  console.log('Request end')
})

app.listen(3000)

```

### Fastify Encapsulated Plugin

Using `fastify-plugin` to expose decorators within isolated scopes:

```typescript
import fastify from 'fastify'
import fp from 'fastify-plugin'

const plugin = fp(async (instance, opts) => {
  instance.decorate('custom', () => 'hello')
  instance.get('/hello', (req, reply) => reply.send(instance.custom()))
})

async function start() {
  const app = fastify()
  await app.register(plugin)
  await app.listen(3000)
}
start()

```

## Key Source Files in Cordis

The Cordis architecture is implemented across several packages:

- **[`packages/core/src/registry.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/registry.ts)**: Defines the `Registry` class that tracks plugin metadata and fiber instances.
- **[`packages/loader/src/index.ts`](https://github.com/cordiverse/cordis/blob/main/packages/loader/src/index.ts)**: Handles plugin loading, entry point resolution, and fiber creation.
- **[`packages/loader/src/config/group.ts`](https://github.com/cordiverse/cordis/blob/main/packages/loader/src/config/group.ts)**: Implements hierarchical plugin grouping.
- **[`packages/include/src/index.ts`](https://github.com/cordiverse/cordis/blob/main/packages/include/src/index.ts)**: Provides the include plugin for configuration file watching.
- **[`packages/hmr/src/index.ts`](https://github.com/cordiverse/cordis/blob/main/packages/hmr/src/index.ts)**: Contains the HMR implementation that disposes and reloads fibers.

## Summary

- **Cordis** provides a **fiber-based runtime** with a central registry, built-in HMR, and granular lifecycle control for complex, long-running services.
- **Koa** offers a lightweight **middleware stack** without native plugin management, requiring external tools for reloading and manual composition.
- **Fastify** delivers **encapsulated scopes** with decorator isolation and lifecycle hooks, though HMR requires external development tools.
- Cordis's **dependency injection** and **group/include plugins** enable hierarchical, configuration-driven architectures not native to Koa or Fastify.
- For applications requiring **hot-reloadable modules** and **fine-grained plugin control**, Cordis provides capabilities that extend beyond Fastify's encapsulation or Koa's middleware pattern.

## Frequently Asked Questions

### What is the main architectural difference between Cordis and Fastify plugins?

Cordis implements a **fiber-based** architecture where each plugin runs in its own fiber with independent lifecycle management, while Fastify uses **encapsulation scopes** that isolate decorators and routes but run within the same process context. Cordis tracks all plugins in a central registry ([`packages/core/src/registry.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/registry.ts)) with metadata, whereas Fastify relies on function-based registration without a central metadata store.

### Does Koa support hot module replacement like Cordis?

No, **Koa does not provide native HMR**. As a middleware-based framework, Koa requires you to add or remove functions from the stack manually, and any hot-reloading must be handled by external process managers like `nodemon` or `ts-node-dev`. In contrast, **Cordis provides `@cordisjs/plugin-hmr`**, which watches source files and performs granular fiber disposal and reloading without restarting the entire application.

### How does Cordis handle plugin dependencies?

Cordis supports **explicit dependency injection** through the `inject` array property on plugin objects. The loader in [`packages/loader/src/index.ts`](https://github.com/cordiverse/cordis/blob/main/packages/loader/src/index.ts) resolves these dependencies before instantiating the plugin fiber. Fastify achieves similar functionality through `fastify-plugin` to break encapsulation, while Koa has no built-in DI mechanism, forcing developers to share state via closures or external containers.

### Which framework is best for building modular, long-running services?

**Cordis** is designed specifically for modular, long-running services that require **fine-grained lifecycle control**, **hot module replacement**, and **hierarchical plugin organization**. Fastify suits high-performance web APIs with its encapsulation model, while Koa remains ideal for lightweight middleware pipelines where minimal overhead is prioritized over plugin management features.