Laizy CMS
Schema

Constraints

Control field validation with required, default, unique, and maxLength constraints in Laizy schemas.

Constraints

Constraints control validation and behavior for each field in your schema. They go inside curly braces after the field type and determine how content is validated when created or updated.

Syntax

Constraints use a key-value syntax inside { } blocks after the field type:

fieldName: FieldType {
  constraintName: value
}

Boolean constraints can omit the value -- just writing the constraint name is equivalent to setting it to true:

// These are equivalent:
title: String { required: true }
title: String { required }

Fields without constraints do not need curly braces at all:

model Author {
  name: String { required: true }
  bio: String
}

Available Constraints

required

Makes a field mandatory when creating content. If a required field is not provided, the creation will fail with a validation error.

Applies to: All field types

model BlogPost {
  title: String {
    required: true
  }

  content: String {
    required: true
  }

  // Optional field — no curly braces needed
  subtitle: String
}

Behavior:

  • Required fields must have a value when creating content
  • Required fields without default generate warning impact during migrations (existing content needs a value)
  • In the generated TypeScript client, required fields are non-optional in the Create input type
  • Optional fields (without required: true) are marked with ? in the Create input type

Generated TypeScript:

export interface CreateBlogPostInput {
  title: string      // required — no ?
  content: string    // required — no ?
  subtitle?: string  // optional — has ?
}

default

Sets a default value that is used when the field is not provided during content creation. Fields with defaults are excluded from the generated Create input type since they always have a fallback value.

Applies to: All field types (value must match the field type)

model BlogPost {
  status: String {
    default: "draft"
  }

  viewCount: Int {
    default: 0
  }

  isPublished: Boolean {
    default: false
  }
}

Behavior:

  • The default value is applied when content is created without this field
  • Fields with defaults are safe to add during migrations (no data loss)
  • Default values are used as auto-fill values during migration when making a field required
  • The value type must match the field type (strings for String, numbers for Int/Float, booleans for Boolean)

Fields with default are excluded from the generated CreateInput interface. Since they always have a value, they do not need to be provided by the caller.

Generated TypeScript:

// 'status' has a default, so it's excluded from CreateInput
export interface CreateBlogPostInput {
  title: string
  content: string
}

// But it still appears in the Update and read interfaces
export interface UpdateBlogPostInput {
  title?: string
  content?: string
  status?: string
}

unique

Enforces uniqueness across all content entries of the same model. No two entries can have the same value for a unique field.

Applies to: All field types

model Author {
  email: String {
    required: true
    unique: true
  }
}

model BlogPost {
  slug: String {
    required: true
    unique: true
  }
}

Behavior:

  • Attempting to create or update content with a duplicate value will fail
  • Unique constraints are enforced at the database level
  • Adding a unique constraint to an existing field is a safe migration (unless duplicates already exist)
  • Commonly combined with required for identifiers like slugs, emails, or SKUs

maxLength

Limits the character count for String fields. Content creation or update will fail if the string exceeds this length.

Applies to: String fields only

model BlogPost {
  title: String {
    required: true
    maxLength: 200
  }

  excerpt: String {
    maxLength: 500
  }
}

Behavior:

  • The value must be a positive integer
  • Validation happens before content is saved
  • Adding or changing maxLength is a safe migration (existing content is not modified, only future writes are validated)
  • Removing maxLength is also safe (less restrictive)

maxLength only applies to String fields. Using it on Int, Float, Boolean, or DateTime fields has no effect.

Combining Constraints

Multiple constraints can be applied to a single field. Each constraint goes on its own line inside the curly braces:

model Product {
  name: String {
    required: true
    maxLength: 200
  }

  sku: String {
    required: true
    unique: true
    maxLength: 50
  }

  price: Float {
    required: true
  }

  inStock: Boolean {
    default: true
  }

  description: String
}

Common Constraint Patterns

Identifier fields (slugs, SKUs, emails):

slug: String {
  required: true
  unique: true
}

Status fields with a default:

status: String {
  default: "draft"
}

Title fields with length limits:

title: String {
  required: true
  maxLength: 200
}

Counter fields starting at zero:

viewCount: Int {
  default: 0
}

Toggle fields defaulting to off:

isPublished: Boolean {
  default: false
}

Constraint Validation Summary

ConstraintValid TypesValue FormatMigration Impact
requiredAlltrue / falseWarning if adding to existing model (needs default values)
defaultAllMust match field typeSafe (provides fallback value)
uniqueAlltrue / falseSafe (unless duplicates exist)
maxLengthStringPositive integerSafe (only affects future writes)

Migration Behavior

When you change constraints in your schema and run laizy sync, the migration planner evaluates the safety of each change:

Safe changes (no confirmation needed):

  • Adding default to any field
  • Adding maxLength or changing its value
  • Making a required field optional (removing required)
  • Adding or removing unique

Warning changes (confirmation required):

  • Making an optional field required without a default (existing content may have null values)
  • Adding a new required field without a default to an existing model

Destructive changes:

  • Removing a field entirely (data loss)
  • Incompatible type changes

The sync command shows these impacts clearly in the migration plan table before asking for confirmation.

Next Steps

  • Field Types -- All available field types and their behaviors
  • Migrations -- How the sync command handles schema changes safely
  • Schema Syntax -- Full reference for the .laizy schema language

On this page