# How to Configure Cordis: A Complete Guide to Context, Loaders, and Runtime Updates

> Configure Cordis with this comprehensive guide. Learn to manage context, loaders, and runtime updates for seamless configuration.

- Repository: [Cordiverse/cordis](https://github.com/cordiverse/cordis)
- Tags: how-to-guide
- Published: 2026-09-13

---

**Cordis stores configuration in a mutable `Loader.Config` object attached to the Context, supporting both static initialization and runtime updates via the `internal/update` event system.**

The `cordiverse/cordis` framework treats configuration as a first-class citizen that lives alongside the dependency injection container. When you configure Cordis, you are not merely passing static settings; you are establishing a reactive configuration graph that propagates changes from the global context down to individual entries and groups.

## The Loader Constructor and Initial Configuration

Configuration enters the system through the `Loader` class constructor in [[`packages/loader/src/index.ts`](https://github.com/cordiverse/cordis/blob/main/packages/loader/src/index.ts)](https://github.com/cordiverse/cordis/blob/main/packages/loader/src/index.ts#L59). The loader accepts a `Context` instance and an optional `Loader.Config` object, which it stores as a public property:

```typescript
// packages/loader/src/index.ts
constructor(ctx: Context, public config: Loader.Config = {}) {
  if (config.baseUrl) {
    this.ctx.baseUrl = config.baseUrl
  }
}

```

This initialization step establishes the **base URL** and other global options immediately. The `config` parameter accepts any plain JavaScript object, allowing you to define arbitrary hierarchical settings without a enforced schema.

## Runtime Configuration Updates

Cordis supports dynamic reconfiguration through its event system. The loader listens for the `internal/update` event to rewrite the stored configuration and notify all dependent components:

```typescript
// packages/loader/src/index.ts
ctx.on('internal/update', function (config, noSave, next) {
  this.entry.options.config = unparse ? unparse(config) : config
  next()
})

```

As shown at [line 74 of the loader index](https://github.com/cordiverse/cordis/blob/main/packages/loader/src/index.ts#L74), the handler receives the new configuration, optionally serializes it using an `unparse` function, and assigns it to the entry's options. Calling `next()` propagates the update through the middleware chain.

## Entry-Level Configuration Interpolation

Individual entries do not directly access the global config object. Instead, they receive an interpolated version specific to their context. In [[`packages/loader/src/config/entry.ts`](https://github.com/cordiverse/cordis/blob/main/packages/loader/src/config/entry.ts)](https://github.com/cordiverse/cordis/blob/main/packages/loader/src/config/entry.ts#L80), the `Entry` class exposes a `config` getter that processes the raw options through the `interpolate` function:

```typescript
// packages/loader/src/config/entry.ts
get config() {
  if (plugin[EntryGroup.key]) return this.options.config
  return interpolate(this.ctx, this.options.config)
}

```

This mechanism allows entries to resolve configuration values that reference context variables or other dynamic sources. If an entry belongs to a group, it returns the raw config; otherwise, it interpolates the values against the current context.

## Group Configuration Propagation

Configuration changes cascade through the hierarchy via groups. The `Group` class in [[`packages/loader/src/config/group.ts`](https://github.com/cordiverse/cordis/blob/main/packages/loader/src/config/group.ts)](https://github.com/cordiverse/cordis/blob/main/packages/loader/src/config/group.ts#L79) listens for the same `internal/update` event and triggers updates for all member entries:

```typescript
// packages/loader/src/config/group.ts
ctx.on('internal/update', (config) => {
  this.update(config)
})

```

When a group's configuration updates, the `update` method iterates over its children and reapplies the configuration, ensuring that the entire tree remains synchronized with the global state.

## Static Configuration with YAML Files

For declarative setups, Cordis supports loading configuration from YAML files. The test suite includes an example at [[`packages/hmr/tests/cordis.yml`](https://github.com/cordiverse/cordis/blob/main/packages/hmr/tests/cordis.yml)](https://github.com/cordiverse/cordis/blob/main/packages/hmr/tests/cordis.yml) that demonstrates the expected structure:

```yaml
plugins:
  - name: example
    config:
      enabled: true
      endpoint: https://api.example.com

```

You can load this file at startup by parsing it with a YAML library and passing the result to the context constructor:

```typescript
import yaml from 'js-yaml'
import { readFileSync } from 'fs'
import { createContext } from '@cordis/loader'

const raw = readFileSync('cordis.yml', 'utf8')
const cfg = yaml.load(raw) as Record<string, any>
const ctx = createContext(cfg)

```

## Practical Configuration Examples

### Initializing with a Custom Configuration

Create a context with predefined settings for plugins, logging, and base URLs:

```typescript
import { createContext } from '@cordis/loader'

const ctx = createContext({
  baseUrl: 'https://my.api.com',
  logger: { level: 'debug' },
  plugins: [
    { name: 'database', config: { connectionString: 'postgres://localhost/db' } },
    { name: 'cache', config: { ttl: 3600 } }
  ]
})

```

### Updating Configuration at Runtime

Modify settings dynamically by emitting the update event with the new configuration partial:

```typescript
// Reduce log verbosity and disable a plugin without restart
ctx.emit('internal/update', {
  logger: { level: 'error' },
  plugins: [
    { name: 'cache', config: { enabled: false } }
  ]
})

```

### Entry-Specific Configuration Access

Inside a plugin or service, access your assigned configuration slice through the entry's `config` property:

```typescript
export default class MyService {
  constructor(ctx: Context) {
    const entry = ctx.get('loader').getEntry(this)
    const myConfig = entry.config
    
    console.log(`Endpoint configured as: ${myConfig.endpoint}`)
  }
}

```

## Summary

- **Global configuration** resides in the `Loader` instance as a public `config` property initialized in the [constructor](https://github.com/cordiverse/cordis/blob/main/packages/loader/src/index.ts#L59).
- **Runtime changes** propagate through the `internal/update` event, which rewrites stored configs at [line 74](https://github.com/cordiverse/cordis/blob/main/packages/loader/src/index.ts#L74).
- **Entry isolation** is maintained through the `interpolate` function in [[`entry.ts`](https://github.com/cordiverse/cordis/blob/main/entry.ts)](https://github.com/cordiverse/cordis/blob/main/packages/loader/src/config/entry.ts#L80), allowing context-aware configuration values.
- **Hierarchical updates** cascade from groups to their children via the event listener in [[`group.ts`](https://github.com/cordiverse/cordis/blob/main/group.ts)](https://github.com/cordiverse/cordis/blob/main/packages/loader/src/config/group.ts#L79).
- **YAML support** enables static configuration files that mirror the JavaScript object structure, as demonstrated in the [test fixtures](https://github.com/cordiverse/cordis/blob/main/packages/hmr/tests/cordis.yml).

## Frequently Asked Questions

### How do I update Cordis configuration at runtime without restarting the application?

Emit the `internal/update` event on the context with the new configuration object. The loader listens for this event at [line 74 of the loader index](https://github.com/cordiverse/cordis/blob/main/packages/loader/src/index.ts#L74) and automatically propagates changes to all registered entries and groups.

### What is the difference between entry config and group config in Cordis?

Entry config applies to individual plugins or services and is processed through the `interpolate` function to resolve context variables. Group config manages collections of entries; when updated, it cascades the configuration to all members through the [`update` method in [`group.ts`](https://github.com/cordiverse/cordis/blob/main/group.ts)](https://github.com/cordiverse/cordis/blob/main/packages/loader/src/config/group.ts#L79).

### Can I use YAML files instead of JavaScript objects to configure Cordis?

Yes. Cordis accepts any plain object as configuration, so you can parse YAML files using libraries like `js-yaml` and pass the resulting object to `createContext()`. The [test suite](https://github.com/cordiverse/cordis/blob/main/packages/hmr/tests/cordis.yml) provides a working example of the expected YAML structure.

### Where is the configuration stored internally within the Cordis framework?

The configuration is stored as a public property `config` on the `Loader` class instance, which is typically attached to the global context. Entries access their specific configuration slice through the getter defined in [[`packages/loader/src/config/entry.ts`](https://github.com/cordiverse/cordis/blob/main/packages/loader/src/config/entry.ts)](https://github.com/cordiverse/cordis/blob/main/packages/loader/src/config/entry.ts#L80), which interpolates values against the current context state.