Skip to main content

Available Operators

Rule Engine JS includes 20+ built-in operators organized into 7 categories:

Quick Reference

OperatorDescriptionExample
eqEquals{ eq: ['age', 18] }
neqNot equals{ neq: ['status', 'inactive'] }
gtGreater than{ gt: ['score', 90] }
gteGreater than or equal{ gte: ['age', 18] }
ltLess than{ lt: ['temperature', 100] }
lteLess than or equal{ lte: ['price', 50] }
OperatorDescriptionExample
andAll conditions must be true{ and: [rule1, rule2] }
orAt least one condition must be true{ or: [rule1, rule2] }
notNegates a condition{ not: [rule] }
OperatorDescriptionExample
containsString contains substring{ contains: ['name', 'John'] }
startsWithString starts with prefix{ startsWith: ['email', 'admin'] }
endsWithString ends with suffix{ endsWith: ['file', '.pdf'] }
regexMatches regular expression{ regex: ['email', '^[a-z]+@'] }
OperatorDescriptionExample
inValue exists in array{ in: ['admin', 'roles'] }
notInValue does not exist in array{ notIn: ['banned', 'users'] }
OperatorDescriptionExample
betweenValue is within range (inclusive){ between: ['age', [18, 65]] }
OperatorDescriptionExample
isNullValue is null or undefined{ isNull: ['optionalField'] }
isNotNullValue is not null/undefined{ isNotNull: ['requiredField'] }
OperatorDescriptionExample
changedValue changed from previous evaluation{ changed: ['status'] }
changedByNumeric value changed by amount{ changedBy: ['price', 10] }
changedFromChanged from specific value{ changedFrom: ['status', 'pending'] }
changedToChanged to specific value{ changedTo: ['status', 'active'] }
increasedNumeric value increased{ increased: ['temperature'] }
decreasedNumeric value decreased{ decreased: ['stock'] }

Operator Syntax

All operators follow a consistent syntax pattern:
{
  operatorName: [argument1, argument2, ...]
}

Single-Argument Operators

// isNull - checks if field is null/undefined
{ isNull: ['optionalField'] }

// not - negates a condition
{ not: [{ eq: ['status', 'active'] }] }

Two-Argument Operators

// eq - equals comparison
{ eq: ['age', 18] }

// contains - substring check
{ contains: ['name', 'John'] }

// in - array membership
{ in: ['admin', 'roles'] }

Multi-Argument Operators

// and - combine multiple conditions
{ and: [
  { gte: ['age', 18] },
  { eq: ['role', 'admin'] },
  { in: ['write', 'permissions'] }
]}

// between - range check
{ between: ['age', [18, 65]] }

Using Rule Helpers

The Rule Helpers API provides a more readable way to build rules:
  • Direct JSON
  • Rule Helpers
const rule = {
  and: [
    { gte: ['age', 18] },
    { eq: ['role', 'admin'] },
    { contains: ['email', '@company.com'] }
  ]
};

Type Coercion

By default, operators perform type coercion for flexibility:
// These all pass with type coercion
{ eq: ['age', '25'] }      // Compares 25 == '25' (true)
{ gte: ['score', '90'] }   // Compares 95 >= '90' (true)
{ contains: ['code', 123] } // Converts 123 to string

// Strict mode disables coercion
const strictEngine = createRuleEngine({ strict: true });
{ eq: ['age', '25'] }      // Compares 25 === '25' (false)
Use strict mode in production for type safety: createRuleEngine({ strict: true })

Operator Composition

Operators can be nested and combined for complex logic:
// Complex nested rule
const rule = {
  and: [
    // Age check
    { between: ['age', [18, 65]] },

    // Role and permissions
    { or: [
      { eq: ['role', 'admin'] },
      { and: [
        { eq: ['role', 'editor'] },
        { in: ['publish', 'permissions'] }
      ]}
    ]},

    // Email validation
    { and: [
      { isNotNull: ['email'] },
      { regex: ['email', '^[^@]+@[^@]+\\.[^@]+$'] }
    ]}
  ]
};

Custom Operators

Extend the engine with custom business logic:
// Register custom operator
engine.registerOperator('isBusinessHours', (args, context) => {
  const now = new Date();
  const hour = now.getHours();
  const day = now.getDay();

  // Monday-Friday, 9 AM - 5 PM
  return day >= 1 && day <= 5 && hour >= 9 && hour < 17;
});

// Use like built-in operators
const rule = {
  and: [
    { isBusinessHours: [] },
    { eq: ['support.available', true] }
  ]
};
Custom operators work seamlessly with all built-in operators and the Rule Helpers API.

Performance Considerations

Operator Order

Place faster operators first in and conditions to fail early
rules.and(
  rules.eq('active', true),  // Fast
  rules.regex('email', pattern) // Slower
)

Avoid Deep Nesting

Deeply nested rules are harder to cache and slower to evaluate
// Prefer flat over deeply nested
rules.or(cond1, cond2, cond3)

Cache-Friendly Paths

Use consistent path names to maximize cache hits
// Good - consistent
rules.eq('user.email', value)

// Avoid - dynamic paths
rules.eq(`${prefix}.email`, value)

Batch Similar Rules

Group related rules for better cache utilization
const userRules = {
  isActive: rules.eq('status', 'active'),
  isAdmin: rules.eq('role', 'admin'),
  hasEmail: rules.isNotNull('email')
}

Next Steps