Creating a MemoryClient
createMemoryClient bootstraps a complete Ethereum execution environment in JavaScript.
Basic usage
import { createMemoryClient } from "tevm";
const client = createMemoryClient();
// Optional: wait for ready (useful for profiling/debugging)
await client.ready();With configuration
import { createMemoryClient, http } from "tevm";
const rpcUrl = process.env.MAINNET_RPC_URL;
if (!rpcUrl) {
throw new Error("MAINNET_RPC_URL is required for fork mode");
}
const client = createMemoryClient({
fork: { transport: http(rpcUrl)({}) },
miningConfig: { type: "auto" },
loggingLevel: "debug",
});
await client.ready();Configuration Options
Fork Configuration
import { createMemoryClient, http } from "tevm";
const rpcUrl = process.env.MAINNET_RPC_URL;
if (!rpcUrl) {
throw new Error("MAINNET_RPC_URL is required for fork mode");
}
const node = createMemoryClient({
fork: {
transport: http(rpcUrl)({}),
blockTag: 17_000_000n, // optional
},
});
await node.ready();Mining Configuration
// Auto: mine after each tx
const node = createMemoryClient({ miningConfig: { type: "auto" } });
// Interval: mine every N ms
const intervalNode = createMemoryClient({
miningConfig: { type: "interval", interval: 12_000 },
});Chain Configuration
import { createMemoryClient } from "tevm";
import { Common } from "tevm/common";
const customNode = createMemoryClient({
common: Common.custom({ chainId: 1337, networkId: 1337 }),
});Or use a preset:
import { createMemoryClient } from "tevm";
import { mainnet, optimism, arbitrum, base } from "tevm/common";
const optimismNode = createMemoryClient({ common: optimism });Want to add your own network?
Add it to viem/chains first, then open an issue on the Tevm repo to request inclusion.
Logging Configuration
const node = createMemoryClient({
loggingLevel: "debug", // 'fatal' | 'error' | 'warn' | 'info' | 'debug' | 'trace'
});
node.logger.debug("Detailed debugging information");
node.logger.info("Informational message");
node.logger.warn("Warning!");
node.logger.error("Error encountered", { details: "Something went wrong" });Custom Precompiles
import { definePrecompile, createContract, parseAbi } from "tevm";
const calculatorPrecompile = definePrecompile({
contract: createContract({
abi: parseAbi([
"function add(uint256 a, uint256 b) returns (uint256)",
"function subtract(uint256 a, uint256 b) returns (uint256)",
]),
address: "0xf2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2",
}),
call: async ({ data, gasLimit }) => {
return {
returnValue: new Uint8Array([0x01]),
executionGasUsed: 200n,
};
},
});
const node = createMemoryClient({
customPrecompiles: [calculatorPrecompile.precompile()],
});Performance Profiling
const node = createMemoryClient({ profiler: true });
await node.ready();
const vm = await node.getVm();
const performanceLogs = vm.evm.getPerformanceLogs();Complete Configuration Reference
| Property | Type | Default | Description |
|---|---|---|---|
fork | { transport: EIP1193RequestFn; blockTag?: BlockTag; } | - | Enables forking from a live network or another Tevm instance |
common | Common | tevmDevnet | Chain configuration object |
loggingLevel | "fatal" | "error" | "warn" | "info" | "debug" | "trace" | "info" | Logging verbosity level |
miningConfig | { type: 'auto' } | { type: 'interval', interval: number } | { type: 'auto' } | Block mining behavior |
customPrecompiles | Precompile[] | [] | Additional precompiled contracts |
allowUnlimitedContractSize | boolean | false | Disables EIP-170 contract size checks |
Best Practices
Always pass a common when forking
- Faster init (no chainId fetch).
- Correct hardfork/EIP behavior per chain.
Without one, tevmDefault is used.
import { createMemoryClient, http } from "tevm";
import { optimism } from "tevm/common";
const client = createMemoryClient({
common: optimism,
fork: { transport: http() },
});
// op-stack-aware: enables l1DataFee calculation
const { l1DataFee } = await client.call({ data });Choose the right mining config
Default is manual mining (recommended). auto mines on each tx; interval mines every N ms; gas mines when a gas threshold is hit.
const testNode = createMemoryClient({ miningConfig: { type: "auto" } });
const simulationNode = createMemoryClient({
miningConfig: { type: "interval", interval: 12_000 },
});Use debug logging when stuck
Tevm produces many debug logs — pipe them through an LLM to triage.
const client = createMemoryClient({ loggingLevel: "debug" });Call client.ready() when profiling
Otherwise the first action absorbs init time. Tevm init is fast (no sync).
Next Steps
Runtime Model · Node Interface · Forking · State · Custom Precompiles

