Best Boilerplates for Analytics Dashboards in 2026
·StarterPick Team
analyticsdashboardchartsboilerplate2026
Analytics Dashboards: Data First, UI Second
The challenge with analytics dashboards isn't the charts — it's the data pipeline. Querying time-series data at scale, aggregating events, and responding in <500ms requires different database patterns than typical CRUD apps.
Quick Comparison
| Stack | Price | Charts | Time-Series DB | Real-time | Best For |
|---|---|---|---|---|---|
| Tremor + Next.js | Free | ✅ Excellent | PostgreSQL/ClickHouse | ✅ Pusher | SaaS analytics dashboards |
| Grafana | Free (self-host) | ✅ | Multiple | ✅ | Infrastructure/DevOps metrics |
| PostHog | Free-$450/mo | ✅ | ClickHouse | ✅ | Product analytics platform |
| Metabase | Free (self-host) | ✅ | Multiple | ❌ | SQL-query BI dashboards |
Tremor — Best React Dashboard Components
Price: Free | Creator: Tremor team
Tailwind CSS dashboard components for Next.js. Area charts, bar charts, line charts, donut charts, metrics cards, tables, and sparklines — all designed for analytics dashboards.
import { AreaChart, Card, Metric, Text, Title } from "@tremor/react";
const data = [
{ date: "Jan 2026", Revenue: 4200, Users: 340 },
{ date: "Feb 2026", Revenue: 5100, Users: 425 },
{ date: "Mar 2026", Revenue: 6800, Users: 580 },
];
export function RevenueChart() {
return (
<Card>
<Title>Monthly Revenue</Title>
<AreaChart
className="h-72 mt-4"
data={data}
index="date"
categories={["Revenue", "Users"]}
colors={["indigo", "cyan"]}
valueFormatter={(v) => `$${v.toLocaleString()}`}
/>
</Card>
);
}
Database Patterns for Analytics
Standard PostgreSQL struggles with analytics queries on large datasets. Solutions:
TimescaleDB (PostgreSQL Extension)
-- TimescaleDB hypertable for time-series data
CREATE TABLE events (
time TIMESTAMPTZ NOT NULL,
user_id UUID,
event_type TEXT,
properties JSONB
);
SELECT create_hypertable('events', 'time'); -- Partitions by time automatically
-- Efficient time-bucketed aggregation
SELECT
time_bucket('1 day', time) AS day,
event_type,
COUNT(*) AS event_count
FROM events
WHERE time > NOW() - INTERVAL '30 days'
GROUP BY 1, 2
ORDER BY 1;
ClickHouse (Columnar Database)
-- ClickHouse for billions of events
CREATE TABLE events (
timestamp DateTime,
user_id UInt64,
event_type String,
properties String -- JSON
) ENGINE = MergeTree()
PARTITION BY toYYYYMM(timestamp)
ORDER BY (event_type, timestamp);
-- 10 billion row query in <1 second
SELECT
toDate(timestamp) AS date,
event_type,
uniq(user_id) AS unique_users,
count() AS total_events
FROM events
WHERE timestamp BETWEEN '2026-01-01' AND '2026-03-08'
GROUP BY 1, 2
ORDER BY 1;
Building a SaaS Metrics Dashboard
The standard metrics every SaaS needs:
// tRPC: SaaS metrics queries
const metricsRouter = router({
mrr: protectedProcedure.query(async ({ ctx }) => {
const activeSubscriptions = await stripe.subscriptions.list({
status: 'active',
limit: 100,
});
const mrr = activeSubscriptions.data.reduce((sum, sub) =>
sum + sub.items.data.reduce((s, item) =>
s + (item.price.unit_amount! * item.quantity! / 100) *
(item.price.recurring!.interval === 'year' ? 1/12 : 1)
, 0)
, 0);
return { mrr, currency: 'usd' };
}),
newUsers: protectedProcedure
.input(z.object({ days: z.number().default(30) }))
.query(async ({ input }) => {
return db.user.groupBy({
by: ['createdAt'],
where: { createdAt: { gte: subDays(new Date(), input.days) } },
_count: true,
});
}),
});
Compare analytics dashboard and SaaS boilerplates on StarterPick.
Check out this boilerplate
View Tremor + Next.js on StarterPick →