dev-tooling/ethers-vs-viem
ethers.js vs viem vs wagmi Selection Guide
ethereumdev-tools👥 Communityconfidence highhealth 100%
v1.0.0·Updated 3/20/2026
Positioning
| Library | Positioning | Use Cases |
|---|---|---|
| ethers.js v6 | Full-featured EVM library, longest history | Backend scripts, Node.js tools |
| viem | Lightweight, type-safe, high-performance | Modern frontend/backend, ethers alternative |
| wagmi | React Hooks wrapper (built on viem) | Top choice for React DApp frontends |
| web3.js | Oldest library, gradually being phased out | Legacy project maintenance only |
Why viem is Replacing ethers
Bundle size: viem ~35KB vs ethers ~280KB (gzipped) Tree-shaking: Import only what you need, unused code excluded Type safety: Automatic ABI type inference, better IDE autocomplete Performance: Faster execution for equivalent requests
// ethers v6
const provider = new ethers.JsonRpcProvider(RPC_URL)
const balance = await provider.getBalance(address)
// viem (same functionality, more lightweight)
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
const client = createPublicClient({ chain: mainnet, transport: http(RPC_URL) })
const balance = await client.getBalance({ address })
wagmi Complete Example (React DApp)
npm install wagmi viem @tanstack/react-query
// wagmi config
import { createConfig, http } from 'wagmi'
import { mainnet, base, arbitrum } from 'wagmi/chains'
import { injected, walletConnect } from 'wagmi/connectors'
export const config = createConfig({
chains: [mainnet, base, arbitrum],
connectors: [injected(), walletConnect({ projectId: 'YOUR_ID' })],
transports: { [mainnet.id]: http(), [base.id]: http(), [arbitrum.id]: http() },
})
// Hooks usage
import { useAccount, useBalance, useReadContract, useWriteContract } from 'wagmi'
function MyDApp() {
const { address, isConnected } = useAccount()
const { data: balance } = useBalance({ address })
const { data: tokenBal } = useReadContract({
address: TOKEN_ADDRESS, abi: ERC20_ABI,
functionName: 'balanceOf', args: [address!],
query: { enabled: !!address }
})
const { writeContract, isPending } = useWriteContract()
return (
<button onClick={() => writeContract({
address: TOKEN_ADDRESS, abi: ERC20_ABI,
functionName: 'transfer', args: [recipient, amount]
})} disabled={isPending}>Transfer</button>
)
}
Decision Tree
What is your project?
- React DApp frontend → wagmi (Hooks wrapper, ready out of the box)
- Next.js/pure frontend, don't want Hooks → viem
- Node.js backend scripts/CLI → viem or ethers v6
- Maintaining legacy project (ethers v5) → Continue using, no rush to migrate
- Maintaining legacy project (web3.js) → Use viem for new features
npm Downloads (2024)
- ethers: ~2.5M/week (still highest, growth slowing)
- viem: ~2M/week (fastest growth)
- wagmi: ~700K/week (rapid growth)
- web3.js: ~500K/week (declining)