TUTORIAL
Building a Next.js Dashboard with Charts (Complete Guide)
Learn how to build a production-ready analytics dashboard in Next.js 14 with real-time charts, KPI cards, and responsive layouts.
UIChart.com·May 28, 2025·10 min read
What We're Building
A complete analytics dashboard with KPI metric cards, a weekly visitors area chart, a top sources bar chart, and a device breakdown donut chart. This is the kind of dashboard you'd ship to a real client.
Project Setup
npx create-next-app@latest my-dashboard --typescript --tailwind --app
cd my-dashboard
npm install recharts
Step 1: Create the Data Layer
In a real app this would come from an API. For now we'll use static data:
// lib/data.ts
export const kpiData = [
{ label: 'Total Revenue', value: '$48,291', change: '+12.4%', up: true },
{ label: 'Active Users', value: '24,891', change: '+8.1%', up: true },
{ label: 'Bounce Rate', value: '38.2%', change: '-3.2%', up: false },
{ label: 'Avg Session', value: '4m 12s', change: '+0.8%', up: true },
];
export const weeklyData = [
{ day: 'Mon', visitors: 1200 },
{ day: 'Tue', visitors: 1900 },
{ day: 'Wed', visitors: 1500 },
{ day: 'Thu', visitors: 2800 },
{ day: 'Fri', visitors: 2400 },
{ day: 'Sat', visitors: 3100 },
{ day: 'Sun', visitors: 2700 },
];
Step 2: KPI Cards Component
'use client';
import { kpiData } from '@/lib/data';
export default function KPICards() {
return (
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4">
{kpiData.map((kpi) => (
<div key={kpi.label} className="bg-gray-900 border border-gray-800 rounded-xl p-5">
<p className="text-sm text-gray-500 mb-2">{kpi.label}</p>
<p className="text-2xl font-bold mb-1">{kpi.value}</p>
<p className={kpi.up ? 'text-green-400 text-sm' : 'text-red-400 text-sm'}>
{kpi.up ? '↑' : '↓'} {kpi.change}
</p>
</div>
))}
</div>
);
}
Step 3: Weekly Visitors Chart
'use client';
import { AreaChart, Area, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts';
import { weeklyData } from '@/lib/data';
export default function VisitorsChart() {
return (
<div className="bg-gray-900 border border-gray-800 rounded-xl p-5">
<h3 className="font-semibold mb-4">Weekly Visitors</h3>
<ResponsiveContainer width="100%" height={240}>
<AreaChart data={weeklyData}>
<defs>
<linearGradient id="visitors" x1="0" y1="0" x2="0" y2="1">
<stop offset="5%" stopColor="#00e5a0" stopOpacity={0.3} />
<stop offset="95%" stopColor="#00e5a0" stopOpacity={0} />
</linearGradient>
</defs>
<CartesianGrid strokeDasharray="3 3" stroke="#1e2328" />
<XAxis dataKey="day" stroke="#5c6370" />
<YAxis stroke="#5c6370" />
<Tooltip />
<Area dataKey="visitors" stroke="#00e5a0" fill="url(#visitors)" strokeWidth={2} />
</AreaChart>
</ResponsiveContainer>
</div>
);
}
Step 4: Assemble the Dashboard Page
// app/dashboard/page.tsx
import KPICards from '@/components/KPICards';
import VisitorsChart from '@/components/VisitorsChart';
export default function DashboardPage() {
return (
<div className="max-w-7xl mx-auto p-6 space-y-6">
<h1 className="text-2xl font-bold">Analytics Overview</h1>
<KPICards />
<VisitorsChart />
</div>
);
}
Step 5: Add Real Data with Server Components
Next.js 14 makes it easy to fetch data on the server and pass it to client chart components:
// app/dashboard/page.tsx (Server Component)
async function getDashboardData() {
const res = await fetch('https://your-api.com/analytics', {
next: { revalidate: 60 } // revalidate every 60s
});
return res.json();
}
export default async function DashboardPage() {
const data = await getDashboardData();
return <VisitorsChart data={data.weekly} />;
}
Performance Tips
- Always add
'use client'to chart components — Recharts uses browser APIs - Use
dynamic()imports withssr: falsefor charts in SSR pages to avoid hydration issues - Set
isAnimationActive={false}on charts that update frequently (real-time data) - Wrap charts in
Suspenseboundaries with skeleton loaders for better UX
#nextjs#dashboard#tutorial#recharts#analytics