Nimbus Analytics
(SaaS Dashboard)A multi-tenant analytics dashboard that turns raw product events into answers in under a second.
- −45% load time
- 12k weekly users
- 99.95% uptime
2025 · Next.js · tRPC · PostgreSQL · Redis · AWS
Problem
(what hurt)
Customers exported CSVs every Monday, rebuilt the same charts by hand and still argued about which numbers were right. Queries against the raw events table took 8–14 seconds and timed out on large accounts.
Project goal: Product teams at 300+ companies were drowning in CSV exports. They needed a real-time analytics dashboard that answers everyday questions in under a second, with no data team in the loop.
Architecture
(how it fits together)
Events stream into Postgres through a queue, where hourly materialized views pre-aggregate the heavy metrics. A tRPC API reads from a Redis cache with 60-second TTLs and falls back to the views, so page loads never touch raw events.
Tech decisions: Next.js for SSR and streaming, tRPC for type-safe APIs end to end, and a Redis cache in front of Postgres materialized views to cut response time. Hosted on AWS with per-tenant rate limits.
- Next.js
- tRPC
- PostgreSQL
- Redis
- AWS
export const metricsRouter = router({
overview: protectedProcedure
.input(z.object({ range: z.enum(["7d", "30d", "90d"]) }))
.query(async ({ ctx, input }) => {
const key = "overview:" + ctx.org.id + ":" + input.range;
const cached = await redis.get(key);
if (cached) return JSON.parse(cached);
const data = await db.metrics.aggregate(ctx.org.id, input.range);
await redis.set(key, JSON.stringify(data), "EX", 60);
return data;
}),
});Features
(what it does)
Type-safe from database to chart
One schema drives the database, the API and the React components, so a renamed column breaks the build, not production.
Streaming dashboards
Server Components stream each widget as soon as its query resolves, so the page is useful before it's finished.
Shareable snapshots
Any view can be frozen into a public, read-only link with its own cache key.
Challenges
(what was hard)
01Noisy neighbours
One huge tenant could slow down everyone else. Per-org rate limits and query budgets kept p95 flat during spikes.
02Cache invalidation
Short TTLs plus event-driven cache busting on writes kept data fresh without hammering Postgres.
Results
- −45% load time
- 12k weekly users
- 99.95% uptime
Median dashboard load dropped from 3.1s to 1.7s, tickets about wrong numbers fell by two thirds, and the product now serves 12k weekly users.
design & code by Shreya Pathak