← rupesh singh

How I reduced latency of fundizr?

When I first launched Fundizr, I focused heavily on shipping features fast.

The product worked. But the performance wasn’t great.

Some pages took 2–4 seconds to fully load. Certain database queries alone were taking 800ms–2s. The frontend was making unnecessary sequential requests. Images were slowing down rendering. APIs were waiting on each other.

Over time, I started treating performance as a feature.

This blog is about the real optimizations I made in production using:

  • Next.js
  • Supabase (Postgres)
  • MongoDB
  • FastAPI
  • Docker
  • AI APIs
  • CDN caching
  • Browser caching
  • PgBouncer

and how those changes significantly reduced latency across Fundizr.


Understanding Where Latency Comes From

A user opening your website is not just “one request”.

A typical request flow looks like this:

Browser
   ↓
Next.js frontend
   ↓
Backend API
   ↓
Database
   ↓
Response returns back through the same chain

Every layer adds latency:

  • DNS lookup
  • TLS handshake
  • CDN routing
  • API execution
  • Database query
  • Serialization
  • Network travel time
  • Browser rendering

When multiple slow operations happen sequentially, latency compounds very fast.


Problem 1: Cold Prisma/Postgres Connections

One of my queries (InvestorHighlights) was taking:

~800ms – 2s

The issue wasn’t only the SQL query itself.

A large part of the delay came from:

  • establishing fresh DB connections
  • Prisma connection overhead
  • connection exhaustion during spikes

The Fix: PgBouncer

I introduced PgBouncer for connection pooling.

Why it helped

A single PostgreSQL connection can consume roughly:

10MB–15MB RAM

Without pooling:

  • many requests create many connections
  • database memory usage increases
  • connection setup becomes expensive

PgBouncer uses asynchronous I/O and efficiently manages thousands of lightweight pooled connections.

Instead of:

Request → New DB Connection → Query

It became:

Request → Reuse Existing Connection → Query

This significantly reduced query startup latency.


Problem 2: Sequential API Calls

Initially, multiple queries in page.tsx were running sequentially.

Something like:

await fetchA()
await fetchB()
await fetchC()

This compounds latency:

A waits → then B waits → then C waits

If each request takes 400ms:

400 + 400 + 400 = 1200ms

The Fix: Promise.all()

I parallelized independent requests using:

await Promise.all([
  fetchA(),
  fetchB(),
  fetchC()
])

Now the total latency became approximately:

max(A, B, C)

instead of the sum of all requests.

This alone reduced page loading time dramatically.


Problem 3: Calling getServerSession() Multiple Times

I noticed that multiple components were independently calling:

getServerSession()

Each call introduced extra overhead:

~100–300ms

especially when repeated across components.

The Fix

Instead of calling it repeatedly:

  • fetch session once
  • pass it as props/context

Before:

Component A → getServerSession()
Component B → getServerSession()
Component C → getServerSession()

After:

Page → getServerSession()
      ↓
Pass session everywhere

This reduced redundant authentication work.


Problem 4: Large Image Payloads

Images were another hidden bottleneck.

Some issues included:

  • oversized payloads
  • remote avatar loading
  • unnecessary optimization overhead
  • blocking rendering

I was also using:

i.pravatar.cc

for avatars, which introduced additional external network requests.

Optimizations I Made

Lazy Loading

Images below the fold now load only when needed.

This reduced:

  • initial payload size
  • render blocking
  • bandwidth usage

Using CDN Delivery

Instead of serving everything directly from origin servers:

  • static assets moved behind CDN caching
  • users fetch content from nearby edge locations

This reduced travel distance and improved Time To First Byte (TTFB).


Disabling Unnecessary Optimization

In Next.js:

images: {
  unoptimized: true
}

In some cases, built-in optimization overhead was actually increasing latency for already optimized assets.

Turning it off selectively improved performance.


Problem 5: Heavy Client-Side JavaScript

I was using:

framer-motion

in hero sections and animations.

The issue:

  • entire animation libraries were loading client-side
  • extra JS bundle size
  • slower hydration

One section alone was adding roughly:

~40KB JS

What I Changed

  • reduced unnecessary animations
  • avoided loading motion components everywhere
  • minimized client components
  • moved more logic server-side

This improved:

  • hydration speed
  • interactivity
  • Lighthouse scores

Understanding Network Travel Time

One important thing developers underestimate:

Physical distance matters

Example:

Frontend (Vercel)
    ↓
Backend API
    ↓
Database

If these services are deployed in different regions:

  • every hop adds latency
  • TCP handshakes increase
  • SSL negotiations repeat

Even:

100ms + 100ms + 100ms

quickly becomes noticeable.

What I Learned

Keeping infrastructure geographically closer matters a lot.

Especially for:

  • AI inference APIs
  • database-heavy apps
  • SSR applications

Browser Cache: One of the Most Powerful Optimizations

A browser cache can eliminate entire network requests.

Instead of:

Browser → Request CSS → Server responds

the browser simply uses local cached files.

This makes repeat visits feel instant.

What I Cached

  • images
  • JS bundles
  • fonts
  • static assets

Using proper cache headers dramatically reduced repeat-load latency.


CDN Caching

CDNs store copies of your content across global edge servers.

Without CDN:

User → India → US Server

With CDN:

User → Nearby Edge Node

This reduces:

  • latency
  • origin server load
  • bandwidth costs

For globally distributed users, this matters a lot.


AI APIs Were Another Bottleneck

Fundizr also uses AI services running through:

  • FastAPI
  • Docker containers
  • model inference pipelines

AI requests are inherently slower than normal APIs because:

  • models load into memory
  • inference takes compute time
  • larger payloads travel over the network

Some optimizations I applied:

  • keeping models warm
  • avoiding repeated initialization
  • caching repeated responses
  • minimizing payload size
  • reducing unnecessary serialization

Biggest Lesson: Latency Compounds

The biggest realization I had:

Small delays stack together

Example:

Operation Latency
DB query 400ms
Session fetch 200ms
Image load 300ms
Sequential API 500ms
JS hydration 400ms

Total:

1.8s+

Users feel the total experience — not individual components.


Final Results

After multiple optimizations:

  • lower TTFB
  • faster page rendering
  • reduced server load
  • improved scalability
  • better Lighthouse scores
  • smoother UX

Most importantly:

the app felt faster.

And users notice that immediately.


Performance Is a Product Feature

A fast application feels:

  • more reliable
  • more premium
  • more trustworthy

Especially in startups, developers often prioritize shipping features first.

But once usage grows, latency becomes very visible.

For me, optimizing Fundizr taught an important lesson:

Performance engineering is not premature optimization when users are waiting seconds for pages to load.

It’s part of building a great product.