Skip to content
lazy devs
5 min readLazy Devs

How to build a customer-facing dashboard

What it really takes to ship a customer-facing dashboard people trust: scope, the hard parts, our stack, rough costs, and the mistakes that get expensive.

Every product eventually grows a dashboard. It is the screen your customer opens first, the one they judge your whole product by in about four seconds. Build it well and it quietly answers questions before anyone has to email you. Build it badly and it becomes a wall of charts nobody reads.

What it is and who it is for

A customer-facing dashboard is the logged-in home screen where your users see their own data: usage, spend, performance, orders, whatever your product produces on their behalf. It is not an internal admin tool and it is not a marketing chart. It is the place a paying customer goes to answer one recurring question without talking to you.

That is the core job, worth saying out loud: a dashboard exists to answer "how am I doing?" at a glance. For a billing product that is "what will I owe this month?" For an analytics product it is "did the thing I shipped move the number?" If your dashboard does not answer that question in the first viewport, before any scrolling or clicking, it has failed its one job no matter how many widgets it has.

The audience is founders who already have data worth showing and now need to show it well. If you are still figuring out the product itself, that is MVP territory and a dashboard is premature.

The MVP feature set

Build first:

  • One summary view with three to five numbers that matter, above the fold, no scrolling.
  • A date-range filter (last 7 days, 30 days, custom). This is table stakes and people forget it.
  • Two or three supporting charts that explain the headline numbers, not decorate them.
  • A data table with sorting and pagination for the underlying records.
  • Empty states and loading states that look intentional, not broken.

Build later:

  • Saved views, custom date comparisons, and per-user dashboard layouts.
  • CSV and PDF export (everyone asks; almost nobody uses it weekly).
  • Drill-downs from a chart into the raw rows behind it.
  • Alerts and digests ("email me when spend crosses X").
  • Multi-account or team switching, if you sell to companies rather than individuals.

The trap is shipping twelve widgets in v1 because each one felt cheap to add. Five widgets people read beat twenty they ignore. Pick the headline numbers by reading your support inbox: whatever customers keep asking about is what your dashboard should lead with.

The hard parts most people underestimate

Aggregations get slow before you notice. The first demo with 200 rows is instant. The first real customer with two million rows times out. Computing SUM over a live table on every page load is the most common reason a dashboard feels slow. You almost always want pre-aggregated rollups. A daily summary table you build incrementally turns a ten-second scan into a five-millisecond lookup:

-- Rollup table: one row per customer per day, updated by a nightly job
-- (or incrementally on write). The dashboard reads this, never raw events.
CREATE TABLE usage_daily (
  customer_id   bigint      NOT NULL,
  day           date        NOT NULL,
  requests      bigint      NOT NULL DEFAULT 0,
  errors        bigint      NOT NULL DEFAULT 0,
  cost_cents    bigint      NOT NULL DEFAULT 0,
  PRIMARY KEY (customer_id, day)
);
 
-- The dashboard's headline query now scans days, not millions of events.
SELECT
  date_trunc('week', day) AS week,
  SUM(requests)           AS requests,
  SUM(cost_cents) / 100.0 AS cost
FROM usage_daily
WHERE customer_id = $1
  AND day >= $2 AND day < $3
GROUP BY 1
ORDER BY 1;

Time zones and date boundaries. "Today" for a customer in Sydney is not "today" in your UTC database clock. Decide early whether ranges are computed in the user's time zone or yours, because a dashboard whose totals do not match the customer's own spreadsheet loses trust instantly.

Permissions and data isolation. Every query has to be scoped to the logged-in customer, every time. One missing WHERE customer_id = $1 and someone sees another company's revenue. This is the bug that ends contracts, and it belongs in your data layer, which is core API and backend engineering work, not a frontend afterthought.

Perceived performance. Even fast dashboards feel slow if every number lands at once after a blank screen. Stream the layout first, then fill each card as its data arrives.

The stack we would reach for

Nothing exotic, on purpose. We build dashboards on Next.js with the App Router so the shell renders on the server and individual cards stream in as their data resolves. That streaming model is the single biggest lever on how fast a dashboard feels.

Data lives in Postgres, with rollup tables for anything aggregated and proper indexes on the columns you filter and group by. Postgres comfortably runs dashboards into the tens of millions of rows before you need anything fancier; if you genuinely outgrow it, a columnar store like ClickHouse is the next step, but most products never get there.

For the UI, TypeScript end to end so the shape of your data is checked from the query to the chart, a component library like shadcn for the table and controls, and a focused charting library (Recharts or visx) rather than a heavyweight BI embed. Auth comes from a hosted provider (Clerk or Auth0) so you are not writing session handling yourself. The whole thing is squarely web app development: a normal stack, applied carefully.

We deliberately avoid embedding a third-party BI tool (Metabase, Looker) into a customer-facing product. They are great internally, but they look like someone else's software bolted onto yours, and they fight you the moment you want your own branding or layout.

Rough timeline and cost

These are ranges, not quotes, and they assume the data already exists somewhere clean.

  • A focused v1 (auth, one summary view, date filter, two or three charts, one data table): roughly 4 to 7 weeks.
  • A production dashboard (rollups, exports, drill-downs, saved views, team accounts): roughly 8 to 14 weeks.

In agency terms that lands somewhere in the low tens of thousands for a solid v1 and grows with scope. The biggest swing factor is rarely the UI. It is the state of your data. Clean source data can halve the timeline; messy data spread across three systems can double it. Get the data honest before you budget the pixels.

What to watch out for

  • Aggregating on read at scale. Charming in the demo, a support fire at 50 customers. Build rollups before you launch, not after the complaints.
  • Vanity metrics. A number nobody can act on is clutter. Every headline figure should change a decision the customer might make.
  • No empty and loading states. New accounts have no data. If your dashboard looks broken on day one, you lose the customer on day one.
  • Cross-tenant leaks. The most expensive bug in this whole category. Scope every query, and test it with two accounts that should never see each other.
  • Refresh ambiguity. Customers want to know if a number is live or from last night. Put a "last updated" timestamp on it and stop the "is this real-time?" emails.
  • Designing for the demo, not the night shift. Build for the impatient user checking on their phone at 11pm, not the patient one in a polished sales walkthrough.

Takeaway

A great customer-facing dashboard is not a pile of charts. It is one screen that answers one question fast, backed by aggregation that stays quick as you grow, with data isolation tight enough to trust. Get those three right and the rest is polish. This is exactly the kind of thing we build, and we are happy to look at your data and tell you honestly what your v1 should be. Come talk to us.

Related service

Web App Development

Production React and Next.js apps, built to last.

Learn more

Want this built right?

This is the work we do every day. Tell us what you are building and we will show you exactly how we would ship it.

hello@lazydevsagency.com