Writing

14 min read

Build High-Performance Web3 Dashboards with Next.js

A practical guide for startup founders and frontend developers on building fast, scalable Web3 dashboards using Next.js, TypeScript, Tailwind CSS, and React Query. Covers architecture, data fetching, performance, and real-world mistakes to avoid.

Next.jsWeb3React QueryDeFi

Why Web3 Dashboards Are Different

Web3 products live or die by their dashboards. A user connecting their wallet for the first time expects to see balances, token values, and recent activity load quickly and reliably.

Unlike traditional SaaS dashboards that query a single owned database, a Web3 dashboard aggregates data from RPC nodes, indexing services, price APIs, and sometimes off-chain databases.

What Makes Web3 Dashboards Complex

  • Multiple RPC requests

  • Blockchain data that can change frequently

  • External price APIs

  • Indexing services

  • Multi-chain data

  • Wallet-specific information

  • Eventually consistent on-chain data

What Makes a Web3 Dashboard Successful

A good dashboard hides this complexity from users. Data should load quickly, remain accurate, and provide clear feedback when information is loading or updating.

What Counts as a Web3 Dashboard?

Web3 dashboards come in several forms depending on the product and the type of blockchain data users need.

DeFi Portfolio Trackers

These dashboards display wallet balances, token values, portfolio allocation, and transaction activity.

Protocol Analytics Dashboards

Protocol dashboards usually show metrics such as:

  • Total Value Locked (TVL)

  • Trading volume

  • Liquidity

  • User activity

  • Protocol performance

NFT Dashboards

NFT dashboards can display collection statistics, ownership data, floor prices, sales activity, and wallet holdings.

DAO Governance Dashboards

DAO dashboards help users monitor proposals, voting activity, treasury balances, and governance participation.

Cross-Chain Asset Managers

These dashboards combine assets and activity from multiple blockchain networks into one interface.

Wallet Connection: Start Here

Wallet connection is usually the entry point for a Web3 dashboard and acts as the primary authentication mechanism.

Recommended Wallet Stack

For modern React and Next.js applications, a common stack includes:

  • wagmi v2

  • viem

  • ConnectKit

  • RainbowKit

  • TanStack Query

These tools can handle wallet detection, chain switching, reconnection, caching, and loading states without requiring everything to be built manually.

Set Up Wagmi and React Query

Wrap the application with WagmiProvider and QueryClientProvider at the layout or provider level.

import { WagmiProvider } from 'wagmi';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ConnectKitProvider } from 'connectkit';
import { config } from '@/lib/wagmi-config';

const queryClient = new QueryClient();

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

Balances and Token Data

Balances are among the first pieces of information users look for after connecting a wallet.

Fetching every token with a separate RPC request can quickly become slow and may increase the risk of hitting rate limits.

Use Multicall for Token Balances

Batch ERC-20 balanceOf calls with multicall through viem or wagmi's useReadContracts.

import { useReadContracts } from 'wagmi';
import { erc20Abi } from 'viem';

export function useTokenBalances(
  address: `0x${string}`,
  tokens: Token[]
) {
  return useReadContracts({
    contracts: tokens.map((token) => ({
      address: token.address,
      abi: erc20Abi,
      functionName: 'balanceOf',
      args: [address],
    })),
    query: {
      staleTime: 30_000,
      refetchInterval: 60_000,
    },
  });
}

Add Token Prices

For fiat values, combine blockchain balance data with price APIs such as CoinGecko or DeFiLlama.

Cache prices and batch requests where possible. This can turn a portfolio containing dozens of tokens into a much smaller number of network requests.

Charts and Analytics

Charts are essential for analytics-heavy Web3 dashboards. They help users understand trends instead of forcing them to interpret raw numbers.

Choose the Right Chart Library

  • Recharts: Good for TVL charts, allocation charts, and comparisons.

  • TradingView Lightweight Charts: Useful for financial and candlestick charts.

  • Tremor: Useful for KPI cards and dashboard-style visualizations.

Prevent Chart Layout Shifts

Give chart containers fixed or predictable heights before the data loads. This prevents the page from jumping when charts are rendered.

import {
  AreaChart,
  Area,
  XAxis,
  YAxis,
  Tooltip,
  ResponsiveContainer,
} from 'recharts';

interface Props {
  data: { date: string; tvl: number }[];
}

export function TVLChart({ data }: Props) {
  return (
    <ResponsiveContainer width="100%" height={320}>
      <AreaChart data={data}>
        <XAxis dataKey="date" />
        <YAxis />
        <Tooltip />
        <Area dataKey="tvl" />
      </AreaChart>
    </ResponsiveContainer>
  );
}

Activity Logs and Transaction History

Transaction feeds require pagination and frequent updates because blockchain activity can change continuously.

Use Blockchain Indexers

Useful options include:

  • The Graph

  • Alchemy Transfers API

  • Ponder

  • Envio

  • Goldsky

Prefer Cursor-Based Pagination

Use cursor-based pagination instead of offset pagination.

Blockchain data can change between requests, which may cause rows to move when offset-based pagination is used.

import { useInfiniteQuery } from '@tanstack/react-query';

export function useTransactionHistory(address: string) {
  return useInfiniteQuery({
    queryKey: ['txHistory', address],
    queryFn: ({ pageParam }) =>
      fetchTransactions(address, pageParam),
    initialPageParam: undefined as string | undefined,
    getNextPageParam: (lastPage) =>
      lastPage.nextCursor,
    staleTime: 20_000,
  });
}

Recommended Tech Stack for Web3 Dashboards

A modern Web3 dashboard can use the following stack:

Frontend Framework

Next.js 14+ with the App Router provides Server Components, route-level caching, and streaming capabilities.

Programming Language

TypeScript helps catch incorrect blockchain data structures and API responses during development.

Styling

Tailwind CSS keeps styling simple and reduces unnecessary CSS overhead.

Server State

TanStack Query v5 handles caching, refetching, loading states, and server-side data.

Blockchain Integration

wagmi v2 + viem provides React hooks and blockchain interaction tools.

Wallet UI

ConnectKit or RainbowKit can provide wallet connection interfaces and multi-wallet support.

Data Visualization

Use Recharts for general dashboard charts and TradingView Lightweight Charts for financial charts.

Blockchain Indexing

Use The Graph, Alchemy, Ponder, Envio, or Goldsky depending on your indexing and latency requirements.

UI Components

shadcn/ui or Radix UI can provide accessible foundational components.

Server Components vs Client Components

The Next.js App Router allows you to separate public data from wallet-dependent interactions.

Use Server Components for Public Data

Public protocol statistics, token lists, price information, and general metrics can often be fetched on the server.

This reduces client-side JavaScript and can improve the initial page experience.

Use Client Components for Wallet Data

Wallet balances, connected addresses, signing actions, and interactive wallet features should remain in client components.

Component Architecture That Scales

A scalable dashboard should separate data fetching, presentation, and wallet logic.

Data Layer

Keep API and blockchain fetching inside:

  • Custom hooks

  • Server-side fetch functions

  • API routes

  • Data access utilities

Components should not directly call RPC endpoints.

Presentation Layer

UI components should receive typed props and focus on rendering the interface.

Wallet Context

Keep wallet-related logic inside a dedicated provider structure so only components that require wallet state depend on wagmi.

Recommended Folder Structure

app/
  dashboard/
    page.tsx

components/
  dashboard/
    WalletSummary.tsx
    TVLChart.tsx
    TokenTable.tsx

hooks/
  useTokenBalances.ts
  useTransactionHistory.ts

lib/
  wagmi-config.ts
  fetchers.ts
  viem-client.ts

Example Dashboard Server Component

import { TokenTable } from '@/components/dashboard/TokenTable';
import { TVLChart } from '@/components/dashboard/TVLChart';
import { fetchProtocolMetrics } from '@/lib/fetchers';

export default async function DashboardPage() {
  const metrics = await fetchProtocolMetrics();

  return (
    <>
      <TVLChart data={metrics.tvl} />
      <TokenTable tokens={metrics.tokens} />
    </>
  );
}

Web3 Dashboard Performance Optimization

Performance should be considered from the beginning rather than added after the dashboard becomes slow.

Batch RPC Requests

Avoid making separate eth_call requests for every token. Use multicall to combine multiple contract reads into fewer RPC requests.

const results = await publicClient.multicall({
  contracts: tokenAddresses.map((address) => ({
    address,
    abi: erc20Abi,
    functionName: 'balanceOf',
    args: [userAddress],
  })),
});

Cache Frequently Requested Data

Configure staleTime, refetchInterval, and gcTime based on how frequently the underlying data changes.

const { data } = useQuery({
  queryKey: ['tvl'],
  queryFn: fetchTVL,
  staleTime: 30_000,
  refetchInterval: 60_000,
  gcTime: 5 * 60_000,
});

Virtualize Large Transaction Lists

For dashboards with hundreds or thousands of transactions, use virtualization so the browser does not render every row at once.

import { useVirtualizer } from '@tanstack/react-virtual';

const rowVirtualizer = useVirtualizer({
  count: transactions.length,
  getScrollElement: () => parentRef.current,
  estimateSize: () => 56,
});

Cache Public API Routes

Public metrics can be cached at the edge to reduce repeated backend requests.

export async function GET() {
  const data = await fetchMetrics();

  return Response.json(data, {
    headers: {
      'Cache-Control':
        's-maxage=60, stale-while-revalidate=300',
    },
  });
}

Common Web3 Dashboard Mistakes

Several technical mistakes can make an otherwise good dashboard slow or unreliable.

Exposing RPC API Keys

Avoid exposing private RPC keys in browser code. Route sensitive requests through your backend or use properly restricted keys.

Fetching Data on Every Render

Without appropriate caching, components can trigger unnecessary requests whenever they mount or re-render.

Ignoring RPC Rate Limits

Public RPC endpoints may not handle production traffic reliably. Use appropriate providers and batching strategies.

Poor Wallet Disconnect Handling

Always handle wallet disconnection and account changes gracefully.

Blocking the Entire Page

One slow data source should not prevent every dashboard section from rendering.

Use Suspense boundaries and skeleton states for independent data regions.

Over-Fetching Transaction History

Do not download an entire transaction history every time a user opens the dashboard. Use pagination and caching.

Ignoring Chain IDs

Validate the connected chain before making contract calls. Otherwise, your application may request data from contracts that do not exist on the selected network.

Treating Loading and Fetching as the Same State

A full loading spinner is useful during the initial request. During background updates, use subtle indicators instead of replacing the entire dashboard.

Web3 Dashboard Pre-Launch Checklist

Before launching, verify that your dashboard:

  • Keeps sensitive RPC keys server-side

  • Uses multicall for multiple contract reads

  • Configures staleTime for different data types

  • Uses Suspense and appropriate skeletons

  • Virtualizes large transaction lists

  • Handles wallet disconnection

  • Caches public API responses

  • Validates chain IDs

  • Works properly on mobile devices

  • Handles wide tables and charts without breaking the layout

FAQ: Building Web3 Dashboards

Which Indexer Should I Use for a Web3 Dashboard?

Start with The Graph for event-based historical blockchain data. Consider Ponder, Envio, or Goldsky when you need custom indexing, advanced aggregations, or lower-latency data.

Should I Use wagmi or ethers.js?

For new React-based Web3 dashboards, wagmi with viem is a strong choice because it integrates well with React applications and TanStack Query.

How Should I Keep Token Prices Fresh?

Batch price requests and cache them for a short period, such as 30–60 seconds, depending on how frequently the application needs updated values.

How Should I Build a Multi-Chain Dashboard?

Pass chainId into data hooks and maintain a chain configuration map containing RPC URLs, explorers, and contract addresses for each supported network.

Does SSR Work for Web3 Dashboards?

Yes. SSR and Server Components are useful for public protocol metrics, token lists, and other non-wallet-specific data. Wallet-specific interactions should remain on the client.

Start Small, Then Scale

Building a Web3 dashboard users trust is primarily a data architecture problem.

Start with the essentials: wallet connection, balances, token data, and transaction history. Then add analytics, charts, multi-chain support, and advanced features as the product grows.

When caching, batching, data boundaries, and component architecture are designed correctly from the beginning, your dashboard can scale without sacrificing speed or user experience.

Get practical Web3 & frontend tips

Short articles on Next.js, Web3 dashboards, and DeFi interfaces. No spam, unsubscribe anytime.

Want help implementing this on your product?

I work with crypto startups and product teams on Web3 dashboards, DeFi interfaces, and Next.js frontends — from architecture through launch. Hire me for defi interface development.