Writing
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.
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
staleTimefor 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.