---
title: "Conditions — Workflows for Laravel | Roundly"
description: "Declarative JSON conditions — all, any, not and field clauses, operators per field type, null, decimal and date semantics, and their publish checks."
url: https://roundly-consulting.com/open-source/docs/workflows-for-laravel/conditions
language: en
---

[All packages](https://roundly-consulting.com/open-source.md)

[Workflows for Laravel](https://roundly-consulting.com/open-source/docs/workflows-for-laravel.md)

# Conditions

Conditions are declarative JSON. There is no expression language, no code and no regex from users: a fixed interpreter walks the parsed tree and reads registered fields only.

```jsonc
{ "all": [                                            // all = AND, any = OR, not = negation; nest freely
    { "field": "subject.amount", "op": "gt", "value": "50000" },
    { "any": [
        { "field": "subject.department", "op": "in", "value": ["legal", "finance"] },
        { "field": "input.urgent", "op": "equals", "value": true } ] },
    { "field": "subject.due_on", "op": "before", "value": { "relative": "P7D" } },   // now + 7 days
    { "field": "owner.plan", "op": "equals", "value": { "ref": "trigger.plan" } }
] }
```

- Left operand: field — a value path (subject.\*, owner.\*, input.\*, trigger.\*, steps.<id>.output.\*).
- Right operand: a literal, {"ref": path}, {"relative": duration} (dates only, relative to now), or \[low, high\] for between.
- Operators: equals, in, gt, lt, between (inclusive), empty, contains, before, after.

The same in the graph builder:

```php
use RoundlyConsulting\Workflows\Graph\Build\{Ref, When};

When::all(
    When::field('subject.amount')->gt('50000'),
    When::any(
        When::field('subject.department')->in(['legal', 'finance']),
        When::field('input.urgent')->equals(true),
    ),
    When::field('subject.title')->contains('laptop', insensitive: true),
    When::not(When::field('subject.note')->isEmpty()),
    When::field('owner.plan')->equals(Ref::trigger('plan')),
);
```

## Operators per field type

| Field type | Allowed operators |
| --- | --- |
| string, text | equals, in, empty, contains (case-sensitive; add "case": "insensitive") |
| integer, decimal | equals, in, gt, lt, between, empty |
| boolean | equals, empty |
| date, datetime | equals, before, after, between, empty |
| enum | equals, in, empty |
| party | equals (by key, or {"kind": "triggered\_by"}), in, empty |
| list | contains, empty |

## Semantics

- null compares false under every operator except empty. empty is true for null, "" and \[\].
- Decimals compare as exact decimal strings (no floats): "50000", 50000 and "50000.00" are equal; exponents are refused.
- A date field compares by calendar date in the version timezone; before/after are strict. A plain YYYY-MM-DD literal is a date in that timezone. A stored date at midnight — a DATE column, Laravel’s date cast, a date trigger input — keeps the calendar day it was stored as, whatever the version and app timezones. A date field that holds a time of day is the day that instant falls on in the version timezone; a datetime compares as an instant.
- A party field equals a model, its key, or the triggering user.
- An unregistered attribute is never read, even if it exists on the model.

## Publish validation

| Problem | Code |
| --- | --- |
| Unknown field | `unknown_field` |
| Operator not allowed for the field type | `operator_not_allowed` |
| Literal of the wrong type | `invalid_value` |
| Undeclared input.\* | `unknown_input` |
| steps.<id> that is not an ancestor | `invalid_reference` |
| Deeper than conditions.max\_depth (6) or more than conditions.max\_clauses (100) clauses | `condition_too_complex` |

## Where conditions appear

condition.when, branch.cases\[\].when, wait.condition, wait.where, schedule for\_each.where, and a trigger’s condition — a filter evaluated before an instance exists; false → no instance, listed as skipped in EmitResult.

## Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

[More ways to support, including crypto](https://roundly-consulting.com/support-us.md)

By donating, you agree to our [donation terms](https://roundly-consulting.com/donation-terms.md).

[Support our open source work (opens in a new tab)](https://donate.stripe.com/dRmeVe8FX5PF1Qd9pXcEw00) [Join us on Patreon (opens in a new tab)](https://www.patreon.com/cw/roundly)

## Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.

[Get a quote in 48 hours](https://roundly-consulting.com/contact.md) [Browse all packages](https://roundly-consulting.com/open-source/docs/workflows-for-laravel.md)
