All posts
Product design

Web App Performance Checklist: Making Dashboards Fast

A web app performance checklist for dashboards: measure first, fix data fetching, render long lists, trim the bundle and keep interactions fast in React and Next.js.

By Mehdi Hassan7 min read

The short answer

Web app performance for dashboards comes down to four areas: fetch data in parallel and close to the database, render only what's on screen, ship less JavaScript on first load, and keep interactions responsive while data updates. Measure real user sessions first, because most slow dashboards are slow from waterfalls and oversized lists, not from the framework.

Key takeaways

  • Measure with real user data and a profiler before changing code. Guessing wastes the most time.
  • Request waterfalls are the top cause of slow dashboards. Start independent queries together.
  • Virtualize or paginate long tables. Rendering thousands of rows is slow in any framework.
  • Load charts, editors and maps on demand rather than in the first bundle.
  • Show the layout immediately with skeletons and stream each panel in as its data arrives.

Part of Full-Stack Product Engineering for Startups: From Figma to Production

How do you make a web app or dashboard load fast?

You make a web app or dashboard load fast by removing request waterfalls, fetching only the data each view needs, rendering only visible rows, splitting heavy components out of the first bundle and streaming the page so the layout appears immediately. Measure first, then work through the checklist below in order, because the early items usually give the biggest gains.

This checklist is for logged-in apps: dashboards, admin panels and SaaS screens used for hours a day. Marketing sites have different priorities, covered in our Core Web Vitals guide for Framer, Webflow and Next.js. It sits within our hub on full-stack product engineering for startups.

How should you measure web app performance first?

Measure web app performance with three tools: real user monitoring for how fast the app feels to actual customers, the browser's performance profiler for what's slow on a single screen, and server timing for slow queries. Without numbers from real sessions, teams tend to optimize the wrong thing.

  • Real user monitoring: track load time per route and interaction responsiveness, segmented by device and plan size. Big accounts often see a very different app.
  • Interaction to Next Paint: Google's metric for responsiveness, explained on web.dev, is just as relevant inside a dashboard as on a public page.
  • Profiler: the React DevTools profiler shows which components re-render and how long they take.
  • Server and database timing: log query durations and look for slow queries, missing indexes and N+1 patterns.

How do you fix slow data fetching in a dashboard?

Fix slow data fetching by starting independent requests at the same time, asking the server for only the fields and rows a view needs, and moving aggregation into the database. Most slow dashboards wait on a chain of requests where each one starts only after the previous one finishes.

  1. Kill waterfalls: start independent queries together rather than awaiting each in turn. In Next.js server components, kick off queries before awaiting them.
  2. Aggregate in the database: compute totals, counts and groupings with SQL, not by downloading every row to the browser.
  3. Index what you filter and sort by: check the query plan for the slowest queries and add indexes for tenant, date and status columns.
  4. Paginate on the server: send a page of results with a cursor, not the full dataset.
  5. Cache shared, expensive results: precompute heavy reports on a schedule and cache them per tenant.
  6. Use a client cache for live views: a query cache library avoids refetching data the user just saw and lets you show stale data while revalidating.

Your database choice shapes how easy this is. Relational databases make aggregation and indexing straightforward, which is one reason we favor Postgres in Supabase vs Firebase vs custom Postgres.

How do you render long lists and tables quickly in React?

Render long lists quickly by only putting the visible rows in the page. Virtualization libraries render the rows in view plus a small buffer and swap them as the user scrolls. Pagination does the same job with less code. Either way, the browser stops laying out thousands of rows it can't show.

  • Virtualize tables and lists with hundreds of rows or more.
  • Stabilize row components so typing in a filter doesn't re-render every row; memoize where the profiler shows it helps, or let the React Compiler handle it where it's enabled.
  • Debounce search and filters so each keystroke doesn't trigger a new request.
  • Move heavy calculations out of render, into the server, a memoized selector or a web worker.
  • Keep state local: state stored high in the tree re-renders everything beneath it.
Why typing in a dashboard filter can feel laggy

When a user types in a filter box, React updates the input's state. If that state lives in a parent component that also renders a large table and several charts, every keystroke re-renders all of them. The input feels sticky, and your responsiveness metric suffers.

The fixes are layered. Keep the input's own state local, and pass a debounced value to the data query. Mark the expensive update as non-urgent with React's transition API, so typing stays responsive while results catch up. Then virtualize the table so each update touches only visible rows. The profiler will show you which of these matters most on your screen.

How do you reduce JavaScript bundle size in a Next.js web app?

Reduce bundle size by measuring what's in it, loading heavy features on demand and keeping server-only work on the server. In a Next.js app, server components send no component JavaScript to the browser, so moving non-interactive parts there is often the biggest single saving.

  • Analyze the bundle with a bundle analyzer to find the largest dependencies.
  • Lazy-load heavy widgets: charts, rich text editors, maps and PDF viewers should load when they're needed, not on every page.
  • Replace oversized libraries with smaller alternatives or native browser features, such as built-in date formatting.
  • Keep client components small: make the interactive leaf a client component, not the whole page.
  • Use the framework's built-ins for images, fonts and third-party scripts, explained in Next.js performance features.

How do you make a dashboard feel fast while data loads?

Make a dashboard feel fast by showing the layout immediately and filling each panel as its data arrives. Streaming with Suspense boundaries lets the shell render first, with skeletons shaped like the final content, so nothing jumps when data lands. Perceived speed matters as much as measured speed.

  1. Render the shell first

    Navigation, headers and filters should appear instantly, without waiting for any query.

  2. Wrap slow panels separately

    Give each chart or table its own loading boundary so one slow query doesn't hold the page.

  3. Use content-shaped skeletons

    Skeletons that match the final layout prevent jumps and tell users what's coming.

  4. Update optimistically

    For simple actions like toggles and renames, update the UI immediately and roll back on failure.

  5. Prefetch likely next views

    Prefetch the routes and data users usually open next, such as a record's detail page.

Loading states are a design decision as much as an engineering one, covered in our guide to web app UI design. For the underlying data patterns, see building a SaaS app with Next.js.

What's the most common web app performance mistake?

The most common mistake is optimizing before measuring: memoizing components, swapping libraries or rewriting in a new framework, when the real cause is a slow query or a request waterfall. A profiler and a slow-query log usually point to a handful of fixes that matter far more than micro-optimizations.

If your app started as a quick AI-generated prototype, performance problems often come bundled with structural ones; our guide to rescuing a vibe-coded app covers that path.

Frequently asked questions

Is server-side rendering always faster for dashboards?
Not always. Server rendering usually shows the first screen sooner, especially on slow devices, because data and HTML arrive together. A client-rendered dashboard can feel faster on repeat navigation once its code and data are cached. Many good dashboards combine both: server-render the initial view, then handle filters and live updates on the client.
How many rows can a table render before it needs virtualization?
There's no fixed number, because it depends on row complexity and the user's device. Simple rows can go further than rows with avatars, menus and inline editing. Measure with the profiler on a mid-range laptop using realistic data. If scrolling or filtering stutters, virtualize or paginate, and test again with your largest customer's dataset.
Do web apps need to care about Core Web Vitals?
Logged-in pages aren't ranked in search, but the metrics still describe user experience well. Interaction to Next Paint is especially useful for dashboards, because it captures the lag users feel when they click, type or filter. Track it per route in real user monitoring, alongside your own load-time metrics for key screens.
Will the React Compiler fix re-render performance?
It helps. The React Compiler automatically memoizes components and values, which removes many unnecessary re-renders without manual work. It doesn't fix slow data fetching, oversized bundles or rendering thousands of rows at once. Treat it as a useful baseline, then still measure and fix the structural causes of slowness.

· CEO & Design Director

Copywriter, designer and developer, and founder of Designify Studio. Over five years, 60+ projects across 14+ industries, for startups that have raised $300M+.

Want this done for you? Monthly retainer, $6,000.

Your ongoing design and development team, for products that keep shipping. $6,000, per month, flat fee. Book a free 30-minute call to see if it fits.

Schedule Call