Last year, I set out to see how much I could improve my site’s performance without relying on commercial performance plugins. Almost everything I’ve implemented has been completely free. The only exception is an image resizing service I host on DigitalOcean for $5/month—though I suspect the results would be similar without it. My goal was to make these optimizations accessible to anyone.
Without compromising functionality, I’ve achieved a 97 on the Lighthouse performance score. Here’s how you can do it too.

Measuring Performance with WebPageTest and Lighthouse
Before making optimizations, it’s important to measure where your site stands. Two of the best tools for this are WebPageTest and Lighthouse.
WebPageTest
WebPageTest provides a detailed breakdown of your site’s performance, including:
- Time to First Byte (TTFB): Measures server response time.
- First Contentful Paint (FCP): When the first piece of content is visible.
- Largest Contentful Paint (LCP): Measures how long it takes for the most important content to load.
- Cumulative Layout Shift (CLS): Tracks visual stability.
- Fully Loaded Time: The time until all page elements are completely loaded.
One of WebPageTest’s most useful features is the waterfall chart, which visually represents the sequence and timing of all network requests made by the browser. This allows you to:
- Identify render-blocking resources slowing down your page.
- Spot slow-loading assets, such as oversized images or unoptimized scripts.
- See parallel vs. sequential loading patterns, helping you determine whether resources are efficiently loaded.

Lighthouse
Lighthouse is built into Chrome DevTools and provides insights into:
- Performance: Page speed, render-blocking resources, and improvements.
- Accessibility: How user-friendly the site is.
- Best Practices: Ensuring up-to-date security and coding standards.
- SEO: Whether your site is optimized for search engines.
To run Lighthouse:
- Open Chrome DevTools (Right-click > Inspect or
Cmd+Option+I
/Ctrl+Shift+I
). - Go to the Lighthouse tab.
- Click Analyze Page Load to generate a report.
Using these tools, you can identify performance bottlenecks, apply the optimizations outlined in this guide, and then retest to measure improvements.
Pick Plugins Carefully
It may seem obvious, but it’s worth emphasizing: Be selective about the plugins you install. I almost left this section out—until I installed a popular contact form plugin and discovered it injected JavaScript and CSS on every single page, even where no forms were used. This kind of bloat slows down your site unnecessarily.
Full Page Cache
Caching HTML at the server level is easy and makes a big impact. I recommend caching HTML in Nginx, but there are many caching plugins available. Additionally, adding a CDN for static assets can further improve performance.
Defer JavaScript and CSS
Since WordPress 6.3, we have had the ability to register scripts with async
or defer
. Still, I don’t see many plugins taking advantage of this. I’ve been using Mark Jaquith’s encute to defer scripts (and styles!)
For reference:
async
: The script is fetched in parallel with the page and executed as soon as it’s ready. Great for progressive enhancement scripts.defer
: The script loads in parallel but executes only after the document has been parsed. Ideal for analytics scripts and non-critical JavaScript.
Lazy Load Images
One of the keys ended up being to lazy load all images after the first post. By default WordPress lazy loads all images except for the first 3. I don’t post that many images. Having an image half way down the page that has fetchpriority=high
was consistently impacting the FCP and LCP. This was probably more important than the image resizing service I mentioned above because it ensures the images are not loaded at all until they’re needed.
Embed Facades
Embedding YouTube videos can have a big impact. Fortunately, Paul Irish’s Lite YouTube Embed replaces the standard embed with a static image and some CSS. When the user clicks the “video” it is replaced with the actual embed. This clever optimization ensures the video is not loaded at all unless you really need it. Similar facades exist for other types of embeds as well.
Inline Critical CSS
Inlining critical CSS ensures above-the-fold content loads quickly. You can use a package like critical in your theme to extract and inline critical styles. You might as well minify your css with something like postcss
and cssnano
while you’re at it. To defer non-critical styles, I’ve added this snippet to my theme:
// Defer non-critical styles
add_filter( 'style_loader_tag', function($html, $handle, $href, $media) {
if ( ! in_array( $handle, ['josh.blog'] ) ) {
return $html;
}
$html = sprintf(
'<link rel="stylesheet" id="%s-css" href="%s" media="print" onload="this.media=\'all\'">',
esc_attr($handle),
esc_url($href)
);
return $html;
}, 10, 4 );
Resource Hints
Resource hints allow browsers to anticipate and optimize how they load resources. The most useful ones for performance are:
preconnect
: Establishes an early connection to an external domain to speed up subsequent requests. Ideal for CDNs and third-party services like Google Fonts.dns-prefetch
: Helps resolve domain names early to reduce latency.prefetch
: Loads low-priority resources in the background for future navigation.prerender
: Fully loads and renders an entire page in the background for seamless navigation.
WordPress has a filter to manage resource hints: wp_resource_hints
. You can use it to add preconnect and dns-prefetch hints dynamically:
function add_resource_hints($hints, $relation_type) {
if ('preconnect' === $relation_type) {
$hints[] = 'https://fonts.googleapis.com';
}
if ('dns-prefetch' === $relation_type) {
$hints[] = 'https://cdnjs.cloudflare.com';
}
return $hints;
}
add_filter('wp_resource_hints', 'add_resource_hints', 10, 2);
Preload Web Fonts
Web fonts can significantly impact performance if not handled correctly. By preloading your primary fonts, you ensure they are available earlier in the page load process, reducing layout shifts and rendering delays.
To preload a web font, use:
<link rel="preload" href="<?php echo get_stylesheet_directory_uri(); ?>/fonts/montserrat-v18-latin-regular.woff2" crossorigin="anonymous" as="font" type="font/woff2">
Best practices for web font optimization:
- Use modern formats: Prefer WOFF2 for smaller file sizes and better compression.
- Subset fonts: Reduce font file size by including only the necessary character sets.
- Load critical fonts first: Preload body and heading fonts, but avoid preloading too many fonts to prevent resource contention.
- Use
font-display: swap
: Allows text to render with a fallback font while the custom font loads.
@font-face {
font-family: 'Montserrat';
src: url('/fonts/montserrat-v18-latin-regular.woff2') format('woff2');
font-display: swap;
}
Preloading and optimizing web fonts properly can help eliminate render-blocking issues and improve perceived performance.
Conclusion
While working on this, I noticed some claims that WordPress is inherently slower than JavaScript frameworks. This shows WordPress can be as fast as anything else.
SwitchUpCB optimized his WordPress score to 100 PageSpeed with less than $10 per month.
https://switchupcb.com/blog/1-second-wordpress-website-page-speed/
I also have 100 on desktop. I should have clarified this is 97 on mobile.