A seafood restaurant on the Karaburun peninsula opened a ticket mid-season: "the menu won't load, customers walk out." Vodafone 4G measured 1.4 Mbps RTT 380 ms, and Lighthouse showed an LCP of 9.2 seconds. The target was concrete: LCP under 1 second, with the waiter-call button tappable within 1.5 s.
Edge Stack: Workers + HTTP/3 + Brotli 11
Layer one — serve rendered HTML straight from Cloudflare Workers KV cache instead of round-tripping to Next.js SSR. We hit 38 ms TTFB at the edge. HTTP/3 (QUIC) survives 4G packet loss without re-handshaking: H/2 took 1.6 s to negotiate; H/3 finishes in 240 ms.
Precompressed assets at Brotli level 11: HTML 22 KB → 6 KB, CSS 41 KB → 9 KB. Brotli ships 34% fewer bytes than gzip on average. Cloudflare Pages enables it, but verify origin responses carry content-encoding: br.
Image Pipeline: AVIF + Lazy + LQIP
Product photography was 72% of total weight. We resize via Cloudflare Image Resizing into three breakpoints — 96px, 320px, 640px — and negotiate AVIF first, WebP second, JPEG fallback. A 320 px AVIF averages 14 KB, one-sixth of the original 89 KB JPEG.
- Above-the-fold (first six items): eager, fetchpriority="high"
- Below-the-fold: IntersectionObserver with 200 px rootMargin
- LQIP: 8×8 base64 blurhash placeholder, under 60 bytes
Font Subsetting and Critical CSS
Inter Variable weighed 312 KB. With glyphhanger we subset to Turkish ranges (U+0100-017F, U+011E, U+0130) producing a 28 KB WOFF2. Combined with font-display: optional, if the font misses the 100 ms budget the system fallback stays — no FOIT, no shift.
The ~4 KB of CSS needed above the fold is inlined in <head>; the rest loads async via the media="print" onload trick. Render-blocking requests dropped from seven to one, and final LCP measured 0.78 s on the same Vodafone 4G connection.
FAQ
What Cache-Control headers should I use? HTML: s-maxage=300, stale-while-revalidate=86400. Hashed assets: public, max-age=31536000, immutable.
Is a Service Worker worth it? Yes for menus. Second-visit open averages 180 ms. Use App Shell + Workbox stale-while-revalidate.
What about 2G fallback? Honor Save-Data: ship 96 px images only, emoji placeholders instead of icons, system-ui fonts. Even on 2G we measured 2.4 s LCP.
Found this helpful? Share it.
Related articles
The Complete Guide to Running a Multilingual Restaurant Menu
Serving international guests? Learn how to set up a menu that automatically spea…
What Is a QR Code Menu? The Complete Guide for Restaurants
A QR code menu lets customers access your full restaurant menu instantly on thei…
Understanding Your Restaurant's Data: A Practical Analytics Guide
Your menu generates data every day. Learn how to read it, act on it, and use it …