Configuration
Every control plane setting, in one table. Guides link here instead of restating options.
The control plane is the Rivet Engine. It reads configuration from files, from environment variables, or from both.
Configuration sources
The engine accepts JSON, JSON5, JSONC, YAML, and YML, plus environment variables.
Environment variables
Prefix a setting with RIVET__ and separate each level of nesting with __. Names are case-insensitive. To set postgres.url:
RIVET__POSTGRES__URL="postgresql://user:password@host:5432/database"
Configuration files
Files are discovered automatically in a platform-specific directory:
| Platform | Path |
|---|---|
| Linux | /etc/rivet/config.json |
| macOS | /Library/Application Support/rivet/config.json |
| Windows | C:\ProgramData\rivet\config.json |
Multiple files in the same directory are merged. /etc/rivet/config.json and /etc/rivet/database.json are loaded together.
Override the search path with --config:
# Load from a specific file
rivet-engine --config /path/to/config.json
# Load from a directory
rivet-engine --config /etc/rivet
# Load multiple paths, merged in order
rivet-engine --config /etc/rivet/base.json --config /etc/rivet/override.json
Reference
Configuration for the private API service.
Configuration for the cache layer.
URL to the HTTP access port for ClickHouse.
URL to the native access port for ClickHouse.
Timeout sent with actor force-wake requests in milliseconds.
Timeout for waiting for an actor to become ready in milliseconds.
Enables the internal websocket health route for debug and latency testing. This is intended for websocket ping/pong verification and should remain disabled in normal deployments.
Host for HTTP traffic
Max HTTP request body size in bytes (first line of defense).
Port for HTTP traffic
Timeout for resolving api-public routes in milliseconds.
Timeout for guard-owned route authorization checks in milliseconds.
TTL for cached route lookups in milliseconds.
Timeout for resolving compute routes in milliseconds.
Timeout for dispatching to each guard routing module in milliseconds.
Timeout for pegboard actor route authorization checks in milliseconds.
Timeout for fetching pegboard actor routing state in milliseconds.
Timeout for resolving pegboard actor query routes in milliseconds.
Timeout for subscribing to pegboard actor routing events in milliseconds.
Timeout for sending pegboard actor wake signals in milliseconds.
Backstop timeout for route resolution in milliseconds. Primary timeout signals live inside each guard routing phase.
Enables TCP_NODELAY on accepted Guard sockets.
Enables W3C trace context propagation (extract from incoming requests, inject into upstream requests/websockets).
Max WebSocket frame size in bytes.
Max WebSocket message size in bytes.
Configuration for the metrics service.
Policy for outbound HTTP requests to user-configured destinations, such as serverless runner URLs. These requests originate from inside the trusted engine network, so without restrictions a caller who can configure a runner can reach internal-only services. The defaults deny every non-globally-routable destination except loopback.
Additional CIDRs that are always permitted, evaluated after `deny_cidrs`. Use this to reach a specific internal service without opening up the whole private range.
Hostnames that are always permitted, whatever they resolve to. Matched exactly and case-insensitively, with no wildcards. Use this for a first-party service whose address is not known ahead of time, such as a Kubernetes service name. Anything served at a listed host becomes reachable by every runner config, so list individual hosts rather than a shared entry point.
Allow plaintext `http://` destinations. When disabled only `https://` is permitted.
Allow destinations that resolve to loopback addresses (127.0.0.0/8, ::1). Enabled by default so local development against `http://localhost:...` works without configuration.
Allow destinations that resolve to private, link-local, shared (CGNAT), or otherwise non-globally-routable addresses. Self-hosted deployments that point runners at addresses on their own network, such as a Docker Compose service name, need this enabled.
Additional CIDRs that are always denied. Takes precedence over every allow rule.
Maximum number of redirects to follow. Every hop is re-checked against this policy.
Amount of runners to query from the allocation queue and choose at random when allocating an actor.
How long to wait for an ack response from the outbound request layer before setting actor as lost. Unit is in milliseconds.
Time to regain one actor creation token per namespace. Unit is in milliseconds.
Max burst of actor creations per namespace before throttling.
How long to wait after starting to attempt to reallocate before before setting actor to sleep. Unit is in milliseconds.
How long to wait after creating and not receiving a starting state before setting actor as lost. Unit is in milliseconds.
How long to wait after stopping and not receiving a stop state before setting actor as lost. Unit is in milliseconds.
Time to delay an actor from rescheduling after a rescheduling failure. Unit is in milliseconds.
Default metadata poll interval for serverless runners when not specified in runner config. Unit is in milliseconds.
How long after last ping before considering a envoy ineligible for allocation. Unit is in milliseconds.
GC interval for actor event demuxer in milliseconds.
Max time since last seen before actor is considered stale, in milliseconds.
Maximum concurrent background expire operations spawned by the read-path envoy expire scheduler.
Maximum pending envoys tracked by the read-path envoy expire scheduler.
Maximum stale entries walked per `scan_for_fresh` call before aborting and returning `None`. Circuit breaker against pathological drain scenarios. Default 16. Range 1..=256.
Number of independent ring samples per allocation. `1` = uniform pick (no slot read), `>= 2` = power-of-K-choices.
Additive random integer added to each candidate's slot count before the min-slot comparison. Decorrelates concurrent allocators reading the same stale `SlotsKey` snapshot. Only relevant when `samples >= 2`. `0` disables. Range 0..=64. Default 4. See `slot_jitter` block in `engine/packages/pegboard/src/workflows/actor2/alloc_serverful/hash.rs` for how the default was sized.
How long to wait before considering an envoy lost and evicting all of its actors. Unit is in milliseconds.
Max response payload size in bytes from actors.
Max time since last pong before the envoy connection is terminated. Unit is in milliseconds.
Ping interval for envoy updates in milliseconds.
Time to regain one inbound WebSocket message token on a single envoy connection. Unit is in microseconds. The envoy connection multiplexes every actor on a runner, so the sustained ceiling is far higher than the per-client gateway limit and needs sub-millisecond granularity to express.
Max burst of inbound WebSocket messages on a single envoy connection before throttling.
GC interval for in-flight requests in milliseconds.
Max HTTP request body size in bytes for requests to actors.
Number of body chunks buffered between a streaming response handler and its HTTP client.
Maximum number of envoy response messages buffered per HTTP request.
Max pending message buffer size for hibernating WebSockets in bytes.
Hibernating WebSocket message ack timeout in milliseconds.
Timeout between streaming HTTP response chunks in milliseconds. Disabled when unset so long-lived streams such as SSE may remain idle.
Timeout for response to start in milliseconds.
Maximum streaming response bytes buffered per HTTP request.
Tunnel ping timeout in milliseconds.
Ping interval for gateway updates in milliseconds.
WebSocket open/handshake timeout in milliseconds.
Time to regain one inbound WebSocket message token on a single connection. Unit is in milliseconds.
Max burst of inbound WebSocket messages on a single connection before throttling.
How long after last ping before considering a hibernating request disconnected. Unit is in milliseconds.
Minimum metadata poll interval for serverless runners. The actual poll interval will be the maximum of this value and the runner config's `metadata_poll_interval` setting. This prevents excessive polling even if the runner config specifies a very short interval. Unit is in milliseconds.
Global pool desired max.
Maximum total size of all preloaded KV data sent with the actor start command. Setting to 0 disables all preloading. Unit is in bytes. Default: 1,048,576 (1 MiB).
Maximum exponent for the reschedule backoff calculation. This controls the maximum backoff duration when rescheduling actors.
How long an actor goes without retries before it's retry count is reset to 0, effectively resetting its backoff to 0. Unit is in milliseconds.
How long after last ping before considering a runner ineligible for allocation. Unit is in milliseconds.
GC interval for actor event demuxer in milliseconds.
Max time since last seen before actor is considered stale, in milliseconds.
How long to wait after last ping before forcibly removing a runner from the database and deleting its workflow, evicting all actors. Note that the runner may still be running and can reconnect. Unit is in milliseconds.
Max response payload size in bytes from actors.
Max time since last pong before the runner connection is terminated. Unit is in milliseconds.
Number of consecutive successes required to clear an active runner pool error. This prevents a single success from clearing an error during flapping conditions. Higher values provide more stability but slower recovery from transient errors.
Ping interval for runner updates in milliseconds.
Maximum exponent for the serverless backoff calculation. This controls the maximum backoff duration when serverlessly connecting to runners.
Time to delay a serverless runner from attempting a new outbound connection after a connection failure. Unit is in milliseconds.
**Deprecated** Configure the drain period in the runner config. Drain grace period for serverless runners. This time is subtracted from the configured request duration. Once `duration - grace` is reached, the runner is sent stop commands for all of its actors. After the grace period is over (i.e. the full duration is reached) the runner websocket is forcibly closed. Unit is in milliseconds.
How long a serverless runner goes without connection failures before it's retry count is reset to 0, effectively resetting its backoff to 0. Unit is in milliseconds.
Sampling frequency in Hz.
Base URL of the Pyroscope server profiles are pushed to. Presence of this block means profiling is available; the profiler itself is toggled at runtime via the `profile enable`/`profile disable` CLI and starts off.
Whether or not to allow running the engine when the previous version that was run is higher than the current version.
Time (in seconds) after which the engine process will forcibly exit after receiving SIGTERM. Must be greater than or equal to both worker_shutdown_duration and guard_shutdown_duration. Defaults to 10 minutes.
How many forgotten loop iterations to retain (per workflow name) in storage for debugging purposes. Defaults to 100. Set "default" key to apply to all workflows.
Time (in seconds) after completion before considering a workflow eligible for pruning. Defaults to 7 days. Set to 0 to never prune workflow data.
Time (in seconds) to periodically check for workflows to prune. Defaults to 12 hours.
Time (in seconds) to allow for guard to wait for pending requests after receiving SIGTERM. Defaults to 10 minutes.
Cluster-wide budget, in bytes per second, per named UniversalDB throttle. Each entry sets the read and write axes independently, for example `udb_throttle_bytes_per_second.depot_compaction.read`. An axis with no entry is unthrottled.
Adjusts worker curve around this value (in millecores, i.e. 1000 = 1 core). Is not a hard limit. When unset, uses /sys/fs/cgroup/cpu.max, and if that is unset uses total host cpu.
Exponential moving average beta term. Defaults to 0.95.
Determine load shedding ratio based on linear mapping on cpu usage. We will gradually pull less workflows as the cpu usage increases. Units are in (permille overall cpu usage, permille) Default: | . . 100% | _____ . | .\ . % wfs | . \ . | . \. 5% | . \_____ |_____.___.______ 0 70% 90% avg cpu usage
Maximum concurrently running workflows of a given workflow name for the **entire cluster**.
Maximum wake condition keys a worker clears when leasing workflows in a single pull. Defaults to 10000.
Maximum workflows a worker attempts to lease in a single pull. Defaults to 1000.
Time (in seconds) to allow for the gasoline worker engine to stop gracefully after receiving SIGTERM. Defaults to 30 seconds.
Cluster-wide budget, in bytes per second, for FoundationDB reads issued by actor `get_pages`. Unset means unthrottled. Reads matter here because a large staged commit makes the pages it staged take the slow read path (their PIDX owner sits above head, so a reader walks history for them), which means read volume spikes exactly when write volume peaks.
Cluster-wide budget, in bytes per second, for FoundationDB writes issued by actor commits, including each segment of a staged commit. Unset means unthrottled, which is the behaviour before this existed. A staged commit lets one actor push an unbounded byte volume through `commit`, so this is the bound for that; it is opt-in because a byte-rate cap on the actor write path stalls user-visible commits, and that is not a default worth taking until an operator asks for it.
Percentage (0-100) of database branches admitted to run compaction, keyed by a stable hash of the branch id. A branch whose hash falls outside the admitted fraction skips starting any compaction job (hot, cold, reclaim) while still tracking its backlog. This is a gradual rollout / load-shedding knob: it bounds how many databases compact at once so enabling compaction over a large uncompacted herd cannot saturate FDB all at once. Re-evaluated on every manager refresh, so raising it lets a previously skipped branch compact on its next check without restarting anything. Defaults to 100 (every branch admitted).
Whether hot compaction folds shard images straight into the live `SHARD` tier instead of staging them and having the install copy them across byte for byte. Halves hot compaction's FDB write volume, because the image stops being written twice. Read per slice, so flipping it takes effect on the next slice without restarting anything. Nothing about the mode is persisted: the install discovers where an image landed by looking for it, so a drain that spans a flip installs correctly either way and a mixed job needs no special handling. No persisted format changes, so there is no version floor to clear before turning this on and nothing on disk to downgrade after turning it off. Rolling back is flipping it off; new slices stage again from that point. A compaction job abandoned mid-drain leaves shard images behind. Normally its successor reproduces the same boundaries and overwrites them, so they do not accumulate. A forced drain takes the live head by design, so an abandoned forced drain can strand images that no later drain revisits; those are inert for reads but nothing reclaims them. Defaults to off.
Utilization of the advancing lanes' budget below which every such charge is admitted. Defaults to 0.5.
Multiplier the lanes that advance the pipeline without duplicating apply to the compaction byte budget before the throttle's admission ramp is evaluated: hot install, cold publish, cold staging, and hot folds that write straight to the shard tier. Install folds staged shards into the manifest and releases the staging area, and cold publish is what lets the cold watermark advance so reclaim may delete. Defaults to 1.0, so the configured byte rate stays an honest cap on everything except reclaim. Cold staging measures against this rather than the staging budget because its heavy output is object-storage bytes, so it leaves no FoundationDB duplicate to bound.
The largest span of txids one hot compaction drain folds before its install advances `hot_watermark_txid`. The watermark is what makes a delta reclaimable, and a drain advances it exactly once, at the end. So this is also the granularity of reclaim eligibility: a branch whose whole history fits in one span holds every delta resident until the entire fold lands, which sets the peak footprint at live shards plus the full delta history. Lowering it folds in smaller chunks so reclaim interleaves and the peak comes down, at the cost of re-folding a page once per chunk that touches it and of running proportionally more jobs. Each drain rounds its own span down to a multiple of the drain head grain; this cap is not itself rounded. Defaults to 512, which keeps a typical branch draining over several jobs rather than one, so reclaim gets more than a single eligibility window per branch.
Cluster-wide budget, in bytes per second, for FoundationDB reads issued by the heavy depot compaction read transactions (hot stage and hot install). Bounds how fast compaction reads a backlog's DELTA history so a deep, overwrite-heavy chain cannot pin a handful of storage processes on reads. Defaults to 64 MiB/s: reads carry no FDB replication amplification so this can sit above the write budget, but the read-amplification pathology (a throttled stage re-reading the same slice) makes an explicit cap worthwhile. Shares the same conflict-free windowed-counter design as the write throttle.
Utilization of the reclaim lane's budget below which every reclaim charge is admitted. Higher than the other lanes so reclaim stays fully admitted across the whole band where they ramp down, instead of merely ramping down more slowly. Defaults to 0.9.
Multiplier the reclaim lane applies to the compaction byte budget before the throttle's admission ramp is evaluated. Above 1.0 on purpose: reclaim deletes rather than produces, so it must keep admitting through the region where every other lane has already backed off, and its own charges land on the same counter so the arrangement stays self-regulating. This is also the bound on how far peak compaction pressure can exceed the configured byte rate. Defaults to 1.5.
Utilization of the staging lane's budget below which every staging charge is admitted. Between this mark and that budget the admit probability ramps linearly to zero. Defaults to 0.5. Applies on the same terms as `compaction_stage_throttle_budget_multiplier`.
How long, in milliseconds, a throttled staging slice backs off before its drain retries. Deliberately far longer than the other lanes. Admission is probabilistic, so a denied slice that retries within the same window keeps rolling dice against the estimate install and reclaim are trying to work under. Backing staging off across several windows removes that retry pressure rather than merely losing each roll. Defaults to 30 seconds. Applies only while `compaction_hot_fold_direct_to_shard` is off, for the same reason the staging multiplier does: a direct fold is not competing with install over a duplicate it created, so parking it that long would only stall the fold.
Multiplier hot staging applies to the compaction byte budget before the throttle's admission ramp is evaluated. Every compaction lane charges one shared counter, so a multiplier below 1 is how much of the total compaction byte rate staging is allowed to occupy before it stops admitting. The lanes that advance the pipeline (install, cold publish, cold staging) and the lane that deletes (reclaim) measure the same counter against larger budgets, so they keep admitting through the region where staging is already denied. This bounds a duplicate. Staging writes a second copy of every page it folds and cannot release either copy until install consumes it, so a cluster where staging wins the shared budget grows its FoundationDB footprint without bound while install and reclaim starve. Defaults to 0.3. Lower it to drain a backlog harder, raise it toward 1.0 to let staging and install compete as peers. Applies only while `compaction_hot_fold_direct_to_shard` is off. A direct fold writes the authoritative image once, so there is no duplicate to bound and the slice measures against `compaction_install_throttle_budget_multiplier` instead.
Cluster-wide budget, in bytes per second, for FoundationDB writes issued by depot compaction (hot compaction and reclaim). Bounds how fast compaction drains a backlog so it cannot saturate FDB's write queue. Defaults to 16 MiB/s, a conservative fraction of the 500 MiB/s sustained disk throughput recommended for FDB in the self-hosting docs, leaving headroom for live traffic and FDB write amplification.
How long, in milliseconds, a depot database branch manager that received no work waits before checking again. Reads never signal the manager, so without a poll a branch that stops being written parks on a deadline-less listen and never reclaims again: its cold-backed hot rows stay resident in FoundationDB forever, and the one-shot stale-PIDX repair never gets dispatched. One reclaim job drains a branch's whole backlog, so this only bounds how long a newly idle branch keeps duplicate hot copies. Defaults to 12 hours. Each wake is a bounded-budget FoundationDB snapshot, so lower it if reclaim latency on idle branches matters more than the cluster-wide refresh cost (at 1M branches, 12 hours is ~23 refreshes/sec).
How long, in milliseconds, a depot database branch manager waits before its next reclaim/GC check after arming one. This is the latency floor on freeing hot rows that compaction has already superseded: the footprint a branch carries stays at its peak for up to this long after the work that made it reclaimable finished. Every wake costs a bounded-budget FoundationDB snapshot per branch, so lower it only where reclaim latency matters more than that per-branch refresh cost. Defaults to 10 minutes.
Spacing, in milliseconds, between the PITR coverage positions hot compaction retains for a database that has no bucket or database policy override. Each position holds a complete image of every shard it covers until it expires, so halving this roughly doubles the retained shard versions. Defaults to 5 minutes.
How long, in milliseconds, PITR coverage is retained for a database that has no bucket or database policy override. History older than this window is reclaimable. Defaults to 7 days.
UNSTABLE: disables SQLite hot compaction.
Must be included in `datacenters`
Capacity of the async-nats client command queue. When this fills, client operations such as subscribe, publish, and drain wait until the connection task catches up.
When true, force every UPS publish to round-trip through NATS instead of taking the in-process fast path for subjects that have a local subscriber on the same engine pod. Opt-in diagnostic; default false.
Capacity of each individual NATS subscriber message buffer. When this fills, async-nats drops the message and emits `SlowConsumer`. Rivet logs this as `nats slow consumer`.
Path to the client certificate file Used for client certificate authentication Equivalent to PostgreSQL's `sslcert` parameter
Path to the client private key file Used for client certificate authentication Equivalent to PostgreSQL's `sslkey` parameter
Path to the root certificate file for verifying the server's certificate Required when using custom certificate authorities (e.g., Supabase) Equivalent to PostgreSQL's `sslrootcert` parameter
Envoy load balancing
pegboard.envoy_load_balancer selects how actors are assigned to envoys. The hash strategy uses a hash ring:
{
"pegboard": {
"envoy_load_balancer": {
"hash": {
"virtual_nodes": 8,
"samples": 2,
"max_scan": 16,
"use_snapshot_read": true
}
}
}
}
Use samples: 1 for a uniform random pick that skips slot reads, or samples: 2 or higher for power-of-K choices over envoy slot counts. Treat virtual_nodes as an operational invariant once envoys have registered: changing it reshuffles the ring.
Telemetry
OpenTelemetry export
The engine exports traces and metrics over OpenTelemetry to a collector you run.
| Variable | Purpose | Default |
|---|---|---|
RIVET_OTEL_ENABLED | Set to 1 to enable export | off |
RIVET_OTEL_GRPC_ENDPOINT | Collector endpoint | http://localhost:4317 |
RIVET_OTEL_SAMPLER_RATIO | Trace sampling ratio | 0.001 |
Crash reporting
The control plane sends crash reports to Rivet’s error-tracking service by default. Disable it with one flag:
{
"telemetry": {
"enabled": false
}
}
Or as an environment variable:
RIVET__TELEMETRY__ENABLED=false