CDM Plugin System Documentation
Overview
CDM plugins extend the language with code generators and migration tools. They run as WebAssembly modules in a sandboxed environment, receiving your schema as input and producing output files like SQL migrations, TypeScript types, or validation code.
Importing Plugins
Plugins are imported at the top of CDM files using @name syntax. All imports must appear before any type definitions.
// Registry plugin (built-in)
@sql {
dialect: "postgres",
schema: "public",
build_output: "./db/schema",
migrations_output: "./db/migrations"
}
// External plugin from git
@analytics from git:https://github.com/myorg/cdm-analytics.git {
version: "1.0.0"
}
// Local plugin (for development)
@custom from ./plugins/my-plugin {
debug: true
}
Reserved Configuration Keys
CDM extracts these keys before passing config to plugins:
| Key | Purpose |
|---|---|
version |
Version constraint for plugin resolution |
build_output |
Output directory for generated files |
migrations_output |
Output directory for migration files |
Plugin Sources
Registry Plugins
Official and curated plugins resolved by name:
@sql
@typescript
@validation
Git Plugins
Any accessible git repository:
@plugin from git:https://github.com/user/repo.git { version: "1.0.0" }
@plugin from git:git@github.com:org/private-repo.git { version: "main" }
Version can be a tag (1.0.0, v2.0.0), branch (main), or commit SHA.
Local Plugins
Filesystem paths for development:
@custom from ./plugins/my-plugin
@shared from ../shared-plugins/common
Configuration Levels
Plugins receive configuration at three levels:
Global Configuration
Applied at the plugin import:
@sql {
dialect: "postgres",
naming_convention: "snake_case"
}
Model Configuration
Applied to specific models or type aliases:
User {
id: UUID
email: string
@sql {
table: "users",
indexes: [{ fields: ["email"], unique: true }]
}
}
Field Configuration
Applied to specific fields:
User {
bio: string {
@sql { type: "TEXT" }
@validation { max_length: 5000 }
}
}
Creating a Plugin
Quick Start
Plugin Structure
cdm-plugin-my-plugin/
├── cdm-plugin.json # Manifest (required)
├── schema.cdm # Settings schema (required)
├── Cargo.toml
├── src/
│ ├── lib.rs
│ ├── validate.rs
│ ├── generate.rs
│ └── migrate.rs
└── README.md
Manifest (cdm-plugin.json)
Settings Schema (schema.cdm)
Define what configuration your plugin accepts:
GlobalSettings {
output_format: "json" | "yaml" = "json"
include_comments: boolean = true
}
ModelSettings {
custom_name?: string
skip: boolean = false
}
FieldSettings {
override_type?: string
exclude: boolean = false
}
Plugin Functions
validate_config (Required)
Validates user configuration. Called for every config block.
use *;
build (Optional)
Transforms the schema into output files.
migrate (Optional)
Generates migration files from schema changes.
Delta Types
When schemas change, plugins receive deltas describing what changed:
| Delta | Description |
|---|---|
ModelAdded |
New model added (includes full after definition) |
ModelRemoved |
Model deleted (includes full before definition) |
ModelRenamed |
Model renamed (includes both definitions) |
FieldAdded |
New field on a model |
FieldRemoved |
Field deleted from a model |
FieldTypeChanged |
Field type modified |
FieldOptionalityChanged |
Field changed to/from optional |
FieldDefaultChanged |
Default value modified |
TypeAliasAdded |
New type alias |
TypeAliasRemoved |
Type alias deleted |
InheritanceAdded |
Model now extends a parent |
InheritanceRemoved |
Model no longer extends a parent |
GlobalConfigChanged |
Plugin config at import level changed |
ModelConfigChanged |
Plugin config on a model changed |
FieldConfigChanged |
Plugin config on a field changed |
Utilities
change_case
Convert strings between naming conventions:
utils.change_case // "user_profile"
utils.change_case // "UserProfile"
utils.change_case // "user-profile"
utils.change_case // "USER_PROFILE"
Building Your Plugin
# Install WASM target
# Build
Testing Locally
Reference your plugin from a CDM file:
@my-plugin from ./path/to/cdm-plugin-my-plugin {
output_format: "yaml"
}
User {
name: string
email: string
}
Then run:
CLI Commands
Sandbox Environment
Plugins run in a WebAssembly sandbox with no access to the host filesystem or network. They receive schema data as JSON input and return output files that CDM writes to configured directories.
Limits apply to memory usage, execution time, and output size to prevent runaway plugins.