Creating a MemoryClient
createMemoryClient bootstraps a complete Ethereum execution environment in JavaScript.
Basic usage
import { createMemoryClient } from "tevm";
const client = createMemoryClient();
// Optional: eagerly finish lazy initialization
await client.tevmReady();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.tevmReady();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.tevmReady();Mining Configuration
// Auto: mine after each tx
const node = createMemoryClient({ miningConfig: { type: "auto" } });
// Interval: mine every N seconds
const intervalNode = createMemoryClient({
miningConfig: { type: "interval", blockTime: 12 },
});Chain Configuration
import { createMemoryClient } from "tevm";
import { createCommon } from "tevm/common";
const customNode = createMemoryClient({
common: createCommon({
id: 1337,
name: "Local chain",
nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
rpcUrls: { default: { http: ["http://localhost:8545"] } },
}),
});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 { createContract, createMemoryClient, definePrecompile, 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: "0x0000000000000000000000000000000000000100",
}),
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.tevmReady();
const vm = await node.transport.tevm.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: 'manual' } | { type: 'auto' } | { type: 'interval', blockTime: number } | { type: 'manual' } | 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 rpcUrl = process.env.OPTIMISM_RPC_URL;
if (!rpcUrl) throw new Error("OPTIMISM_RPC_URL is required");
const client = createMemoryClient({
common: optimism,
fork: { transport: http(rpcUrl)({}) },
});
const block = await client.getBlock({ blockTag: "latest" });Choose the right mining config
Default is manual mining. auto mines submitted transactions immediately; interval uses blockTime in seconds.
const testNode = createMemoryClient({ miningConfig: { type: "auto" } });
const simulationNode = createMemoryClient({
miningConfig: { type: "interval", blockTime: 12 },
});Use debug logging when stuck
Tevm produces many debug logs — pipe them through an LLM to triage.
const client = createMemoryClient({ loggingLevel: "debug" });Call client.tevmReady() 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

