# Cordis Service Initialization Sequence: How the Framework Boots Up

> Understand the Cordis service initialization sequence. Learn how Cordis boots up by creating a Context, registering services, merging configurations, and executing init hooks.

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

---

**Cordis initializes services through a deterministic pipeline that creates a Context, registers Service instances via reflection, merges configurations through interceptor chains, and executes dependency-aware init hooks.**

Cordis employs a systematic **service initialization sequence** that transforms plain configuration objects into fully wired applications. This process centers on the `Context` class and the abstract `Service` base defined in `@cordis/core`. Understanding this boot pipeline is essential for developers building plugins or custom services that must initialize in the correct order with access to the proper configuration.

## Step 1: Context Creation via the Entry Point

The sequence begins when you call `create()` from the `@cordis/create` package. Located in [`packages/create/src/index.ts`](https://github.com/cordiverse/cordis/blob/main/packages/create/src/index.ts), this function instantiates a new `Context` object and immediately registers all built-in core services—including the logger, timer, and loader—before user-defined services are processed.

```typescript
import { create } from '@cordis/create'

// Creates context and registers built-in services
const app = create({
  myService: { greeting: 'Hello, Cordis!' }
})

```

## Step 2: Service Construction and Self-Registration

When a service class extends the abstract `Service` base class from [`packages/core/src/service.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/service.ts), its constructor executes a specific registration protocol:

- **Identification**: The constructor reads the `static provide` field to determine the service name (e.g., `static provide = 'myService'`).
- **Tracking**: It creates an internal *tracker* object that records the association between the service instance and its context.
- **Reflection**: It calls `ctx.reflect.provide(name, self, this[Service.check])` to register the instance with the context’s reflector.

This self-registration mechanism ensures that every service automatically inserts itself into the framework's dependency graph upon instantiation.

## Step 3: Registry Population

The `ctx.reflect.provide` method delegates to the registry implementation in [`packages/core/src/registry.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/registry.ts). This registry maintains a map of service names to their instances and records dependency relationships. The registry is crucial for later phases because it tracks which services depend on others, enabling the framework to respect initialization order during the boot phase.

## Step 4: Configuration Resolution

Before a service becomes fully operational, Cordis merges its configuration. The `Service[Symbol.resolveConfig]` method (defined in [`packages/core/src/service.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/service.ts)) walks the context’s interceptor chain to compose the final configuration object. This allows multiple plugins or中间件 to contribute to or override service settings before the service starts consuming them.

## Step 5: The Initialization Phase

Once all services are constructed and registered, the framework triggers the initialization phase by calling `ctx.start()` (or `app.start()`). The context iterates over the registry and, for any service that defines the static `[Service.init]` symbol, invokes that hook:

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

export class MyService extends Service<{ greeting: string }> {
  static provide = 'myService'
  
  static [Service.init] (ctx: Context) {
    ctx.logger.info('MyService has been initialized')
  }
}

```

This hook supports asynchronous operations, allowing services to open database connections, start timers, or perform network discovery before the application declares itself ready.

## Step 6: Dependency-Aware Ordering

The initialization sequence respects **isolates** (plugin boundaries) and explicit dependency metadata. If a service declares `dependsOn`, the framework ensures those dependencies initialize first. The `Context.isolate` map ensures services only see configuration and sibling services belonging to the same isolate, preventing cross-plugin side effects and providing clean sandboxing.

## Step 7: Application Ready State

After all `[Service.init]` hooks resolve successfully, the `Context` is fully operational. Users can retrieve service instances via `ctx.get('serviceName')` or access them directly on the application object if exported as proxies.

## Complete Working Example

```typescript
// src/my-service.ts
import { Service, Context } from '@cordis/core'

export class MyService extends Service<{ greeting: string }> {
  static provide = 'myService'
  
  static [Service.init] (ctx: Context) {
    ctx.logger.info('MyService has been initialized')
  }

  get greeting() {
    return this.config.greeting
  }
}

```

```typescript
// src/app.ts
import { create } from '@cordis/create'
import { MyService } from './my-service'

const app = create({
  myService: { greeting: 'Hello, Cordis!' }
})

// Triggers the full initialization sequence
await app.start()

console.log(app.myService.greeting) // → "Hello, Cordis!"

```

## Summary

- **`create()`** in [`packages/create/src/index.ts`](https://github.com/cordiverse/cordis/blob/main/packages/create/src/index.ts) constructs the `Context` and instantiates core services.
- **Service constructors** in [`packages/core/src/service.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/service.ts) self-register via `ctx.reflect.provide()` using the `static provide` identifier.
- The **registry** in [`packages/core/src/registry.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/registry.ts) tracks instances and dependencies.
- **`Service[Symbol.resolveConfig]`** merges configuration through the interceptor chain.
- **`[Service.init]`** hooks execute asynchronously during `ctx.start()` in dependency-aware order.
- **Isolates** via `Context.isolate` enforce plugin boundaries during initialization.

## Frequently Asked Questions

### What triggers the service initialization sequence in Cordis?

The sequence starts when you invoke `create()` from `@cordis/create`, which constructs a `Context` instance and immediately instantiates built-in services. The initialization phase completes when you explicitly call `await app.start()`, which triggers the `[Service.init]` hooks for all registered services.

### How does Cordis handle dependencies between services during initialization?

Cordis tracks dependencies through the registry in [`packages/core/src/registry.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/registry.ts) and respects explicit `dependsOn` metadata declared on service classes. The initialization iterator processes services in a dependency-aware order, ensuring that prerequisite services complete their `[Service.init]` hooks before dependent services begin theirs.

### Can service initialization hooks be asynchronous?

Yes. The `[Service.init]` static method can be `async` or return a Promise. The framework in [`packages/core/src/service.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/service.ts) awaits these hooks during the `ctx.start()` phase, allowing services to perform asynchronous setup such as establishing database connections or loading remote configuration before the application becomes ready.

### Where does Cordis store the mapping between service names and instances?

Cordis stores this mapping in the context's registry, implemented in [`packages/core/src/registry.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/registry.ts). When a service constructor calls `ctx.reflect.provide()`, the framework populates this registry with the service name (derived from `static provide`), the instance reference, and dependency metadata, making services retrievable via `ctx.get('serviceName')`.