Optimistic MUD state on a real EVM
@tevm/mud runs your MUD system calls locally, in the browser, on a real EVM before they
are confirmed on chain — and exposes the resulting state through the same MUD Stash APIs
your game already uses.
Quickstart →
It is a MUD plugin, not a fork: your mud.config.ts, your systems, your Stash and
your SyncProvider stay exactly as they are.
The problem
A MUD client writes through writeContract, then waits for the transaction to be
mined and indexed before the Stash reflects the change. That round trip is
hundreds of milliseconds at best, and seconds on a congested chain. Games feel
broken at those latencies.
The usual fix is hand-written optimistic updates: for every system call you also write a JavaScript function that guesses what the contract would have done. That guess drifts from Solidity the moment anyone touches a system, and it cannot see the parts of your logic that read other tables.
The solution
Instead of guessing, execute. @tevm/mud intercepts writeContract, runs the
call against a Tevm MemoryClient forked from your RPC, decodes
the resulting MUD Store events, and applies them to an optimistic overlay on top
of your Stash. The prediction is your Solidity, so it cannot drift.
When the canonical transaction lands, the sync adapter reconciles it and drops the optimistic overlay for that transaction.
import { createOptimisticHandler } from '@tevm/mud'
const optimistic = createOptimisticHandler({ client, storeAddress, stash, config })
// Reads that include not-yet-confirmed writes
optimistic.getOptimisticState()
optimistic.getOptimisticRecord({ table: config.tables.Position, key: { player } })Or in React:
import { useOptimisticRecord } from '@tevm/mud/react'
const position = useOptimisticRecord({ table: config.tables.Position, key: { player } })What you get
Correct predictions
The optimistic state comes from running your actual system bytecode, including cross-table reads and reverts.
Zero per-system code
No optimistic reducer to write or maintain — the prediction is your Solidity.
Real transaction lifecycle
Subscribe to simulating → optimistic → confirmed | reverted for each write.
Drop-in Stash reads
getOptimisticRecord / getOptimisticRecords mirror @latticexyz/stash's getRecord /
getRecords, with React hooks that re-render on optimistic and canonical updates.
Try it
Send increment() and watch the Stash update optimistically — then reconcile on confirmation,
or roll back when the canonical transaction reverts:
| key | field | value |
|---|---|---|
| 0x00…01 | value | 41 |
| 0x00…01 | lastUpdatedBy | 0xf39F…2266 |
Next
The Tevm family
This site is one of the *.tevm.sh docs sites — jump between them:

