How I optimized page load by 50% for a SaaS dashboard

March 3, 2026

Web optimizations suddenly become important as your product grows. It loads images, videos, tables etc.

What could be the possible ways to optimize a SAAS dashboard? I will completely guide you through the ways of optimization programmatically.


Reducing Assets Sizes

  • Compression: If your web page loads a bunch of images, you would probably need to compress them. Image Optim, FreeConvert are the best tools to compress images.

  • WebP/AVIF formats: We don't use png format for images on the web because webp gives us much smaller file size with similar visual quality. You can use CloudConvert to convert your images into webp file format.

  • Next.js/React: next/image is best for automatic image optimization. Learn more

// next.js example code
// source: https://nextjs.org/docs/app/api-reference/components/image
import Image from 'next/image'

<Image
  src="/profile.webp"
  width={500}
  height={500}
  alt="Picture of the author"
/>

Lazy Loading

It's about loading different parts of UI, sequentially, or even dynamically.

Next.js allows us to use React Lazy and Suspense in a composite way. Which is next/dynamic.

import { Suspense } from "react";
import dynamic from 'next/dynamic'

// loads directly when used 
const ComponentA = dynamic(() => import('../components/A'))

// ssr: false allows us to load the component directly on the client side
const ComponentB = dynamic(() => import('../components/B'), { ssr: false})


// page.js
export default function Page() {
  return (
    { /* using suspense to lazy load on the client side with fallback ui */ }
    <Suspense fallback={<p>Loading...</p>}>
      <div>Component B:</div>
      { /* while ComponentB lazy load itself */ }
      { /* but only when the condition is met */ }
      {someState && <ComponentB />}
    </Suspense>
  );
}

// Above example shows the beset hierarchical way to lazy load entire component

The interesting thing it offers is loading.js. You can wrap your entire route in a custom loading state by adding a new file along the page.js.

Optimize API calls

  1. fetch: For the server components, you should be using fetch as here. Here you can pass options as { cache: "force-cache" | "no-store" } or
  const data = await fetch('https://api.vercel.app/blog')
  const posts = await data.json()

  const API = "https://jsonplaceholder.typicode.com/todos/";

  fetch(API, { cache: "no-cache" }) // it means don't cache anything, fetches resources on every single request

  fetch(API, { cache: "force-cache" }) // it caches the page on the first render 

  fetch(API, { cache: "force-cache", next: { revalidate: 60 } }) // same, but revalidate after the interval
  1. TanStack Query/React: For the client components, you should be using some client side resource fetching library. For example, in tanstack query,
import axios from "axios";
import { useQuery } from "@tanstack/react-query";

const fetchPosts = async () => {
  // use axios for fetching
  const { data } = await axios.get("/api/posts");
  return data;
};

const {
  isPending, // boolean (true|false)
  isError, // boolean (true|false)
  data, // contains the JSON data
  error // instanceof Error
} = useQuery({
  queryKey: ["posts"],
  queryFn: fetchPosts,
  staleTime: 60000, // re-validation
});