← Back to Home

Models

Define your domain models in JSON

What are Models?

Models are JSON files that describe your domain. Clay reads these models and uses them with templates to generate code. Think of models as the blueprint for what you want to build.

Basic Model Structure

{
  "name": "user-service",
  "generators": ["./generators/api"],
  "model": {
    "types": [
      {
        "name": "User",
        "fields": [
          { "name": "id", "type": "string" },
          { "name": "email", "type": "string" },
          { "name": "name", "type": "string" }
        ]
      }
    ]
  }
}

Model Properties

name (required)

The name of your model/project:

"name": "user-service"

generators (required)

Array of generators to run on this model:

"generators": [
  "./generators/api",
  "./generators/frontend",
  "clay-model-documentation"
]

model (required)

Your actual domain model structure. Can be any JSON structure:

"model": {
  "types": [...],
  "services": [...],
  "config": {...}
}

Special Properties

mixin

Apply JavaScript functions to transform parts of your model:

{
  "name": "order-service",
  "mixins": ["mixins/add-timestamps.js"],
  "model": {
    "types": [
      {
        "name": "Order",
        "mixin": ["add-timestamps"],
        "fields": [...]
      }
    ]
  }
}

Mixin file example (mixins/add-timestamps.js):

module.exports = function(type) {
  type.fields = type.fields || [];
  type.fields.push(
    { name: 'createdAt', type: 'timestamp' },
    { name: 'updatedAt', type: 'timestamp' }
  );
  return type;
};

include

Split large models into multiple files:

{
  "name": "my-app",
  "model": {
    "types": [
      { "include": "entities/user.json" },
      { "include": "entities/order.json" }
    ],
    "events": [
      { "include": "events/user-events.json" }
    ]
  }
}

Included file (entities/user.json):

{
  "name": "User",
  "fields": [
    { "name": "id", "type": "string" },
    { "name": "email", "type": "string" }
  ]
}

Model Organization

Recommended directory structure:

clay/
├── model.json              # Main model file
├── mixins/                 # Reusable transformations
│   ├── timestamps.js
│   └── validation.js
├── entities/               # Split model files
│   ├── user.json
│   ├── order.json
│   └── product.json
└── generators/             # Custom generators
    └── api/
        ├── generator.json
        └── templates/

JSONPath Selectors

Generators use JSONPath to select parts of your model. Common patterns:

Pattern Selects
$.model.types[*] All types
$.model.types[*].fields[*] All fields of all types
$.model.types[?(@.isActive)] Types where isActive is true
$.model.types[*].fields[?(@.type=='array')] Array-type fields

Test JSONPath expressions with:

clay test-path ./clay/model.json "$.model.types[*].fields[*]"

Example: E-commerce Model

{
  "name": "ecommerce",
  "generators": ["./generators/api", "./generators/frontend"],
  "mixins": ["mixins/timestamps.js", "mixins/validation.js"],
  "model": {
    "types": [
      {
        "name": "Product",
        "mixin": ["timestamps", "validation"],
        "fields": [
          { "name": "id", "type": "string", "required": true },
          { "name": "name", "type": "string", "required": true },
          { "name": "price", "type": "number", "required": true },
          { "name": "description", "type": "string" },
          { "name": "category", "type": "string", "required": true }
        ],
        "commands": [
          {
            "name": "updatePrice",
            "parameters": [
              { "name": "newPrice", "type": "number" }
            ],
            "raises": "price_updated"
          }
        ]
      },
      {
        "name": "Order",
        "mixin": ["timestamps"],
        "fields": [
          { "name": "id", "type": "string", "required": true },
          { "name": "userId", "type": "string", "required": true },
          { "name": "items", "type": "array", "required": true },
          { "name": "total", "type": "number", "required": true },
          { "name": "status", "type": "string", "required": true }
        ]
      }
    ]
  }
}

Best Practices

💡 Pro Tip: Use the clay watch command during development. It automatically regenerates code whenever you modify your model!