From the trenches
BOBR

Builder-first crypto. Informative, inclusive, and a little degen.

Build a Base App in 2026: The Essential 6-Step Guide

MiniKit and Farcaster mini-apps stopped working inside the Base App on April 9, 2026. Here's the current wagmi + viem + SIWE stack, step by step.

Shiloh
Shiloh

The dev and artist of BasedBOBR, painter, full-stack dev, ape.store speaker

·13 min read·Updated July 8, 2026
Developer working late to build a Base app, laptop and coffee on the desk. Photo by Daniil Komov on Pexels.
TL;DR
  • Farcaster mini-apps and MiniKit stopped working inside the Base App on April 9, 2026.
  • The current stack is wagmi, viem, and Sign-In with Ethereum, registered through Base.dev.
  • Existing mini apps can often migrate in hours; new apps should skip the old spec entirely.

If you want to build a Base app in 2026, most tutorials you'll find first are already wrong. They walk through Farcaster's mini-app spec and Coinbase's old MiniKit package. That playbook stopped working on April 9, 2026, when the Base App switched to treating every app as a standard web app instead of a Farcaster frame.

The Base App now runs on wagmi, viem, and Sign-In with Ethereum. No Farcaster manifest. No FID lookups. Just a wallet and a normal web stack.

This guide walks through the current setup step by step: project scaffolding, wallet connection, authentication, a working contract, and registering on Base.dev. Every command below comes from Base's live documentation, not a cached tutorial from last year. Think of it as a wagmi Base tutorial for the post-MiniKit era: six steps, one wallet stack, enough to build a Base app in an afternoon.

What changed: After April 9, 2026, the Base App stopped reading Farcaster manifests entirely. Fourteen mini-app SDK methods, including signIn, sendToken, and composeCast, no longer fire inside the Base App. Every app is now a standard web app plus a wallet, per Base's own migration guide.

Why the Old Mini App Playbook Broke

For about two years, "build on Base" meant building a Farcaster mini app. You wrote a farcaster.json manifest, wired up MiniKit, and let Warpcast or the Base App render your frame.

That model is gone inside the Base App specifically. Farcaster itself still supports mini apps elsewhere. But if your users find you through the Base app itself, you're building a standard web app now.

The Farcaster mini-app deprecation caught plenty of teams off guard, especially ones that shipped just weeks before April 9. If that's you, the migration table below tells you how much work is actually left.

Old (Farcaster mini-app)New (standard web app)
.well-known/farcaster.json manifestApp metadata registered on Base.dev
Farcaster SDK signInSIWE via wagmi's useSignMessage
FID-based user contextWallet address via useAccount
Neynar webhooks for eventsBase Notifications API (wallet-address based)
composeCast, viewProfile, openMiniAppDeep links and standard web UI

The methods that quietly stopped working

A few of the deprecated calls are worth flagging by name, since old starter templates still ship with them:

  • signIn and addMiniApp: no longer invoked, replace signIn with SIWE
  • sendToken and swapToken: build the transaction yourself with useWriteContract or viem
  • viewCast, composeCast, ready: not applicable inside the Base App anymore
  • User context / FID: read the connected wallet address with wagmi's useAccount instead

Should You Migrate an Existing App or Start Fresh?

If you already shipped a Farcaster mini app for the Base App, you have a decision to make before touching any code. Not every project needs a full rebuild.

Your situationWhat to do
Mini app only used signIn and basic wallet readsSwap in wagmi + SIWE, keep everything else. A few hours of work.
Mini app leaned heavily on composeCast, FID identity, or Farcaster notificationsExpect a real rewrite of your auth and notification layers.
Haven't shipped anything yetSkip the old spec entirely and build straight on the current stack below.

Base also published a migration skill for exactly this. Running npx skills add base/skills and asking your coding agent to migrate the app can save a lot of the mechanical work, especially the wagmi config and provider boilerplate.

Whether you migrate or start fresh, the goal is the same: build a Base app that works under the Base App 2026 rules, not the old mini-app spec.

What You Need to Build a Base App

You'll need Node.js installed, a Base-compatible wallet (Coinbase Wallet or a Base Account), and some Base Sepolia testnet ETH from a faucet if you plan to deploy a contract.

You'll also want a free account on Base.dev for the registration step later. Nothing to set up yet, just have it ready.

A quick checklist before Step 1:

  • Node.js 18 or newer installed
  • A wallet that supports Base (Coinbase Wallet, MetaMask, or a Base Account)
  • Base Sepolia testnet ETH from a faucet, if you're deploying a contract
  • A Base.dev account, even an empty one, ready for later
  • Foundry installed, only if Step 5 applies to your app

Abstract glowing digital network representing the Base blockchain infrastructure. Photo by Pachon in Motion on Pexels.
Abstract glowing digital network representing the Base blockchain infrastructure. Photo by Pachon in Motion on Pexels.

Step 1: Scaffold the Project

Start with a standard Next.js app, then add the wallet stack:

npx create-next-app@latest my-base-app --typescript --tailwind --app
cd my-base-app
npm install wagmi viem @tanstack/react-query @base-org/account

That's the entire dependency list to build a Base app today. No Farcaster SDK, no MiniKit package.

Step 2: Configure wagmi for Base

Create config/wagmi.ts and set up the Base chain with two connectors: injected for browser wallets and baseAccount for the Base Account smart wallet.

import { http, createConfig, createStorage, cookieStorage } from 'wagmi'
import { base } from 'wagmi/chains'
import { baseAccount, injected } from 'wagmi/connectors'

export const config = createConfig({
  chains: [base],
  connectors: [injected(), baseAccount({ appName: 'My Base App' })],
  storage: createStorage({ storage: cookieStorage }),
  ssr: true,
  transports: { [base.id]: http() },
})

Use ssr: true with cookieStorage. Skipping it causes hydration mismatches in Next.js the first time a wallet connects.

Wrap the app in providers

'use client'
import { WagmiProvider } from 'wagmi'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { config } from '@/config/wagmi'

const queryClient = new QueryClient()

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <WagmiProvider config={config}>
      <QueryClientProvider client={queryClient}>
        {children}
      </QueryClientProvider>
    </WagmiProvider>
  )
}

Step 3: Connect a Wallet the Right Way

Wallet connection has four states, not two. Most broken demos only check isConnected and end up flashing a "Connect" button for a split second on every page load.

'use client'
import { useAccount, useConnect, useDisconnect } from 'wagmi'

export function ConnectWallet() {
  const { address, isConnected, isConnecting, isReconnecting } = useAccount()
  const { connect, connectors } = useConnect()
  const { disconnect } = useDisconnect()

  if (isReconnecting) return <div>Reconnecting...</div>
  if (!isConnected) {
    return (
      <div className="flex flex-col gap-2">
        {connectors.map((connector) => (
          <button key={connector.uid} onClick={() => connect({ connector })}>
            Connect {connector.name}
          </button>
        ))}
      </div>
    )
  }
  return (
    <div className="flex items-center gap-3">
      <span className="font-mono text-sm">{address?.slice(0, 6)}...{address?.slice(-4)}</span>
      <button onClick={() => disconnect()}>Disconnect</button>
    </div>
  )
}

Watch for this: checking only isConnected causes UI flashes on page load. Handle isConnecting and isReconnecting too, or your app looks broken for a beat every time someone returns.

Close-up of a hand holding a smartphone showing a digital wallet app interface. Photo by Tranmautritam on Pexels.
Close-up of a hand holding a smartphone showing a digital wallet app interface. Photo by Tranmautritam on Pexels.

Step 4: Add Sign-In with Ethereum

SIWE authentication is the direct replacement for Farcaster's old signIn call, and it's the only sign-in path the Base App still recognizes. Generate a nonce, build the SIWE message, get a signature, then verify it.

const nonce = generateSiweNonce()
const message = createSiweMessage({
  address,
  chainId,
  domain: window.location.host,
  nonce,
  uri: window.location.origin,
  version: '1',
})
const signature = await signMessageAsync({ message })
const valid = await publicClient.verifySiweMessage({ message, signature })

Client-side verification is fine for a quick prototype. For anything real, move nonce generation and verification to your server, and issue a session after a valid check. Otherwise a replayed signature could pass twice.

Step 5: Deploy and Wire Up a Contract

If your app needs a smart contract, Foundry is the fastest way to get one on Base Sepolia:

mkdir contracts && cd contracts
curl -L https://foundry.paradigm.xyz | bash
foundryup
forge init --no-git
forge create ./src/Counter.sol:Counter --rpc-url https://sepolia.base.org --account deployer

Reading from the deployed contract is a single hook:

const { data: count } = useReadContract({
  address: COUNTER_ADDRESS,
  abi: counterAbi,
  functionName: 'number',
  chainId: base.id,
})

Writing needs a bit more care. A write has three states worth showing the user: signature pending, on-chain confirmation, and success. Pair useWriteContract with useWaitForTransactionReceipt and useSwitchChain.

const { writeContract, data: hash, isPending } = useWriteContract()
const { isSuccess } = useWaitForTransactionReceipt({ hash })

useEffect(() => {
  if (isSuccess) {
    queryClient.invalidateQueries({ queryKey: ['readContract'] })
  }
}, [isSuccess, queryClient])

Skip useSwitchChain and wagmi will silently try to switch the wallet's network in the background the moment the wallet is on the wrong chain, which confuses users more than it helps.

Batch transactions for smart wallets

If you want batch transactions (multiple calls in one signature) for smart wallet users, check wallet capabilities first using the EIP-5792 batch transaction standard via wagmi's useCapabilities.

const { data: capabilities } = useCapabilities()
const supportsBatching = capabilities?.[base.id]?.atomic?.status === 'ready'

Calling useSendCalls against a regular EOA wallet that doesn't support batching throws immediately, so always gate it behind that capability check. Base Accounts support it out of the box; most browser extension wallets don't yet.

Faster confirmations with Flashblocks

If your app feels laggy waiting on confirmations, swap to the preconf chain in your wagmi config:

import { baseSepoliaPreconf } from 'wagmi/chains'

export const config = createConfig({
  chains: [baseSepoliaPreconf],
  transports: { [baseSepoliaPreconf.id]: http() },
})

Flashblocks deliver incremental blocks roughly every 200ms instead of waiting for a full block, and it's a one-line config change, nothing else in your app needs to know about it.

Step 6: Register on Base.dev and Ship

Once your app works locally and is deployed (Vercel is the common choice for Next.js apps), the last step to build a Base app that's actually discoverable is registering it on Base.dev.

Base.dev is the replacement for Farcaster-based discovery. Under the old model, the Base App found your app through its Farcaster manifest and whatever frame data it exposed. Now discovery, metadata, and builder attribution all live in one place instead of being scattered across a manifest file and a social protocol.

You'll fill in:

  • App name, icon, and tagline
  • A short description and screenshots
  • A category and your primary URL
  • A builder code (optional, but worth adding)

If you already registered an app under the old Farcaster manifest system, good news: you don't need to redo it. Existing metadata carries over.

Hand holding a smartphone with a blank screen, ready for an app launch mockup. Photo by Jakub Zerdzicki on Pexels.
Hand holding a smartphone with a blank screen, ready for an app launch mockup. Photo by Jakub Zerdzicki on Pexels.

Notifications work differently now too. Instead of Neynar webhooks tied to a Farcaster FID, the Base Notifications API sends to wallet addresses directly. If you had a notification flow built on the old system, that's the piece to rebuild first, since it touches your backend and not just your frontend components.

The practical upside is fewer accounts to juggle. The old stack meant a Farcaster developer account, a Neynar API key, and a Base project, three separate dashboards for one app. The current model collapses that down to your own backend plus a single Base.dev listing.

Testing Your Base App Before You Register It

Don't register on Base.dev until you've actually clicked through the app once, end to end, on testnet. It catches problems a code review misses.

CheckHow
Wallet connects without a flashReload the page mid-session, watch for a flicker
SIWE signature completesSign in, then reload and confirm the session persists
Contract read worksLoad the page and confirm on-chain data actually renders
Contract write confirmsSubmit a write on Base Sepolia, watch all three states fire
Wrong-network handlingSwitch your wallet to a different chain first, then try to write

Base Sepolia's faucet gives you enough test ETH to run through all five checks without spending anything real. If a write silently fails, it's almost always the missing useSwitchChain mistake below.

Common Mistakes to Avoid

  • Skipping useSwitchChain. Without it, a write on the wrong network triggers a silent background chain switch instead of a clear error, and users just see a stuck "pending" button.
  • Trusting useChainId for your contract's chain. It returns the wallet's current chain, not the chain your contract is deployed on. Check both before assuming a read will work.
  • Forgetting as const on your ABI. Without it, wagmi can't infer function names or argument types, and TypeScript stops catching real bugs before they ship.
  • Calling useSendCalls blind. Always confirm supportsBatching first. An EOA wallet will throw the moment you try to batch calls it can't handle.
  • Testing only on desktop. Most Base App traffic is mobile. A wallet flow that works fine in a desktop browser extension can still break inside a mobile in-app browser.

FAQ

Is Farcaster mini-app development completely dead? No. Farcaster itself still supports mini apps outside the Base App, at docs.farcaster.xyz. It's specifically the Base App that moved to the standard web app model. If the Base App was your only distribution channel, you need to migrate now.

Do I still need OnchainKit or MiniKit to build a Base app? Not for the Base App itself. Some OnchainKit UI components still work fine in a standard web app, but the MiniKit-specific hooks and the Farcaster manifest flow are no longer necessary.

What happens to an app that never migrates? It still loads, but as a plain web page. Farcaster-only features like composeCast or FID-based identity simply stop firing, so any flow depending on them breaks silently.

Where do I actually register a new app on Base.dev? Create a project directly at Base.dev and fill in the app metadata fields listed in Step 6. There's also a migration skill available via npx skills add base/skills if you want an agent to handle an existing app's migration for you.

Do I need a builder code? It's optional, but it's how attribution and any builder rewards get tracked back to you. Skip it and your app still works fine, you just leave attribution on the table.

Can I still use Coinbase Wallet's old frame-based login inside the Base App? No. Frame-based login was part of the Farcaster mini-app spec, and it's one of the fourteen methods the Base App stopped invoking on April 9, 2026. SIWE is the only supported path now.

Does Flashblocks change how I write my app's code? No, it's purely a config swap on the chain you point wagmi at. Nothing else in your components needs to change to benefit from faster confirmations.

Colorful programming code on a computer screen, the kind of debugging session anyone who wants to build a Base app should expect. Photo by Nemuel Sereti on Pexels.
Colorful programming code on a computer screen, the kind of debugging session anyone who wants to build a Base app should expect. Photo by Nemuel Sereti on Pexels.

Building a Base app today means fewer moving parts than the mini-app era, not more. One wallet stack, one auth pattern, one registration step. Check the Builders section for what other teams are shipping on this stack, or browse the Guides hub for the next piece: wiring up gasless transactions with a paymaster.

#base#wagmi#minikit-migration

Comments

0/2000