# Plugin Configuration Validation in Cordis Using @standard-schema/spec

> Learn how Cordis validates plugin configuration using @standard-schema/spec. Discover the validation process and error handling during fiber initialization.

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

---

**Cordis validates plugin configuration by treating the static `Config` property as a Standard Schema and invoking its `~standard.validate` method during fiber initialization, throwing a dedicated `ValidationError` for any constraint violations.**

Cordis leverages the `@standard-schema/spec` package to enforce runtime type safety on plugin configurations. When a plugin defines a schema via its `Config` static property, the framework automatically validates all provided options against that schema before the plugin's `apply` function executes.

## Declaring Configuration Schemas in Plugins

In Cordis, plugins expose their configuration requirements through a static `Config` property defined on the `Plugin.Base` interface.

### The Plugin.Base Interface

As defined in [`packages/core/src/registry.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/registry.ts), the base plugin interface accepts an optional `Config` property typed as `StandardSchemaV1`:

```typescript
export interface Plugin.Base<T = any> {
  /** optional schema for the plugin's config */
  Config?: StandardSchemaV1<any, T>
}

```

This property connects the plugin to a concrete schema object that conforms to the Standard Schema specification.

### Runtime Schema Storage

When a plugin is registered, Cordis stores its configuration schema on the internal `Plugin.Runtime` object. From [`packages/core/src/registry.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/registry.ts):

```typescript
runtime = { name, callback, fibers: new DisposableList(), Config: plugin.Config }

```

This ensures the schema remains accessible throughout the plugin's lifecycle for validation during instantiation.

## The Configuration Validation Pipeline

Cordis validates configuration during fiber construction through a dedicated resolution function that interfaces directly with the Standard Schema validator.

### Validation Entry Point

The `Fiber` constructor initiates validation by calling `resolveConfig` with the runtime object and user-provided configuration. In [`packages/core/src/fiber.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/fiber.ts):

```typescript
this.config = resolveConfig(runtime, config)

```

This single call triggers the entire validation workflow before the plugin receives its configuration.

### Schema Resolution and Validation

The `resolveConfig` function checks for the special `~standard` key introduced by `@standard-schema/spec` and executes the schema's `validate` method. From [`packages/core/src/fiber.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/fiber.ts):

```typescript
const result = runtime.Config['~standard'].validate(config)

```

The `~standard` property contains the standardized validation interface defined by the `@standard-schema/spec` package, ensuring interoperability with any schema library that implements the specification.

### Error Handling with ValidationError

When validation fails, Cordis throws a custom `ValidationError` that formats schema issues for readability. In [`packages/core/src/fiber.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/fiber.ts):

```typescript
if (result.issues) throw new ValidationError(result.issues)

```

Defined in [`packages/core/src/fiber.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/fiber.ts) (lines 19‑27), this error class bubbles up to the plugin registration point, causing instantiation to fail and logging detailed constraint violations.

## Practical Implementation Examples

### Defining a Plugin with Schema Validation

Here is a complete example of defining a Cordis plugin with a Standard Schema configuration:

```typescript
import { StandardSchemaV1 } from '@standard-schema/spec'

export const MyPlugin = {
  name: 'my',
  // Define a schema using the StandardSchemaV1 DSL
  Config: StandardSchemaV1.object({
    port: StandardSchemaV1.number().minimum(0).maximum(65535).default(8080),
    debug: StandardSchemaV1.boolean().default(false),
  }),
  apply(ctx, config) {
    // `config` is already validated and coerced to the correct types
    ctx.logger.info(`Listening on ${config.port}, debug=${config.debug}`)
  },
}

```

### Loading and Validating Plugins

When loading the plugin, valid configurations proceed normally while invalid inputs trigger immediate errors:

```typescript
import { createContext } from 'cordis'

const ctx = createContext()
await ctx.plugin(MyPlugin, { port: 3000 })   // valid – runs normally
await ctx.plugin(MyPlugin, { port: -1 })    // throws ValidationError

```

### Catching Validation Errors

Handle configuration errors gracefully by catching `ValidationError`:

```typescript
try {
  await ctx.plugin(MyPlugin, { port: -1 })
} catch (err) {
  if (err instanceof ValidationError) {
    console.error('Plugin config error:', err.message)
  }
}

```

## Key Source Files and Dependencies

The configuration validation system spans three critical locations in the Cordis core:

- **[`packages/core/src/registry.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/registry.ts)** – Declares `Plugin.Base.Config` as `StandardSchemaV1` and stores the schema on the runtime object during plugin registration.
- **[`packages/core/src/fiber.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/fiber.ts)** – Implements `resolveConfig`, invokes `runtime.Config['~standard'].validate`, and throws `ValidationError` when issues are detected.
- **[`packages/core/src/fiber.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/fiber.ts) (lines 19‑27)** – Defines the `ValidationError` class that formats schema validation issues for debugging.
- **[`packages/core/package.json`](https://github.com/cordiverse/cordis/blob/main/packages/core/package.json)** – Lists `@standard-schema/spec` as a dependency (`^1.1.0`), providing the standardized validation interface.

## Summary

- **Cordis delegates all configuration validation to `@standard-schema/spec`**, checking plugin configs against Standard Schema definitions before initialization.
- **Plugins declare schemas via the static `Config` property** on `Plugin.Base`, which gets stored on the `Plugin.Runtime` object for lifecycle access.
- **The `Fiber` constructor triggers validation** through `resolveConfig`, which calls the schema's `~standard.validate` method.
- **Validation failures throw `ValidationError`** with detailed formatting of schema issues, halting plugin instantiation immediately.
- **No manual validation is required** in plugin code; Cordis guarantees type-safe, validated configuration objects in the `apply` function.

## Frequently Asked Questions

### What happens if a plugin doesn't define a Config schema?

If the `Config` property is undefined on the plugin object, Cordis skips schema validation entirely and passes the raw configuration object directly to the plugin's `apply` function. According to the source in [`packages/core/src/registry.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/registry.ts), the `Config` property is optional on `Plugin.Base`, making schema validation an opt-in feature for type safety.

### Can I use any schema library with Cordis configuration validation?

Yes, any library that implements the Standard Schema specification (`@standard-schema/spec`) is compatible with Cordis. The framework specifically looks for the `~standard` property on the schema object and calls its `validate` method, as implemented in [`packages/core/src/fiber.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/fiber.ts), ensuring interoperability across Zod, Valibot, ArkType, or other compliant validators.

### How does Cordis handle nested configuration objects?

Cordis delegates nested object validation entirely to the Standard Schema implementation. When `resolveConfig` calls `runtime.Config['~standard'].validate(config)` in [`packages/core/src/fiber.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/fiber.ts), the schema library handles deep validation of nested properties. Any issues found at any depth are aggregated in the `result.issues` array and thrown as a single `ValidationError`.

### Where is the ValidationError class defined and how do I import it?

The `ValidationError` class is defined in [`packages/core/src/fiber.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/fiber.ts) between lines 19‑27. You can import it from the `@cordis/core` package to perform instance checks when catching configuration errors: `import { ValidationError } from '@cordis/core'`. This allows you to distinguish schema validation failures from other runtime errors during plugin registration.