BUILD A DASHBOARD
Build a full admin dashboard with FABRK in 7 steps. Every code block is copy-paste ready.
[STEP 1 — SCAFFOLD]
Use the FABRK CLI to scaffold a new project with the dashboard template. This gives you a Next.js app pre-wired with all FABRK packages.
npx create-fabrk-app my-dashboard --template dashboard
cd my-dashboard
pnpm installThe dashboard template includes the design system, components, core runtime, and a starter layout. You can also start from scratch with the basic template.
[STEP 2 — CONFIGURE]
Edit fabrk.config.ts at your project root to enable teams, feature flags, and notifications for your dashboard.
import { defineFabrkConfig } from '@fabrk/config'
export default defineFabrkConfig({
app: {
name: 'My Dashboard',
url: 'http://localhost:3000',
},
teams: {
enabled: true,
roles: ['admin', 'editor', 'viewer'],
maxMembers: 25,
},
featureFlags: {
enabled: true,
flags: {
'advanced-analytics': { enabled: false, description: 'Show advanced charts' },
'export-csv': { enabled: true, description: 'Allow CSV export' },
},
},
notifications: {
enabled: true,
channels: ['in-app'],
},
})defineFabrkConfig function provides full type safety and autocomplete.[STEP 3 — LAYOUT]
Create a dashboard layout with sidebar navigation using DashboardShell. The sidebar uses a partial border (border-r) so it does NOT get mode.radius.
'use client'
import { cn } from '@fabrk/core'
import { mode } from '@fabrk/design-system'
import Link from 'next/link'
import { usePathname } from 'next/navigation'
const sidebarItems = [
{ id: 'overview', label: 'OVERVIEW', href: '/dashboard' },
{ id: 'analytics', label: 'ANALYTICS', href: '/dashboard/analytics' },
{ id: 'users', label: 'USERS', href: '/dashboard/users' },
{ id: 'settings', label: 'SETTINGS', href: '/dashboard/settings' },
]
export default function DashboardLayout({
children,
}: {
children: React.ReactNode
}) {
const pathname = usePathname()
return (
<div className="flex min-h-screen">
{/* Sidebar — partial border, NO mode.radius */}
<aside className="w-64 border-r border-border bg-card p-4 shrink-0">
<div className={cn('text-primary font-bold text-lg mb-8', mode.font)}>
{'>'} MY DASHBOARD
</div>
<nav className="space-y-1">
{sidebarItems.map((item) => (
<Link
key={item.id}
href={item.href}
className={cn(
'block px-3 py-2 text-xs transition-colors',
mode.font,
pathname === item.href
? 'text-primary bg-primary/10 border-l-2 border-primary'
: 'text-muted-foreground hover:text-foreground'
)}
>
{item.label}
</Link>
))}
</nav>
</aside>
{/* Main content area */}
<main className="flex-1 overflow-y-auto">{children}</main>
</div>
)
}[STEP 4 — KPI CARDS]
Add KPI cards to show key metrics at the top of your dashboard. Each card shows a title, value, and optional trend indicator.
'use client'
import { KPICard } from '@fabrk/components'
import { cn } from '@fabrk/core'
import { mode } from '@fabrk/design-system'
const stats = [
{ title: 'REVENUE', value: '$48,290', trend: 12.5 },
{ title: 'USERS', value: '3,847', trend: 8.3 },
{ title: 'ORDERS', value: '1,024', trend: -2.1 },
{ title: 'UPTIME', value: '99.97%', trend: 0.1 },
]
export default function DashboardPage() {
return (
<div className="p-6 space-y-6">
{/* Header */}
<div>
<h1 className={cn('text-xl font-bold uppercase', mode.font)}>
OVERVIEW
</h1>
<p className="text-sm text-muted-foreground">
Your dashboard at a glance.
</p>
</div>
{/* KPI row */}
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4">
{stats.map((s) => (
<KPICard
key={s.title}
title={s.title}
value={s.value}
trend={s.trend}
/>
))}
</div>
</div>
)
}[STEP 5 — CHARTS]
Add BarChart and LineChart components for data visualization. Wrap them in a Card with a full border (needs mode.radius).
import { KPICard, Card, BarChart, LineChart } from '@fabrk/components'
const revenueData = [
{ label: 'Mon', value: 6200 },
{ label: 'Tue', value: 7800 },
{ label: 'Wed', value: 5400 },
{ label: 'Thu', value: 8200 },
{ label: 'Fri', value: 9100 },
{ label: 'Sat', value: 4300 },
{ label: 'Sun', value: 3800 },
]
const trendData = [
{ label: 'Week 1', value: 18200 },
{ label: 'Week 2', value: 22400 },
{ label: 'Week 3', value: 19800 },
{ label: 'Week 4', value: 28100 },
]
// Add this inside DashboardPage, below the KPI row:
{/* Charts row */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
<Card className={cn('p-6 border border-border', mode.radius)}>
<h3 className={cn(
'text-xs uppercase text-muted-foreground mb-4',
mode.font
)}>
[WEEKLY REVENUE]
</h3>
<BarChart data={revenueData} />
</Card>
<Card className={cn('p-6 border border-border', mode.radius)}>
<h3 className={cn(
'text-xs uppercase text-muted-foreground mb-4',
mode.font
)}>
[MONTHLY TREND]
</h3>
<LineChart data={trendData} />
</Card>
</div>[STEP 6 — DATA TABLE]
Add a DataTable with sortable columns to display structured data. The table header uses a partial border (border-b), so it does NOT get mode.radius.
import { Card, Badge, DataTable } from '@fabrk/components'
const users = [
{ name: 'Jason', email: 'jason@example.com', role: 'Admin', status: 'Active' },
{ name: 'Sarah', email: 'sarah@example.com', role: 'Editor', status: 'Active' },
{ name: 'Mike', email: 'mike@example.com', role: 'Viewer', status: 'Invited' },
{ name: 'Alex', email: 'alex@example.com', role: 'Editor', status: 'Active' },
]
const columns = [
{ key: 'name', label: 'NAME', sortable: true },
{ key: 'email', label: 'EMAIL', sortable: true },
{ key: 'role', label: 'ROLE' },
{ key: 'status', label: 'STATUS' },
]
// Add this inside DashboardPage, below the charts:
{/* Data table */}
<Card className={cn('border border-border', mode.radius)}>
<div className="p-4 border-b border-border flex items-center justify-between">
<h3 className={cn(
'text-xs uppercase text-muted-foreground',
mode.font
)}>
[RECENT USERS]
</h3>
<Badge variant="secondary">[{users.length} TOTAL]</Badge>
</div>
<DataTable columns={columns} data={users} />
</Card>[STEP 7 — DEPLOY]
Build and deploy your dashboard. The FABRK CLI handles production optimization.
# Build for production
fabrk build
# Deploy to Vercel
vercel
# Or deploy to any Node.js host
fabrk build && node .next/standalone/server.jsSet your environment variables on the hosting platform before deploying.
# Required
DATABASE_URL="postgresql://..."
NEXTAUTH_SECRET="your-secret-here"
NEXTAUTH_URL="https://yourdomain.com"
# Optional (based on config)
STRIPE_SECRET_KEY="sk_live_..."
RESEND_API_KEY="re_..."
ANTHROPIC_API_KEY="sk-ant-..."
S3_BUCKET="your-bucket"
S3_REGION="us-east-1"PRODUCTION CONFIG
Update your fabrk.config.ts for production with security features enabled.
import { defineFabrkConfig } from '@fabrk/config'
export default defineFabrkConfig({
app: {
name: 'My Dashboard',
url: 'https://yourdomain.com',
},
security: {
csrf: true,
csp: true,
rateLimit: true,
auditLog: true,
headers: true,
cors: {
origins: ['https://yourdomain.com'],
},
},
email: {
adapter: 'resend',
from: 'noreply@yourdomain.com',
},
})- Enable CSRF, CSP, and rate limiting in security config
- Switch email from console adapter to Resend
- Set NEXTAUTH_URL to your production domain
- Generate a strong NEXTAUTH_SECRET with
openssl rand -base64 32 - Use PrismaTeamStore and PrismaAuditStore instead of in-memory stores
- Configure connection pooling for serverless databases
[COMPLETE EXAMPLE]
Here is the full dashboard page with all components combined into a single file. Copy this for a complete working dashboard.
'use client'
import { KPICard, Card, Badge, BarChart, LineChart, DataTable } from '@fabrk/components'
import { cn } from '@fabrk/core'
import { mode } from '@fabrk/design-system'
const stats = [
{ title: 'REVENUE', value: '$48,290', trend: 12.5 },
{ title: 'USERS', value: '3,847', trend: 8.3 },
{ title: 'ORDERS', value: '1,024', trend: -2.1 },
{ title: 'UPTIME', value: '99.97%', trend: 0.1 },
]
const revenueData = [
{ label: 'Mon', value: 6200 },
{ label: 'Tue', value: 7800 },
{ label: 'Wed', value: 5400 },
{ label: 'Thu', value: 8200 },
{ label: 'Fri', value: 9100 },
{ label: 'Sat', value: 4300 },
{ label: 'Sun', value: 3800 },
]
const trendData = [
{ label: 'Week 1', value: 18200 },
{ label: 'Week 2', value: 22400 },
{ label: 'Week 3', value: 19800 },
{ label: 'Week 4', value: 28100 },
]
const users = [
{ name: 'Jason', email: 'jason@example.com', role: 'Admin', status: 'Active' },
{ name: 'Sarah', email: 'sarah@example.com', role: 'Editor', status: 'Active' },
{ name: 'Mike', email: 'mike@example.com', role: 'Viewer', status: 'Invited' },
{ name: 'Alex', email: 'alex@example.com', role: 'Editor', status: 'Active' },
]
const columns = [
{ key: 'name', label: 'NAME', sortable: true },
{ key: 'email', label: 'EMAIL', sortable: true },
{ key: 'role', label: 'ROLE' },
{ key: 'status', label: 'STATUS' },
]
export default function DashboardPage() {
return (
<div className="p-6 space-y-6">
<div>
<h1 className={cn('text-xl font-bold uppercase', mode.font)}>OVERVIEW</h1>
<p className="text-sm text-muted-foreground">Your dashboard at a glance.</p>
</div>
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4">
{stats.map((s) => (
<KPICard key={s.title} title={s.title} value={s.value} trend={s.trend} />
))}
</div>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
<Card className={cn('p-6 border border-border', mode.radius)}>
<h3 className={cn('text-xs uppercase text-muted-foreground mb-4', mode.font)}>
[WEEKLY REVENUE]
</h3>
<BarChart data={revenueData} />
</Card>
<Card className={cn('p-6 border border-border', mode.radius)}>
<h3 className={cn('text-xs uppercase text-muted-foreground mb-4', mode.font)}>
[MONTHLY TREND]
</h3>
<LineChart data={trendData} />
</Card>
</div>
<Card className={cn('border border-border', mode.radius)}>
<div className="p-4 border-b border-border flex items-center justify-between">
<h3 className={cn('text-xs uppercase text-muted-foreground', mode.font)}>
[RECENT USERS]
</h3>
<Badge variant="secondary">[4 TOTAL]</Badge>
</div>
<DataTable columns={columns} data={users} />
</Card>
</div>
)
}- Add authentication with the Authentication Guide
- Add payments with the Payments Guide
- Add AI features with the AI Integration Guide
- Customize the theme in your design system config