๐ฏ The Ultimate JSON-Based Rule Engine for Modern Applications
Quick Start โข Packages โข Examples โข Documentation โข Why This?
Transform complex business logic into elegant, maintainable JSON rules. Stop hardcoding decisions, start building intelligent systems that adapt to your business needs.
// From this mess...
if (user.tier === 'vip' && order.total > 100 && user.country === 'US') {
return { discount: 0.20, shipping: 'free' };
} else if (user.isNew && order.total > 50) {
return { discount: 0.10, shipping: 'standard' };
} // ... 50 more lines of spaghetti code
// To this elegance...
const result = await RuleEngine.evaluate(discountRules, { user, order });- ๐ฏ Zero Dependencies - Pure JavaScript excellence, no supply chain bloat
- ๐๏ธ Lightning Fast - 17,000+ rule evaluations per second with complex JSONPath support at 55,000+ ops/sec
- ๐ก๏ธ TypeScript Native - Fully typed with generic support for bulletproof type safety
- ๐ง Extensible Architecture - Create & register custom operators without core modifications
- ๐ Universal - Node.js, browsers, edge functions, Deno, Bun everywhere
- ๐ JSONPath Support - Navigate complex objects:
$.user.profile.settings.theme - ๐ Self-Referencing - Dynamic field references:
"value": "$.maxPrice" - ๐งฉ 121+ Operators - From basic comparisons to advanced pattern matching
- ๐๏ธ Visual Builder - Drag-and-drop UI for non-technical stakeholders
- ๐ง Extensible Core - Plugin custom operators without touching internals
- ๐ก๏ธ Type-Safe APIs - Generic interfaces ensure compile-time safety
- ๐ Rule Introspection - Reverse-engineer possible inputs from rule definitions
- โก Performance Optimized - Optional validation bypass for trusted rules
- ๐ญ Data Mutations - Preprocess data before evaluation
This monorepo contains two powerful packages:
| Package | Description | Install |
|---|---|---|
| @usex/rule-engine |
Fully typed core engine with generic support & custom operators | npm install @usex/rule-engine |
| @usex/rule-engine-builder |
Visual rule builder for React applications | npm install @usex/rule-engine-builder |
The core package is built with TypeScript-first design, providing complete type safety:
// Type-safe rule definitions with generics
interface DiscountResult {
discount: number;
code: string;
description: string;
}
// Generic rule with full type inference
const discountRule: Rule<DiscountResult> = {
conditions: [
{
and: [
{ field: "$.user.tier", operator: "equals", value: "premium" },
{ field: "$.order.total", operator: "greater-than", value: 100 }
],
result: {
discount: 0.20, // โ
Type-safe
code: "PREMIUM20", // โ
Type-safe
description: "20% premium discount" // โ
Type-safe
}
}
],
default: { discount: 0, code: "", description: "No discount" }
};
// Evaluation with full type inference
const result = await RuleEngine.evaluate<DiscountResult>(discountRule, orderData);
// result.value is automatically typed as DiscountResult โ
Extend the engine with your business-specific logic:
import { OperatorRegistry, BaseOperator } from '@usex/rule-engine';
// 1. Create your custom operator
class IsWeekendOperator extends BaseOperator {
name = 'is-weekend';
category = 'datetime';
evaluate(fieldValue: Date): boolean {
const day = fieldValue.getDay();
return day === 0 || day === 6; // Sunday or Saturday
}
}
class BulkDiscountEligibleOperator extends BaseOperator {
name = 'bulk-discount-eligible';
category = 'business';
evaluate(orderData: any, threshold: number): boolean {
return orderData.quantity >= threshold || orderData.value >= threshold * 10;
}
}
// 2. Register your operators
OperatorRegistry.register(new IsWeekendOperator());
OperatorRegistry.register(new BulkDiscountEligibleOperator());
// 3. Use them in your rules immediately
const weekendRule = {
conditions: {
and: [
{ field: "$.currentDate", operator: "is-weekend", value: true },
{ field: "$.order", operator: "bulk-discount-eligible", value: 10 }
],
result: {
discount: 0.25,
reason: "Weekend bulk discount!"
}
}
};
// 4. Full TypeScript support for your custom operators
const result = await RuleEngine.evaluate(weekendRule, {
currentDate: new Date(),
order: { quantity: 15, value: 200 }
}); // โ
Fully typed, including custom operators// Define complex result types
interface AccessControlResult {
allowed: boolean;
permissions: string[];
level: 'admin' | 'user' | 'guest';
expiresAt?: Date;
}
interface UserData {
role: string;
department: string;
clearanceLevel: number;
}
// Generic rule with both input and output types
const accessRule: Rule<AccessControlResult, UserData> = {
conditions: [
{
and: [
{ field: "role", operator: "equals", value: "admin" },
{ field: "clearanceLevel", operator: "greater-than", value: 5 }
],
result: {
allowed: true,
permissions: ["read", "write", "delete"],
level: "admin"
}
}
],
default: {
allowed: false,
permissions: [],
level: "guest"
}
};
// Type-safe evaluation with input validation
const userData: UserData = {
role: "admin",
department: "engineering",
clearanceLevel: 8
};
const access = await RuleEngine.evaluate<AccessControlResult, UserData>(
accessRule,
userData
);
// Both input and output are fully typed โ
npm install @usex/rule-engineimport { RuleEngine } from '@usex/rule-engine';
// Define a discount rule
const discountRule = {
conditions: [
{
// VIP customers get 20% off orders over $100
and: [
{ field: "$.customer.tier", operator: "equals", value: "vip" },
{ field: "$.order.total", operator: "greater-than", value: 100 }
],
result: { discount: 0.20, message: "VIP discount applied! ๐" }
},
{
// First-time buyers get 10% off orders over $50
and: [
{ field: "$.customer.orderCount", operator: "equals", value: 0 },
{ field: "$.order.total", operator: "greater-than", value: 50 }
],
result: { discount: 0.10, message: "Welcome! First order discount ๐" }
}
],
default: { discount: 0, message: "No discount available" }
};
// Apply the rule
const orderData = {
customer: { tier: "vip", orderCount: 5 },
order: { total: 150, items: ["laptop", "mouse"] }
};
const result = await RuleEngine.evaluate(discountRule, orderData);
console.log(result);
// { value: { discount: 0.20, message: "VIP discount applied! ๐" }, isPassed: true }npm install @usex/rule-engine-builder @usex/rule-engine reactimport React, { useState } from 'react';
import { RuleBuilder } from '@usex/rule-engine-builder';
import { RuleEngine } from '@usex/rule-engine';
function App() {
const [rule, setRule] = useState(null);
const availableFields = [
{ name: '$.user.tier', type: 'string', label: 'User Tier' },
{ name: '$.user.age', type: 'number', label: 'User Age' },
{ name: '$.order.total', type: 'number', label: 'Order Total' },
{ name: '$.order.items', type: 'array', label: 'Order Items' }
];
const testData = {
user: { tier: 'premium', age: 28 },
order: { total: 150, items: ['laptop', 'mouse'] }
};
return (
<div className="app">
<h1>Build Your Business Rules Visually</h1>
<RuleBuilder
rule={rule}
onRuleChange={setRule}
availableFields={availableFields}
testData={testData}
theme="auto"
showPreview={true}
showHistory={true}
/>
{rule && (
<button onClick={async () => {
const result = await RuleEngine.evaluate(rule, testData);
console.log('Rule Result:', result);
}}>
Test Rule
</button>
)}
</div>
);
}const pricingRules = {
conditions: [
{
// Black Friday: 50% off everything
and: [
{ field: "$.event.name", operator: "equals", value: "black-friday" },
{ field: "$.event.active", operator: "equals", value: true }
],
result: { discount: 0.50, code: "BLACKFRIDAY50", expires: "2025-11-30T23:59:59Z" }
},
{
// Bulk orders: tiered discounts
or: [
{ field: "$.cart.quantity", operator: "greater-than", value: 50 },
{ field: "$.cart.value", operator: "greater-than", value: 1000 }
],
result: { discount: 0.15, code: "BULK15", shipping: "free" }
},
{
// New customer welcome
and: [
{ field: "$.customer.orderHistory.length", operator: "equals", value: 0 },
{ field: "$.cart.value", operator: "greater-than", value: 50 }
],
result: { discount: 0.10, code: "WELCOME10", message: "Welcome! Enjoy 10% off your first order ๐" }
}
],
default: { discount: 0, message: "Regular pricing applies" }
};const accessControlRules = {
conditions: [
{
// Super admin: full access
and: [
{ field: "role", operator: "equals", value: "super-admin" },
{ field: "status", operator: "equals", value: "active" }
],
result: {
permissions: ["read", "write", "delete", "admin"],
level: "unlimited",
expires: null
}
},
{
// Department manager: departmental access during business hours
and: [
{ field: "role", operator: "equals", value: "manager" },
{ field: "department", operator: "exists", value: true },
{ field: "$.currentTime", operator: "time-between", value: ["09:00", "17:00"] }
],
result: {
permissions: ["read", "write"],
level: "department",
scope: "$.department",
expires: "$.session.loginTime + 8h"
}
}
],
default: { permissions: [], level: "none", message: "Access denied" }
};const registrationValidation = {
conditions: {
and: [
// Email validation
{
field: "email",
operator: "email",
value: true,
message: "Please enter a valid email address"
},
// Strong password requirements
{
and: [
{
field: "password",
operator: "min-length",
value: 8,
message: "Password must be at least 8 characters long"
},
{
field: "password",
operator: "matches",
value: ".*[A-Z].*",
message: "Password must contain at least one uppercase letter"
},
{
field: "password",
operator: "matches",
value: ".*[0-9].*",
message: "Password must contain at least one number"
}
]
},
// Age verification
{
field: "birthDate",
operator: "date-before",
value: "$.today - 18 years",
message: "You must be 18 or older to register"
}
]
}
};Compare fields against other fields dynamically:
const budgetRule = {
conditions: {
and: [
// Actual cost must not exceed budget
{
field: "$.project.actualCost",
operator: "less-than-or-equals",
value: "$.project.approvedBudget"
},
// Start date must be before end date
{
field: "$.project.startDate",
operator: "date-before",
value: "$.project.endDate"
}
]
}
};Construct complex rules programmatically:
const complexRule = RuleEngine.builder()
.add({
and: [
{ field: "userType", operator: "equals", value: "premium" },
{ field: "subscriptionActive", operator: "equals", value: true }
],
result: { access: "premium", features: ["analytics", "api", "support"] }
})
.add({
and: [
{ field: "userType", operator: "equals", value: "basic" },
{ field: "trialExpired", operator: "equals", value: false }
],
result: { access: "basic", features: ["dashboard"] }
})
.default({ access: "none", features: [] })
.build(true); // Validate during buildUnderstand what your rules need:
const insights = RuleEngine.introspect(complexRule);
console.log(insights);
// {
// fields: ["userType", "subscriptionActive", "trialExpired"],
// operators: ["equals"],
// possibleResults: [
// { access: "premium", features: ["analytics", "api", "support"] },
// { access: "basic", features: ["dashboard"] },
// { access: "none", features: [] }
// ],
// complexity: "medium",
// estimatedPerformance: "fast"
// }Real-world performance data from actual benchmark runs (10,000 iterations each)
| Operation | Hz (ops/sec) | Avg Time | Performance Grade |
|---|---|---|---|
| Simple Rules (3-5 conditions) | ~16,900 | 0.059ms | ๐ Lightning Fast |
| Complex Rules (nested evaluation) | ~17,400 | 0.057ms | ๐ฅ Blazing |
| Complex Rules (priority-based) | ~8,000 | 0.126ms | โก Very Fast |
| Array Operations | ~45,400 | 0.022ms | ๐ Ultra Fast |
| Feature | Hz (ops/sec) | Avg Time | Performance Grade |
|---|---|---|---|
| JSONPath Resolution (simple) | ~55,000 | 0.018ms | ๐ฅ Blazing Fast |
| JSONPath Deep Nested Access | ~54,000 | 0.019ms | ๐ฅ Blazing Fast |
| JSONPath Array Processing | ~49,500 | 0.020ms | ๐ Ultra Fast |
| Self-Referencing (complex) | ~33,600 | 0.030ms | ๐ Excellent |
| Data Mutations (simple) | ~16,300 | 0.061ms | ๐ Fast |
| Data Mutations (complex) | ~34,100 | 0.029ms | ๐ Excellent |
| Operation | Hz (ops/sec) | Use Case | Performance |
|---|---|---|---|
| Rule Builder (simple) | ~12,000,000 | Rule Construction | โก Instant |
| Rule Builder (complex) | ~94,300 | Complex Rule Building | ๐ Very Fast |
| Rule Validation | ~67,000 | Schema Validation | ๐ฅ Blazing |
| Error Handling | ~1,661,000 | Exception Processing | โก Instant |
-
Trust Mode: Skip validation for 20% performance boost
const result = await RuleEngine.evaluate(rule, data, true);
-
Batch Processing: Process multiple records at once
const results = await RuleEngine.evaluate(rule, arrayOfData);
-
Operator Selection: Prefer specific operators over general ones
{ operator: "equals" } // โ Fast { operator: "matches" } // โ ๏ธ Slower for simple cases
| Category | Count | Examples |
|---|---|---|
| Comparison | 6 | equals, greater-than, less-than |
| String | 12 | like, starts-with, matches |
| Numeric | 11 | between, divisible-by, even |
| Array | 12 | contains, contains-any, array-length |
| Date/Time | 14 | date-after, date-between, time-equals |
| Type | 10 | string, number, boolean |
| Existence | 6 | exists, empty, null-or-undefined |
| Boolean | 4 | truthy, falsy, boolean-string |
| Pattern | 2 | matches, not-matches |
| Length | 8 | min-length, max-length, length-between |
| Persian | 6 | persian-alpha, persian-number |
| Validation | 30+ | email, url, uuid, alpha-numeric |
// String operations
{ field: "name", operator: "equals", value: "John" }
{ field: "email", operator: "like", value: "*@gmail.com" }
{ field: "description", operator: "matches", value: "^Product.*" }
// Numeric comparisons
{ field: "age", operator: "greater-than", value: 18 }
{ field: "price", operator: "between", value: [10, 100] }
// Array operations
{ field: "roles", operator: "contains", value: "admin" }
{ field: "tags", operator: "contains-all", value: ["urgent", "review"] }
// Date/time
{ field: "expiryDate", operator: "date-before-now", value: true }
{ field: "openTime", operator: "time-after", value: "09:00" }
// Validation
{ field: "email", operator: "email", value: true }
{ field: "password", operator: "min-length", value: 8 }The core package is 100% TypeScript with comprehensive generic interfaces:
// ๐ก๏ธ Full generic support for input and output types
interface UserPermissions {
canRead: boolean;
canWrite: boolean;
canDelete: boolean;
level: 'admin' | 'user' | 'guest';
}
interface UserContext {
role: string;
department: string;
active: boolean;
}
// โ
Type-safe rule with both input/output generics
const accessRule: Rule<UserPermissions, UserContext> = {
conditions: [
{
and: [
{ field: "role", operator: "equals", value: "admin" },
{ field: "active", operator: "equals", value: true }
],
result: {
canRead: true,
canWrite: true,
canDelete: true,
level: "admin" // โ
Autocomplete & validation
}
}
],
default: {
canRead: false,
canWrite: false,
canDelete: false,
level: "guest" // โ
Type-safe default
}
};
// โ
Fully typed evaluation with IntelliSense
const result = await RuleEngine.evaluate<UserPermissions, UserContext>(
accessRule,
{ role: "admin", department: "IT", active: true }
);
// result.value is automatically typed as UserPermissions with full IDE support โ
Custom operators inherit full TypeScript support:
// โ
Typed custom operator interface
interface CustomOperator<T = any, V = any> {
name: string;
category: string;
evaluate(fieldValue: T, operatorValue: V): boolean;
}
// โ
Type-safe custom operator implementation
class DateRangeOperator implements CustomOperator<Date, [Date, Date]> {
name = 'date-within-range';
category = 'datetime';
evaluate(fieldValue: Date, [start, end]: [Date, Date]): boolean {
return fieldValue >= start && fieldValue <= end;
}
}
// โ
Generic operator registration with type safety
OperatorRegistry.register<Date, [Date, Date]>(new DateRangeOperator());- ๐ Core README - Complete API reference and examples
- ๐ฏ Operators Guide - All 121+ operators with examples
- ๐ก Best Practices - Production patterns and tips
- ๐ Migration Guide - Upgrading from other engines
- ๐๏ธ Builder README - React components and integration
- ๐จ Component Reference - All UI components
- โจ๏ธ Keyboard Shortcuts - Professional navigation
- ๐ฏ Integration Examples - Framework guides
- ๐๏ธ Architecture Guide - System design and patterns
- ๐ ๏ธ Development Setup - Contributing and development
- ๐ Comparison Guide - vs other rule engines
- Node.js >= 18.12.0
- pnpm >= 10.11.0
# Clone the repository
git clone https://github.com/ali-master/rule-engine.git
cd rule-engine
# Install dependencies
pnpm install
# Build all packages
pnpm build
# Run tests
pnpm test
# Run linter
pnpm lint| Script | Description |
|---|---|
pnpm build |
Build all packages |
pnpm test |
Run all tests |
pnpm lint |
Lint all packages |
pnpm test:types |
Type checking |
pnpm test:bench |
Performance benchmarks |
| Feature | @usex/rule-engine | json-rules-engine | node-rules |
|---|---|---|---|
| Zero Dependencies | โ | โ | โ |
| TypeScript Native | โ 100% + Generics | โ | |
| Custom Operators | โ Full Support | โ | |
| JSONPath Support | โ | โ | โ |
| Self-Referencing | โ | โ | โ |
| Visual Builder | โ | โ | โ |
| Generic Support | โ Input/Output | โ | โ |
| Performance (ops/sec) | 17k+ (55k+ JSONPath) | 45k | 30k |
| Bundle Size | 12KB | 45KB | 38KB |
| Browser Support | โ | โ | โ |
| Rule Introspection | โ | โ | โ |
| Fluent Builder | โ | โ | โ |
We love contributions! Whether it's:
- ๐ Bug reports and fixes
- โจ New operators or features
- ๐ Documentation improvements
- ๐จ Examples and tutorials
- ๐๏ธ UI components for the builder
See our Contributing Guide for details.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- โ Core rule engine with 121+ operators
- โ Full TypeScript support with generics
- โ Custom operator registration system
- โ Visual rule builder for React
- โ Comprehensive documentation
- โ Performance optimizations
- ๐ Enhanced TypeScript utilities (type guards, validators)
- ๐ Operator marketplace with community operators
- ๐ Rule templates and marketplace
- ๐ GraphQL integration
- ๐ More operator types (geo, financial)
- ๐ Advanced debugging tools
- ๐ฎ AI-powered rule suggestions
- ๐ฎ Visual rule debugger
- ๐ฎ Collaborative editing
- ๐ฎ Mobile app support
- ๐ฎ Multi-language operators
This project is licensed under the MIT License - see the LICENSE file for details.
- Thanks to all contributors who have helped shape this project
- Inspired by json-rules-engine and other rule engines
- Built with modern web technologies and best practices
- ๐ Documentation - Complete guides and references
- ๐ Issue Tracker - Bug reports and feature requests
- ๐ญ Discussions - Community Q&A and ideas
- ๐ง Email - Direct contact
Built with โค๏ธ by Ali Torki for the developer community
โญ Star us on GitHub โข ๐ฆ View on npm โข ๐ Read the Docs
Making complex business logic simple, one rule at a time.