Migrate from v1 to v2 
Wagmi Core v2 redesigns the core APIs to mesh better with Viem. This major version transforms Wagmi into a light wrapper around Viem, sprinkling in multichain support and account management. As such, there are some breaking changes and deprecations to be aware of outlined in this guide.
To get started, install the latest version of Wagmi and it's required peer dependencies.
pnpm add @wagmi/core viem@2.x @wagmi/connectorsnpm install @wagmi/core viem@2.x @wagmi/connectorsyarn add @wagmi/core viem@2.x @wagmi/connectorsbun add @wagmi/core viem@2.x @wagmi/connectorsWagmi Core v2 should be the last major version that will have this many actionable breaking changes.
Moving forward, new functionality will be opt-in with old functionality being deprecated alongside the new features. This means upgrading to the latest major versions will not require immediate changes.
Not ready to migrate yet?
The Wagmi Core v1 docs are still available at 1.x.wagmi.sh/core.
Dependencies 
Dropped CommonJS support 
Wagmi v2 no longer publishes a separate cjs tag since very few people use this tag and ESM is the future. See Sindre Sorhus' guide for more info about switching to ESM.
Actions 
Removed config singleton 
Before v2, when you called createConfig, it set a global config singleton that was used internally by actions. For v2, config is now a required first parameter for actions.
import { getAccount, readContract } from '@wagmi/core'
import { parseAbi } from 'viem'
import { config } from './config'
const account = getAccount()
const account = getAccount(config)
const balanceOf = readContract({ 
const balanceOf = readContract(config, { 
  address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
  abi: parseAbi(['function balanceOf(address) view returns (uint256)']),
  functionName: 'balanceOf',
  args: ['0xd2135CfB216b74109775236E36d4b433F1DF507B'],
})import { http, createConfig } from '@wagmi/core'
import { mainnet, sepolia } from '@wagmi/core/chains'
export const config = createConfig({
  chains: [mainnet, sepolia],
  transports: {
    [mainnet.id]: http(),
    [sepolia.id]: http(),
  },
})The previous global config singleton made it so you couldn't use multiple Config objects in the same project. In addition, we think passing config is more explicit and makes it easier to understand what's going on. Finally, types can be inferred directly from the config, like chain properties and more.
Removed getContract 
Removed getContract export. Use Viem's getContract instead.
import { getContract } from '@wagmi/core'
import { getContract } from 'viem'
const contract = getContract()
const contract = getContract()Removed getNetwork and watchNetwork 
The getNetwork and watchNetwork actions were removed since the connected chain is typically based on the connected account.
- Use - config.chainsinstead to get- chains.ts- import { getNetwork } from '@wagmi/core' const { chains } = getNetwork() const chains = config.chainsts- import { http, createConfig } from '@wagmi/core' import { mainnet, sepolia } from '@wagmi/core/chains' export const config = createConfig({ chains: [mainnet, sepolia], transports: { [mainnet.id]: http(), [sepolia.id]: http(), }, })
- Use - getAccountand- config.chainsinstead to get- chain.ts- import { getNetwork } from '@wagmi/core' import { getAccount } from '@wagmi/core' import { config } from './config' const { chain } = getNetwork() const { chainId } = getAccount(config) const chain = chains.find(chain => chain.id === chainId)ts- import { http, createConfig } from '@wagmi/core' import { mainnet, sepolia } from '@wagmi/core/chains' export const config = createConfig({ chains: [mainnet, sepolia], transports: { [mainnet.id]: http(), [sepolia.id]: http(), }, })- Before v2, - getNetwork().chaincould result in an invalid chain if the active connector's- chainIdwas not configured in the list of- config.chains. Using- getAccountand- config.chainsis more work, but ensures that chain is either valid or not defined. You can also use- getAccount(config).chainif you don't care about the chain being- undefinedwhen not configured.
- Use - watchAccountinstead of- watchNetwork.ts- import { watchNetwork } from '@wagmi/core' import { watchAccount } from '@wagmi/core' import { config } from './config' const unwatch = watchNetwork((data) => console.log('Changed!', data)) const unwatch = watchAccount(config, { onChange(data) { const chains = config.chains const chain = chains.find(chain => chain.id === data.chainId) }, })ts- import { http, createConfig } from '@wagmi/core' import { mainnet, sepolia } from '@wagmi/core/chains' export const config = createConfig({ chains: [mainnet, sepolia], transports: { [mainnet.id]: http(), [sepolia.id]: http(), }, })
Removed getWebSocketPublicClient and watchWebSocketPublicClient 
Viem Transports now determine the type of client that is returned. You can use getPublicClient and watchPublicClient to retrieve Viem PublicClient instances.
Alternatively, you can use getClient and watchClient to retrieve plain Viem Client instances. This is a better option for users that care about optimizing bundle size to be as small as possible.
Removed watchReadContract, watchReadContracts, and watchReadMulticall 
Use watchBlockNumber along with readContract, readContracts, and multicall actions instead. Before v2, watchReadContract, watchReadContracts, and watchReadMulticall were all wrappers around watchBlockNumber and this simplifies the API.
import { watchReadContract } from '@wagmi/core'
import { watchBlockNumber, readContract } from '@wagmi/core'
import { config } from './config'
const unwatch = watchReadContract(
  { 
    address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', 
    abi: parseAbi(['function balanceOf(address) view returns (uint256)']), 
    functionName: 'balanceOf', 
    args: ['0xd2135CfB216b74109775236E36d4b433F1DF507B'], 
  },
  (result) => console.log('Changed!', result),
)
const unwatch = watchBlockNumber(config, { 
  onBlockNumber() { 
    const balanceOf = readContract(config, { 
      address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', 
      abi: parseAbi(['function balanceOf(address) view returns (uint256)']), 
      functionName: 'balanceOf', 
      args: ['0xd2135CfB216b74109775236E36d4b433F1DF507B'], 
    })
    console.log('Changed!', balanceOf)
  }, 
})import { http, createConfig } from '@wagmi/core'
import { mainnet, sepolia } from '@wagmi/core/chains'
export const config = createConfig({
  chains: [mainnet, sepolia],
  transports: {
    [mainnet.id]: http(),
    [sepolia.id]: http(),
  },
})Removed fetchFeeData 
Removed fetchFeeData. Use estimateFeesPerGas instead.
import { fetchFeeData } from '@wagmi/core'
import { estimateFeesPerGas } from '@wagmi/core'
import { config } from './config'
const result = await fetchFeeData()
const result = await estimateFeesPerGas(config)import { http, createConfig } from '@wagmi/core'
import { mainnet, sepolia } from '@wagmi/core/chains'
export const config = createConfig({
  chains: [mainnet, sepolia],
  transports: {
    [mainnet.id]: http(),
    [sepolia.id]: http(),
  },
})Removed prepareWriteContract 
Removed prepareWriteContract. Use simulateContract instead.
import { prepareWriteContract } from '@wagmi/core'
import { simulateContract } from '@wagmi/core'
import { config } from './config'
const result = await prepareWriteContract({ ... })
const result = await simulateContract(config, { ... })import { http, createConfig } from '@wagmi/core'
import { mainnet, sepolia } from '@wagmi/core/chains'
export const config = createConfig({
  chains: [mainnet, sepolia],
  transports: {
    [mainnet.id]: http(),
    [sepolia.id]: http(),
  },
})Removed prepareSendTransaction 
Removed prepareSendTransaction. Use estimateGas instead.
import { prepareSendTransaction } from '@wagmi/core'
import { estimateGas } from '@wagmi/core'
import { config } from './config'
const result = await prepareSendTransaction({ ... })
const result = await estimateGas(config, { ... })import { http, createConfig } from '@wagmi/core'
import { mainnet, sepolia } from '@wagmi/core/chains'
export const config = createConfig({
  chains: [mainnet, sepolia],
  transports: {
    [mainnet.id]: http(),
    [sepolia.id]: http(),
  },
})Updated sendTransaction and writeContract return type 
Updated sendTransaction and writeContract return type from { hash: `0x${string}` } to `0x${string}`.
const result = await sendTransaction({ hash: '0x...' })
result.hash
resultUpdated connect return type 
Updated connect return type from { account: Address; chain: { id: number; unsupported?: boolean }; connector: Connector } to { accounts: readonly Address[]; chainId: number }. This better reflects the ability to have multiple accounts per connector.
Renamed parameters and return types 
All hook parameters and return types follow the naming pattern of [PascalCaseActionName]Parameters and [PascalCaseActionName]ReturnType. For example, GetAccountParameters and GetAccountReturnType.
import { GetAccountConfig, GetAccountResult } from '@wagmi/core'
import { GetAccountParameters, GetAccountReturnType } from '@wagmi/core'Connectors 
Moved Wagmi Connectors to peer dependencies 
Wagmi Core v2 no longer exports connectors via the '@wagmi/core/connectors/*' entrypoints. Instead, you should install the @wagmi/connectors package.
pnpm add @wagmi/connectorsnpm install @wagmi/connectorsyarn add @wagmi/connectorsbun add @wagmi/connectorsAnd import connectors from there.
import { injected } from '@wagmi/connectors'See the connectors documentation for more information.
Updated connector API 
In order to maximize type-safety and ease of creating connectors, the connector API changed. Follow the Creating Connectors guide for more info on creating new connectors and converting Wagmi v1 connectors.
Removed individual entrypoints 
Previously, each connector had its own entrypoint to optimize tree-shaking. Since all connectors now have package.json#sideEffects enabled, this is no longer necessary and the entrypoint is unified. Use the '@wagmi/connectors' package instead.
import { InjectedConnector } from '@wagmi/core/connectors/injected'
import { CoinbaseWalletConnector } from '@wagmi/core/connectors/coinbaseWallet'
import { coinbaseWallet, injected } from '@wagmi/connectors'Removed MetaMaskConnector 
The MetaMaskConnector was removed since it was nearly the same thing as the InjectedConnector. Use the injected connector instead, along with the target parameter set to 'metaMask', for the same behavior.
import { MetaMaskConnector } from '@wagmi/core/connectors/metaMask'
import { injected } from '@wagmi/connectors'
const connector = new MetaMaskConnector()
const connector = injected({ target: 'metaMask' })Renamed connectors 
In Wagmi v1, connectors were classes you needed to instantiate. In Wagmi v2, connectors are functions. As a result, the API has changed. Connectors have the following new names:
- CoinbaseWalletConnectoris now- coinbaseWallet.
- InjectedConnectoris now- injected.
- SafeConnectoris now- safe.
- WalletConnectConnectoris now- walletConnect.
To create a connector, you now call the connector function with parameters.
import { WalletConnectConnector } from '@wagmi/core/connectors/walletConnect'
import { walletConnect } from '@wagmi/connectors'
const connector = new WalletConnectConnector({ 
const connector = walletConnect({ 
  projectId: '3fcc6bba6f1de962d911bb5b5c3dba68',
})Removed WalletConnectLegacyConnector 
WalletConnect v1 was sunset June 28, 2023. Use the walletConnect connector instead.
import { WalletConnectLegacyConnector } from '@wagmi/core/connectors/walletConnectLegacy'
import { walletConnect } from '@wagmi/connectors'
const connector = new WalletConnectLegacyConnector({ 
const connector = walletConnect({ 
  projectId: '3fcc6bba6f1de962d911bb5b5c3dba68',
})Chains 
Updated '@wagmi/core/chains' entrypoint 
Chains now live in the Viem repository. As a result, the '@wagmi/core/chains' entrypoint now proxies all chains from 'viem/chains' directly.
Removed mainnet and sepolia from main entrypoint 
Since the '@wagmi/core/chains' entrypoint now proxies 'viem/chains', mainnet and sepolia were removed from the main entrypoint. Use the '@wagmi/core/chains' entrypoint instead.
import { mainnet, sepolia } from '@wagmi/core'
import { mainnet, sepolia } from '@wagmi/core/chains'Errors 
A number of errors were renamed to better reflect their functionality or replaced by Viem errors.
Miscellaneous 
Removed internal ENS normalization 
Before v2, Wagmi handled ENS name normalization internally for getEnsAddress, getEnsAvatar, and getEnsResolver, using Viem's normalize function. This added extra bundle size as full normalization is quite heavy. For v2, you must normalize ENS names yourself before passing them to these actions. You can use Viem's normalize function or any other function that performs UTS-46 normalization.
import { getEnsAddress } from '@wagmi/core'
import { normalize } from 'viem'
import { config } from './config'
const result = await getEnsAddress(config, {
  name: 'wevm.eth', 
  name: normalize('wevm.eth'), 
})import { http, createConfig } from '@wagmi/core'
import { mainnet, sepolia } from '@wagmi/core/chains'
export const config = createConfig({
  chains: [mainnet, sepolia],
  transports: {
    [mainnet.id]: http(),
    [sepolia.id]: http(),
  },
})By inverting control, Wagmi lets you choose how much normalization to do. For example, maybe your project only allows ENS names that are numeric so no normalization is not needed. Check out the ENS documentation for more information on normalizing names.
Removed configureChains 
The Wagmi v2 Config now has native multichain support using the chains parameter so the configureChains function is no longer required.
import { configureChains, createConfig } from '@wagmi/core'
import { http, createConfig } from '@wagmi/core'
import { mainnet, sepolia } from '@wagmi/core/chains'
const { chains, publicClient } = configureChains(
  [mainnet, sepolia],
  [publicProvider(), publicProvider()],
)
export const config = createConfig({
  publicClient, 
  chains: [mainnet, sepolia], 
  transports: { 
    [mainnet.id]: http(), 
    [sepolia.id]: http(), 
  }, 
})Removed ABI exports 
Import from Viem instead.
import { erc20ABI } from '@wagmi/core'
import { erc20Abi } from 'viem'Removed '@wagmi/core/providers/* entrypoints 
It never made sense that we would have provider URLs hardcoded in the Wagmi codebase. Use Viem transports along with RPC provider URLs instead.
import { alchemyProvider } from '@wagmi/core/providers/alchemy'
import { http } from 'viem'
const transport = http('https://mainnet.example.com')Updated createConfig parameters 
- Removed autoConnect. The reconnecting behavior must be managed manually and is not related to the WagmiConfig. Use thereconnectaction instead.
- Removed publicClientandwebSocketPublicClient. Usetransportsorclientinstead.
- Removed logger. Wagmi no longer logs debug information to console.
Updated Config object 
- Removed config.connector. Useconfig.state.connections.get(config.state.current)?.connectorinstead.
- Removed config.data. Useconfig.state.connections.get(config.state.current)instead.
- Removed config.error. Was unused and not needed.
- Removed config.lastUsedChainId. Useconfig.state.connections.get(config.state.current)?.chainIdinstead.
- Removed config.publicClient. Useconfig.getClient()orgetPublicClientinstead.
- Removed config.status. Useconfig.state.statusinstead.
- Removed config.webSocketClient. Useconfig.getClient()orgetPublicClientinstead.
- Removed config.clearState. Was unused and not needed.
- Removed config.autoConnect(). Usereconnectaction instead.
- Renamed config.setConnectors. Useconfig._internal.setConnectorsinstead.
- Removed config.setLastUsedConnector. Useconfig.storage?.setItem('recentConnectorId', connectorId)instead.
- Removed getConfig.configshould be passed explicitly to actions instead of using globalconfig.
Deprecations 
Deprecated getBalance token parameter 
Moving forward, getBalance will only work for native currencies, thus the token parameter is no longer supported. Use readContracts instead.
import { getBalance } from '@wagmi/core'
import { readContracts } from '@wagmi/core'
import { erc20Abi } from 'viem'
import { config } from './config'
const result = await getBalance(config, { 
  address: '0x4557B18E779944BFE9d78A672452331C186a9f48', 
  token: '0x6B175474E89094C44Da98b954EedeAC495271d0F', 
})
const result = await readContracts(config, { 
  allowFailure: false, 
  contracts: [ 
    { 
      address: '0x6B175474E89094C44Da98b954EedeAC495271d0F', 
      abi: erc20Abi, 
      functionName: 'balanceOf', 
      args: ['0x4557B18E779944BFE9d78A672452331C186a9f48'], 
    }, 
    { 
      address: '0x6B175474E89094C44Da98b954EedeAC495271d0F', 
      abi: erc20Abi, 
      functionName: 'decimals', 
    }, 
    { 
      address: '0x6B175474E89094C44Da98b954EedeAC495271d0F', 
      abi: erc20Abi, 
      functionName: 'symbol', 
    }, 
  ] 
})Deprecated getBalance unit parameter and formatted return value 
Moving forward, getBalance will not accept the unit parameter or return a formatted value. Instead you can call formatUnits from Viem directly or use another number formatting library, like dnum instead.
import { formatUnits } from 'viem'
import { getBalance } from '@wagmi/core'
const result = await getBalance({
  address: '0x4557B18E779944BFE9d78A672452331C186a9f48',
  unit: 'ether', 
})
result.formatted
formatUnits(result.value, result.decimals)Deprecated getToken 
Moving forward, getToken is no longer supported. Use readContracts instead.
import { getToken } from '@wagmi/core'
import { readContracts } from '@wagmi/core'
import { erc20Abi } from 'viem'
import { config } from './config'
const result = await getToken(config, { 
  address: '0x6B175474E89094C44Da98b954EedeAC495271d0F', 
})
const result = await readContracts(config, { 
  allowFailure: false, 
  contracts: [ 
    { 
      address: '0x6B175474E89094C44Da98b954EedeAC495271d0F', 
      abi: erc20Abi, 
      functionName: 'decimals', 
    }, 
    { 
      address: '0x6B175474E89094C44Da98b954EedeAC495271d0F', 
      abi: erc20Abi, 
      functionName: 'name', 
    }, 
    { 
      address: '0x6B175474E89094C44Da98b954EedeAC495271d0F', 
      abi: erc20Abi, 
      functionName: 'symbol', 
    }, 
    { 
      address: '0x6B175474E89094C44Da98b954EedeAC495271d0F', 
      abi: erc20Abi, 
      functionName: 'totalSupply', 
    }, 
  ] 
})Deprecated formatUnits parameters and return values 
The formatUnits parameter and related return values (e.g. result.formatted) are deprecated for the following actions:
Instead you can call formatUnits from Viem directly or use another number formatting library, like dnum instead.
import { formatUnits } from 'viem'
import { getToken } from '@wagmi/core'
const result = await getToken({
  address: '0x6B175474E89094C44Da98b954EedeAC495271d0F',
  formatUnits: 'ether',
})
result.totalSupply.formatted
formatUnits(result.totalSupply.value, 18)This allows us to invert control to users so they can handle number formatting however they want, taking into account precision, localization, and more.
Renamed actions 
The following actions were renamed to better reflect their functionality and underlying Viem actions:
- fetchBalanceis now- getBalance
- fetchBlockNumberis now- getBlockNumber
- fetchEnsAddressis now- getEnsAddress
- fetchEnsAvataris now- getEnsAvatar
- fetchEnsNameis now- getEnsName
- fetchEnsResolveris now- getEnsResolver
- fetchTokenis now- getToken
- fetchTransactionis now- getTransaction
- switchNetworkis now- switchChain
- waitForTransactionis now- waitForTransactionReceipt