
Most of the sites we build and look after are owned by small teams, or by one person. Nobody has a performance engineer or a budget for monitoring services. The site has to load well anyway, because the people visiting it are mostly on a mid-range Android phone, on a mobile connection that is fine one minute and poor the next. That is the ordinary Indian visitor, and it is who we build for.
The good news is that the things which matter most for speed are not the expensive ones. They are a handful of habits, most of them free, that apply equally to Next.js, WordPress, or plain HTML. This is the short list we keep coming back to, in the order we would tackle it.
Start by measuring with what the browser already gives you
Before changing anything, open the site on your own phone over mobile data, not office wifi. Does the text appear quickly? Does the page sit blank? Does the layout jump as things load? That experience is what you are trying to improve, and it is worth feeling it yourself before trusting any number.
Then open the browser's developer tools. Every major browser ships them; there is nothing to install. Three panels do most of the work:
- Network shows every file the page requests, its size, and how long it took. Sort by size. The biggest rows are usually where the problem is.
- Lighthouse (in Chrome) audits the page on a simulated slow connection and names the specific files to fix.
- Performance records a load and shows where the time went, useful once the obvious problems are gone.
Use the throttling option in the Network panel to simulate a slower connection. Do this before buying any tool. Most paid services wrap the same measurements, and the built-in ones are enough for a small site.
Images are usually the biggest problem
On almost every slow site we have opened, the single largest cost is images. Not the number of them, but their size. A photo straight off a camera or a stock site can be several thousand pixels wide, and it gets sent in full to a phone whose screen is a fraction of that.
Resize to the size it is displayed at
If an image sits in a column that is never wider than a few hundred pixels, it does not need to be thousands of pixels wide. Export it at roughly the largest size it will be shown at, allowing for high-density screens, and no larger.
Use a modern format
WebP and AVIF produce far smaller files than JPEG or PNG at the same visual quality, and every current browser supports WebP. If your tooling supports AVIF with a fallback, use it; if not, WebP alone is a large improvement.
Tell the browser the dimensions
Give every image its width and height attributes so the browser can reserve the space before the file arrives. This is what stops the page jumping as images load, and it costs nothing.
<img src="/team.webp" width="800" height="533" alt="The team at the Baleshwar office" loading="lazy" />
loading="lazy" tells the browser not to fetch images below the fold until the visitor scrolls towards them. Use it on everything except the first image or two at the top, which should load immediately.
On Next.js, the built-in image component handles resizing, format conversion and lazy loading for you. On WordPress, the core and a good image plugin do most of it. Either way the habit is the same: never upload a file larger than you need.
Do not ship JavaScript you do not need
A kilobyte of JavaScript costs more than a kilobyte of image, because the phone has to download it, parse it and run it before the page becomes usable. On a low-end phone that step is slow in a way that is invisible on a developer's laptop.
The usual sources of unneeded JavaScript:
- Analytics, chat widgets, heat maps and social embeds, each pulling in its own bundle. Keep the ones you actually read and drop the rest.
- WordPress plugins that load their scripts on every page, even where the feature is not used. Many have a setting to limit this; if not, ask whether you need the plugin.
- Component libraries imported in full when you use two components from them.
- Animation libraries used for a single fade-in that CSS could do.
The Network panel, filtered to JS, shows what you are shipping. Go through the list once. It is common to find a script for a feature removed months ago that nobody noticed. For anything that must stay but is not needed straight away, load it after the page is interactive; most tag managers and widgets have a deferred option.
Fonts: fewer files, and show text while they load
Custom fonts are worth having but easy to overdo. Each weight and style is a separate file, and five weights plus italics is a lot of type to download before any of it appears.
Pick two or three weights and stick to them. Use WOFF2, the smallest format every current browser supports. Host the files yourself, so the browser is not opening a connection to another server before it can draw text.
Most importantly, tell the browser to show text in a fallback font while the custom one loads:
@font-face {
font-family: "Body";
src: url("/fonts/body.woff2") format("woff2");
font-display: swap;
}
font-display: swap means the visitor can start reading immediately. Without it, some browsers hold the text invisible until the font arrives, and on a poor connection that is a long, blank wait.
Caching headers: make the second visit cheap
When a visitor comes back, or moves to a second page, the browser should not download the same logo, stylesheet and fonts again. Whether it does depends on the Cache-Control header your server sends with each file.
The pattern that works for most sites is simple. Files that change rarely and get a new name when they do (a hashed stylesheet, a versioned font) can be cached for a long time. HTML pages, which change without renaming, should be checked with the server on each visit.
Cache-Control: public, max-age=31536000, immutable # hashed static assets
Cache-Control: no-cache # HTML pages
Next.js sets long cache headers on its hashed build output by default. On WordPress, a caching plugin or your host usually handles it, but confirm in the Network panel that a Cache-Control value is actually present on a stylesheet. It is surprisingly often missing.
A content delivery network puts copies of your files on servers closer to the visitor, and several offer a free tier that is enough for a small site. It is worth setting up before you have a measured problem.
Keep the first thing the visitor sees light
Everything above the fold is what the visitor judges the site by. A full-width hero video or a carousel of five large images can hold up the whole first impression. Ask what the visitor needs to see first. Usually it is a heading, a sentence and one image. Load those with priority and let the rest arrive as they scroll.
Make it a habit, not a project
None of this needs a performance team. It needs someone to open the Network panel once a month, sort by size, and ask why the biggest things are there. It needs the person uploading images to resize them first. It needs a moment's thought before adding another script.
We do this on our own sites and on the WordPress sites we look after through WPfolk, and the list above is most of what we actually do. It is not clever. It is just done regularly, which is what keeps a site fast for the visitor on an ordinary phone and an ordinary connection, which is nearly everyone.
