Web3 Development · 5 min read ·
Learn how to build reliable Web3 frontends with wagmi hooks and viem clients, from wallet connections to contract reads, writes, and event UX.
Web3 frontends have a reputation for being fragile: wallet state desyncs, flaky RPCs, mismatched chain IDs, and “transaction submitted” UIs that never resolve. The wagmi + viem stack is the most practical answer we’ve seen to this problem in the React ecosystem.
wagmi provides the React-first primitives (hooks, caching, connectors, and opinionated ergonomics). viem provides the low-level engine (typed EVM interactions, transports, account abstraction readiness, and predictable behavior). Together, they let you build a frontend that feels like modern app development—not a collection of web3 edge cases.
If you built dapps in the ethers.js era, you probably wrote a lot of glue code: instantiate providers/signers, manage chain switching, debounce reads, poll for receipts, and recover from RPC failures. wagmi absorbs most of that into a coherent state model.
viem is the other half of the story. It’s a lighter, more explicit EVM client that favors:
const.The result: less incidental complexity and fewer UX dead ends.
The most common production failure isn’t your UI—it’s infrastructure assumptions. Configure your clients like you expect failures.
Typical wagmi setup involves creating a config with chains and transports (RPC URLs). In production, prefer:
Practical stance: start with HTTP + fallback; add WebSocket for real-time UX only when you can operate it reliably.
wagmi connectors abstract wallet types (Injected, WalletConnect, Coinbase, Safe, etc.) and unify connection state.
In frontend architecture, separate:
A solid pattern is to keep connection UI components dumb (just call wagmi actions) and keep business logic in feature modules.
Common gotcha: “connected” does not mean “ready to write.” The user might be on the wrong chain, the wallet may be locked, or the connector may not support the method you want.
Most dapps overfetch. wagmi’s read hooks integrate with TanStack Query under the hood, so you get caching, refetch controls, and invalidation patterns that mirror Web2.
Guidelines we use:
enabled flags to avoid calls before prerequisites exist (address connected, chain selected, inputs valid).readContracts (multicall) reduces latency and RPC load.Example scenario: a lending UI needs collateralBalance, debtBalance, and healthFactor. Don’t fire three independent reads on every render—batch them and only refetch when inputs change or a transaction completes.
The single best way to reduce reverted transactions (and angry users) is to simulate before you send.
With viem, simulation is a first-class concept: you can run a call with the exact arguments and value, see if it would revert, and estimate gas more reliably. In wagmi, the write flow often looks like:
This isn’t just “nice”: it’s the difference between a professional app and a demo.
Opinionated UX rule: if simulation fails, show a human-readable reason and stop. Don’t let users “try anyway” unless you know what you’re doing (advanced mode).
Most teams only design “success.” Real users live in “pending.”
A robust transaction UX includes:
wagmi’s receipt hooks make it straightforward to wait for confirmations. For production, we typically wait 1 confirmation for UX responsiveness, while the backend/indexer (if any) can require more.
ERC-20 approvals are where UX goes to die. Get them right.
Best practices:
If you’re building DeFi, this flow is not optional—treat it as a first-class product surface.
On-chain events are tempting for “live updates,” but they introduce operational and UX complexity (WebSocket stability, chain reorgs, duplicated logs).
Use events when:
Otherwise, polling reads with sane intervals is often simpler and more reliable.
One underrated win in the wagmi + viem stack is how far you can push typing.
If you define your ABI as a const and keep it near the feature code, you get:
In teams, this reduces code review overhead and speeds up integration with Solidity changes.
Before shipping:
wagmi + viem is the most pragmatic stack for modern Web3 frontend development because it cleanly separates concerns: wagmi handles React state, connectors, and query ergonomics; viem handles the EVM with explicit, typed, reliable primitives.
If you build with a simulation-first write path, cache reads intentionally, and treat transaction pending states as a first-class UX, you’ll ship a dapp that feels dependable—even when wallets and RPCs aren’t.