Static Site Performance: How to Make Your Site Load Instantly
Static sites start with a significant performance advantage — pre-built HTML served from a CDN is inherently faster than dynamically rendered pages. But "faster by default" doesn't mean "as fast as possible." There are concrete optimizations that separate a good static site from an exceptional one. Here's how to close that gap.
Understand Your Baseline
Before optimizing, measure. The three metrics that matter most for real-world performance are Google's Core Web Vitals:
- Largest Contentful Paint (LCP) — how long until the main content is visible. Target under 2.5 seconds.
- Cumulative Layout Shift (CLS) — how much the page jumps around as it loads. Target under 0.1.
- Interaction to Next Paint (INP) — how responsive the page is to user input. Target under 200ms.
Run your site through [PageSpeed Insights](https://pagespeed.web.dev) and [WebPageTest](https://webpagetest.org) before and after each optimization to confirm the impact.
Optimize Images (The Biggest Win)
Images are typically the largest assets on any page and the most impactful to optimize.
Use modern formats. WebP and AVIF offer 25–50% smaller file sizes than JPEG and PNG at equivalent quality. Most modern static site generators handle format conversion automatically:
- Next.js: built-in
component - Astro:
component from@astrojs/image - Hugo:
resources.Processwithwebpformat
Size images correctly. Never serve a 2400px image to display at 400px. Use responsive images with srcset to serve different sizes to different viewports.
Lazy load below-the-fold images. Add loading="lazy" to any image that isn't in the initial viewport. This defers fetching until the user scrolls near it.
Set explicit width and height on all tags to prevent layout shift (CLS).
Minimize JavaScript
Excess JavaScript is the primary cause of slow interactive sites. The browser must download, parse, and execute JS before the page responds to input.
Audit your bundle. Use tools like webpack-bundle-analyzer or Rollup's visualizer to see exactly what's in your JS bundle and where the weight comes from.
Remove unused code. Tree-shaking eliminates unused exports, but only if you import specifically (import { Button } from 'ui-lib') rather than wholesale (import * from 'ui-lib').
Code-split aggressively. Load JavaScript only for the features the current page needs. Next.js does this automatically per-page; Astro ships no JS by default and hydrates islands on demand.
Defer non-critical scripts. Third-party scripts for analytics, chat widgets, and A/B testing often load synchronously. Add defer or async attributes, and consider loading them after the initial page interaction.
Leverage CDN Caching Correctly
Static sites are uniquely well-suited to aggressive CDN caching, but the cache headers must be correct.
Long-lived cache for hashed assets. CSS and JS files with content hashes in their names (e.g., app.a3f2c1.js) should have Cache-Control: public, max-age=31536000, immutable. The content hash guarantees the URL changes when content changes, so it's safe to cache forever.
Short or no cache for HTML. HTML files reference hashed assets, so they must be fresh. Use Cache-Control: public, max-age=0, must-revalidate for HTML, ensuring browsers always get the latest routing information.
Preconnect to third-party origins. Add for external resources like fonts, analytics, and API domains. This establishes the TCP and TLS connection early, reducing latency when those resources are needed.
Optimize Web Fonts
Web fonts are a common source of invisible-text flash and layout shift.
- Use
font-display: swapin your@font-facedeclarations so text is visible in a fallback font while the custom font loads. - Subset fonts to include only the characters your site uses (reduces file size by 60–80% for Latin-only sites).
- Self-host fonts rather than loading from Google Fonts to avoid cross-origin round-trips.
- Use
preloadfor your primary font file:.
Eliminate Render-Blocking Resources
Anything in that blocks rendering delays LCP. Audit your HTML head:
- Move non-critical CSS to load asynchronously or inline the critical CSS.
- Remove or defer any synchronous
tags in the head. - Use the
mediaattribute on stylesheets (e.g.,media="print") to load non-critical CSS without blocking rendering.
Enable Brotli Compression
Brotli compresses text assets (HTML, CSS, JS) 15–30% smaller than gzip. PandaStack handles compression at the CDN layer automatically, but confirm your static host is serving Brotli by checking the Content-Encoding: br response header.
Performance on PandaStack
Static sites deployed on PandaStack benefit from CDN delivery out of the box. Configure your build in pandastack.json with your buildCommand and outputDir, connect your GitHub repository, and PandaStack handles deployment and distribution on every push. Your optimization work in code translates directly to real-world performance improvements for your users.
Start measuring, optimize systematically, and deploy at [dashboard.pandastack.io](https://dashboard.pandastack.io).