Risor vs CEL
CEL (Common Expression Language) is Google's expression language for policy and configuration. It's safe, fast, and standardized across Go, C++, Java, Rust, Python, and TypeScript. You'll find it in Kubernetes admission controllers, Google Cloud IAM, Firebase security rules, and Envoy.
CEL evaluates single expressions. When you need variables, multi-step computation, or functions, you need a scripting language.
Simple Conditions
Both handle single expressions the same way:
request.auth.claims.role == "admin"
|| (resource.classification == "public"
&& request.method in ["GET", "HEAD"])
Multi-step Logic
CEL requires chaining separate evaluations with host code bridging them:
// Expression 1: calculate discount tier
account.total_spend > 10000 ? 0.20 : account.total_spend > 5000 ? 0.10 : 0.05
// Expression 2: host injects tier from expression 1
line_items.map(i, i.price * i.quantity).sum() * (1.0 - discount_tier)
Risor handles it in one script:
let tier = if (account.total_spend > 10000) { 0.20 }
else if (account.total_spend > 5000) { 0.10 }
else { 0.05 }
let subtotal = line_items.map(i => i.price * i.quantity) |> math.sum
subtotal * (1 - tier)Comparison
| Property | CEL | Risor |
|---|---|---|
| Scope | Single expressions | Multi-statement scripts |
| Variables / functions | No | Yes |
| Pattern matching / pipes | No | Yes |
| Sandboxed | Yes | Yes (empty by default) |
| Type system | Protobuf-centric | Native host types |
| Syntax | C-like | TypeScript-like |
| Feature control | Fixed | Host chooses which features to enable |
| Cross-language | Go, C++, Java, Rust, Python, TS | Go (Rust and TS planned) |
Performance
CEL is fast at what it does. On a simple conditional, CEL evaluates in 0.08 µs versus Risor's 15.2 µs. Its flat evaluation tree has almost zero runtime overhead.
But CEL can only evaluate single expressions. It has no reduce, no sum, no variables. Our benchmark suite includes two harder scenarios (filtering 10,000 records, and a multi-step business logic pipeline) and CEL can't participate in either. The host would need to loop over results in Go code.
On memory, Risor is smaller: 2.2 KB per compiled instance versus CEL's 23.1 KB (10.5×). CEL carries protobuf type metadata.
| Scenario | CEL | Risor |
|---|---|---|
| Simple expression (warm) | 0.08 µs | 15.2 µs |
| Data processing (10k records) | N/A | 4.20 ms |
| Business logic (500 records) | N/A | 273 µs |
| Heap per instance (simple) | 23.1 KB | 2.2 KB |
When to Choose CEL
- Your logic fits in a single expression
- You're in the Kubernetes ecosystem
- You need cross-language evaluation with protobuf types
When to Choose Risor
- You need variables, conditionals, or multi-step computation
- You want TypeScript-like syntax and native host types
- You want the host to control which language features are available
Learn More
- Operators (pipes, spread, destructuring)