Blog / Performance
A WordPress homepage in 22 requests
The short version
- 22 requests, 1.9 MB, 175 ms server response for a full WordPress homepage.
- All 21 sub-requests come from the site’s own domain. Zero third-party calls.
- Two of the 22 should not be there, and I explain which.
Load koredesignbuild.com and your browser makes 22 requests. That is the whole homepage: styles, scripts, fonts, images, everything.
There is no trick. Nothing is being lazy-loaded off-screen to flatter the number, and nothing is hidden behind an interaction. I am going to list all 22, and you will see the interesting part is not what I did. It is what is absent.
22
total requests, 1.9 MB transferred, 175 ms to first byte
What the 22 actually are
| Type | Count | What |
|---|---|---|
| Document | 1 | The HTML itself |
| CSS | 3 | One WordPress core sheet, two theme bundles from Vite |
| JavaScript | 3 | Theme bundle, one core script, one I want gone |
| Fonts | 5 | Montserrat and Poppins weights, self-hosted |
| Images | 10 | Logo, hero, and the project photos above the fold |
Ten of those images are the actual content of the page. A construction company sells with photographs, so I am not going to apologise for the photographs. That leaves twelve requests of infrastructure to run an entire website.
The number that matters more
Every one of the 21 sub-requests comes from koredesignbuild.com. Not one third-party domain. No font CDN, no tag manager loading three more scripts, no chat widget, no cookie banner service, no A/B testing tool blocking the render while it decides which headline you get.
Why this matters more than the count
Each third-party domain costs a DNS lookup, a TCP handshake and a TLS negotiation before it sends a single byte. Three third-party services can cost you more time than your entire first-party payload, and you do not control when any of them get slower.
The fonts are the clearest example. Pulling Montserrat from a font CDN is one line and feels free. It is a separate DNS lookup, a separate connection, and a render-blocking dependency on somebody else’s uptime. Self-hosting them made the site faster and stopped leaking visitor IPs to a third party, which matters more in Canada than people assume.
Two of the 22 should not be there
This is my client’s site and I built it, so I get to be the one who points at the flaws.
Still loading
wp-emoji-release.min.js
WordPress ships an emoji polyfill for browsers that stopped needing it years ago. It runs on every page of most WordPress sites on earth.
Should be
Dequeued in the theme.
Four lines in functions.php. Saves a request and a few kilobytes of parse time on every single page view.
The second one is the fonts. They are self-hosted, which is right, but they are shipping as .ttf rather than .woff2. WOFF2 is typically 30 to 40 percent smaller for identical rendering, and it has been safe to use for years. Five font files means that mistake is repeated five times.
Neither is catastrophic. Both are on the list. I am including them because a performance post where everything went perfectly is a performance post nobody should believe.
How you get to 22, and it is not optimisation
Every time I have seen someone try to fix a slow WordPress site, they reach for a caching plugin. Caching is genuinely useful and it is also the last step, not the first. You cannot cache your way out of loading eleven stylesheets.
The count is low here for one boring reason: the theme is custom, so nothing is loading that the page does not use.
- A multipurpose theme ships CSS and JS for every layout it supports, then you use one of them.
- A page builder loads its own runtime, its icon library and its animation engine before your content appears.
- Each plugin enqueues its assets on every page, whether that page uses the plugin or not.
None of that is present, so there is nothing to strip out. The performance is not a feature I added. It is the absence of things I never installed.
Speed is mostly a subtraction problem that people try to solve by addition.
Check your own in two minutes
Open your homepage, DevTools, Network tab, hard refresh. Then read three things:
- Request count. Under 40 is healthy. Over 80 means something is loading that the page does not use.
- Distinct domains. Every extra one is a connection you do not control. Ask what each is for and who is still using it.
- Anything loading before the first image. That is your render-blocking chain, and it is where the seconds actually go.
You do not need a tool or a subscription. The waterfall tells you everything, and it does not exaggerate.