Getting Started

Risor is a fast, embedded scripting language for Go. Scripts compile to bytecode and run on a lightweight virtual machine. In a few minutes, you'll go from installation to running your first script.

Installation

Add Risor to your Go project (requires Go 1.25 or later):

go get github.com/deepnoodle-ai/risor/v2

Your First Script

The quickest path to "Hello, World!" is risor.Eval, which compiles and runs a script in one call:

package main
 
import (
    "context"
    "fmt"
    "github.com/deepnoodle-ai/risor/v2"
)
 
func main() {
    result, err := risor.Eval(context.Background(), `"Hello, World!"`)
    if err != nil {
        panic(err)
    }
    fmt.Println(result) // Hello, World!
}

Secure by Default

Scripts start in a completely empty sandbox: no built-in functions, no modules, no external state. This is intentional. Your Go application decides exactly what a script can and cannot do.

// This script can only use literal values and basic operators
result, err := risor.Eval(ctx, `[1, 2, 3].map(x => x * 2)`)
fmt.Println(result) // [2, 4, 6]

Using Built-in Functions

Pass risor.Builtins() to give scripts access to Risor's standard library (len, sorted, keys, filter, type, and more):

source := `
let items = ["cherry", "apple", "banana"]
let result = sorted(items)
sprintf("Found %d items: %v", len(result), result)
`
result, err := risor.Eval(ctx, source, risor.WithEnv(risor.Builtins()))
fmt.Println(result) // Found 3 items: [apple, banana, cherry]

See Built-in Functions for the complete list.

Custom Environment

Inject your own variables and functions into the script environment:

env := map[string]any{
    "price":    100.0,
    "quantity": 5,
    "tax_rate": 0.08,
}
result, err := risor.Eval(ctx, "price * quantity * (1 + tax_rate)",
    risor.WithEnv(env),
)
fmt.Println(result) // 540

WithEnv options are additive, so layer the standard library with your own additions:

result, err := risor.Eval(ctx, source,
    risor.WithEnv(risor.Builtins()),
    risor.WithEnv(map[string]any{
        "user":  currentUser,
        "limit": 100,
    }),
)

Compile Once, Run Many Times

For hot paths, separate compilation from execution. Compiled bytecode is immutable and safe for concurrent reuse across goroutines.

// Compile once
code, err := risor.Compile(ctx, script, risor.WithEnv(risor.Builtins()))
if err != nil {
    panic(err)
}
 
// Run with different inputs
inputs := []int{10, 20, 30}
for _, val := range inputs {
    env := risor.Builtins()
    env["input"] = val
    result, err := risor.Run(ctx, code, risor.WithEnv(env))
    if err != nil {
        panic(err)
    }
    fmt.Println(result)
}

The Risor Language

Risor's syntax will feel familiar if you know JavaScript, with a few twists:

// Variables and template strings
let name = "Risor"
let greeting = `Hello, ${name}!`
 
// Arrow functions
let double = x => x * 2
 
// Lists and functional methods (no loops!)
let numbers = [1, 2, 3, 4, 5]
let evens = numbers.filter(x => x % 2 == 0)
let sum = numbers.reduce(0, (acc, x) => acc + x)
 
// Maps
let config = {"timeout": 30, "retries": 3}
let timeout = config["timeout"]
 
// Pipe operator for data pipelines
let evens = range(20) |> filter(x => x % 2 == 0) |> list
let result = evens.map(x => x * x)
 
// If-expressions
let status = if (result != nil) { "ok" } else { "error" }

See the Language Overview for a complete guide.

Resource Limits

Running untrusted code? Set instruction limits, stack depth limits, and timeouts:

result, err := risor.Eval(ctx, source,
    risor.WithEnv(risor.Builtins()),
    risor.WithMaxSteps(100000),
    risor.WithMaxStackDepth(50),
    risor.WithTimeout(5 * time.Second),
)

See Resource Limits for details.

Key Features

  • Secure by default. Empty environment; scripts can only access what you provide.
  • Familiar syntax. JavaScript-like with arrow functions, template strings, destructuring.
  • Bytecode compiled. Fast execution on a lightweight VM.
  • Concurrent safe. Compiled bytecode can be reused across goroutines.
  • Resource limits. Control instruction count, stack depth, and timeouts.
  • Syntax restriction. Limit scripts to expressions only or basic scripting.

Next Steps


Risor © 2026 Deep Noodle