What does bounded mean?
Always terminates
The virtual machine enforces restrictions that bound execution. Scripts can't hang your application.
Empty sandbox
Scripts start with zero capabilities. No I/O, no network, no filesystem. The host application decides what to expose.
Adjustable complexity
Three built-in presets: expression only, basic scripting, or full language. Expose exactly the complexity each use case needs.
Choose your sophistication level
Risor ships with three syntax presets, and individual features can be toggled on or off for more granular control. Each context gets exactly the language surface it needs.
Language features
Reads like TypeScript, with pipe operators, match expressions, and richer methods on lists and maps. Language changes are made conservatively, only when there is clear need.
Arrow functions & closures
let greet = name => "hello " + name
let add = (a, b) => a + b
let counter = () => {
let n = 0
return () => { n = n + 1; n }
}Nullish coalescing
let name = user.name ?? "anonymous"
let port = config.port ?? 8080
let deep = a?.b?.c ?? fallback
let list = data ?? []
let timeout = opts.timeout ?? 30Destructuring
let {name, role} = user
let [first, ...rest] = items
let {host, port: p} = config
let [a, b] = [1, 2]
let {x, y, ...other} = pointPipe operator
let result = data
|> transform
|> validate
|> serialize
|> compressMatch expressions
let label = match status {
"active" => "ON"
"paused" => "WAIT"
"error" => "ERR"
_ => "OFF"
}Try/catch expressions
let val = try {
parse(raw)
} catch e {
defaults
}
let ok = try { connect(url) } catch e { nil }Object & map literals
let config = {
timeout: 30,
retries: 3,
tags: ["prod", "us-east"],
nested: { enabled: true },
}Collection methods
items.filter(x => x.active)
.map(x => x.name)
.sorted()
.join(", ")
// ["Alice", "Carol"]The Risor virtual machine
Risor compiles to bytecode and runs on a lightweight virtual machine built for speed and safety. The Go implementation is pure Go with no CGo and no reflection.
Bytecode compiled
Source is compiled to bytecode before execution. The compilation step catches errors early and keeps evaluation fast.
Stack based VM
A purpose built stack machine executes bytecode with predictable performance. No tree-walking interpreter overhead.
Resource bounded
The VM enforces instruction count limits and recursion depth. Runaway scripts are stopped before they cause problems.
Lightweight instantiation
Each compiled instance uses 2-8 KB of heap. Spin up thousands of isolated evaluations without pooling — where other runtimes need 100 KB to 2 MB per instance.
One language, multiple runtimes
Risor is a language specification, not a library for one host. The Go runtime is production-ready. Native Rust and TypeScript runtimes are in active development, sharing a conformance test suite.
Go
The primary runtime. Pure Go, no CGo, single binary. Production-ready today.
Full language specification
Bytecode-compiled VM
Native Go type interop
One import, one function call
Rust
A native Rust runtime is in active development, targeting WASM and edge environments.
TypeScript
A native TypeScript runtime is in active development for Node.js and browser environments.
Use cases
Dynamic Rules
Pricing, eligibility, validation. Update logic faster than deploys.
User Scripting
Let users extend your app. The sandbox ensures their code can't break yours.
Data Pipelines
Filter, transform, reshape. Pipe operators chain operations without loops.
Policy Evaluation
Authorization rules in imperative syntax. No new paradigm to learn.
Embed Risor in 5 minutes
One import. One function call. Full sandboxed scripting in your Go application.