When Vercel Speed Insights Roasted My 'Fast' Website

Today

Performance optimization challenges

"Your website has a 94 Real Experience Score! That's... actually pretty good?"

"But your Time to First Byte is 1.84 seconds and your avatar image is 1.3MB..."

Me, staring at Vercel Speed Insights, realizing my "fast" website was actually serving a small novel as a profile picture.

The Humbling Moment

I thought my portfolio was fast. I mean, it felt fast on my development machine with lightning internet. Then Vercel Speed Insights decided to deliver some tough love:

The Bad News:

The Good News:

So close to greatness, yet so far. Time to go detective mode.


The 1.3MB Avatar Disaster

First stop: investigating what was causing that slow Largest Contentful Paint. I checked my public/ folder and nearly choked on my coffee:

public/
├── me.png (1.3MB) 😱
├── iitm.png (494KB) 
├── ib.png (320KB)
├── srmist.svg (170KB)
└── ... (more oversized logos)

My avatar was 1.3MB. For context, that's larger than some entire websites. No wonder my LCP was struggling!

The Math:


Detective Mode: Finding All the Culprits

Beyond the obvious image size issues, I discovered several performance killers:

1. Animation Overkill

// Running at 40fps constantly, even when not visible
const frame = useCallback(() => {
  const interval = 1000 / 40; // Too aggressive!
  // Complex canvas drawing operations...
}, []);

2. Render-Blocking BlurFade Animations

const BLUR_FADE_DELAY = 0.04; // Delaying content appearance
// Multiple animations stacking delays...

3. No Image Loading Strategy

// All images loading at once, no prioritization
<Image src={project.image} /> // No lazy loading
<AvatarImage src={logoUrl} /> // No lazy loading

4. Missing Optimization Hints


The Performance Surgery

Time to fix everything systematically:

1. Avatar Image Compression (CRITICAL)

Before: 1.3MB PNG monster After: 330KB compressed (75% reduction!)

# Using online tools like TinyPNG
Original: 1.3MB Compressed: 330KB
Load time: ~3.5s ~0.8s (336% faster!)

2. Smart Animation Optimization

// Before: Constant 40fps animation
const frame = useCallback(() => {
  const interval = 1000 / 40;
  // runs constantly...
}, []);
 
// After: Visibility-aware 30fps animation
const frame = useCallback(() => {
  // Skip if not visible - save CPU!
  if (!isVisible.current) return;
  
  const interval = 1000 / 30; // Reduced framerate
  // Still smooth, uses 25% less CPU
}, []);

3. Intersection Observer Magic

// Pause animations when not visible
useEffect(() => {
  const observer = new IntersectionObserver(
    ([entry]) => {
      isVisible.current = entry.isIntersecting;
      if (!entry.isIntersecting) {
        stopped.current = true; // Save battery!
      }
    },
    { threshold: 0.1 }
  );
  
  observer.observe(canvas);
  return () => observer.disconnect();
}, []);

4. Aggressive Image Optimization

// Critical above-the-fold image
<AvatarImage 
  src={DATA.avatarUrl} 
  priority // Load first!
  style={{ objectFit: 'cover' }}
/>
 
// Non-critical images
<Image
  src={image}
  loading="lazy" // Load when needed
  sizes="(max-width: 768px) 100vw, 50vw"
  placeholder="blur" // Smooth transitions
  blurDataURL="data:image/jpeg;base64,..." 
/>

5. Resource Optimization

// In layout.tsx head
<head>
  {/* Preload critical assets */}
  <link rel="preload" href="/me.png" as="image" />
  
  {/* DNS prefetch external services */}
  <link rel="dns-prefetch" href="//vercel.live" />
  <link rel="dns-prefetch" href="//vitals.vercel-insights.com" />
</head>

6. Next.js Config Enhancements

// next.config.mjs
const nextConfig = {
  images: {
    formats: ['image/webp', 'image/avif'], // Modern formats
    deviceSizes: [640, 750, 828, 1080, 1200, 1920],
    imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
  },
  experimental: {
    optimizePackageImports: ['lucide-react', 'react-markdown'],
  },
};

The Results: Speed Demon Unleashed

Performance Improvements:

📊 Performance Metrics Comparison:

Time to First Byte
• Before: 1.84s → After: ~1.0s
46% faster improvement!

🎨 First Contentful Paint
• Before: 2.09s → After: ~1.2s
43% faster improvement!

🖼️ Largest Contentful Paint
• Before: 2.76s → After: ~1.8s
35% faster improvement!

🚀 Avatar Load Time
• Before: ~3.5s → After: ~0.8s
336% faster improvement!

Expected Real Experience Score: 94 → 98+ 📈


Visual Quality: Zero Compromise

The Concerns:

The Reality:


Lessons Learned

1. Images Are Usually the Villain

That 1.3MB avatar was doing more damage than all my JavaScript combined. Always audit your public/ folder first.

2. Perception > Perfection

Users care more about seeing something quickly than perfect animations. Fast First Contentful Paint beats silky 60fps background effects.

3. Mobile-First Performance

Desktop hides performance sins with fast CPUs and connections. Optimize for the slower mobile experience.

4. Measure, Don't Guess

Vercel Speed Insights (and tools like Lighthouse) reveal the truth about real user experience. Use them religiously.

5. Progressive Enhancement

Start with fast, basic functionality. Layer on the fancy animations and effects after core content loads.


Technical Deep Dive: The Optimization Stack

Image Strategy

  1. Compress ruthlessly - Target <50KB for avatars, <20KB for logos
  2. Use modern formats - WebP/AVIF over PNG/JPEG
  3. Implement proper loading - Priority for above-fold, lazy for below
  4. Add placeholders - Blur transitions prevent layout shift

Animation Strategy

  1. Reduce unnecessary work - 30fps vs 40fps, pause when invisible
  2. Use CSS transforms - GPU acceleration for smooth movement
  3. Intersection observers - Only animate what users can see
  4. Debounce aggressively - Especially important for mobile

Bundle Strategy

  1. Dynamic imports - Load heavy components when needed
  2. Package optimization - Tree-shake unused icon/utility imports
  3. Code splitting - Separate routes, separate bundles
  4. Preload hints - Help browser prioritize critical resources

TL;DR


"Fast websites aren't built, they're optimized.
Start with a good foundation, then ruthlessly eliminate every unnecessary byte and millisecond." ⚡💻

Pro tip: Always test your "fast" website on a slow connection with a potato phone. Your MacBook Pro lies to you about performance! 📱🥔