Benchmark → Run

Run

Fire real requests against a RoExpress route, named port, vanilla RemoteFunction, or RemoteEvent. A warmup pass runs first (results discarded) to prime the JIT and connection, then iterations measured requests are collected.

bench:Run()

bench:Run(route: string, config?: Config) → Results

Benchmarks a route on the main RoExpress channel. Returns a Results table with min, avg, median, p95, p99, max, errors, throughput, and more.

bench:RunOnPort()

bench:RunOnPort(portNetwork: Network, route: string, config?: Config) → Results

Same as Run but fires against a named port channel. Obtain portNetwork with RoExpress("Network", "portName").

bench:RunRemoteFunction()

bench:RunRemoteFunction(remote: RemoteFunction, config?: Config) → Results

Full round-trip benchmark against a vanilla RemoteFunction. Calls remote:InvokeServer(...) and measures until the response arrives — directly comparable to a RoExpress route benchmark.

bench:RunRemoteEvent()

bench:RunRemoteEvent(remote: RemoteEvent, config?: Config) → Results

Fire-only timing for a vanilla RemoteEvent. Measures the client-side cost of FireServer — this is not round-trip. The target field reads "RemoteEvent (fire only)" so Compare output makes the distinction clear.

RemoteEvent results are not round-trip. They will be much faster than any round-trip benchmark and cannot be directly compared. Use RunRemoteFunction for a fair comparison against RoExpress routes.

bench:RunAndPrint()

bench:RunAndPrint(route: string, config?: Config) → Results

Convenience wrapper — runs and prints in one call. Returns Results so you can store it for Compare.

Config

All run methods accept the same optional config table. Fields that don't apply to a target type are ignored.

FieldTypeDefaultDescription
method"GET" | "POST" | "PUT" | "DELETE""GET"HTTP method — RoExpress targets only
dataany?nilRequest body — RoExpress targets only
args{ any }?{}Arguments unpacked into FireServer / InvokeServer — vanilla remotes only
iterationsnumber?20Measured requests
warmupnumber?3Discarded warm-up requests (JIT / connection)
intervalnumber?0Seconds between requests (0 = back-to-back)
timeoutnumber?nilPer-request timeout passed to Network — RoExpress only
labelstring?route / remote.NameDisplay name in Print / Compare output

Results

FieldTypeDescription
labelstringDisplay name (from config or auto-assigned)
targetstring"RoExpress" · "RoExpress Port" · "RemoteFunction" · "RemoteEvent (fire only)"
methodstringGET / POST / PUT / DELETE / invoke / fire
minnumberFastest request (ms)
avgnumberMean RTT (ms)
mediannumberp50 (ms)
p95number95th percentile (ms)
p99number99th percentile (ms)
maxnumberSlowest request (ms)
errorsnumberFailed request count
errorCodes{ [number]: number }Error count per HTTP status code
throughputnumberRequests per second (wall-clock)
totalnumberTotal wall time for all iterations (ms)
completednumberIterations actually measured
iterationsnumberConfigured iteration count
warmupnumberConfigured warmup count

bench:Print()

bench:Print(results: Results) → ()

Writes a formatted summary to the Studio output window. The header line shows the target type and method so you can identify each run at a glance.

── player/123   [RoExpress GET] × 20  (warmup: 3) ───────────────
   min          4.21 ms
   avg          6.83 ms
   median       6.10 ms
   p95         12.44 ms
   p99         18.07 ms
   max         18.71 ms
   ─────────────────────────────────────────────────────────────
   errors       0 / 20
   throughput   8.3 req/s
──────────────────────────────────────────────────────────────────

Example — GET request benchmark

local bench = RoExpress("Benchmark")

-- RoExpress main channel
local result = bench:RunAndPrint("player/123", {
    method     = "GET",
    iterations = 30,
    warmup     = 5,
    label      = "player GET",
})

-- Named port channel
local combatNet = RoExpress("Network", "combat")
local portResult = bench:RunOnPort(combatNet, "shoot/123", {
    method = "POST",
    data   = { weapon = "AK47" },
    label  = "combat POST shoot",
})
bench:Print(portResult)

-- Vanilla RemoteFunction round-trip
local rs       = game:GetService("ReplicatedStorage")
local echoFunc = rs:WaitForChild("EchoFunc")
local rfResult = bench:RunRemoteFunction(echoFunc, {
    args       = { "payload" },
    iterations = 30,
    label      = "vanilla RF echo",
})
bench:Print(rfResult)
Rate limiting. With interval = 0 and high iteration counts you may see 429 errors in results.errorCodes. Call tokenBucket:Reset() on the server before each run to clear per-player state.

See also

← Benchmark  ·  Compare | side-by-side p95/p99 analysis  ·  Network | the instance Benchmark fires through  ·  TokenBucket | rate limits that affect results