DEV Community

Enes Demirci
Enes Demirci

Posted on

Why Your Next.js Site on Cloudflare Pages Isn't Scoring 100 on PageSpeed

I kept hitting the same three problems deploying Next.js App Router
sites as a static export on Cloudflare Pages across multiple client
projects. None of them throw a loud error — they just quietly cost
PageSpeed points until you know to look for them.

Here's the site scoring 100/100 across the board, verified today:

Image

1. next/image breaks silently in static export

The default Image Optimization API calls a live server endpoint to
resize and re-encode images on demand. output: 'export' produces no
server — Cloudflare Pages serves static files only. The component
doesn't always throw; it can silently serve unoptimized full-size
originals instead.

Fix:

// next.config.js
images: {
  unoptimized: true,
},
Enter fullscreen mode Exit fullscreen mode

You lose automatic resizing, so pre-export images as WebP/AVIF before
they enter the project rather than shipping camera-resolution files.

2. A manual Google Fonts link tag blocks first paint

This pattern is everywhere:

<link href="https://fonts.googleapis.com/css2?family=Inter" rel="stylesheet">
Enter fullscreen mode Exit fullscreen mode

It forces a round trip to a third-party domain before any text can
render. On the mobile connections PageSpeed simulates, that's a direct
hit to Largest Contentful Paint.

Fix — use next/font, which downloads the font at build time and
self-hosts it from your own domain:

import { Inter } from "next/font/google";
const inter = Inter({ subsets: ["latin"], display: "swap" });
Enter fullscreen mode Exit fullscreen mode

Zero runtime request to Google's servers.

3. Cloudflare Pages doesn't cache aggressively by default

You have to declare it yourself in a public/_headers file:

/_next/static/*
  Cache-Control: public, max-age=31536000, immutable
Enter fullscreen mode Exit fullscreen mode

The result

Same site, same content, three small changes — Performance,
Accessibility, Best Practices, and SEO all at 100, desktop and mobile.

I packaged this as a Claude Code/Cursor skill so I don't have to
re-solve it by hand on every new client project — free diagnostic
version is on GitHub, full pack with ready-made
config templates is here.

Happy to answer questions about static export edge cases in the
comments.

Top comments (0)