Why Risor

Go excels at building reliable systems. But sometimes your application needs to let other people define behavior at runtime: business rules, data pipelines, plugins, AI agent tools. Risor is a scripting layer for Go that's secure by default, compiled to bytecode, and readable if you know JavaScript.

Use Cases

Configuration & Business Rules

Hardcoded pricing rules and feature flags require a deploy to change. Store them as Risor scripts instead and evaluate on the fly. Each script runs in a sandbox with only the variables you provide. No filesystem, no network, no surprises.

// Risor script: evaluate a discount rule
let discount = if (customer.tier == "enterprise") { 0.20 } else { 0.05 }
price * quantity * (1 - discount)
// Go: evaluate a user-defined pricing rule
env := map[string]any{"customer": customer, "price": 99.0, "quantity": 10}
result, _ := risor.Eval(ctx, rule, risor.WithEnv(env))

Data Transformation Pipelines

Let users define ETL steps or processing logic without touching Go code. Risor's pipe operator (|>) makes transformation chains readable and composable. Compile once, run against every record.

// Risor script: transform raw records
let active = input |> filter(r => r.status == "active") |> list
active.map(r => r.amount * rate)
// Go: run a user-defined transform against each batch
code, _ := risor.Compile(ctx, userScript, risor.WithEnv(risor.Builtins()))
result, _ := risor.Run(ctx, code, risor.WithEnv(map[string]any{
    "input": records, "rate": exchangeRate,
}))

Plugin Systems

Let third parties extend your application without recompiling it. Each plugin is a Risor script loaded at runtime. You control exactly which functions and data each plugin can access. A misbehaving plugin cannot touch the host.

// Risor plugin: custom webhook formatter
let payload = {"event": event.type, "user": event.user.email}
to_json(payload)
// Go: load and run a plugin script from disk
source, _ := os.ReadFile("plugins/webhook.risor")
result, _ := risor.Eval(ctx, string(source),
    risor.WithEnv(risor.Builtins()),
    risor.WithEnv(map[string]any{"event": event}),
)

AI Agent Tool Definitions

AI agents need callable tools with clear inputs and outputs. Risor scripts work well here: concise, sandboxed, and easy for an LLM to generate or modify. Register each script as a callable tool and control resource limits from Go.

// Risor tool: summarize a customer record
let categories = customer.orders.map(o => o.category)
let tags = categories.unique()
{"name": customer.name, "total_orders": len(customer.orders), "tags": tags}
// Go: register a Risor script as an agent tool
code, _ := risor.Compile(ctx, toolScript, risor.WithEnv(risor.Builtins()))
agent.RegisterTool("summarize_customer", func(customer any) (any, error) {
    return risor.Run(ctx, code, risor.WithEnv(map[string]any{
        "customer": customer,
    }))
})

End-User Scripting

SaaS platforms often need to let customers write automations, validations, or computed fields. With resource limits and syntax restriction, Risor gives you a safe scripting surface without putting your infrastructure at risk.

// Risor: user-defined validation rule
let valid = order.total > 0 && all(order.items.map(i => i.quantity > 0))
if (!valid) { error("invalid order") } else { order }
// Go: run user script with strict limits
result, err := risor.Eval(ctx, userScript,
    risor.WithEnv(map[string]any{"order": order}),
    risor.WithMaxSteps(10000),
    risor.WithTimeout(100 * time.Millisecond),
)

Testing & Prototyping

Prototype new features as Risor scripts and iterate without recompiling. Once the logic stabilizes, promote it to Go. This workflow also works well for integration test scenarios that exercise your system's scripting layer.

// Risor: prototype a scoring algorithm
let amounts = events.map(e => if (e.type == "purchase") { e.amount * 2 } else { 1 })
let score = amounts.reduce(0, (a, b) => a + b)
// Go: hot-reload a script during development
source, _ := os.ReadFile("scripts/score.risor")
result, _ := risor.Eval(ctx, string(source),
    risor.WithEnv(risor.Builtins()),
    risor.WithEnv(map[string]any{"events": testEvents}),
)

Why Risor Over Alternatives

Several languages can be embedded in Go. Here's how Risor compares. (See full benchmarks for methodology and complete results.)

vs. Lua

Lua is proven, but Go implementations (GopherLua) are no longer actively maintained, and Lua's conventions (1-based indexing, global-by-default variables, no native JSON) create friction. Risor is also faster: 15.2 µs vs 29.0 µs on simple expressions (1.9×), 273 µs vs 611 µs on business logic (2.2×). The memory gap is even larger: 7.6 KB per compiled business logic instance versus GopherLua's 1,889 KB (249×). Detailed comparison.

vs. JavaScript (goja)

Goja is fast: 0.6 µs for a simple expression versus Risor's 15.2 µs, and about 2× faster on business logic too. But Goja exposes the full JS standard library by default (opt-out sandbox), and its memory footprint grows under load. 114.0 KB per business logic instance versus Risor's 7.6 KB. If you're running thousands of concurrent evaluations, that 15× difference matters. Detailed comparison.

vs. Starlark

Starlark (the Bazel configuration language) is intentionally minimal. No pipe operator, no pattern matching, no template strings, and far fewer utility functions. The moment your scripts need to do more than simple configuration, you'll outgrow it.

vs. CEL

CEL evaluates simple expressions in 0.08 µs, 190× faster than Risor for a single conditional. But CEL has no variables, no reduce, no multi-step computation. It can't sum a filtered list without host code bridging multiple evaluations. Risor handles everything CEL does plus data pipelines, business logic, and user-defined functions. Detailed comparison.

vs. OPA / Rego

OPA is fast on trivial expressions (4.9 µs), but its declarative evaluation model compounds at scale: 11.91 ms for data processing versus Risor's 4.20 ms, and 1.38 ms for business logic versus 273 µs. OPA also carries 80-100 KB per instance versus Risor's 2-8 KB. And Rego's syntax has a steep learning curve. Detailed comparison.

Next Steps


Risor © 2026 Deep Noodle