Zodra

Type Basics

Define object types with primitive fields, validations, and defaults

Type Basics

Types are the foundation of Zodra. Define them in app/types/ and they become the single source of truth for your backend and frontend.

Defining a type

app/types/customer.rb
Zodra.type :customer do
  uuid :id
  string :name
  string :email
  string? :phone
  timestamps
end

Each type is registered globally in the TypeRegistry and can be referenced by name from contracts, other types, and generated output.

Primitive types

MethodRuby typeZod output
stringStringz.string()
integerIntegerz.number().int()
decimalBigDecimalz.number()
numberNumericz.number()
booleanBooleanz.boolean()
datetimeDateTimez.iso.datetime()
dateDatez.iso.date()
uuidStringz.uuid()
binaryStringz.string()

Optional fields

Append ? to any type method to make the field optional:

Zodra.type :profile do
  string :name           # required
  string? :bio           # optional
  integer? :age          # optional
end

This is equivalent to passing optional: true:

string :bio, optional: true

Nullable fields

A nullable field accepts nil as a value but is still required in the payload:

Zodra.type :customer do
  string :notes, nullable: true
end

Optional and nullable are independent — a field can be both:

string? :notes, nullable: true  # can be omitted OR set to nil

Validations

min / max

For strings, validates length. For numbers, validates value:

string :name, min: 1, max: 255    # length between 1 and 255
integer :age, min: 0, max: 150    # value between 0 and 150
decimal :price, min: 0            # non-negative

format

Adds format validation hint (used in generated TypeScript):

string :email, format: "email"

enum

Restricts values to a fixed set:

string :status, enum: %w[draft published archived]
integer :priority, enum: [1, 2, 3]

For reusable enums, see Enums and Unions.

default

Sets a default value:

boolean :published, default: false
string :role, default: "member"
integer :priority, default: 0

Key aliasing

Use as: to override the generated key name for a field. The Ruby attribute name stays the same for serialization, but the exported TypeScript/Zod key uses the alias:

Zodra.type :product do
  uuid :id
  string :name
  string :internal_code, as: "code"
end

Generates:

export const ProductSchema = z.object({
  id: z.uuid(),
  name: z.string(),
  code: z.string(),   // aliased from :internal_code
});

This is useful when the Ruby attribute name differs from the desired API field name.

Timestamps

The timestamps shortcut adds created_at and updated_at datetime fields:

Zodra.type :post do
  uuid :id
  string :title
  timestamps  # adds created_at and updated_at
end

On this page