Randomness And Determinism
Reducers must be deterministic. Every replica needs to reproduce the same result from the same logged inputs, so module code should use host-provided time and randomness rather than ambient JavaScript globals.
Reducer Randomness
Section titled “Reducer Randomness”Inside Effect-based reducers, use Random.* from effect/Random. The constrained server
runtime wires Effect randomness to the call context’s deterministic random
stream.
import * as Effect from "effect/Effect"import * as Random from "effect/Random"
const roll = Effect.gen(function* () { const die = yield* Random.nextIntBetween(1, 6) const fraction = yield* Random.next return { die, fraction }})Wall Clock
Section titled “Wall Clock”Use the call timestamp supplied by the current context instead of ambient clock
globals. In guarded development runs, Date.now() and no-argument new Date()
throw ReducerWallClockNotAllowedError; Math.random throws
ReducerGlobalRandomNotAllowedError; suspended Effects, promises, timers, and
microtasks throw ReducerAsyncNotAllowedError.
The Effect clock is wired to the same transaction timestamp, so Effect.Clock
and DateTime.now are deterministic inside server handlers.
UUID Helpers
Section titled “UUID Helpers”Reducer, transaction, and HTTP handler contexts expose deterministic UUID
helpers. Use ctx.newUuidV4() and ctx.newUuidV7() when a row needs a stable
identifier produced inside server module code.
import * as Effect from "effect/Effect"import * as Stdb from "effect-spacetimedb"
declare const Module: Stdb.AnyStdbModule
const { ReducerCtx } = Module
const ids = Effect.gen(function* () { const ctx = yield* ReducerCtx return { randomId: ctx.newUuidV4(), timeSortableId: ctx.newUuidV7(), }})Strength
Section titled “Strength”Reducer randomness is useful for gameplay-grade choices: shuffles, loot rolls, procedural content, and reproducible simulations. It is not appropriate for secrets, tokens, authentication, anti-cheat, or any security-sensitive value.
If a value must be unpredictable, generate it outside the deterministic reducer with a trusted source of entropy and pass it in as an argument.
- Use
Random.*fromeffect/Randominside server handlers. - Use context randomness only at low-level interop boundaries.
- Never use
Math.randomfor server semantics. - Never use ambient wall-clock reads for committed server semantics.
- Treat reducer randomness as deterministic and non-cryptographic.
Not affiliated with SpacetimeDB (Clockwork Laboratories) or Effect (Effectful Technologies).