Extension overview

Last updated: 2026-06-18

Use this page when you want to extend schema-dsl but are not sure whether you need a custom type, a factory, a chain method, a validation keyword, or a plugin manager.

The extension system has several layers. They can be combined, but they solve different jobs.

Which extension should I use?

GoalRecommended documentTypical result
Reuse a DSL literal such as tenantId!Custom DSL Typess({ tenant: 'tenantId!' })
Expose a discoverable factoryCustom s.xxx() Factoriess.tenantId().require()
Add a builder methodCustom Chain Methodss('string!').tenantId()
Keep direct String-chain authoringCustom Chain Methods, String Extensions'string!'.tenantId() after transform or explicit String support
Add a validation keywordCustom Validation Keywords{ type: 'number', isEven: true }
Isolate extensions per app, tenant, plugin, or workerFramework Integration, Runtime Isolationconst runtime = createRuntime({ types })
Coordinate install/uninstall and hooksPlugin Manager (Advanced)pluginManager.install(schemaDsl, 'plugin')
Combine several extension types in one packageAdvanced Extension Recipestype + factory + keyword + locale

The three schema authoring layers

Custom extension work is easiest to reason about when you separate these layers:

LayerWhat it controlsExample
DSL typeA reusable literal parsed by the DSL parsertenantId!
Namespace factoryA discoverable function on s / dsls.tenantId()
Chain methodA method on an existing builders('string!').tenantId()

A single extension definition can expose the first two layers with registerExtension({ literal, factoryName, schema }). A custom chain method is a separate concern because it needs a runtime builder method and TypeScript interface augmentation.

Global and runtime-scoped extensions

Use the global schema-dsl/pure entry when an application has one extension set loaded at startup:

import { s } from 'schema-dsl/pure';

s.registerExtension({
  literal: 'tenant-id',
  factoryName: 'tenantId',
  schema: { type: 'string', pattern: '^tenant_[a-z0-9]+$' }
});

Use schema-dsl/runtime when a framework, plugin host, tenant, test suite, or worker needs isolated extension state:

import { createRuntime } from 'schema-dsl/runtime';

const runtime = createRuntime({
  types: {
    tenantId: { type: 'string', pattern: '^tenant_[a-z0-9]+$' }
  }
});
  1. Read Custom DSL Types if you want reusable literals.
  2. Read Custom s.xxx() Factories if you want editor-discoverable factories.
  3. Read Custom Chain Methods if you want new builder methods.
  4. Read Framework Integration before wiring extensions into a real application or framework.
  5. Read Plugin Manager (Advanced) only when you need plugin lifecycle and hooks.

Corresponding sample file

Example entry: extensions-overview.ts Note: Shows the custom DSL type, namespace factory, runtime-scoped type, and validation keyword paths side by side.