# Cordis Config Patching System for Insert, Override, and Group Management

> Discover the Cordis config patching system. Effortlessly modify include configurations with insertions, overrides, and group management without altering original files. Enhance your project today.

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

---

**Cordis lets a project modify an include configuration at load time without touching the original file through a declarative patching system that supports insertions, property overrides, and group-aware hierarchy management.**

The **Cordis config patching system** provides runtime modification of plugin configurations through the `@cordisjs/plugin-include` package. This architecture enables teams to overlay environment-specific changes, toggle features, and extend modular plugin trees—all while keeping base configuration files pristine.

## How the Config Patching System Works

The patching lifecycle operates in two stages: **static configuration transformation** performed by the include plugin, followed by **runtime context propagation** handled by the loader. Together, these enable hot-reloadable, hierarchical plugin management.

### Core Patch Operations

Cordis recognizes three fundamental operations based on patch object structure:

| Operation | Trigger | Target Behavior |
|-----------|---------|-----------------|
| **Insert** | Patch contains `insert` property | Add new entries to root list or specified group |
| **Override** | Patch has `id` but no `insert` | Modify existing entry properties |
| **Group-aware lookup** | Any patch with `id` referencing a group | Navigate nested `config` arrays via `entryMap` |

## Insert Operation: Adding New Entries

The **insert operation** appends plugin entries to either the root configuration array or a specific group's nested configuration.

In [`packages/include/src/index.ts`](https://github.com/cordiverse/cordis/blob/main/packages/include/src/index.ts), the `applyPatches` function handles insertion at lines [101–135](https://github.com/cordiverse/cordis/blob/main/packages/include/src/index.ts#L101-L135):

- When `insert` is present and `id` is omitted, entries push to the root list
- When `id` specifies a group, entries append to that group's `config` array
- Non-group targets trigger a warning via the loader logger

```typescript
// packages/include/src/index.ts (simplified)
if (patch.insert) {
  const target = patch.id ? entryMap.get(patch.id) : undefined
  if (target?.options.group) {
    // Insert into group's nested config
    target.options.config ??= []
    target.options.config.push(...patch.insert)
  } else if (!patch.id) {
    // Insert at root level
    result.push(...patch.insert)
  }
}

```

## Override Operation: Modifying Existing Entries

The **override operation** updates properties of an existing entry without full replacement. This requires a mandatory `id` and optionally validates against `name`.

From [`packages/include/src/index.ts`](https://github.com/cordiverse/cordis/blob/main/packages/include/src/index.ts) lines [136–162](https://github.com/cordiverse/cordis/blob/main/packages/include/src/index.ts#L136-L162):

1. Locate target via `entryMap.get(patch.id)`
2. Verify optional `name` match (emits warning on mismatch)
3. Assign every patch key except `id` directly onto the entry

Common override targets include `disabled` (boolean), `config` (object), `name` (string), and `group` (boolean).

## Group Management and Entry Map

Cordis builds a recursive **entry map** to enable fast lookup across arbitrarily nested group hierarchies. This structure is constructed at lines [105–114](https://github.com/cordiverse/cordis/blob/main/packages/include/src/index.ts#L105-L114):

```typescript
// Recursive map construction for O(1) lookups
const entryMap = new Map<string, EntryOptions>()

function walk(entries: EntryOptions[], path: string) {
  for (const entry of entries) {
    entryMap.set(entry.id, { path, options: entry })
    if (entry.group && entry.config) {
      walk(entry.config, `${path}.${entry.id}`)
    }
  }
}

```

This **group management** capability allows patches to target deeply nested plugin structures without knowledge of absolute array indices.

## Runtime Propagation via Patch Context

When configuration changes affect running services, Cordis triggers the **patch-context waterfall** in [`packages/loader/src/config/entry.ts`](https://github.com/cordiverse/cordis/blob/main/packages/loader/src/config/entry.ts) lines [84–92](https://github.com/cordiverse/cordis/blob/main/packages/loader/src/config/entry.ts#L84-L92):

```typescript
// packages/loader/src/config/entry.ts
private _patchContext(diff: string[]) {
  this.context.waterfall('loader/patch-context', this, () => {
    Object.setPrototypeOf(this.ctx, this.parent.ctx)

    if (this.fiber?.uid && (diff.includes('config') || this.options.group)) {
      this.fiber.update(this._resolveConfig(this.fiber.runtime!.callback), true)
    }
  })
}

```

The waterfall mechanism ensures **fiber re-initialization** occurs with proper context inheritance when `config` changes or the entry represents a group.

## Complete Patch Configuration Example

```yaml

# base.yml — original include file (immutable)

- id: core-group
  name: ./group-plugin
  group: true
  config:
    - id: database
      name: ./database-plugin
      config: { host: 'localhost' }
    - id: cache
      name: ./cache-plugin

```

```typescript
// Runtime patch application via @cordisjs/plugin-include
await ctx.loader.create({
  name: '@cordisjs/plugin-include',
  config: {
    path: './base.yml',
    patches: [
      // Insert: Add plugin to root
      { insert: [{ id: 'metrics', name: './metrics-plugin' }] },

      // Insert: Add plugin to existing group
      { id: 'core-group', insert: [{ id: 'queue', name: './queue-plugin' }] },

      // Override: Disable existing entry
      { id: 'cache', disabled: true },

      // Override: Modify configuration
      { id: 'database', config: { host: 'prod.db.internal', poolSize: 20 } },

      // Override: With name validation
      { id: 'metrics', name: './metrics-plugin', config: { interval: 5000 } }
    ]
  }
})

```

Result after patch application:
- `metrics` and `queue` plugins load with their configurations
- `cache` entry exists but remains inactive (`disabled: true`)
- `database` connects to production host with enlarged connection pool

## Key Implementation Files

| File | Responsibility |
|------|---------------|
| [`packages/include/src/index.ts`](https://github.com/cordiverse/cordis/blob/main/packages/include/src/index.ts) | Patch processing logic (`applyPatches`, `entryMap` construction) |
| [`packages/loader/src/config/entry.ts`](https://github.com/cordiverse/cordis/blob/main/packages/loader/src/config/entry.ts) | Runtime fiber updates via `_patchContext` |
| [`packages/include/tests/patch.spec.ts`](https://github.com/cordiverse/cordis/blob/main/packages/include/tests/patch.spec.ts) | Comprehensive test coverage for all patch variants |
| [`packages/include/tests/fixtures/base.yml`](https://github.com/cordiverse/cordis/blob/main/packages/include/tests/fixtures/base.yml) | Reference configuration for test scenarios |

## Summary

- **Insert operation** adds entries to root lists or group configurations via the `insert` property, processed in [`packages/include/src/index.ts`](https://github.com/cordiverse/cordis/blob/main/packages/include/src/index.ts) lines 101–135
- **Override operation** mutates existing entries by `id`, supporting property-level updates without full replacement (lines 136–162)
- **Group management** relies on recursive `entryMap` construction enabling fast hierarchical lookups
- **Runtime propagation** uses the `loader/patch-context` waterfall to re-initialize fibers when configuration changes
- The complete system spans static transformation (`@cordisjs/plugin-include`) and dynamic updates (`@cordisjs/loader`)

## Frequently Asked Questions

### How does Cordis handle patches targeting non-existent entries?

The patching system emits warnings through the loader logger when an `id` cannot be found in `entryMap`, or when a `name` verification fails. The patch is skipped but processing continues for remaining patches.

### Can I insert entries into multiple nested groups simultaneously?

No—each insert patch targets a single group via one `id`. To insert across multiple branches, specify separate patch objects with distinct `id` references in the `patches` array.

### What happens when I override the `group` property of an existing entry?

Changing `group: true` to `group: false` (or vice versa) alters how subsequent patches resolve the entry's nested `config` array. The `entryMap` is rebuilt during the next patch cycle, so structural changes take effect immediately for remaining patches in the same operation.

### Is there a performance cost to large patch arrays?

The `entryMap` construction is O(n) over total entry count, making patch application efficient even for deep hierarchies. However, each config change triggering `_patchContext` may cause fiber re-initialization—batch related overrides into single patches where possible to minimize runtime overhead.