# Cordis StandardSchemaV1 Validation Integration: Complete Implementation Guide

> Implement Cordis StandardSchemaV1 validation seamlessly. This guide shows how Cordis automatically rejects invalid configs at registration, ensuring smooth plugin operations.

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

---

**Cordis automatically validates plugin configurations against StandardSchemaV1 schemas at registration time, rejecting invalid configs before the `apply` hook executes.**

Cordis is a meta-framework that enables spatiotemporal composability through a lightweight plugin system, with **Cordis StandardSchemaV1 validation integration** serving as the foundation for type-safe configuration management. This architecture leverages the `@standard-schema/spec` package to enforce configuration contracts at the boundary between the framework and plugin code.

## How StandardSchemaV1 Validation Works in Cordis

The validation pipeline operates synchronously during plugin registration, ensuring that only type-safe configurations reach plugin instances.

### The Validation Pipeline

When `ctx.plugin()` is invoked, Cordis executes a six-step validation sequence:

1. **Schema Detection** – `RegistryService` inspects the static `Config` property on the plugin definition (typed as `StandardSchemaV1<any, T>`)
2. **Config Extraction** – The supplied configuration object is extracted from the plugin call arguments
3. **Schema Validation** – The `schemastery` validator (aliased as `z`) validates the config against the schema
4. **Type Narrowing** – Validated data is cast to the TypeScript type parameter `T`
5. **Fiber Instantiation** – A `Fiber` instance is created with the guaranteed-valid configuration
6. **Error Propagation** – Validation failures reject the registration promise with descriptive path-based error messages

Because validation occurs inside `RegistryService.plugin()` before `Fiber` construction, the framework guarantees that the `apply` hook receives only sanitized input.

### Core Components

**`RegistryService`** ([`packages/core/src/registry.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/registry.ts)) orchestrates the validation flow. It reads the optional `Config` field from plugin definitions and delegates validation to the schema engine before creating fiber instances.

**`Fiber`** ([`packages/core/src/fiber.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/fiber.ts)) represents the plugin execution context. Its constructor receives the already-validated configuration object, eliminating the need for defensive programming inside plugin logic.

**`Context`** ([`packages/core/src/context.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/context.ts)) exposes the public `plugin()` and `inject()` methods that trigger the validation pipeline in `RegistryService`.

**`schemastery`** ([`packages/logger-console/src/shared.ts`](https://github.com/cordiverse/cordis/blob/main/packages/logger-console/src/shared.ts)) provides the actual validation implementation, wrapping `StandardSchemaV1` methods to perform runtime type checking and coercion.

## Implementing Schema Validation in Plugins

Plugin developers define configuration contracts through the static `Config` property using StandardSchemaV1 builders.

### Defining a Plugin Config Schema

Create a schema object that describes required fields, defaults, and formats:

```typescript
// src/plugins/api-client.ts
import { Context } from 'cordis';
import { StandardSchemaV1 } from '@standard-schema/spec';

export const ApiClientPlugin = {
  Config: StandardSchemaV1.object({
    endpoint: StandardSchemaV1.string()
      .description('Base URL for API requests')
      .format('uri')
      .required(),
    timeout: StandardSchemaV1.number()
      .default(5000)
      .minimum(100)
      .description('Request timeout in milliseconds'),
    retries: StandardSchemaV1.number()
      .integer()
      .default(3),
  }),

  async apply(ctx: Context, config: { endpoint: string; timeout: number; retries: number }) {
    ctx.logger.info(`Connecting to ${config.endpoint}`);
    // Config is guaranteed to match the schema shape
  },
};

export default ApiClientPlugin;

```

### Registering and Validating Plugins

Registration triggers immediate validation. Valid configs proceed to instantiation; invalid configs throw before any side effects occur:

```typescript
// src/index.ts
import { createApp } from '@cordis/create';
import ApiClientPlugin from './plugins/api-client';

const app = createApp({});

// Validation happens here, before apply() runs
await app.plugin(ApiClientPlugin, {
  endpoint: 'https://api.example.com',
  timeout: 10000,
  retries: 5,
});

await app.start();

```

### Error Handling and Type Safety

When validation fails, `RegistryService` rejects with a detailed error message specifying the path and constraint violation:

```

Schema validation error:
 - /endpoint: required string (uri) missing
 - /timeout: number must be >= 100

```

The TypeScript type system narrows the configuration parameter in the `apply` method to match the schema's output type, providing IntelliSense and compile-time checking alongside runtime validation.

## Core Source Files and Implementation Details

Understanding the source architecture helps debug validation behavior and extend the framework:

- **[`packages/core/src/registry.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/registry.ts)** – Contains the `RegistryService` class with the `plugin()` method that extracts `Config` schemas and invokes validation before fiber creation
- **[`packages/core/src/fiber.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/fiber.ts)** – Defines the `Fiber` class constructor that receives validated config objects after schema checking succeeds
- **[`packages/core/src/context.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/context.ts)** – Implements the public API surface (`ctx.plugin`, `ctx.inject`) that delegates to the registry's validation pipeline
- **[`packages/logger-console/src/shared.ts`](https://github.com/cordiverse/cordis/blob/main/packages/logger-console/src/shared.ts)** – Demonstrates the `schemastery` integration pattern used for StandardSchemaV1 validation throughout the framework
- **[`packages/create/src/index.ts`](https://github.com/cordiverse/cordis/blob/main/packages/create/src/index.ts)** – Entry point for `createApp()` that assembles the validation-enabled service container

## Summary

- **Early Validation** – Cordis StandardSchemaV1 validation integration catches configuration errors during plugin registration, preventing invalid states from reaching runtime.
- **Type Safety** – The `Config` static property bridges runtime validation with TypeScript's static type system, narrowing config types in the `apply` method.
- **Centralized Logic** – `RegistryService` in [`packages/core/src/registry.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/registry.ts) manages all validation orchestration, keeping plugin code free from defensive checks.
- **Standard Schema Compliance** – Cordis implements the `@standard-schema/spec` protocol, ensuring interoperability with ecosystem tools that understand StandardSchemaV1.

## Frequently Asked Questions

### What is StandardSchemaV1 in the Cordis framework?

StandardSchemaV1 is the validation specification from `@standard-schema/spec` that Cordis uses to define type-safe configuration schemas for plugins. It provides a fluent API for building validation rules (object shapes, string formats, number ranges) that are enforced at plugin registration time.

### How does Cordis handle validation errors?

When a configuration fails validation, `RegistryService` rejects the promise returned by `ctx.plugin()` with a `Schema validation error` message that includes the exact path (e.g., `/timeout`) and the constraint violation. This prevents the `Fiber` from being created and stops invalid plugins from starting.

### Where is the validation logic implemented in Cordis source code?

The validation orchestration lives in [`packages/core/src/registry.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/registry.ts) inside the `RegistryService` class, while the actual schema checking is performed by `schemastery` wrappers shown in [`packages/logger-console/src/shared.ts`](https://github.com/cordiverse/cordis/blob/main/packages/logger-console/src/shared.ts). The `Fiber` class in [`packages/core/src/fiber.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/fiber.ts) receives the validated output.

### Can I compose or reuse schemas across multiple plugins?

Yes. Because `StandardSchemaV1` supports schema composition, you can extract common configuration shapes into reusable variables and spread them into plugin `Config` definitions. The validation engine in Cordis treats composed schemas identically to inline definitions, maintaining full type inference.