0.433 (21 Jan 2026)

21 January, 2026

This release unifies the expression system across Keel, making all arithmetic operators, aggregate functions, and scalar functions work consistently in @where, @set, @permission, and @computed expressions.

Unified Expression System

Expressions now work consistently across all contexts. Arithmetic operators, aggregate functions, and scalar functions that previously only worked in computed fields can now be used in permissions, filters, and set expressions.

Arithmetic in Permissions

You can now use calculations in permission rules to control access based on computed values:

model Budget {
  fields {
    limit Decimal
    spent Decimal
  }
 
  actions {
    list listBudgetsWithBalance() {
      // Permission based on arithmetic
      @permission(expression: budget.limit - budget.spent > 100)
    }
  }
}

Aggregate Functions in Filters

Use aggregate functions in @where expressions to filter based on related data:

model Customer {
  fields {
    orders Order[]
  }
 
  actions {
    list listHighValueCustomers() {
      // Filter customers by total order value
      @where(SUM(customer.orders.total) > 1000)
    }
 
    list listFrequentBuyers() {
      // Filter by number of orders
      @where(COUNT(customer.orders.id) >= 5)
    }
  }
}

Conditional Logic in Set Expressions

Apply conditional updates using the IF function in @set expressions:

model Product {
  fields {
    isActive Boolean
    price Decimal
    finalPrice Decimal
  }
 
  actions {
    update applyDiscount(id) {
      // Set different prices based on conditions
      @set(product.finalPrice = IF(product.isActive, product.price * 0.9, product.price))
    }
  }
}

This unification means you can now use the full expression feature set—including SUM, COUNT, AVG, MIN, MAX, MEDIAN, conditional variants like SUMIF and COUNTIF, date functions like YEAR, MONTH, ADDDAYS, and the IF function—across all expression contexts.

New Scalar Functions

This release also introduces scalar functions for conditional logic and date operations:

FunctionDescriptionExample
IFReturns one value if condition is true, another if falseIF(order.isPriority, "Rush", "Standard")
YEARExtracts the year from a date or timestampYEAR(order.createdAt)
MONTHExtracts the month (1-12) from a date or timestampMONTH(order.createdAt)
DAYExtracts the day of month (1-31) from a date or timestampDAY(order.createdAt)
HOURExtracts the hour (0-23) from a timestampHOUR(order.createdAt)
MINUTEExtracts the minute (0-59) from a timestampMINUTE(order.createdAt)
SECONDExtracts the second (0-59) from a timestampSECOND(order.createdAt)
ADDDAYSAdds or subtracts days from a date or timestampADDDAYS(order.dueDate, 7)
ADDMONTHSAdds or subtracts months from a date or timestampADDMONTHS(subscription.startDate, 1)
ADDYEARSAdds or subtracts years from a date or timestampADDYEARS(contract.startDate, 2)
DIFFCalculates the difference in days between two datesDIFF(task.deadline, task.startedAt)

See the Expressions reference for the complete list of supported functions and detailed usage examples.

Schema Formatting with keel format

You can now automatically format your Keel schema files using the new keel format command. This ensures consistent code style across your project.

keel format

The command formats all .keel files in your project, standardizing indentation, spacing, and structure. This is especially useful for team projects where maintaining consistent formatting matters. You can also integrate it into your pre-commit hooks or CI pipeline to enforce formatting standards.

Learn more about Keel CLI commands in the CLI documentation.

Automatic Foreign Key Indexes

Keel now automatically creates database indexes for all foreign key columns during migrations. This improves query performance for relationship lookups without any changes to your schema.

For example, when you define a relationship like this:

model Order {
  fields {
    customer Customer
    items OrderItem[]
  }
}
 
model OrderItem {
  fields {
    order Order
    product Product
  }
}

Keel will now automatically create indexes on the customerId column in the order table and on the orderId and productId columns in the order_item table. These indexes make queries that filter or join on relationships significantly faster, especially as your data grows.

This optimization happens automatically in new migrations—no action needed on your part. For more on relationships and how Keel generates database tables, see the Models documentation.

Fixes and Improvements

  • Fixed permission logic for flows and tasks with multiple @permission rules. Multiple rules now correctly use OR logic, meaning access is granted if any of the permission conditions are met.
  • Fixed validation for computed field expressions to prevent using model type names directly in expressions.

For a full list of fixes and improvements, check out our GitHub releases page (opens in a new tab).

For any issues or feedback, please contact us at help@keel.so.

Thank you for using Keel!